# HG changeset patch
# User ewendeli
# Date 1359927837 -3600
# Node ID b5cb079ecaa4006688e18113b13e0277e2b66138
# Parent 20b605466ccb1b3725eb25314d9e8782199630c5# Parent 77443715ec55cf6fa0ed04d39a273719afcc9c2a
Merge
diff -r 77443715ec55 -r b5cb079ecaa4 .hgtags
--- a/.hgtags Mon Nov 05 17:03:33 2012 -0500
+++ b/.hgtags Sun Feb 03 22:43:57 2013 +0100
@@ -288,3 +288,27 @@
4547dc71db765276e027b0c2780b724bae0a07d3 jdk8-b61
d0337c31c8be7716369b4e7c3bd5f352983c6a06 hs25-b06
dccd40de8db1fa96f186e6179907818d75320440 jdk8-b62
+dc16fe422c535ecd4e9f80fb814a1bb9704da6f5 hs25-b07
+acabb5c282f59be7e3238920b2ea06b684ab68f7 jdk8-b63
+8cb93eadfb6dcab88d91b8e2cd3e0e07d0ac4048 hs25-b08
+5920f72e799c8133d1066c4a62fa1fafcb729966 jdk8-b64
+b4ee7b773144a88af8b6b92e4384dea82cb948d8 hs25-b09
+0f7290a03b24bd562583fa325d3566c21c51fb94 jdk8-b65
+cfc5309f03b7bd6c1567618b63cf1fc74c0f2a8f hs25-b10
+01684f7fee1b86222be69bc23841ec2a4416696c jdk8-b66
+b61d9c88b759d1594b8af1655598e8fa00393672 hs25-b11
+25bdce771bb3a7ae9825261a284d292cda700122 jdk8-b67
+a35a72dd2e1255239d31f796f9f693e49b36bc9f hs25-b12
+121aa71316af6cd877bf455e775fa3fdbcdd4b65 jdk8-b68
+b6c9c0109a608eedbb6b868d260952990e3c91fe hs25-b13
+cb8a4e04bc8c104de8a2f67463c7e31232bf8d68 jdk8-b69
+990bbd393c239d95310ccc38094e57923bbf1d4a hs25-b14
+e94068d4ff52849c8aa0786a53a59b63d1312a39 jdk8-b70
+0847210f85480bf3848dc90bc2ab23c0a4791b55 jdk8-b71
+d5cb5830f570d1304ea4b196dde672a291b55f29 jdk8-b72
+1e129851479e4f5df439109fca2c7be1f1613522 hs25-b15
+11619f33cd683c2f1d6ef72f1c6ff3dacf5a9f1c jdk8-b73
+70c89bd6b895a10d25ca70e08093c09ff2005fda hs25-b16
+1a3e54283c54aaa8b3437813e8507fbdc966e5b6 jdk8-b74
+b4391649e91ea8d37f66317a03d6d2573a93d10d hs25-b17
+6778d0b1659323a506ca47600ca29a9d9f8b383d jdk8-b75
diff -r 77443715ec55 -r b5cb079ecaa4 agent/doc/c2replay.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/agent/doc/c2replay.html Sun Feb 03 22:43:57 2013 +0100
@@ -0,0 +1,41 @@
+
+
+
+C2 Replay
+
+
+
+
+C2 compiler replay
+
+The C2 compiler replay is a function to repeat the compiling process from a crashed java process in compiled method
+This function only exists in debug version of VM
+
+Usage
+
+First, use SA to attach to the core file, if suceeded, do
+ clhsdb>dumpreplaydata | -a | [> replay.txt]
+ create file replay.txt, address is address of Method, or nmethod(CodeBlob)
+ clhsdb>buildreplayjars [all | boot | app]
+ create files:
+ all:
+ app.jar, boot.jar
+ boot:
+ boot.jar
+ app:
+ app.jar
+ exit SA now.
+Second, use the obtained replay text file, replay.txt and jar files, app.jar and boot.jar, using debug version of java
+ java -Xbootclasspath/p:boot.jar -cp app.jar -XX:ReplayDataFile= -XX:+ReplayCompiles ....
+ This will replay the compiling process.
+
+ With ReplayCompiles, the replay will recompile all the methods in app.jar, and in boot.jar to emulate the process in java app.
+
+notes:
+ 1) Most time, we don't need the boot.jar which is the classes loaded from JDK. It will be only modified when an agent(JVMDI) is running and modifies the classes.
+ 2) If encounter error as "" not found, that means the SA is using a VMStructs which is different from the one with corefile. In this case, SA has a utility tool vmstructsdump which is located at agent/src/os//proc/
+
+ Use this tool to dump VM type library:
+ vmstructsdump libjvm.so > .db
+
+ set env SA_TYPEDB=.db (refer different shell for set envs)
diff -r 77443715ec55 -r b5cb079ecaa4 agent/doc/clhsdb.html
--- a/agent/doc/clhsdb.html Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/doc/clhsdb.html Sun Feb 03 22:43:57 2013 +0100
@@ -37,12 +37,19 @@
Available commands:
assert true | false turn on/off asserts in SA code
attach pid | exec core attach SA to a process or core
+ buildreplayjars [all | boot | app] build jars for replay, boot.jar for bootclasses, app.jar for application classes
class name find a Java class from debuggee and print oop
classes print all loaded Java classes with Klass*
detach detach SA from current target
dis address [ length ] disassemble (sparc/x86) specified number of instructions from given address
+ dissemble address disassemble nmethod
+ dumpcfg -a | id Dump the PhaseCFG for every compiler thread that has one live
dumpclass { address | name } [ directory ] dump .class file for given Klass* or class name
+ dumpcodecache dump codecache contents
dumpheap [ file ] dump heap in hprof binary format
+ dumpideal -a | id dump ideal graph like debug flag -XX:+PrintIdeal
+ dumpilt -a | id dump inline tree for C2 compilation
+ dumpreplaydata | -a | [>replay.txt] dump replay data into a file
echo [ true | false ] turn on/off command echo mode
examine [ address/count ] | [ address,address] show contents of memory from given address
field [ type [ name fieldtype isStatic offset address ] ] print info about a field of HotSpot type
@@ -51,29 +58,35 @@
help [ command ] print help message for all commands or just given command
history show command history. usual !command-number syntax works.
inspect expression inspect a given oop
+ intConstant [ name [ value ] ] print out hotspot integer constant(s)
jdis address show bytecode disassembly of a given Method*
jhisto show Java heap histogram
jseval script evaluate a given string as JavaScript code
jsload file load and evaluate a JavaScript file
jstack [-v] show Java stack trace of all Java threads. -v is verbose mode
livenmethods show all live nmethods
+ longConstant [ name [ value ] ] print out hotspot long constant(s)s
mem address [ length ] show contents of memory -- also shows closest ELF/COFF symbol if found
pmap show Solaris pmap-like output
print expression print given Klass*, Method* or arbitrary address
printas type expression print given address as given HotSpot type. eg. print JavaThread <address>
+ printmdo -a | expression print method data oop
printstatics [ type ] print static fields of given HotSpot type (or all types if none specified)
pstack [-v] show mixed mode stack trace for all Java, non-Java threads. -v is verbose mode
quit quit CLHSDB tool
reattach detach and re-attach SA to current target
+ revptrs find liveness of oops
scanoops start end [ type ] scan a Oop from given start to end address
search [ heap | codecache | threads ] value search a value in heap or codecache or threads
source filename load and execute CLHSDB commands from given file
symbol name show address of a given ELF/COFF symbol
sysprops show all Java System properties
+ thread id show thread of id
threads show all Java threads
tokenize ...
type [ type [ name super isOop isInteger isUnsigned size ] ] show info. on HotSpot type
universe print gc universe
+ vmstructsdump dump hotspot type library in text
verbose true | false turn on/off verbose mode
versioncheck [ true | false ] turn on/off debuggee VM version check
whatis address print info about any arbitrary address
@@ -114,5 +127,11 @@
+C2 Compilation Replay
+
+When a java process crashes in compiled method, usually a core file is saved.
+The C2 replay function can reproduce the compiling process in the core.
+c2replay.html
+
diff -r 77443715ec55 -r b5cb079ecaa4 agent/doc/index.html
--- a/agent/doc/index.html Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/doc/index.html Sun Feb 03 22:43:57 2013 +0100
@@ -220,6 +220,12 @@
+
C2 Compilation Replay
+
+When a java process crashes in compiled method, usually a core file is saved.
+The C2 replay function can reproduce the compiling process in the core.
+c2replay.html
+
Debugging transported core dumps
When a core dump is moved from the machine where it was produced to a
diff -r 77443715ec55 -r b5cb079ecaa4 agent/make/Makefile
--- a/agent/make/Makefile Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/make/Makefile Sun Feb 03 22:43:57 2013 +0100
@@ -58,10 +58,8 @@
sun.jvm.hotspot.debugger.cdbg.basic.amd64 \
sun.jvm.hotspot.debugger.cdbg.basic.x86 \
sun.jvm.hotspot.debugger.dummy \
-sun.jvm.hotspot.debugger.ia64 \
sun.jvm.hotspot.debugger.linux \
sun.jvm.hotspot.debugger.linux.amd64 \
-sun.jvm.hotspot.debugger.linux.ia64 \
sun.jvm.hotspot.debugger.linux.x86 \
sun.jvm.hotspot.debugger.posix \
sun.jvm.hotspot.debugger.posix.elf \
@@ -77,7 +75,6 @@
sun.jvm.hotspot.debugger.win32.coff \
sun.jvm.hotspot.debugger.windbg \
sun.jvm.hotspot.debugger.windbg.amd64 \
-sun.jvm.hotspot.debugger.windbg.ia64 \
sun.jvm.hotspot.debugger.windbg.x86 \
sun.jvm.hotspot.debugger.x86 \
sun.jvm.hotspot.gc_implementation \
@@ -97,10 +94,8 @@
sun.jvm.hotspot.runtime.bsd \
sun.jvm.hotspot.runtime.bsd_amd64 \
sun.jvm.hotspot.runtime.bsd_x86 \
-sun.jvm.hotspot.runtime.ia64 \
sun.jvm.hotspot.runtime.linux \
sun.jvm.hotspot.runtime.linux_amd64 \
-sun.jvm.hotspot.runtime.linux_ia64 \
sun.jvm.hotspot.runtime.linux_sparc \
sun.jvm.hotspot.runtime.linux_x86 \
sun.jvm.hotspot.runtime.posix \
@@ -109,7 +104,6 @@
sun.jvm.hotspot.runtime.solaris_x86 \
sun.jvm.hotspot.runtime.sparc \
sun.jvm.hotspot.runtime.win32_amd64 \
-sun.jvm.hotspot.runtime.win32_ia64 \
sun.jvm.hotspot.runtime.win32_x86 \
sun.jvm.hotspot.runtime.x86 \
sun.jvm.hotspot.tools \
@@ -152,7 +146,6 @@
sun/jvm/hotspot/debugger/cdbg/basic/amd64/*.java \
sun/jvm/hotspot/debugger/cdbg/basic/x86/*.java \
sun/jvm/hotspot/debugger/dummy/*.java \
-sun/jvm/hotspot/debugger/ia64/*.java \
sun/jvm/hotspot/debugger/linux/*.java \
sun/jvm/hotspot/debugger/linux/x86/*.java \
sun/jvm/hotspot/debugger/posix/*.java \
@@ -168,7 +161,6 @@
sun/jvm/hotspot/debugger/sparc/*.java \
sun/jvm/hotspot/debugger/win32/coff/*.java \
sun/jvm/hotspot/debugger/windbg/*.java \
-sun/jvm/hotspot/debugger/windbg/ia64/*.java \
sun/jvm/hotspot/debugger/windbg/x86/*.java \
sun/jvm/hotspot/debugger/x86/*.java \
sun/jvm/hotspot/gc_implementation/g1/*.java \
@@ -186,10 +178,8 @@
sun/jvm/hotspot/runtime/bsd/*.java \
sun/jvm/hotspot/runtime/bsd_amd64/*.java \
sun/jvm/hotspot/runtime/bsd_x86/*.java \
-sun/jvm/hotspot/runtime/ia64/*.java \
sun/jvm/hotspot/runtime/linux/*.java \
sun/jvm/hotspot/runtime/linux_amd64/*.java \
-sun/jvm/hotspot/runtime/linux_ia64/*.java \
sun/jvm/hotspot/runtime/linux_sparc/*.java \
sun/jvm/hotspot/runtime/linux_x86/*.java \
sun/jvm/hotspot/runtime/posix/*.java \
@@ -198,7 +188,6 @@
sun/jvm/hotspot/runtime/solaris_x86/*.java \
sun/jvm/hotspot/runtime/sparc/*.java \
sun/jvm/hotspot/runtime/win32_amd64/*.java \
-sun/jvm/hotspot/runtime/win32_ia64/*.java \
sun/jvm/hotspot/runtime/win32_x86/*.java \
sun/jvm/hotspot/runtime/x86/*.java \
sun/jvm/hotspot/tools/*.java \
@@ -258,6 +247,7 @@
SA_PROPERTIES = $(OUTPUT_DIR)/sa.properties
JAVAC = $(JDK_HOME)/bin/javac
+JAVA = $(JDK_HOME)/bin/java
JAVADOC = $(JDK_HOME)/bin/javadoc
RMIC = $(JDK_HOME)/bin/rmic
@@ -298,7 +288,7 @@
.PHONY: natives
natives:
- cd ../src/os/`java -classpath $(OUTPUT_DIR) sun.jvm.hotspot.utilities.PlatformInfo`; $(MAKE) all
+ cd ../src/os/`$(JAVA) -classpath $(OUTPUT_DIR) sun.jvm.hotspot.utilities.PlatformInfo`; $(MAKE) all
.PHONY: sa-jdi.jar
sa-jdi.jar:
@@ -323,5 +313,5 @@
clean::
rm -rf filelist
- cd ../src/os/`java -classpath $(OUTPUT_DIR) sun.jvm.hotspot.utilities.PlatformInfo`; $(MAKE) clean
+ cd ../src/os/`$(JAVA) -classpath $(OUTPUT_DIR) sun.jvm.hotspot.utilities.PlatformInfo`; $(MAKE) clean
rm -rf $(BUILD_DIR)/*
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java
--- a/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Sun Feb 03 22:43:57 2013 +0100
@@ -33,6 +33,7 @@
import sun.jvm.hotspot.types.Field;
import sun.jvm.hotspot.HotSpotTypeDataBase;
import sun.jvm.hotspot.types.basic.BasicType;
+import sun.jvm.hotspot.types.basic.BasicTypeDataBase;
import sun.jvm.hotspot.types.CIntegerType;
import sun.jvm.hotspot.code.*;
import sun.jvm.hotspot.compiler.*;
@@ -448,6 +449,112 @@
}
}
},
+ new Command("dumpreplaydata", "dumpreplaydata {
| -a | }", false) {
+ // This is used to dump replay data from ciInstanceKlass, ciMethodData etc
+ // default file name is replay.txt, also if java crashes in compiler
+ // thread, this file will be dumped in error processing.
+ public void doit(Tokens t) {
+ if (t.countTokens() != 1) {
+ usage();
+ return;
+ }
+ String name = t.nextToken();
+ Address a = null;
+ try {
+ a = VM.getVM().getDebugger().parseAddress(name);
+ } catch (NumberFormatException e) { }
+ if (a != null) {
+ // only nmethod, Method, MethodData and InstanceKlass needed to
+ // dump replay data
+
+ CodeBlob cb = VM.getVM().getCodeCache().findBlob(a);
+ if (cb != null && (cb instanceof NMethod)) {
+ ((NMethod)cb).dumpReplayData(out);
+ return;
+ }
+ // assume it is Metadata
+ Metadata meta = Metadata.instantiateWrapperFor(a);
+ if (meta != null) {
+ meta.dumpReplayData(out);
+ } else {
+ usage();
+ return;
+ }
+ }
+ // Not an address
+ boolean all = name.equals("-a");
+ Threads threads = VM.getVM().getThreads();
+ for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ thread.printThreadIDOn(new PrintStream(bos));
+ if (all || bos.toString().equals(name)) {
+ if (thread instanceof CompilerThread) {
+ CompilerThread ct = (CompilerThread)thread;
+ ciEnv env = ct.env();
+ if (env != null) {
+ env.dumpReplayData(out);
+ }
+ }
+ }
+ }
+ }
+ },
+ new Command("buildreplayjars", "buildreplayjars [ all | app | boot ] | [ prefix ]", false) {
+ // This is used to dump jar files of all the classes
+ // loaded in the core. Everything on the bootclasspath
+ // will go in boot.jar and everything else will go in
+ // app.jar. Then the classes can be loaded by the replay
+ // jvm using -Xbootclasspath/p:boot.jar -cp app.jar. boot.jar usually
+ // not needed, unless changed by jvmti.
+ public void doit(Tokens t) {
+ int tcount = t.countTokens();
+ if (tcount > 2) {
+ usage();
+ return;
+ }
+ try {
+ String prefix = "";
+ String option = "all"; // default
+ switch(tcount) {
+ case 0:
+ break;
+ case 1:
+ option = t.nextToken();
+ if (!option.equalsIgnoreCase("all") && !option.equalsIgnoreCase("app") &&
+ !option.equalsIgnoreCase("root")) {
+ prefix = option;
+ option = "all";
+ }
+ break;
+ case 2:
+ option = t.nextToken();
+ prefix = t.nextToken();
+ break;
+ default:
+ usage();
+ return;
+ }
+ if (!option.equalsIgnoreCase("all") && !option.equalsIgnoreCase("app") &&
+ !option.equalsIgnoreCase("boot")) {
+ usage();
+ return;
+ }
+ ClassDump cd = new ClassDump();
+ if (option.equalsIgnoreCase("all") || option.equalsIgnoreCase("boot")) {
+ cd.setClassFilter(new BootFilter());
+ cd.setJarOutput(prefix + "boot.jar");
+ cd.run();
+ }
+ if (option.equalsIgnoreCase("all") || option.equalsIgnoreCase("app")) {
+ cd.setClassFilter(new NonBootFilter());
+ cd.setJarOutput(prefix + "app.jar");
+ cd.run();
+ }
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ }
+ }
+ },
new Command("findpc", "findpc address", false) {
public void doit(Tokens t) {
if (t.countTokens() != 1) {
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciArrayKlass.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciArrayKlass.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciArrayKlass.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciBaseObject.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
@@ -50,4 +50,8 @@
public ciBaseObject(Address addr) {
super(addr);
}
+
+ public void dumpReplayData(PrintStream out) {
+ out.println("# Unknown ci type " + getAddress().getAddressAt(0));
+ }
}
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciConstant.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciConstant.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciConstant.java Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2012, 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
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
@@ -60,4 +60,8 @@
public ciConstant(Address addr) {
super(addr);
}
+
+ public void dumpReplayData(PrintStream out) {
+ // Nothing to be done
+ }
}
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciEnv.java Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2012, 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
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
@@ -74,4 +74,29 @@
public CompileTask task() {
return new CompileTask(taskField.getValue(this.getAddress()));
}
+
+ public void dumpReplayData(PrintStream out) {
+ out.println("JvmtiExport can_access_local_variables " +
+ (JvmtiExport.canAccessLocalVariables() ? '1' : '0'));
+ out.println("JvmtiExport can_hotswap_or_post_breakpoint " +
+ (JvmtiExport.canHotswapOrPostBreakpoint() ? '1' : '0'));
+ out.println("JvmtiExport can_post_on_exceptions " +
+ (JvmtiExport.canPostOnExceptions() ? '1' : '0'));
+
+ GrowableArray objects = factory().objects();
+ out.println("# " + objects.length() + " ciObject found");
+ for (int i = 0; i < objects.length(); i++) {
+ ciMetadata o = objects.at(i);
+ out.println("# ciMetadata" + i + " @ " + o);
+ o.dumpReplayData(out);
+ }
+ CompileTask task = task();
+ Method method = task.method();
+ int entryBci = task.osrBci();
+ Klass holder = method.getMethodHolder();
+ out.println("compile " + holder.getName().asString() + " " +
+ OopUtilities.escapeString(method.getName().asString()) + " " +
+ method.getSignature().asString() + " " +
+ entryBci);
+ }
}
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciField.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciField.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciField.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciInstance.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciInstance.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciInstance.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciInstanceKlass.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
@@ -80,4 +80,84 @@
public boolean isInitialized() {
return initState() == CLASS_STATE_FULLY_INITIALIZED;
}
+
+ public void dumpReplayData(PrintStream out) {
+ InstanceKlass ik = (InstanceKlass)getMetadata();
+ ConstantPool cp = ik.getConstants();
+
+ // Try to record related loaded classes
+ Klass sub = ik.getSubklassKlass();
+ while (sub != null) {
+ if (sub instanceof InstanceKlass) {
+ out.println("instanceKlass " + sub.getName().asString());
+ }
+ sub = sub.getNextSiblingKlass();
+ }
+
+ final int length = (int) cp.getLength();
+ out.print("ciInstanceKlass " + name() + " " + (isLinked() ? 1 : 0) + " " + (isInitialized() ? 1 : 0) + " " + length);
+ for (int index = 1; index < length; index++) {
+ out.print(" " + cp.getTags().at(index));
+ }
+ out.println();
+ if (isInitialized()) {
+ Field[] staticFields = ik.getStaticFields();
+ for (int i = 0; i < staticFields.length; i++) {
+ Field f = staticFields[i];
+ Oop mirror = ik.getJavaMirror();
+ if (f.isFinal() && !f.hasInitialValue()) {
+ out.print("staticfield " + name() + " " +
+ OopUtilities.escapeString(f.getID().getName()) + " " +
+ f.getFieldType().getSignature().asString() + " ");
+ if (f instanceof ByteField) {
+ ByteField bf = (ByteField)f;
+ out.println(bf.getValue(mirror));
+ } else if (f instanceof BooleanField) {
+ BooleanField bf = (BooleanField)f;
+ out.println(bf.getValue(mirror) ? 1 : 0);
+ } else if (f instanceof ShortField) {
+ ShortField bf = (ShortField)f;
+ out.println(bf.getValue(mirror));
+ } else if (f instanceof CharField) {
+ CharField bf = (CharField)f;
+ out.println(bf.getValue(mirror) & 0xffff);
+ } else if (f instanceof IntField) {
+ IntField bf = (IntField)f;
+ out.println(bf.getValue(mirror));
+ } else if (f instanceof LongField) {
+ LongField bf = (LongField)f;
+ out.println(bf.getValue(mirror));
+ } else if (f instanceof FloatField) {
+ FloatField bf = (FloatField)f;
+ out.println(Float.floatToRawIntBits(bf.getValue(mirror)));
+ } else if (f instanceof DoubleField) {
+ DoubleField bf = (DoubleField)f;
+ out.println(Double.doubleToRawLongBits(bf.getValue(mirror)));
+ } else if (f instanceof OopField) {
+ OopField bf = (OopField)f;
+ Oop value = bf.getValue(mirror);
+ if (value == null) {
+ out.println("null");
+ } else if (value.isInstance()) {
+ Instance inst = (Instance)value;
+ if (inst.isA(SystemDictionary.getStringKlass())) {
+ out.println("\"" + OopUtilities.stringOopToEscapedString(inst) + "\"");
+ } else {
+ out.println(inst.getKlass().getName().asString());
+ }
+ } else if (value.isObjArray()) {
+ ObjArray oa = (ObjArray)value;
+ Klass ek = (ObjArrayKlass)oa.getKlass();
+ out.println(oa.getLength() + " " + ek.getName().asString());
+ } else if (value.isTypeArray()) {
+ TypeArray ta = (TypeArray)value;
+ out.println(ta.getLength());
+ } else {
+ out.println(value);
+ }
+ }
+ }
+ }
+ }
+ }
}
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciKlass.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciKlass.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciKlass.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciMetadata.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciMetadata.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciMetadata.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciMethod.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethod.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethod.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
@@ -88,4 +88,19 @@
st.printf(" %s::%s", method.getMethodHolder().getName().asString().replace('/', '.'),
method.getName().asString());
}
+
+ public void dumpReplayData(PrintStream out) {
+ Method method = (Method)getMetadata();
+ NMethod nm = method.getNativeMethod();
+ Klass holder = method.getMethodHolder();
+ out.println("ciMethod " +
+ holder.getName().asString() + " " +
+ OopUtilities.escapeString(method.getName().asString()) + " " +
+ method.getSignature().asString() + " " +
+ method.getInvocationCounter() + " " +
+ method.getBackedgeCounter() + " " +
+ interpreterInvocationCount() + " " +
+ interpreterThrowoutCount() + " " +
+ instructionsSize());
+ }
}
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciMethodData.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethodData.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciMethodData.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
@@ -174,4 +174,52 @@
}
}
+ public void dumpReplayData(PrintStream out) {
+ MethodData mdo = (MethodData)getMetadata();
+ Method method = mdo.getMethod();
+ Klass holder = method.getMethodHolder();
+ out.print("ciMethodData " +
+ holder.getName().asString() + " " +
+ OopUtilities.escapeString(method.getName().asString()) + " " +
+ method.getSignature().asString() + " " +
+ state() + " " + currentMileage());
+ byte[] orig = orig();
+ out.print(" orig " + orig.length);
+ for (int i = 0; i < orig.length; i++) {
+ out.print(" " + (orig[i] & 0xff));
+ }
+
+ long[] data = data();
+ out.print(" data " + data.length);
+ for (int i = 0; i < data.length; i++) {
+ out.print(" 0x" + Long.toHexString(data[i]));
+ }
+ int count = 0;
+ for (int round = 0; round < 2; round++) {
+ if (round == 1) out.print(" oops " + count);
+ ProfileData pdata = firstData();
+ for ( ; isValid(pdata); pdata = nextData(pdata)) {
+ if (pdata instanceof ciReceiverTypeData) {
+ ciReceiverTypeData vdata = (ciReceiverTypeData)pdata;
+ for (int i = 0; i < vdata.rowLimit(); i++) {
+ ciKlass k = vdata.receiverAt(i);
+ if (k != null) {
+ if (round == 0) count++;
+ else out.print(" " + ((vdata.dp() + vdata.cellOffset(vdata.receiverCellIndex(i))) / MethodData.cellSize) + " " + k.name());
+ }
+ }
+ } else if (pdata instanceof ciVirtualCallData) {
+ ciVirtualCallData vdata = (ciVirtualCallData)pdata;
+ for (int i = 0; i < vdata.rowLimit(); i++) {
+ ciKlass k = vdata.receiverAt(i);
+ if (k != null) {
+ if (round == 0) count++;
+ else out.print(" " + ((vdata.dp() + vdata.cellOffset(vdata.receiverCellIndex(i))) / MethodData.cellSize + " " + k.name()));
+ }
+ }
+ }
+ }
+ }
+ out.println();
+ }
}
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciObjArrayKlass.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciObjArrayKlass.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciObjArrayKlass.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciObject.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciObject.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciObject.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciObjectFactory.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciObjectFactory.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciObjectFactory.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciReceiverTypeData.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciReceiverTypeData.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciReceiverTypeData.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciSymbol.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciSymbol.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciSymbol.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciType.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciType.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciType.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciTypeArrayKlass.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciTypeArrayKlass.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciTypeArrayKlass.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/ci/ciVirtualCallData.java
--- a/agent/src/share/classes/sun/jvm/hotspot/ci/ciVirtualCallData.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/ci/ciVirtualCallData.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/classfile/ClassLoaderData.java
--- a/agent/src/share/classes/sun/jvm/hotspot/classfile/ClassLoaderData.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/classfile/ClassLoaderData.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java
--- a/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/code/NMethod.java Sun Feb 03 22:43:57 2013 +0100
@@ -498,6 +498,42 @@
method.getSignature().asString();
}
+ public void dumpReplayData(PrintStream out) {
+ HashMap h = new HashMap();
+ for (int i = 1; i < getMetadataLength(); i++) {
+ Metadata meta = Metadata.instantiateWrapperFor(getMetadataAt(i));
+ System.err.println(meta);
+ if (h.get(meta) != null) continue;
+ h.put(meta, meta);
+ if (meta instanceof InstanceKlass) {
+ ((InstanceKlass)meta).dumpReplayData(out);
+ } else if (meta instanceof Method) {
+ ((Method)meta).dumpReplayData(out);
+ MethodData mdo = ((Method)meta).getMethodData();
+ if (mdo != null) {
+ mdo.dumpReplayData(out);
+ }
+ }
+ }
+ Method method = getMethod();
+ if (h.get(method) == null) {
+ method.dumpReplayData(out);
+ MethodData mdo = method.getMethodData();
+ if (mdo != null) {
+ mdo.dumpReplayData(out);
+ }
+ }
+ if (h.get(method.getMethodHolder()) == null) {
+ ((InstanceKlass)method.getMethodHolder()).dumpReplayData(out);
+ }
+ Klass holder = method.getMethodHolder();
+ out.println("compile " + holder.getName().asString() + " " +
+ OopUtilities.escapeString(method.getName().asString()) + " " +
+ method.getSignature().asString() + " " +
+ getEntryBCI());
+
+ }
+
//--------------------------------------------------------------------------------
// Internals only below this point
//
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java
--- a/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/compiler/CompileTask.java Sun Feb 03 22:43:57 2013 +0100
@@ -56,7 +56,7 @@
}
public Method method() {
- Address oh = methodField.getValue(getAddress()).getAddressAt(0);
+ Address oh = methodField.getValue(getAddress());
return (Method)Metadata.instantiateWrapperFor(oh);
}
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java
--- a/agent/src/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java Sun Feb 03 22:43:57 2013 +0100
@@ -272,9 +272,10 @@
public static final int _fast_aldc = 229;
public static final int _fast_aldc_w = 230;
public static final int _return_register_finalizer = 231;
- public static final int _shouldnotreachhere = 232; // For debugging
+ public static final int _invokehandle = 232;
+ public static final int _shouldnotreachhere = 233; // For debugging
- public static final int number_of_codes = 233;
+ public static final int number_of_codes = 234;
// Flag bits derived from format strings, can_trap, can_rewrite, etc.:
// semantic flags:
@@ -787,20 +788,22 @@
def(_fast_aaccess_0 , "fast_aaccess_0" , "b_JJ" , null , BasicType.getTObject() , 1, true , _aload_0 );
def(_fast_faccess_0 , "fast_faccess_0" , "b_JJ" , null , BasicType.getTObject() , 1, true , _aload_0 );
- def(_fast_iload , "fast_iload" , "bi" , null , BasicType.getTInt() , 1, false, _iload);
- def(_fast_iload2 , "fast_iload2" , "bi_i" , null , BasicType.getTInt() , 2, false, _iload);
- def(_fast_icaload , "fast_icaload" , "bi_" , null , BasicType.getTInt() , 0, false, _iload);
+ def(_fast_iload , "fast_iload" , "bi" , null , BasicType.getTInt() , 1, false, _iload );
+ def(_fast_iload2 , "fast_iload2" , "bi_i" , null , BasicType.getTInt() , 2, false, _iload );
+ def(_fast_icaload , "fast_icaload" , "bi_" , null , BasicType.getTInt() , 0, false, _iload );
// Faster method invocation.
- def(_fast_invokevfinal , "fast_invokevfinal" , "bJJ" , null , BasicType.getTIllegal(), -1, true, _invokevirtual);
+ def(_fast_invokevfinal , "fast_invokevfinal" , "bJJ" , null , BasicType.getTIllegal(), -1, true, _invokevirtual );
def(_fast_linearswitch , "fast_linearswitch" , "" , null , BasicType.getTVoid() , -1, false, _lookupswitch );
def(_fast_binaryswitch , "fast_binaryswitch" , "" , null , BasicType.getTVoid() , -1, false, _lookupswitch );
+ def(_fast_aldc , "fast_aldc" , "bj" , null , BasicType.getTObject(), 1, true, _ldc );
+ def(_fast_aldc_w , "fast_aldc_w" , "bJJ" , null , BasicType.getTObject(), 1, true, _ldc_w );
def(_return_register_finalizer, "return_register_finalizer", "b" , null , BasicType.getTVoid() , 0, true, _return );
- def(_fast_aldc , "fast_aldc" , "bj" , null , BasicType.getTObject(), 1, true, _ldc );
- def(_fast_aldc_w , "fast_aldc_w" , "bJJ" , null , BasicType.getTObject(), 1, true, _ldc_w );
+ // special handling of signature-polymorphic methods
+ def(_invokehandle , "invokehandle" , "bJJ" , null , BasicType.getTIllegal(), -1, true, _invokevirtual );
def(_shouldnotreachhere , "_shouldnotreachhere" , "b" , null , BasicType.getTVoid() , 0, false);
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/memory/LoaderConstraintTable.java
--- a/agent/src/share/classes/sun/jvm/hotspot/memory/LoaderConstraintTable.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/memory/LoaderConstraintTable.java Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2012, 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
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/oops/BitData.java
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/BitData.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/BitData.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/ConstMethod.java Sun Feb 03 22:43:57 2013 +0100
@@ -48,6 +48,7 @@
private static int HAS_CHECKED_EXCEPTIONS;
private static int HAS_LOCALVARIABLE_TABLE;
private static int HAS_EXCEPTION_TABLE;
+ private static int HAS_GENERIC_SIGNATURE;
private static synchronized void initialize(TypeDataBase db) throws WrongTypeException {
Type type = db.lookupType("ConstMethod");
@@ -60,13 +61,16 @@
HAS_CHECKED_EXCEPTIONS = db.lookupIntConstant("ConstMethod::_has_checked_exceptions").intValue();
HAS_LOCALVARIABLE_TABLE = db.lookupIntConstant("ConstMethod::_has_localvariable_table").intValue();
HAS_EXCEPTION_TABLE = db.lookupIntConstant("ConstMethod::_has_exception_table").intValue();
+ HAS_GENERIC_SIGNATURE = db.lookupIntConstant("ConstMethod::_has_generic_signature").intValue();
// Size of Java bytecodes allocated immediately after ConstMethod*.
codeSize = new CIntField(type.getCIntegerField("_code_size"), 0);
nameIndex = new CIntField(type.getCIntegerField("_name_index"), 0);
signatureIndex = new CIntField(type.getCIntegerField("_signature_index"), 0);
- genericSignatureIndex = new CIntField(type.getCIntegerField("_generic_signature_index"),0);
idnum = new CIntField(type.getCIntegerField("_method_idnum"), 0);
+ maxStack = new CIntField(type.getCIntegerField("_max_stack"), 0);
+ maxLocals = new CIntField(type.getCIntegerField("_max_locals"), 0);
+ sizeOfParameters = new CIntField(type.getCIntegerField("_size_of_parameters"), 0);
// start of byte code
bytecodeOffset = type.getSize();
@@ -92,8 +96,10 @@
private static CIntField codeSize;
private static CIntField nameIndex;
private static CIntField signatureIndex;
- private static CIntField genericSignatureIndex;
private static CIntField idnum;
+ private static CIntField maxStack;
+ private static CIntField maxLocals;
+ private static CIntField sizeOfParameters;
// start of bytecode
private static long bytecodeOffset;
@@ -134,13 +140,29 @@
}
public long getGenericSignatureIndex() {
- return genericSignatureIndex.getValue(this);
+ if (hasGenericSignature()) {
+ return getAddress().getCIntegerAt(offsetOfGenericSignatureIndex(), 2, true);
+ } else {
+ return 0;
+ }
}
public long getIdNum() {
return idnum.getValue(this);
}
+ public long getMaxStack() {
+ return maxStack.getValue(this);
+ }
+
+ public long getMaxLocals() {
+ return maxLocals.getValue(this);
+ }
+
+ public long getSizeOfParameters() {
+ return sizeOfParameters.getValue(this);
+ }
+
public Symbol getName() {
return getMethod().getName();
}
@@ -235,8 +257,10 @@
visitor.doCInt(codeSize, true);
visitor.doCInt(nameIndex, true);
visitor.doCInt(signatureIndex, true);
- visitor.doCInt(genericSignatureIndex, true);
visitor.doCInt(codeSize, true);
+ visitor.doCInt(maxStack, true);
+ visitor.doCInt(maxLocals, true);
+ visitor.doCInt(sizeOfParameters, true);
}
// Accessors
@@ -353,6 +377,10 @@
return ret;
}
+ private boolean hasGenericSignature() {
+ return (getFlags() & HAS_GENERIC_SIGNATURE) != 0;
+ }
+
//---------------------------------------------------------------------------
// Internals only below this point
@@ -377,8 +405,14 @@
return getSize() * VM.getVM().getObjectHeap().getOopSize() - 2;
}
+ // Offset of the generic signature index
+ private long offsetOfGenericSignatureIndex() {
+ return offsetOfLastU2Element();
+ }
+
private long offsetOfCheckedExceptionsLength() {
- return offsetOfLastU2Element();
+ return hasGenericSignature() ? offsetOfLastU2Element() - 2 :
+ offsetOfLastU2Element();
}
private int getCheckedExceptionsLength() {
@@ -431,7 +465,8 @@
} else if (hasCheckedExceptions()) {
return offsetOfCheckedExceptions() - 2;
} else {
- return offsetOfLastU2Element();
+ return hasGenericSignature() ? offsetOfLastU2Element() - 2 :
+ offsetOfLastU2Element();
}
}
@@ -460,7 +495,8 @@
if (hasCheckedExceptions()) {
return offsetOfCheckedExceptions() - 2;
} else {
- return offsetOfLastU2Element();
+ return hasGenericSignature() ? offsetOfLastU2Element() - 2 :
+ offsetOfLastU2Element();
}
}
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Sun Feb 03 22:43:57 2013 +0100
@@ -121,7 +121,7 @@
Address addr = cache.getValue(getAddress());
return (ConstantPoolCache) VMObjectFactory.newObject(ConstantPoolCache.class, addr);
}
- public Klass getPoolHolder() { return (Klass) poolHolder.getValue(this); }
+ public InstanceKlass getPoolHolder() { return (InstanceKlass)poolHolder.getValue(this); }
public int getLength() { return (int)length.getValue(getAddress()); }
public Oop getResolvedReferences() {
Address handle = resolvedReferences.getValue(getAddress());
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPoolCache.java Sun Feb 03 22:43:57 2013 +0100
@@ -86,7 +86,7 @@
public void printValueOn(PrintStream tty) {
- tty.print("ConstantPoolCache for " + getConstants().getPoolHolder().getName().asString());
+ tty.print("ConstantPoolCache for " + getConstants().getPoolHolder().getName().asString() + " address = " + getAddress() + " offset = " + baseOffset);
}
public int getLength() {
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/oops/Field.java
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/Field.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Field.java Sun Feb 03 22:43:57 2013 +0100
@@ -110,6 +110,8 @@
public Symbol getSignature() { return signature; }
public Symbol getGenericSignature() { return genericSignature; }
+ public boolean hasInitialValue() { return holder.getFieldInitialValueIndex(fieldIndex) != 0; }
+
//
// Following acccessors are for named, non-VM fields only
//
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/InstanceKlass.java Sun Feb 03 22:43:57 2013 +0100
@@ -52,6 +52,9 @@
private static int LOW_OFFSET;
private static int HIGH_OFFSET;
private static int FIELD_SLOTS;
+ private static short FIELDINFO_TAG_SIZE;
+ private static short FIELDINFO_TAG_MASK;
+ private static short FIELDINFO_TAG_OFFSET;
// ClassState constants
private static int CLASS_STATE_ALLOCATED;
@@ -96,9 +99,13 @@
NAME_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::name_index_offset").intValue();
SIGNATURE_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::signature_index_offset").intValue();
INITVAL_INDEX_OFFSET = db.lookupIntConstant("FieldInfo::initval_index_offset").intValue();
- LOW_OFFSET = db.lookupIntConstant("FieldInfo::low_offset").intValue();
- HIGH_OFFSET = db.lookupIntConstant("FieldInfo::high_offset").intValue();
+ LOW_OFFSET = db.lookupIntConstant("FieldInfo::low_packed_offset").intValue();
+ HIGH_OFFSET = db.lookupIntConstant("FieldInfo::high_packed_offset").intValue();
FIELD_SLOTS = db.lookupIntConstant("FieldInfo::field_slots").intValue();
+ FIELDINFO_TAG_SIZE = db.lookupIntConstant("FIELDINFO_TAG_SIZE").shortValue();
+ FIELDINFO_TAG_MASK = db.lookupIntConstant("FIELDINFO_TAG_MASK").shortValue();
+ FIELDINFO_TAG_OFFSET = db.lookupIntConstant("FIELDINFO_TAG_OFFSET").shortValue();
+
// read ClassState constants
CLASS_STATE_ALLOCATED = db.lookupIntConstant("InstanceKlass::allocated").intValue();
CLASS_STATE_LOADED = db.lookupIntConstant("InstanceKlass::loaded").intValue();
@@ -278,7 +285,7 @@
}
public short getFieldGenericSignatureIndex(int index) {
- int len = getFields().length();
+ // int len = getFields().length();
int allFieldsCount = getAllFieldsCount();
int generic_signature_slot = allFieldsCount * FIELD_SLOTS;
for (int i = 0; i < allFieldsCount; i++) {
@@ -314,8 +321,12 @@
public int getFieldOffset(int index) {
U2Array fields = getFields();
- return VM.getVM().buildIntFromShorts(fields.at(index * FIELD_SLOTS + LOW_OFFSET),
- fields.at(index * FIELD_SLOTS + HIGH_OFFSET));
+ short lo = fields.at(index * FIELD_SLOTS + LOW_OFFSET);
+ short hi = fields.at(index * FIELD_SLOTS + HIGH_OFFSET);
+ if ((lo & FIELDINFO_TAG_MASK) == FIELDINFO_TAG_OFFSET) {
+ return VM.getVM().buildIntFromShorts(lo, hi) >> FIELDINFO_TAG_SIZE;
+ }
+ throw new RuntimeException("should not reach here");
}
// Accessors for declared fields
@@ -325,7 +336,7 @@
public KlassArray getTransitiveInterfaces() { return new KlassArray(transitiveInterfaces.getValue(getAddress())); }
public int getJavaFieldsCount() { return (int) javaFieldsCount.getValue(this); }
public int getAllFieldsCount() {
- int len = getFields().length();
+ int len = getFields().length();
int allFieldsCount = 0;
for (; allFieldsCount*FIELD_SLOTS < len; allFieldsCount++) {
short flags = getFieldAccessFlags(allFieldsCount);
@@ -581,6 +592,19 @@
}
}
+ public Field[] getStaticFields() {
+ U2Array fields = getFields();
+ int length = getJavaFieldsCount();
+ ArrayList result = new ArrayList();
+ for (int index = 0; index < length; index++) {
+ Field f = newField(index);
+ if (f.isStatic()) {
+ result.add(f);
+ }
+ }
+ return (Field[])result.toArray(new Field[result.size()]);
+ }
+
public void iterateNonStaticFields(OopVisitor visitor, Oop obj) {
if (getSuper() != null) {
((InstanceKlass) getSuper()).iterateNonStaticFields(visitor, obj);
@@ -979,4 +1003,84 @@
}
return -1;
}
+
+ public void dumpReplayData(PrintStream out) {
+ ConstantPool cp = getConstants();
+
+ // Try to record related loaded classes
+ Klass sub = getSubklassKlass();
+ while (sub != null) {
+ if (sub instanceof InstanceKlass) {
+ out.println("instanceKlass " + sub.getName().asString());
+ }
+ sub = sub.getNextSiblingKlass();
+ }
+
+ final int length = (int) cp.getLength();
+ out.print("ciInstanceKlass " + getName().asString() + " " + (isLinked() ? 1 : 0) + " " + (isInitialized() ? 1 : 0) + " " + length);
+ for (int index = 1; index < length; index++) {
+ out.print(" " + cp.getTags().at(index));
+ }
+ out.println();
+ if (isInitialized()) {
+ Field[] staticFields = getStaticFields();
+ for (int i = 0; i < staticFields.length; i++) {
+ Field f = staticFields[i];
+ Oop mirror = getJavaMirror();
+ if (f.isFinal() && !f.hasInitialValue()) {
+ out.print("staticfield " + getName().asString() + " " +
+ OopUtilities.escapeString(f.getID().getName()) + " " +
+ f.getFieldType().getSignature().asString() + " ");
+ if (f instanceof ByteField) {
+ ByteField bf = (ByteField)f;
+ out.println(bf.getValue(mirror));
+ } else if (f instanceof BooleanField) {
+ BooleanField bf = (BooleanField)f;
+ out.println(bf.getValue(mirror) ? 1 : 0);
+ } else if (f instanceof ShortField) {
+ ShortField bf = (ShortField)f;
+ out.println(bf.getValue(mirror));
+ } else if (f instanceof CharField) {
+ CharField bf = (CharField)f;
+ out.println(bf.getValue(mirror) & 0xffff);
+ } else if (f instanceof IntField) {
+ IntField bf = (IntField)f;
+ out.println(bf.getValue(mirror));
+ } else if (f instanceof LongField) {
+ LongField bf = (LongField)f;
+ out.println(bf.getValue(mirror));
+ } else if (f instanceof FloatField) {
+ FloatField bf = (FloatField)f;
+ out.println(Float.floatToRawIntBits(bf.getValue(mirror)));
+ } else if (f instanceof DoubleField) {
+ DoubleField bf = (DoubleField)f;
+ out.println(Double.doubleToRawLongBits(bf.getValue(mirror)));
+ } else if (f instanceof OopField) {
+ OopField bf = (OopField)f;
+
+ Oop value = bf.getValue(mirror);
+ if (value == null) {
+ out.println("null");
+ } else if (value.isInstance()) {
+ Instance inst = (Instance)value;
+ if (inst.isA(SystemDictionary.getStringKlass())) {
+ out.println("\"" + OopUtilities.stringOopToEscapedString(inst) + "\"");
+ } else {
+ out.println(inst.getKlass().getName().asString());
+ }
+ } else if (value.isObjArray()) {
+ ObjArray oa = (ObjArray)value;
+ Klass ek = (ObjArrayKlass)oa.getKlass();
+ out.println(oa.getLength() + " " + ek.getName().asString());
+ } else if (value.isTypeArray()) {
+ TypeArray ta = (TypeArray)value;
+ out.println(ta.getLength());
+ } else {
+ out.println(value);
+ }
+ }
+ }
+ }
+ }
+ }
}
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/oops/Metadata.java
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/Metadata.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Metadata.java Sun Feb 03 22:43:57 2013 +0100
@@ -79,4 +79,7 @@
}
abstract public void printValueOn(PrintStream tty);
+ public void dumpReplayData(PrintStream out) {
+ out.println("# Unknown Metadata");
+ }
}
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/oops/Method.java
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/Method.java Sun Feb 03 22:43:57 2013 +0100
@@ -50,9 +50,6 @@
constMethod = type.getAddressField("_constMethod");
methodData = type.getAddressField("_method_data");
methodSize = new CIntField(type.getCIntegerField("_method_size"), 0);
- maxStack = new CIntField(type.getCIntegerField("_max_stack"), 0);
- maxLocals = new CIntField(type.getCIntegerField("_max_locals"), 0);
- sizeOfParameters = new CIntField(type.getCIntegerField("_size_of_parameters"), 0);
accessFlags = new CIntField(type.getCIntegerField("_access_flags"), 0);
code = type.getAddressField("_code");
vtableIndex = new CIntField(type.getCIntegerField("_vtable_index"), 0);
@@ -84,9 +81,6 @@
private static AddressField constMethod;
private static AddressField methodData;
private static CIntField methodSize;
- private static CIntField maxStack;
- private static CIntField maxLocals;
- private static CIntField sizeOfParameters;
private static CIntField accessFlags;
private static CIntField vtableIndex;
private static CIntField invocationCounter;
@@ -135,9 +129,9 @@
}
/** WARNING: this is in words, not useful in this system; use getObjectSize() instead */
public long getMethodSize() { return methodSize.getValue(this); }
- public long getMaxStack() { return maxStack.getValue(this); }
- public long getMaxLocals() { return maxLocals.getValue(this); }
- public long getSizeOfParameters() { return sizeOfParameters.getValue(this); }
+ public long getMaxStack() { return getConstMethod().getMaxStack(); }
+ public long getMaxLocals() { return getConstMethod().getMaxLocals(); }
+ public long getSizeOfParameters() { return getConstMethod().getSizeOfParameters(); }
public long getNameIndex() { return getConstMethod().getNameIndex(); }
public long getSignatureIndex() { return getConstMethod().getSignatureIndex(); }
public long getGenericSignatureIndex() { return getConstMethod().getGenericSignatureIndex(); }
@@ -177,7 +171,7 @@
bci. It is required that there is currently a bytecode at this
bci. */
public int getOrigBytecodeAt(int bci) {
- BreakpointInfo bp = ((InstanceKlass) getMethodHolder()).getBreakpoints();
+ BreakpointInfo bp = getMethodHolder().getBreakpoints();
for (; bp != null; bp = bp.getNext()) {
if (bp.match(this, bci)) {
return bp.getOrigBytecode();
@@ -238,7 +232,7 @@
}
// Method holder (the Klass holding this method)
- public Klass getMethodHolder() { return getConstants().getPoolHolder(); }
+ public InstanceKlass getMethodHolder() { return getConstants().getPoolHolder(); }
// Access flags
public boolean isPublic() { return getAccessFlagsObj().isPublic(); }
@@ -284,9 +278,6 @@
public void iterateFields(MetadataVisitor visitor) {
visitor.doCInt(methodSize, true);
- visitor.doCInt(maxStack, true);
- visitor.doCInt(maxLocals, true);
- visitor.doCInt(sizeOfParameters, true);
visitor.doCInt(accessFlags, true);
}
@@ -358,6 +349,25 @@
buf.append(")");
return buf.toString().replace('/', '.');
}
+
+ public void dumpReplayData(PrintStream out) {
+ NMethod nm = getNativeMethod();
+ int code_size = 0;
+ if (nm != null) {
+ code_size = (int)nm.codeEnd().minus(nm.getVerifiedEntryPoint());
+ }
+ Klass holder = getMethodHolder();
+ out.println("ciMethod " +
+ holder.getName().asString() + " " +
+ OopUtilities.escapeString(getName().asString()) + " " +
+ getSignature().asString() + " " +
+ getInvocationCounter() + " " +
+ getBackedgeCounter() + " " +
+ interpreterInvocationCount() + " " +
+ interpreterThrowoutCount() + " " +
+ code_size);
+ }
+
public int interpreterThrowoutCount() {
return (int) interpreterThrowoutCountField.getValue(this);
}
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/oops/MethodData.java
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/MethodData.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/MethodData.java Sun Feb 03 22:43:57 2013 +0100
@@ -332,4 +332,59 @@
public int currentMileage() {
return 20000;
}
+
+ public void dumpReplayData(PrintStream out) {
+ Method method = getMethod();
+ Klass holder = method.getMethodHolder();
+ out.print("ciMethodData " +
+ holder.getName().asString() + " " +
+ OopUtilities.escapeString(method.getName().asString()) + " " +
+ method.getSignature().asString() + " " +
+ "2" + " " +
+ currentMileage());
+ byte[] orig = orig();
+ out.print(" orig " + orig.length);
+ for (int i = 0; i < orig.length; i++) {
+ out.print(" " + (orig[i] & 0xff));
+ }
+
+ long[] data = data();
+ out.print(" data " + data.length);
+ for (int i = 0; i < data.length; i++) {
+ out.print(" 0x" + Long.toHexString(data[i]));
+ }
+ int count = 0;
+ for (int round = 0; round < 2; round++) {
+ if (round == 1) out.print(" oops " + count);
+ ProfileData pdata = firstData();
+ for ( ; isValid(pdata); pdata = nextData(pdata)) {
+ if (pdata instanceof ReceiverTypeData) {
+ ReceiverTypeData vdata = (ReceiverTypeData)pdata;
+ for (int i = 0; i < vdata.rowLimit(); i++) {
+ Klass k = vdata.receiver(i);
+ if (k != null) {
+ if (round == 0) count++;
+ else out.print(" " +
+ (dpToDi(vdata.dp() +
+ vdata.cellOffset(vdata.receiverCellIndex(i))) / cellSize) + " " +
+ k.getName().asString());
+ }
+ }
+ } else if (pdata instanceof VirtualCallData) {
+ VirtualCallData vdata = (VirtualCallData)pdata;
+ for (int i = 0; i < vdata.rowLimit(); i++) {
+ Klass k = vdata.receiver(i);
+ if (k != null) {
+ if (round == 0) count++;
+ else out.print(" " +
+ (dpToDi(vdata.dp() +
+ vdata.cellOffset(vdata.receiverCellIndex(i))) / cellSize) + " " +
+ k.getName().asString());
+ }
+ }
+ }
+ }
+ }
+ out.println();
+ }
}
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/oops/ProfileData.java
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/ProfileData.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/ProfileData.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/oops/RetData.java
--- a/agent/src/share/classes/sun/jvm/hotspot/oops/RetData.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/oops/RetData.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/Block.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/Block.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/Block.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/Block_Array.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/Block_Array.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/Block_Array.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/Block_List.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/Block_List.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/Block_List.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/CallDynamicJavaNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/CallDynamicJavaNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/CallDynamicJavaNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/CallJavaNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/CallJavaNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/CallJavaNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/CallNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/CallNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/CallNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/CallRuntimeNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/CallRuntimeNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/CallRuntimeNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/CallStaticJavaNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/CallStaticJavaNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/CallStaticJavaNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/Compile.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/Compile.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/Compile.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/HaltNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/HaltNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/HaltNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/InlineTree.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/InlineTree.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/InlineTree.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/JVMState.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/JVMState.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/JVMState.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/LoopNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/LoopNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/LoopNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/MachCallJavaNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/MachCallJavaNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/MachCallJavaNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/MachCallNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/MachCallNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/MachCallNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/MachCallRuntimeNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/MachCallRuntimeNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/MachCallRuntimeNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/MachCallStaticJavaNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/MachCallStaticJavaNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/MachCallStaticJavaNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/MachIfNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/MachIfNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/MachIfNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/MachNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/MachNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/MachNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/MachReturnNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/MachReturnNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/MachReturnNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/MachSafePointNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/MachSafePointNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/MachSafePointNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/MultiNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/MultiNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/MultiNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/Node.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/Node.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/Node.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/Node_Array.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/Node_Array.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/Node_Array.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/Node_List.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/Node_List.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/Node_List.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/Phase.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/Phase.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/Phase.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/PhaseCFG.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/PhaseCFG.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/PhaseCFG.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/PhaseRegAlloc.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/PhaseRegAlloc.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/PhaseRegAlloc.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/PhiNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/PhiNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/PhiNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/ProjNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/ProjNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/ProjNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/RegionNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/RegionNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/RegionNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/RootNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/RootNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/RootNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/SafePointNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/SafePointNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/SafePointNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/opto/TypeNode.java
--- a/agent/src/share/classes/sun/jvm/hotspot/opto/TypeNode.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/opto/TypeNode.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/prims/JvmtiExport.java
--- a/agent/src/share/classes/sun/jvm/hotspot/prims/JvmtiExport.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/prims/JvmtiExport.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/runtime/Bytes.java
--- a/agent/src/share/classes/sun/jvm/hotspot/runtime/Bytes.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/runtime/Bytes.java Sun Feb 03 22:43:57 2013 +0100
@@ -30,24 +30,10 @@
/** Encapsulates some byte-swapping operations defined in the VM */
public class Bytes {
- // swap if client platform is different from server's.
private boolean swap;
public Bytes(MachineDescription machDesc) {
- String cpu = PlatformInfo.getCPU();
- if (cpu.equals("sparc")) {
- if (machDesc.isBigEndian()) {
- swap = false;
- } else {
- swap = true;
- }
- } else { // intel
- if (machDesc.isBigEndian()) {
- swap = true;
- } else {
- swap = false;
- }
- }
+ swap = !machDesc.isBigEndian();
}
/** Should only swap if the hardware's underlying byte order is
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ByteCodeRewriter.java
--- a/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ByteCodeRewriter.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ByteCodeRewriter.java Sun Feb 03 22:43:57 2013 +0100
@@ -29,6 +29,11 @@
import sun.jvm.hotspot.utilities.*;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.runtime.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.AccessControlContext;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedActionException;
public class ByteCodeRewriter
{
@@ -38,8 +43,20 @@
private byte[] code;
private Bytes bytes;
- public static final boolean DEBUG = false;
private static final int jintSize = 4;
+ public static final boolean DEBUG;
+
+ static {
+ String debug = (String) AccessController.doPrivileged(
+ new PrivilegedAction() {
+ public Object run() {
+ return System.getProperty("sun.jvm.hotspot.tools.jcore.ByteCodeRewriter.DEBUG");
+ }
+ }
+ );
+ DEBUG = (debug != null ? debug.equalsIgnoreCase("true") : false);
+ }
+
protected void debugMessage(String message) {
System.out.println(message);
@@ -54,6 +71,18 @@
}
+ protected short getConstantPoolIndexFromRefMap(int rawcode, int bci) {
+ int refIndex;
+ String fmt = Bytecodes.format(rawcode);
+ switch (fmt.length()) {
+ case 2: refIndex = 0xFF & method.getBytecodeByteArg(bci); break;
+ case 3: refIndex = 0xFFFF & bytes.swapShort(method.getBytecodeShortArg(bci)); break;
+ default: throw new IllegalArgumentException();
+ }
+
+ return (short)cpool.objectToCPIndex(refIndex);
+ }
+
protected short getConstantPoolIndex(int rawcode, int bci) {
// get ConstantPool index from ConstantPoolCacheIndex at given bci
String fmt = Bytecodes.format(rawcode);
@@ -95,6 +124,12 @@
int hotspotcode = Bytecodes._illegal;
int len = 0;
+ if (DEBUG) {
+ String msg = method.getMethodHolder().getName().asString() + "." +
+ method.getName().asString() +
+ method.getSignature().asString();
+ debugMessage(msg);
+ }
for (int bci = 0; bci < code.length;) {
hotspotcode = Bytecodes.codeAt(method, bci);
bytecode = Bytecodes.javaCode(hotspotcode);
@@ -133,15 +168,15 @@
case Bytecodes._ldc_w:
if (hotspotcode != bytecode) {
- // fast_aldc_w puts constant in CP cache
- cpoolIndex = getConstantPoolIndex(hotspotcode, bci + 1);
+ // fast_aldc_w puts constant in reference map
+ cpoolIndex = getConstantPoolIndexFromRefMap(hotspotcode, bci + 1);
writeShort(code, bci + 1, cpoolIndex);
}
break;
case Bytecodes._ldc:
if (hotspotcode != bytecode) {
- // fast_aldc puts constant in CP cache
- cpoolIndex = getConstantPoolIndex(hotspotcode, bci + 1);
+ // fast_aldc puts constant in reference map
+ cpoolIndex = getConstantPoolIndexFromRefMap(hotspotcode, bci + 1);
code[bci + 1] = (byte)(cpoolIndex);
}
break;
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/utilities/GenericGrowableArray.java
--- a/agent/src/share/classes/sun/jvm/hotspot/utilities/GenericGrowableArray.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/GenericGrowableArray.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/classes/sun/jvm/hotspot/utilities/GrowableArray.java
--- a/agent/src/share/classes/sun/jvm/hotspot/utilities/GrowableArray.java Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/GrowableArray.java Sun Feb 03 22:43:57 2013 +0100
@@ -16,9 +16,9 @@
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
+ * 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.
*
*/
diff -r 77443715ec55 -r b5cb079ecaa4 agent/src/share/native/sadis.c
--- a/agent/src/share/native/sadis.c Mon Nov 05 17:03:33 2012 -0500
+++ b/agent/src/share/native/sadis.c Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright 2012, Oracle and/or its affiliates. All Rights Reserved.
+ * Copyright (c) 2012, 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
diff -r 77443715ec55 -r b5cb079ecaa4 make/Makefile
--- a/make/Makefile Mon Nov 05 17:03:33 2012 -0500
+++ b/make/Makefile Sun Feb 03 22:43:57 2013 +0100
@@ -453,14 +453,30 @@
ifeq ($(JVM_VARIANT_ZEROSHARK), true)
$(EXPORT_JRE_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(SHARK_DIR)/%.$(LIBRARY_SUFFIX)
$(install-file)
+ $(EXPORT_JRE_LIB_ARCH_DIR)/%.debuginfo): $(SHARK_DIR)/%.debuginfo
+ $(install-file)
+ $(EXPORT_JRE_LIB_ARCH_DIR)/%.diz: $(SHARK_DIR)/%.diz
+ $(install-file)
$(EXPORT_SERVER_DIR)/%.$(LIBRARY_SUFFIX): $(SHARK_DIR)/%.$(LIBRARY_SUFFIX)
$(install-file)
+ $(EXPORT_SERVER_DIR)/%.debuginfo: $(SHARK_DIR)/%.debuginfo
+ $(install-file)
+ $(EXPORT_SERVER_DIR)/%.diz: $(SHARK_DIR)/%.diz
+ $(install-file)
endif
ifeq ($(JVM_VARIANT_ZERO), true)
$(EXPORT_JRE_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(ZERO_DIR)/%.$(LIBRARY_SUFFIX)
$(install-file)
+ $(EXPORT_JRE_LIB_ARCH_DIR)/%.debuginfo: $(ZERO_DIR)/%.debuginfo
+ $(install-file)
+ $(EXPORT_JRE_LIB_ARCH_DIR)/%.diz: $(ZERO_DIR)/%.diz
+ $(install-file)
$(EXPORT_SERVER_DIR)/%.$(LIBRARY_SUFFIX): $(ZERO_DIR)/%.$(LIBRARY_SUFFIX)
$(install-file)
+ $(EXPORT_SERVER_DIR)/%.debuginfo: $(ZERO_DIR)/%.debuginfo
+ $(install-file)
+ $(EXPORT_SERVER_DIR)/%.diz: $(ZERO_DIR)/%.diz
+ $(install-file)
endif
ifeq ($(JVM_VARIANT_MINIMAL1), true)
$(EXPORT_JRE_LIB_ARCH_DIR)/%.$(LIBRARY_SUFFIX): $(MINIMAL1_DIR)/%.$(LIBRARY_SUFFIX)
diff -r 77443715ec55 -r b5cb079ecaa4 make/bsd/Makefile
--- a/make/bsd/Makefile Mon Nov 05 17:03:33 2012 -0500
+++ b/make/bsd/Makefile Sun Feb 03 22:43:57 2013 +0100
@@ -47,10 +47,10 @@
# Along with VM, Serviceability Agent (SA) is built for SA/JDI binding.
# JDI binding on SA produces two binaries:
-# 1. sa-jdi.jar - This is build before building libjvm[_g].so
+# 1. sa-jdi.jar - This is built before building libjvm.so
# Please refer to ./makefiles/sa.make
-# 2. libsa[_g].so - Native library for SA - This is built after
-# libjsig[_g].so (signal interposition library)
+# 2. libsa.so - Native library for SA - This is built after
+# libjsig.so (signal interposition library)
# Please refer to ./makefiles/vm.make
# If $(GAMMADIR)/agent dir is not present, SA components are not built.
@@ -181,9 +181,9 @@
#
# What you get with each target:
#
-# debug* - "thin" libjvm_g - debug info linked into the gamma_g launcher
+# debug* - "thin" libjvm - debug info linked into the gamma launcher
# fastdebug* - optimized compile, but with asserts enabled
-# jvmg* - "fat" libjvm_g - debug info linked into libjvm_g.so
+# jvmg* - "fat" libjvm - debug info linked into libjvm.so
# optimized* - optimized compile, no asserts
# profiled* - gprof
# product* - the shippable thing: optimized compile, no asserts, -DPRODUCT
diff -r 77443715ec55 -r b5cb079ecaa4 make/bsd/makefiles/buildtree.make
--- a/make/bsd/makefiles/buildtree.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/bsd/makefiles/buildtree.make Sun Feb 03 22:43:57 2013 +0100
@@ -449,12 +449,7 @@
echo " exit 0"; \
echo "fi"; \
echo ""; \
- echo "# Use gamma_g if it exists"; \
- echo ""; \
echo "GAMMA_PROG=gamma"; \
- echo "if [ -f gamma_g ]; then "; \
- echo " GAMMA_PROG=gamma_g"; \
- echo "fi"; \
echo ""; \
echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \
echo " # Ensure architecture for gamma and JAVA_HOME is the same."; \
diff -r 77443715ec55 -r b5cb079ecaa4 make/bsd/makefiles/debug.make
--- a/make/bsd/makefiles/debug.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/bsd/makefiles/debug.make Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,6 @@
"Please use 'make jvmg' to build debug JVM. \n" \
"----------------------------------------------------------------------\n")
-G_SUFFIX = _g
VERSION = debug
SYSDEFS += -DASSERT -DDEBUG
PICFLAGS = DEFAULT
diff -r 77443715ec55 -r b5cb079ecaa4 make/bsd/makefiles/dtrace.make
--- a/make/bsd/makefiles/dtrace.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/bsd/makefiles/dtrace.make Sun Feb 03 22:43:57 2013 +0100
@@ -38,12 +38,10 @@
# Bsd does not build libjvm_db, does not compile on macosx
# disabled in build: rule in vm.make
JVM_DB = libjvm_db
-#LIBJVM_DB = libjvm_db.dylib
-LIBJVM_DB = libjvm$(G_SUFFIX)_db.dylib
+LIBJVM_DB = libjvm_db.dylib
JVM_DTRACE = jvm_dtrace
-#LIBJVM_DTRACE = libjvm_dtrace.dylib
-LIBJVM_DTRACE = libjvm$(G_SUFFIX)_dtrace.dylib
+LIBJVM_DTRACE = libjvm_dtrace.dylib
JVMOFFS = JvmOffsets
JVMOFFS.o = $(JVMOFFS).o
@@ -80,9 +78,7 @@
ifneq ("${ISA}","${BUILDARCH}")
XLIBJVM_DB = 64/$(LIBJVM_DB)
-XLIBJVM_DB_G = 64/$(LIBJVM_DB_G)
XLIBJVM_DTRACE = 64/$(LIBJVM_DTRACE)
-XLIBJVM_DTRACE_G = 64/$(LIBJVM_DTRACE_G)
XARCH = $(subst sparcv9,v9,$(shell echo $(ISA)))
$(XLIBJVM_DB): $(DTRACE_SRCDIR)/$(JVM_DB).c $(JVMOFFS).h $(LIBJVM_DB_MAPFILE)
@@ -90,14 +86,12 @@
$(QUIETLY) mkdir -p 64/ ; \
$(CC) $(SYMFLAG) -xarch=$(XARCH) -D$(TYPE) -I. -I$(GENERATED) \
$(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c #-lc
-# [ -f $(XLIBJVM_DB_G) ] || { ln -s $(LIBJVM_DB) $(XLIBJVM_DB_G); }
$(XLIBJVM_DTRACE): $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE)
@echo Making $@
$(QUIETLY) mkdir -p 64/ ; \
$(CC) $(SYMFLAG) -xarch=$(XARCH) -D$(TYPE) -I. \
$(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c #-lc -lthread -ldoor
-# [ -f $(XLIBJVM_DTRACE_G) ] || { ln -s $(LIBJVM_DTRACE) $(XLIBJVM_DTRACE_G); }
endif # ifneq ("${ISA}","${BUILDARCH}")
@@ -141,13 +135,11 @@
@echo Making $@
$(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) -D$(TYPE) -I. -I$(GENERATED) \
$(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c -Wall # -lc
-# [ -f $(LIBJVM_DB_G) ] || { ln -s $@ $(LIBJVM_DB_G); }
$(LIBJVM_DTRACE): $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(XLIBJVM_DTRACE) $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE)
@echo Making $@
$(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) -D$(TYPE) -I. \
$(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c #-lc -lthread -ldoor
-# [ -f $(LIBJVM_DTRACE_G) ] || { ln -s $@ $(LIBJVM_DTRACE_G); }
#$(DTRACE).d: $(DTRACE_SRCDIR)/hotspot.d $(DTRACE_SRCDIR)/hotspot_jni.d \
# $(DTRACE_SRCDIR)/hs_private.d $(DTRACE_SRCDIR)/jhelper.d
diff -r 77443715ec55 -r b5cb079ecaa4 make/bsd/makefiles/fastdebug.make
--- a/make/bsd/makefiles/fastdebug.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/bsd/makefiles/fastdebug.make Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1999, 2012 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
@@ -58,7 +58,6 @@
# Linker mapfile
MAPFILE = $(GAMMADIR)/make/bsd/makefiles/mapfile-vers-debug
-G_SUFFIX = _g
VERSION = optimized
SYSDEFS += -DASSERT -DFASTDEBUG
PICFLAGS = DEFAULT
diff -r 77443715ec55 -r b5cb079ecaa4 make/bsd/makefiles/gcc.make
--- a/make/bsd/makefiles/gcc.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/bsd/makefiles/gcc.make Sun Feb 03 22:43:57 2013 +0100
@@ -284,9 +284,9 @@
# Use the stabs format for debugging information (this is the default
# on gcc-2.91). It's good enough, has all the information about line
-# numbers and local variables, and libjvm_g.so is only about 16M.
+# numbers and local variables, and libjvm.so is only about 16M.
# Change this back to "-g" if you want the most expressive format.
-# (warning: that could easily inflate libjvm_g.so to 150M!)
+# (warning: that could easily inflate libjvm.so to 150M!)
# Note: The Itanium gcc compiler crashes when using -gstabs.
DEBUG_CFLAGS/ia64 = -g
DEBUG_CFLAGS/amd64 = -g
diff -r 77443715ec55 -r b5cb079ecaa4 make/bsd/makefiles/jsig.make
--- a/make/bsd/makefiles/jsig.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/bsd/makefiles/jsig.make Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2012, 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
@@ -24,16 +24,13 @@
# Rules to build signal interposition library, used by vm.make
-# libjsig[_g].so: signal interposition library
+# libjsig.so: signal interposition library
JSIG = jsig
-JSIG_G = $(JSIG)$(G_SUFFIX)
ifeq ($(OS_VENDOR), Darwin)
LIBJSIG = lib$(JSIG).dylib
- LIBJSIG_G = lib$(JSIG_G).dylib
else
LIBJSIG = lib$(JSIG).so
- LIBJSIG_G = lib$(JSIG_G).so
endif
JSIGSRCDIR = $(GAMMADIR)/src/os/$(Platform_os_family)/vm
@@ -58,7 +55,6 @@
@echo Making signal interposition lib...
$(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \
$(LFLAGS_JSIG) $(JSIG_DEBUG_CFLAGS) -o $@ $<
- $(QUIETLY) [ -f $(LIBJSIG_G) ] || { ln -s $@ $(LIBJSIG_G); }
install_jsig: $(LIBJSIG)
@echo "Copying $(LIBJSIG) to $(DEST_JSIG)"
diff -r 77443715ec55 -r b5cb079ecaa4 make/bsd/makefiles/jvmg.make
--- a/make/bsd/makefiles/jvmg.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/bsd/makefiles/jvmg.make Sun Feb 03 22:43:57 2013 +0100
@@ -37,7 +37,6 @@
# Linker mapfile
MAPFILE = $(GAMMADIR)/make/bsd/makefiles/mapfile-vers-debug
-G_SUFFIX = _g
VERSION = debug
SYSDEFS += -DASSERT -DDEBUG
PICFLAGS = DEFAULT
diff -r 77443715ec55 -r b5cb079ecaa4 make/bsd/makefiles/mapfile-vers-debug
--- a/make/bsd/makefiles/mapfile-vers-debug Mon Nov 05 17:03:33 2012 -0500
+++ b/make/bsd/makefiles/mapfile-vers-debug Sun Feb 03 22:43:57 2013 +0100
@@ -1,9 +1,9 @@
#
-# @(#)mapfile-vers-debug 1.18 07/10/25 16:47:35
+# @(#)mapfile-vers-debug 1.18 07/10/25 16:47:35
#
#
-# Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -126,8 +126,9 @@
JVM_GetClassModifiers;
JVM_GetClassName;
JVM_GetClassNameUTF;
- JVM_GetClassSignature;
+ JVM_GetClassSignature;
JVM_GetClassSigners;
+ JVM_GetClassTypeAnnotations;
JVM_GetComponentType;
JVM_GetDeclaredClasses;
JVM_GetDeclaringClass;
@@ -154,6 +155,7 @@
JVM_GetMethodIxNameUTF;
JVM_GetMethodIxSignatureUTF;
JVM_GetMethodParameterAnnotations;
+ JVM_GetMethodParameters;
JVM_GetPrimitiveArrayElement;
JVM_GetProtectionDomain;
JVM_GetSockName;
@@ -203,7 +205,6 @@
JVM_NewMultiArray;
JVM_OnExit;
JVM_Open;
- JVM_PrintStackTrace;
JVM_RaiseSignal;
JVM_RawMonitorCreate;
JVM_RawMonitorDestroy;
@@ -283,7 +284,7 @@
# This is for Forte Analyzer profiling support.
AsyncGetCallTrace;
- # INSERT VTABLE SYMBOLS HERE
+ # INSERT VTABLE SYMBOLS HERE
local:
*;
diff -r 77443715ec55 -r b5cb079ecaa4 make/bsd/makefiles/mapfile-vers-product
--- a/make/bsd/makefiles/mapfile-vers-product Mon Nov 05 17:03:33 2012 -0500
+++ b/make/bsd/makefiles/mapfile-vers-product Sun Feb 03 22:43:57 2013 +0100
@@ -3,7 +3,7 @@
#
#
-# Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -128,6 +128,7 @@
JVM_GetClassNameUTF;
JVM_GetClassSignature;
JVM_GetClassSigners;
+ JVM_GetClassTypeAnnotations;
JVM_GetComponentType;
JVM_GetDeclaredClasses;
JVM_GetDeclaringClass;
@@ -154,6 +155,7 @@
JVM_GetMethodIxNameUTF;
JVM_GetMethodIxSignatureUTF;
JVM_GetMethodParameterAnnotations;
+ JVM_GetMethodParameters;
JVM_GetPrimitiveArrayElement;
JVM_GetProtectionDomain;
JVM_GetSockName;
@@ -203,7 +205,6 @@
JVM_NewMultiArray;
JVM_OnExit;
JVM_Open;
- JVM_PrintStackTrace;
JVM_RaiseSignal;
JVM_RawMonitorCreate;
JVM_RawMonitorDestroy;
diff -r 77443715ec55 -r b5cb079ecaa4 make/bsd/makefiles/optimized.make
--- a/make/bsd/makefiles/optimized.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/bsd/makefiles/optimized.make Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1999, 2012, 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
@@ -40,5 +40,4 @@
# Linker mapfile
MAPFILE = $(GAMMADIR)/make/bsd/makefiles/mapfile-vers-debug
-G_SUFFIX =
VERSION = optimized
diff -r 77443715ec55 -r b5cb079ecaa4 make/bsd/makefiles/product.make
--- a/make/bsd/makefiles/product.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/bsd/makefiles/product.make Sun Feb 03 22:43:57 2013 +0100
@@ -40,7 +40,6 @@
# Linker mapfile
MAPFILE = $(GAMMADIR)/make/bsd/makefiles/mapfile-vers-product
-G_SUFFIX =
SYSDEFS += -DPRODUCT
VERSION = optimized
diff -r 77443715ec55 -r b5cb079ecaa4 make/bsd/makefiles/saproc.make
--- a/make/bsd/makefiles/saproc.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/bsd/makefiles/saproc.make Sun Feb 03 22:43:57 2013 +0100
@@ -24,16 +24,13 @@
# Rules to build serviceability agent library, used by vm.make
-# libsaproc[_g].so: serviceability agent
+# libsaproc.so: serviceability agent
SAPROC = saproc
-SAPROC_G = $(SAPROC)$(G_SUFFIX)
ifeq ($(OS_VENDOR), Darwin)
LIBSAPROC = lib$(SAPROC).dylib
- LIBSAPROC_G = lib$(SAPROC_G).dylib
else
LIBSAPROC = lib$(SAPROC).so
- LIBSAPROC_G = lib$(SAPROC_G).so
endif
AGENT_DIR = $(GAMMADIR)/agent
@@ -114,7 +111,6 @@
$(SA_DEBUG_CFLAGS) \
-o $@ \
$(SALIBS)
- $(QUIETLY) [ -f $(LIBSAPROC_G) ] || { ln -s $@ $(LIBSAPROC_G); }
install_saproc: $(BUILDLIBSAPROC)
$(QUIETLY) if [ -e $(LIBSAPROC) ] ; then \
diff -r 77443715ec55 -r b5cb079ecaa4 make/bsd/makefiles/vm.make
--- a/make/bsd/makefiles/vm.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/bsd/makefiles/vm.make Sun Feb 03 22:43:57 2013 +0100
@@ -138,11 +138,9 @@
JVM = jvm
ifeq ($(OS_VENDOR), Darwin)
LIBJVM = lib$(JVM).dylib
- LIBJVM_G = lib$(JVM)$(G_SUFFIX).dylib
CFLAGS += -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE
else
LIBJVM = lib$(JVM).so
- LIBJVM_G = lib$(JVM)$(G_SUFFIX).so
endif
SPECIAL_PATHS:=adlc c1 gc_implementation opto shark libadt
@@ -314,7 +312,6 @@
$(LFLAGS_VM) -o $@ $(sort $(LIBJVM.o)) $(LIBS_VM); \
$(LINK_LIB.CXX/POST_HOOK) \
rm -f $@.1; ln -s $@ $@.1; \
- [ -f $(LIBJVM_G) ] || { ln -s $@ $(LIBJVM_G); ln -s $@.1 $(LIBJVM_G).1; }; \
}
DEST_JVM = $(JDK_LIBDIR)/$(VM_SUBDIR)/$(LIBJVM)
diff -r 77443715ec55 -r b5cb079ecaa4 make/excludeSrc.make
--- a/make/excludeSrc.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/excludeSrc.make Sun Feb 03 22:43:57 2013 +0100
@@ -79,10 +79,10 @@
CXXFLAGS += -DSERIALGC
CFLAGS += -DSERIALGC
Src_Files_EXCLUDE += \
- binaryTreeDictionary.cpp cmsAdaptiveSizePolicy.cpp cmsCollectorPolicy.cpp \
+ cmsAdaptiveSizePolicy.cpp cmsCollectorPolicy.cpp \
cmsGCAdaptivePolicyCounters.cpp cmsLockVerifier.cpp cmsPermGen.cpp compactibleFreeListSpace.cpp \
- concurrentMarkSweepGeneration.cpp concurrentMarkSweepThread.cpp freeBlockDictionary.cpp \
- freeChunk.cpp freeList.cpp promotionInfo.cpp vmCMSOperations.cpp collectionSetChooser.cpp \
+ concurrentMarkSweepGeneration.cpp concurrentMarkSweepThread.cpp \
+ freeChunk.cpp adaptiveFreeList.cpp promotionInfo.cpp vmCMSOperations.cpp collectionSetChooser.cpp \
concurrentG1Refine.cpp concurrentG1RefineThread.cpp concurrentMark.cpp concurrentMarkThread.cpp \
dirtyCardQueue.cpp g1AllocRegion.cpp g1BlockOffsetTable.cpp g1CollectedHeap.cpp g1GCPhaseTimes.cpp \
g1CollectorPolicy.cpp g1ErgoVerbose.cpp g1_globals.cpp g1HRPrinter.cpp g1MarkSweep.cpp \
diff -r 77443715ec55 -r b5cb079ecaa4 make/hotspot_version
--- a/make/hotspot_version Mon Nov 05 17:03:33 2012 -0500
+++ b/make/hotspot_version Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -31,11 +31,11 @@
#
# Don't put quotes (fail windows build).
-HOTSPOT_VM_COPYRIGHT=Copyright 2012
+HOTSPOT_VM_COPYRIGHT=Copyright 2013
HS_MAJOR_VER=25
HS_MINOR_VER=0
-HS_BUILD_NUMBER=06
+HS_BUILD_NUMBER=17
JDK_MAJOR_VER=1
JDK_MINOR_VER=8
diff -r 77443715ec55 -r b5cb079ecaa4 make/linux/Makefile
--- a/make/linux/Makefile Mon Nov 05 17:03:33 2012 -0500
+++ b/make/linux/Makefile Sun Feb 03 22:43:57 2013 +0100
@@ -47,10 +47,10 @@
# Along with VM, Serviceability Agent (SA) is built for SA/JDI binding.
# JDI binding on SA produces two binaries:
-# 1. sa-jdi.jar - This is build before building libjvm[_g].so
+# 1. sa-jdi.jar - This is built before building libjvm.so
# Please refer to ./makefiles/sa.make
-# 2. libsa[_g].so - Native library for SA - This is built after
-# libjsig[_g].so (signal interposition library)
+# 2. libsa.so - Native library for SA - This is built after
+# libjsig.so (signal interposition library)
# Please refer to ./makefiles/vm.make
# If $(GAMMADIR)/agent dir is not present, SA components are not built.
@@ -181,9 +181,9 @@
#
# What you get with each target:
#
-# debug* - "thin" libjvm_g - debug info linked into the gamma_g launcher
+# debug* - "thin" libjvm - debug info linked into the gamma launcher
# fastdebug* - optimized compile, but with asserts enabled
-# jvmg* - "fat" libjvm_g - debug info linked into libjvm_g.so
+# jvmg* - "fat" libjvm - debug info linked into libjvm.so
# optimized* - optimized compile, no asserts
# profiled* - gprof
# product* - the shippable thing: optimized compile, no asserts, -DPRODUCT
diff -r 77443715ec55 -r b5cb079ecaa4 make/linux/makefiles/buildtree.make
--- a/make/linux/makefiles/buildtree.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/linux/makefiles/buildtree.make Sun Feb 03 22:43:57 2013 +0100
@@ -442,12 +442,7 @@
echo " exit 0"; \
echo "fi"; \
echo ""; \
- echo "# Use gamma_g if it exists"; \
- echo ""; \
echo "GAMMA_PROG=gamma"; \
- echo "if [ -f gamma_g ]; then "; \
- echo " GAMMA_PROG=gamma_g"; \
- echo "fi"; \
echo ""; \
echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \
echo " # Ensure architecture for gamma and JAVA_HOME is the same."; \
diff -r 77443715ec55 -r b5cb079ecaa4 make/linux/makefiles/debug.make
--- a/make/linux/makefiles/debug.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/linux/makefiles/debug.make Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,6 @@
"Please use 'make jvmg' to build debug JVM. \n" \
"----------------------------------------------------------------------\n")
-G_SUFFIX = _g
VERSION = debug
SYSDEFS += -DASSERT -DDEBUG
PICFLAGS = DEFAULT
diff -r 77443715ec55 -r b5cb079ecaa4 make/linux/makefiles/defs.make
--- a/make/linux/makefiles/defs.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/linux/makefiles/defs.make Sun Feb 03 22:43:57 2013 +0100
@@ -170,68 +170,70 @@
# overridden in some situations, e.g., a BUILD_FLAVOR != product
# build.
- ifeq ($(BUILD_FLAVOR), product)
- FULL_DEBUG_SYMBOLS ?= 1
- ENABLE_FULL_DEBUG_SYMBOLS = $(FULL_DEBUG_SYMBOLS)
- else
- # debug variants always get Full Debug Symbols (if available)
- ENABLE_FULL_DEBUG_SYMBOLS = 1
- endif
- _JUNK_ := $(shell \
- echo >&2 "INFO: ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS)")
- # since objcopy is optional, we set ZIP_DEBUGINFO_FILES later
+ # Due to the multiple sub-make processes that occur this logic gets
+ # executed multiple times. We reduce the noise by at least checking that
+ # BUILD_FLAVOR has been set.
+ ifneq ($(BUILD_FLAVOR),)
+ ifeq ($(BUILD_FLAVOR), product)
+ FULL_DEBUG_SYMBOLS ?= 1
+ ENABLE_FULL_DEBUG_SYMBOLS = $(FULL_DEBUG_SYMBOLS)
+ else
+ # debug variants always get Full Debug Symbols (if available)
+ ENABLE_FULL_DEBUG_SYMBOLS = 1
+ endif
+ _JUNK_ := $(shell \
+ echo >&2 "INFO: ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS)")
+ # since objcopy is optional, we set ZIP_DEBUGINFO_FILES later
- ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
- # Default OBJCOPY comes from GNU Binutils on Linux:
- DEF_OBJCOPY=/usr/bin/objcopy
- ifdef CROSS_COMPILE_ARCH
- # don't try to generate .debuginfo files when cross compiling
- _JUNK_ := $(shell \
- echo >&2 "INFO: cross compiling for ARCH $(CROSS_COMPILE_ARCH)," \
- "skipping .debuginfo generation.")
- OBJCOPY=
- else
+ ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
+ # Default OBJCOPY comes from GNU Binutils on Linux
+ ifeq ($(CROSS_COMPILE_ARCH),)
+ DEF_OBJCOPY=/usr/bin/objcopy
+ else
+ # Assume objcopy is part of the cross-compilation toolset
+ ifneq ($(ALT_COMPILER_PATH),)
+ DEF_OBJCOPY=$(ALT_COMPILER_PATH)/objcopy
+ endif
+ endif
OBJCOPY=$(shell test -x $(DEF_OBJCOPY) && echo $(DEF_OBJCOPY))
ifneq ($(ALT_OBJCOPY),)
_JUNK_ := $(shell echo >&2 "INFO: ALT_OBJCOPY=$(ALT_OBJCOPY)")
OBJCOPY=$(shell test -x $(ALT_OBJCOPY) && echo $(ALT_OBJCOPY))
endif
- endif
- else
- OBJCOPY=
- endif
- ifeq ($(OBJCOPY),)
- _JUNK_ := $(shell \
- echo >&2 "INFO: no objcopy cmd found so cannot create .debuginfo files.")
- ENABLE_FULL_DEBUG_SYMBOLS=0
- _JUNK_ := $(shell \
- echo >&2 "INFO: ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS)")
- else
- _JUNK_ := $(shell \
- echo >&2 "INFO: $(OBJCOPY) cmd found so will create .debuginfo files.")
+ ifeq ($(OBJCOPY),)
+ _JUNK_ := $(shell \
+ echo >&2 "INFO: no objcopy cmd found so cannot create .debuginfo files. You may need to set ALT_OBJCOPY.")
+ ENABLE_FULL_DEBUG_SYMBOLS=0
+ _JUNK_ := $(shell \
+ echo >&2 "INFO: ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS)")
+ else
+ _JUNK_ := $(shell \
+ echo >&2 "INFO: $(OBJCOPY) cmd found so will create .debuginfo files.")
- # Library stripping policies for .debuginfo configs:
- # all_strip - strips everything from the library
- # min_strip - strips most stuff from the library; leaves minimum symbols
- # no_strip - does not strip the library at all
- #
- # Oracle security policy requires "all_strip". A waiver was granted on
- # 2011.09.01 that permits using "min_strip" in the Java JDK and Java JRE.
- #
- # Currently, STRIP_POLICY is only used when Full Debug Symbols is enabled.
- #
- STRIP_POLICY ?= min_strip
+ # Library stripping policies for .debuginfo configs:
+ # all_strip - strips everything from the library
+ # min_strip - strips most stuff from the library; leaves minimum symbols
+ # no_strip - does not strip the library at all
+ #
+ # Oracle security policy requires "all_strip". A waiver was granted on
+ # 2011.09.01 that permits using "min_strip" in the Java JDK and Java JRE.
+ #
+ # Currently, STRIP_POLICY is only used when Full Debug Symbols is enabled.
+ #
+ STRIP_POLICY ?= min_strip
- _JUNK_ := $(shell \
- echo >&2 "INFO: STRIP_POLICY=$(STRIP_POLICY)")
+ _JUNK_ := $(shell \
+ echo >&2 "INFO: STRIP_POLICY=$(STRIP_POLICY)")
- ZIP_DEBUGINFO_FILES ?= 1
+ ZIP_DEBUGINFO_FILES ?= 1
- _JUNK_ := $(shell \
- echo >&2 "INFO: ZIP_DEBUGINFO_FILES=$(ZIP_DEBUGINFO_FILES)")
- endif
-endif
+ _JUNK_ := $(shell \
+ echo >&2 "INFO: ZIP_DEBUGINFO_FILES=$(ZIP_DEBUGINFO_FILES)")
+ endif
+ endif # ENABLE_FULL_DEBUG_SYMBOLS=1
+ endif # BUILD_FLAVOR
+endif # JDK_6_OR_EARLIER
JDK_INCLUDE_SUBDIR=linux
diff -r 77443715ec55 -r b5cb079ecaa4 make/linux/makefiles/fastdebug.make
--- a/make/linux/makefiles/fastdebug.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/linux/makefiles/fastdebug.make Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1999, 2012, 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
@@ -58,7 +58,6 @@
# Linker mapfile
MAPFILE = $(GAMMADIR)/make/linux/makefiles/mapfile-vers-debug
-G_SUFFIX = _g
VERSION = optimized
SYSDEFS += -DASSERT -DFASTDEBUG
PICFLAGS = DEFAULT
diff -r 77443715ec55 -r b5cb079ecaa4 make/linux/makefiles/gcc.make
--- a/make/linux/makefiles/gcc.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/linux/makefiles/gcc.make Sun Feb 03 22:43:57 2013 +0100
@@ -229,9 +229,9 @@
else
# Use the stabs format for debugging information (this is the default
# on gcc-2.91). It's good enough, has all the information about line
- # numbers and local variables, and libjvm_g.so is only about 16M.
+ # numbers and local variables, and libjvm.so is only about 16M.
# Change this back to "-g" if you want the most expressive format.
- # (warning: that could easily inflate libjvm_g.so to 150M!)
+ # (warning: that could easily inflate libjvm.so to 150M!)
# Note: The Itanium gcc compiler crashes when using -gstabs.
DEBUG_CFLAGS/ia64 = -g
DEBUG_CFLAGS/amd64 = -g
diff -r 77443715ec55 -r b5cb079ecaa4 make/linux/makefiles/jsig.make
--- a/make/linux/makefiles/jsig.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/linux/makefiles/jsig.make Sun Feb 03 22:43:57 2013 +0100
@@ -24,17 +24,12 @@
# Rules to build signal interposition library, used by vm.make
-# libjsig[_g].so: signal interposition library
+# libjsig.so: signal interposition library
JSIG = jsig
LIBJSIG = lib$(JSIG).so
-JSIG_G = $(JSIG)$(G_SUFFIX)
-LIBJSIG_G = lib$(JSIG_G).so
-
LIBJSIG_DEBUGINFO = lib$(JSIG).debuginfo
LIBJSIG_DIZ = lib$(JSIG).diz
-LIBJSIG_G_DEBUGINFO = lib$(JSIG_G).debuginfo
-LIBJSIG_G_DIZ = lib$(JSIG_G).diz
JSIGSRCDIR = $(GAMMADIR)/src/os/$(Platform_os_family)/vm
@@ -60,7 +55,6 @@
@echo Making signal interposition lib...
$(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \
$(LFLAGS_JSIG) $(JSIG_DEBUG_CFLAGS) -o $@ $< -ldl
- $(QUIETLY) [ -f $(LIBJSIG_G) ] || { ln -s $@ $(LIBJSIG_G); }
ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
$(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBJSIG_DEBUGINFO)
$(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJSIG_DEBUGINFO) $@
@@ -72,11 +66,9 @@
# implied else here is no stripping at all
endif
endif
- [ -f $(LIBJSIG_G_DEBUGINFO) ] || { ln -s $(LIBJSIG_DEBUGINFO) $(LIBJSIG_G_DEBUGINFO); }
ifeq ($(ZIP_DEBUGINFO_FILES),1)
- $(ZIPEXE) -q -y $(LIBJSIG_DIZ) $(LIBJSIG_DEBUGINFO) $(LIBJSIG_G_DEBUGINFO)
- $(RM) $(LIBJSIG_DEBUGINFO) $(LIBJSIG_G_DEBUGINFO)
- [ -f $(LIBJSIG_G_DIZ) ] || { ln -s $(LIBJSIG_DIZ) $(LIBJSIG_G_DIZ); }
+ $(ZIPEXE) -q -y $(LIBJSIG_DIZ) $(LIBJSIG_DEBUGINFO)
+ $(RM) $(LIBJSIG_DEBUGINFO)
endif
endif
diff -r 77443715ec55 -r b5cb079ecaa4 make/linux/makefiles/jvmg.make
--- a/make/linux/makefiles/jvmg.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/linux/makefiles/jvmg.make Sun Feb 03 22:43:57 2013 +0100
@@ -37,7 +37,6 @@
# Linker mapfile
MAPFILE = $(GAMMADIR)/make/linux/makefiles/mapfile-vers-debug
-G_SUFFIX = _g
VERSION = debug
SYSDEFS += -DASSERT -DDEBUG
PICFLAGS = DEFAULT
diff -r 77443715ec55 -r b5cb079ecaa4 make/linux/makefiles/mapfile-vers-debug
--- a/make/linux/makefiles/mapfile-vers-debug Mon Nov 05 17:03:33 2012 -0500
+++ b/make/linux/makefiles/mapfile-vers-debug Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -124,6 +124,7 @@
JVM_GetClassNameUTF;
JVM_GetClassSignature;
JVM_GetClassSigners;
+ JVM_GetClassTypeAnnotations;
JVM_GetComponentType;
JVM_GetDeclaredClasses;
JVM_GetDeclaringClass;
@@ -150,6 +151,7 @@
JVM_GetMethodIxNameUTF;
JVM_GetMethodIxSignatureUTF;
JVM_GetMethodParameterAnnotations;
+ JVM_GetMethodParameters;
JVM_GetPrimitiveArrayElement;
JVM_GetProtectionDomain;
JVM_GetSockName;
@@ -199,7 +201,6 @@
JVM_NewMultiArray;
JVM_OnExit;
JVM_Open;
- JVM_PrintStackTrace;
JVM_RaiseSignal;
JVM_RawMonitorCreate;
JVM_RawMonitorDestroy;
diff -r 77443715ec55 -r b5cb079ecaa4 make/linux/makefiles/mapfile-vers-product
--- a/make/linux/makefiles/mapfile-vers-product Mon Nov 05 17:03:33 2012 -0500
+++ b/make/linux/makefiles/mapfile-vers-product Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -124,6 +124,7 @@
JVM_GetClassNameUTF;
JVM_GetClassSignature;
JVM_GetClassSigners;
+ JVM_GetClassTypeAnnotations;
JVM_GetComponentType;
JVM_GetDeclaredClasses;
JVM_GetDeclaringClass;
@@ -150,6 +151,7 @@
JVM_GetMethodIxNameUTF;
JVM_GetMethodIxSignatureUTF;
JVM_GetMethodParameterAnnotations;
+ JVM_GetMethodParameters;
JVM_GetPrimitiveArrayElement;
JVM_GetProtectionDomain;
JVM_GetSockName;
@@ -199,7 +201,6 @@
JVM_NewMultiArray;
JVM_OnExit;
JVM_Open;
- JVM_PrintStackTrace;
JVM_RaiseSignal;
JVM_RawMonitorCreate;
JVM_RawMonitorDestroy;
diff -r 77443715ec55 -r b5cb079ecaa4 make/linux/makefiles/optimized.make
--- a/make/linux/makefiles/optimized.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/linux/makefiles/optimized.make Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1999, 2012, 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
@@ -40,5 +40,4 @@
# Linker mapfile
MAPFILE = $(GAMMADIR)/make/linux/makefiles/mapfile-vers-debug
-G_SUFFIX =
VERSION = optimized
diff -r 77443715ec55 -r b5cb079ecaa4 make/linux/makefiles/product.make
--- a/make/linux/makefiles/product.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/linux/makefiles/product.make Sun Feb 03 22:43:57 2013 +0100
@@ -40,7 +40,6 @@
# Linker mapfile
MAPFILE = $(GAMMADIR)/make/linux/makefiles/mapfile-vers-product
-G_SUFFIX =
SYSDEFS += -DPRODUCT
VERSION = optimized
diff -r 77443715ec55 -r b5cb079ecaa4 make/linux/makefiles/saproc.make
--- a/make/linux/makefiles/saproc.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/linux/makefiles/saproc.make Sun Feb 03 22:43:57 2013 +0100
@@ -26,18 +26,13 @@
# Rules to build serviceability agent library, used by vm.make
-# libsaproc[_g].so: serviceability agent
+# libsaproc.so: serviceability agent
SAPROC = saproc
LIBSAPROC = lib$(SAPROC).so
-SAPROC_G = $(SAPROC)$(G_SUFFIX)
-LIBSAPROC_G = lib$(SAPROC_G).so
-
LIBSAPROC_DEBUGINFO = lib$(SAPROC).debuginfo
LIBSAPROC_DIZ = lib$(SAPROC).diz
-LIBSAPROC_G_DEBUGINFO = lib$(SAPROC_G).debuginfo
-LIBSAPROC_G_DIZ = lib$(SAPROC_G).diz
AGENT_DIR = $(GAMMADIR)/agent
@@ -99,7 +94,6 @@
$(SA_DEBUG_CFLAGS) \
-o $@ \
-lthread_db
- $(QUIETLY) [ -f $(LIBSAPROC_G) ] || { ln -s $@ $(LIBSAPROC_G); }
ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
$(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBSAPROC_DEBUGINFO)
$(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBSAPROC_DEBUGINFO) $@
@@ -111,11 +105,9 @@
# implied else here is no stripping at all
endif
endif
- [ -f $(LIBSAPROC_G_DEBUGINFO) ] || { ln -s $(LIBSAPROC_DEBUGINFO) $(LIBSAPROC_G_DEBUGINFO); }
ifeq ($(ZIP_DEBUGINFO_FILES),1)
- $(ZIPEXE) -q -y $(LIBSAPROC_DIZ) $(LIBSAPROC_DEBUGINFO) $(LIBSAPROC_G_DEBUGINFO)
- $(RM) $(LIBSAPROC_DEBUGINFO) $(LIBSAPROC_G_DEBUGINFO)
- [ -f $(LIBSAPROC_G_DIZ) ] || { ln -s $(LIBSAPROC_DIZ) $(LIBSAPROC_G_DIZ); }
+ $(ZIPEXE) -q -y $(LIBSAPROC_DIZ) $(LIBSAPROC_DEBUGINFO)
+ $(RM) $(LIBSAPROC_DEBUGINFO)
endif
endif
diff -r 77443715ec55 -r b5cb079ecaa4 make/linux/makefiles/vm.make
--- a/make/linux/makefiles/vm.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/linux/makefiles/vm.make Sun Feb 03 22:43:57 2013 +0100
@@ -138,12 +138,9 @@
JVM = jvm
LIBJVM = lib$(JVM).so
-LIBJVM_G = lib$(JVM)$(G_SUFFIX).so
LIBJVM_DEBUGINFO = lib$(JVM).debuginfo
LIBJVM_DIZ = lib$(JVM).diz
-LIBJVM_G_DEBUGINFO = lib$(JVM)$(G_SUFFIX).debuginfo
-LIBJVM_G_DIZ = lib$(JVM)$(G_SUFFIX).diz
SPECIAL_PATHS:=adlc c1 gc_implementation opto shark libadt
@@ -323,7 +320,6 @@
$(LFLAGS_VM) -o $@ $(sort $(LIBJVM.o)) $(LIBS_VM); \
$(LINK_LIB.CXX/POST_HOOK) \
rm -f $@.1; ln -s $@ $@.1; \
- [ -f $(LIBJVM_G) ] || { ln -s $@ $(LIBJVM_G); ln -s $@.1 $(LIBJVM_G).1; }; \
if [ \"$(CROSS_COMPILE_ARCH)\" = \"\" ] ; then \
if [ -x /usr/sbin/selinuxenabled ] ; then \
/usr/sbin/selinuxenabled; \
@@ -336,24 +332,21 @@
fi \
fi \
}
-ifeq ($(CROSS_COMPILE_ARCH),)
- ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
+
+ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
$(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(LIBJVM_DEBUGINFO)
$(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DEBUGINFO) $@
- ifeq ($(STRIP_POLICY),all_strip)
+ ifeq ($(STRIP_POLICY),all_strip)
$(QUIETLY) $(STRIP) $@
- else
- ifeq ($(STRIP_POLICY),min_strip)
+ else
+ ifeq ($(STRIP_POLICY),min_strip)
$(QUIETLY) $(STRIP) -g $@
- # implied else here is no stripping at all
- endif
+ # implied else here is no stripping at all
endif
- $(QUIETLY) [ -f $(LIBJVM_G_DEBUGINFO) ] || ln -s $(LIBJVM_DEBUGINFO) $(LIBJVM_G_DEBUGINFO)
- ifeq ($(ZIP_DEBUGINFO_FILES),1)
- $(ZIPEXE) -q -y $(LIBJVM_DIZ) $(LIBJVM_DEBUGINFO) $(LIBJVM_G_DEBUGINFO)
- $(RM) $(LIBJVM_DEBUGINFO) $(LIBJVM_G_DEBUGINFO)
- [ -f $(LIBJVM_G_DIZ) ] || { ln -s $(LIBJVM_DIZ) $(LIBJVM_G_DIZ); }
- endif
+ endif
+ ifeq ($(ZIP_DEBUGINFO_FILES),1)
+ $(ZIPEXE) -q -y $(LIBJVM_DIZ) $(LIBJVM_DEBUGINFO)
+ $(RM) $(LIBJVM_DEBUGINFO)
endif
endif
diff -r 77443715ec55 -r b5cb079ecaa4 make/solaris/Makefile
--- a/make/solaris/Makefile Mon Nov 05 17:03:33 2012 -0500
+++ b/make/solaris/Makefile Sun Feb 03 22:43:57 2013 +0100
@@ -38,10 +38,10 @@
# Along with VM, Serviceability Agent (SA) is built for SA/JDI binding.
# JDI binding on SA produces two binaries:
-# 1. sa-jdi.jar - This is build before building libjvm[_g].so
+# 1. sa-jdi.jar - This is built before building libjvm.so
# Please refer to ./makefiles/sa.make
-# 2. libsaproc[_g].so - Native library for SA - This is built after
-# libjsig[_g].so (signal interposition library)
+# 2. libsaproc.so - Native library for SA - This is built after
+# libjsig.so (signal interposition library)
# Please refer to ./makefiles/vm.make
# If $(GAMMADIR)/agent dir is not present, SA components are not built.
@@ -141,9 +141,9 @@
#
# What you get with each target:
#
-# debug* - "thin" libjvm_g - debug info linked into the gamma_g launcher
+# debug* - "thin" libjvm - debug info linked into the gamma launcher
# fastdebug* - optimized compile, but with asserts enabled
-# jvmg* - "fat" libjvm_g - debug info linked into libjvm_g.so
+# jvmg* - "fat" libjvm - debug info linked into libjvm.so
# optimized* - optimized compile, no asserts
# profiled* - gprof
# product* - the shippable thing: optimized compile, no asserts, -DPRODUCT
diff -r 77443715ec55 -r b5cb079ecaa4 make/solaris/makefiles/buildtree.make
--- a/make/solaris/makefiles/buildtree.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/solaris/makefiles/buildtree.make Sun Feb 03 22:43:57 2013 +0100
@@ -436,12 +436,7 @@
echo " exit 0"; \
echo "fi"; \
echo ""; \
- echo "# Use gamma_g if it exists"; \
- echo ""; \
echo "GAMMA_PROG=gamma"; \
- echo "if [ -f gamma_g ]; then "; \
- echo " GAMMA_PROG=gamma_g"; \
- echo "fi"; \
echo ""; \
echo "if [ \"$(OS_VENDOR)\" = \"Darwin\" ]; then "; \
echo " # Ensure architecture for gamma and JAVA_HOME is the same."; \
diff -r 77443715ec55 -r b5cb079ecaa4 make/solaris/makefiles/debug.make
--- a/make/solaris/makefiles/debug.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/solaris/makefiles/debug.make Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
#
-# Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 1998, 2012, 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
@@ -53,7 +53,6 @@
"Please use 'gnumake jvmg' to build debug JVM. \n" \
"-------------------------------------------------------------------------\n")
-G_SUFFIX = _g
VERSION = debug
SYSDEFS += -DASSERT -DDEBUG
PICFLAGS = DEFAULT
diff -r 77443715ec55 -r b5cb079ecaa4 make/solaris/makefiles/defs.make
--- a/make/solaris/makefiles/defs.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/solaris/makefiles/defs.make Sun Feb 03 22:43:57 2013 +0100
@@ -109,60 +109,63 @@
# overridden in some situations, e.g., a BUILD_FLAVOR != product
# build.
- ifeq ($(BUILD_FLAVOR), product)
- FULL_DEBUG_SYMBOLS ?= 1
- ENABLE_FULL_DEBUG_SYMBOLS = $(FULL_DEBUG_SYMBOLS)
- else
- # debug variants always get Full Debug Symbols (if available)
- ENABLE_FULL_DEBUG_SYMBOLS = 1
- endif
- _JUNK_ := $(shell \
- echo >&2 "INFO: ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS)")
- # since objcopy is optional, we set ZIP_DEBUGINFO_FILES later
-
- ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
- # Default OBJCOPY comes from the SUNWbinutils package:
- DEF_OBJCOPY=/usr/sfw/bin/gobjcopy
- OBJCOPY=$(shell test -x $(DEF_OBJCOPY) && echo $(DEF_OBJCOPY))
- ifneq ($(ALT_OBJCOPY),)
- _JUNK_ := $(shell echo >&2 "INFO: ALT_OBJCOPY=$(ALT_OBJCOPY)")
- OBJCOPY=$(shell test -x $(ALT_OBJCOPY) && echo $(ALT_OBJCOPY))
+ # Due to the multiple sub-make processes that occur this logic gets
+ # executed multiple times. We reduce the noise by at least checking that
+ # BUILD_FLAVOR has been set.
+ ifneq ($(BUILD_FLAVOR),)
+ ifeq ($(BUILD_FLAVOR), product)
+ FULL_DEBUG_SYMBOLS ?= 1
+ ENABLE_FULL_DEBUG_SYMBOLS = $(FULL_DEBUG_SYMBOLS)
+ else
+ # debug variants always get Full Debug Symbols (if available)
+ ENABLE_FULL_DEBUG_SYMBOLS = 1
endif
- else
- OBJCOPY=
- endif
-
- ifeq ($(OBJCOPY),)
- _JUNK_ := $(shell \
- echo >&2 "INFO: no objcopy cmd found so cannot create .debuginfo files.")
- ENABLE_FULL_DEBUG_SYMBOLS=0
_JUNK_ := $(shell \
echo >&2 "INFO: ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS)")
- else
- _JUNK_ := $(shell \
- echo >&2 "INFO: $(OBJCOPY) cmd found so will create .debuginfo files.")
+ # since objcopy is optional, we set ZIP_DEBUGINFO_FILES later
+
+ ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
+ # Default OBJCOPY comes from the SUNWbinutils package:
+ DEF_OBJCOPY=/usr/sfw/bin/gobjcopy
+ OBJCOPY=$(shell test -x $(DEF_OBJCOPY) && echo $(DEF_OBJCOPY))
+ ifneq ($(ALT_OBJCOPY),)
+ _JUNK_ := $(shell echo >&2 "INFO: ALT_OBJCOPY=$(ALT_OBJCOPY)")
+ OBJCOPY=$(shell test -x $(ALT_OBJCOPY) && echo $(ALT_OBJCOPY))
+ endif
+
+ ifeq ($(OBJCOPY),)
+ _JUNK_ := $(shell \
+ echo >&2 "INFO: no objcopy cmd found so cannot create .debuginfo files.")
+ ENABLE_FULL_DEBUG_SYMBOLS=0
+ _JUNK_ := $(shell \
+ echo >&2 "INFO: ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS)")
+ else
+ _JUNK_ := $(shell \
+ echo >&2 "INFO: $(OBJCOPY) cmd found so will create .debuginfo files.")
- # Library stripping policies for .debuginfo configs:
- # all_strip - strips everything from the library
- # min_strip - strips most stuff from the library; leaves minimum symbols
- # no_strip - does not strip the library at all
- #
- # Oracle security policy requires "all_strip". A waiver was granted on
- # 2011.09.01 that permits using "min_strip" in the Java JDK and Java JRE.
- #
- # Currently, STRIP_POLICY is only used when Full Debug Symbols is enabled.
- #
- STRIP_POLICY ?= min_strip
+ # Library stripping policies for .debuginfo configs:
+ # all_strip - strips everything from the library
+ # min_strip - strips most stuff from the library; leaves minimum symbols
+ # no_strip - does not strip the library at all
+ #
+ # Oracle security policy requires "all_strip". A waiver was granted on
+ # 2011.09.01 that permits using "min_strip" in the Java JDK and Java JRE.
+ #
+ # Currently, STRIP_POLICY is only used when Full Debug Symbols is enabled.
+ #
+ STRIP_POLICY ?= min_strip
- _JUNK_ := $(shell \
- echo >&2 "INFO: STRIP_POLICY=$(STRIP_POLICY)")
+ _JUNK_ := $(shell \
+ echo >&2 "INFO: STRIP_POLICY=$(STRIP_POLICY)")
- ZIP_DEBUGINFO_FILES ?= 1
+ ZIP_DEBUGINFO_FILES ?= 1
- _JUNK_ := $(shell \
- echo >&2 "INFO: ZIP_DEBUGINFO_FILES=$(ZIP_DEBUGINFO_FILES)")
- endif
-endif
+ _JUNK_ := $(shell \
+ echo >&2 "INFO: ZIP_DEBUGINFO_FILES=$(ZIP_DEBUGINFO_FILES)")
+ endif
+ endif # ENABLE_FULL_DEBUG_SYMBOLS=1
+ endif # BUILD_FLAVOR
+endif # JDK_6_OR_EARLIER
JDK_INCLUDE_SUBDIR=solaris
diff -r 77443715ec55 -r b5cb079ecaa4 make/solaris/makefiles/dtrace.make
--- a/make/solaris/makefiles/dtrace.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/solaris/makefiles/dtrace.make Sun Feb 03 22:43:57 2013 +0100
@@ -39,21 +39,15 @@
JVM_DB = libjvm_db
LIBJVM_DB = libjvm_db.so
-LIBJVM_DB_G = libjvm$(G_SUFFIX)_db.so
LIBJVM_DB_DEBUGINFO = libjvm_db.debuginfo
LIBJVM_DB_DIZ = libjvm_db.diz
-LIBJVM_DB_G_DEBUGINFO = libjvm$(G_SUFFIX)_db.debuginfo
-LIBJVM_DB_G_DIZ = libjvm$(G_SUFFIX)_db.diz
JVM_DTRACE = jvm_dtrace
LIBJVM_DTRACE = libjvm_dtrace.so
-LIBJVM_DTRACE_G = libjvm$(G_SUFFIX)_dtrace.so
LIBJVM_DTRACE_DEBUGINFO = libjvm_dtrace.debuginfo
LIBJVM_DTRACE_DIZ = libjvm_dtrace.diz
-LIBJVM_DTRACE_G_DEBUGINFO = libjvm$(G_SUFFIX)_dtrace.debuginfo
-LIBJVM_DTRACE_G_DIZ = libjvm$(G_SUFFIX)_dtrace.diz
JVMOFFS = JvmOffsets
JVMOFFS.o = $(JVMOFFS).o
@@ -96,25 +90,18 @@
XLIBJVM_DIR = 64
XLIBJVM_DB = $(XLIBJVM_DIR)/$(LIBJVM_DB)
-XLIBJVM_DB_G = $(XLIBJVM_DIR)/$(LIBJVM_DB_G)
XLIBJVM_DTRACE = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE)
-XLIBJVM_DTRACE_G = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_G)
XLIBJVM_DB_DEBUGINFO = $(XLIBJVM_DIR)/$(LIBJVM_DB_DEBUGINFO)
XLIBJVM_DB_DIZ = $(XLIBJVM_DIR)/$(LIBJVM_DB_DIZ)
-XLIBJVM_DB_G_DEBUGINFO = $(XLIBJVM_DIR)/$(LIBJVM_DB_G_DEBUGINFO)
-XLIBJVM_DB_G_DIZ = $(XLIBJVM_DIR)/$(LIBJVM_DB_G_DIZ)
XLIBJVM_DTRACE_DEBUGINFO = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_DEBUGINFO)
XLIBJVM_DTRACE_DIZ = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_DIZ)
-XLIBJVM_DTRACE_G_DEBUGINFO = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_G_DEBUGINFO)
-XLIBJVM_DTRACE_G_DIZ = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_G_DIZ)
$(XLIBJVM_DB): $(ADD_GNU_DEBUGLINK) $(FIX_EMPTY_SEC_HDR_FLAGS) $(DTRACE_SRCDIR)/$(JVM_DB).c $(JVMOFFS).h $(LIBJVM_DB_MAPFILE)
@echo Making $@
$(QUIETLY) mkdir -p $(XLIBJVM_DIR) ; \
$(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. -I$(GENERATED) \
$(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c -lc
- [ -f $(XLIBJVM_DB_G) ] || { ln -s $(LIBJVM_DB) $(XLIBJVM_DB_G); }
ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
# gobjcopy crashes on "empty" section headers with the SHF_ALLOC flag set.
# Clear the SHF_ALLOC flag (if set) from empty section headers.
@@ -137,13 +124,11 @@
# implied else here is no stripping at all
endif
endif
- [ -f $(XLIBJVM_DB_G_DEBUGINFO) ] || { cd $(XLIBJVM_DIR) && ln -s $(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB_G_DEBUGINFO); }
ifeq ($(ZIP_DEBUGINFO_FILES),1)
# Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) is not
# in the archived name:
- ( cd $(XLIBJVM_DIR) && $(ZIPEXE) -q -y $(LIBJVM_DB_DIZ) $(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB_G_DEBUGINFO) )
- $(RM) $(XLIBJVM_DB_DEBUGINFO) $(XLIBJVM_DB_G_DEBUGINFO)
- [ -f $(XLIBJVM_DB_G_DIZ) ] || { cd $(XLIBJVM_DIR) && ln -s $(LIBJVM_DB_DIZ) $(LIBJVM_DB_G_DIZ); }
+ ( cd $(XLIBJVM_DIR) && $(ZIPEXE) -q -y $(LIBJVM_DB_DIZ) $(LIBJVM_DB_DEBUGINFO) )
+ $(RM) $(XLIBJVM_DB_DEBUGINFO)
endif
endif
@@ -152,7 +137,6 @@
$(QUIETLY) mkdir -p $(XLIBJVM_DIR) ; \
$(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. \
$(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c -lc -lthread -ldoor
- [ -f $(XLIBJVM_DTRACE_G) ] || { ln -s $(LIBJVM_DTRACE) $(XLIBJVM_DTRACE_G); }
ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
# Clear the SHF_ALLOC flag (if set) from empty section headers.
$(QUIETLY) $(FIX_EMPTY_SEC_HDR_FLAGS) $@
@@ -170,13 +154,11 @@
# implied else here is no stripping at all
endif
endif
- [ -f $(XLIBJVM_DTRACE_G_DEBUGINFO) ] || { cd $(XLIBJVM_DIR) && ln -s $(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE_G_DEBUGINFO); }
ifeq ($(ZIP_DEBUGINFO_FILES),1)
# Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) is not
# in the archived name:
- ( cd $(XLIBJVM_DIR) && $(ZIPEXE) -q -y $(LIBJVM_DTRACE_DIZ) $(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE_G_DEBUGINFO) )
- $(RM) $(XLIBJVM_DTRACE_DEBUGINFO) $(XLIBJVM_DTRACE_G_DEBUGINFO)
- [ -f $(XLIBJVM_DTRACE_G_DIZ) ] || { cd $(XLIBJVM_DIR) && ln -s $(LIBJVM_DTRACE_DIZ) $(LIBJVM_DTRACE_G_DIZ); }
+ ( cd $(XLIBJVM_DIR) && $(ZIPEXE) -q -y $(LIBJVM_DTRACE_DIZ) $(LIBJVM_DTRACE_DEBUGINFO))
+ $(RM) $(XLIBJVM_DTRACE_DEBUGINFO)
endif
endif
@@ -224,7 +206,6 @@
@echo Making $@
$(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) -D$(TYPE) -I. -I$(GENERATED) \
$(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c -lc
- [ -f $(LIBJVM_DB_G) ] || { ln -s $@ $(LIBJVM_DB_G); }
ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
# Clear the SHF_ALLOC flag (if set) from empty section headers.
$(QUIETLY) $(FIX_EMPTY_SEC_HDR_FLAGS) $@
@@ -240,11 +221,9 @@
# implied else here is no stripping at all
endif
endif
- [ -f $(LIBJVM_DB_G_DEBUGINFO) ] || { ln -s $(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB_G_DEBUGINFO); }
ifeq ($(ZIP_DEBUGINFO_FILES),1)
- $(ZIPEXE) -q -y $(LIBJVM_DB_DIZ) $(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB_G_DEBUGINFO)
- $(RM) $(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB_G_DEBUGINFO)
- [ -f $(LIBJVM_DB_G_DIZ) ] || { ln -s $(LIBJVM_DB_DIZ) $(LIBJVM_DB_G_DIZ); }
+ $(ZIPEXE) -q -y $(LIBJVM_DB_DIZ) $(LIBJVM_DB_DEBUGINFO)
+ $(RM) $(LIBJVM_DB_DEBUGINFO)
endif
endif
@@ -252,7 +231,6 @@
@echo Making $@
$(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) -D$(TYPE) -I. \
$(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c -lc -lthread -ldoor
- [ -f $(LIBJVM_DTRACE_G) ] || { ln -s $@ $(LIBJVM_DTRACE_G); }
ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
# Clear the SHF_ALLOC flag (if set) from empty section headers.
$(QUIETLY) $(FIX_EMPTY_SEC_HDR_FLAGS) $@
@@ -268,11 +246,9 @@
# implied else here is no stripping at all
endif
endif
- [ -f $(LIBJVM_DTRACE_G_DEBUGINFO) ] || { ln -s $(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE_G_DEBUGINFO); }
ifeq ($(ZIP_DEBUGINFO_FILES),1)
- $(ZIPEXE) -q -y $(LIBJVM_DTRACE_DIZ) $(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE_G_DEBUGINFO)
- $(RM) $(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE_G_DEBUGINFO)
- [ -f $(LIBJVM_DTRACE_G_DIZ) ] || { ln -s $(LIBJVM_DTRACE_DIZ) $(LIBJVM_DTRACE_G_DIZ); }
+ $(ZIPEXE) -q -y $(LIBJVM_DTRACE_DIZ) $(LIBJVM_DTRACE_DEBUGINFO)
+ $(RM) $(LIBJVM_DTRACE_DEBUGINFO)
endif
endif
diff -r 77443715ec55 -r b5cb079ecaa4 make/solaris/makefiles/fastdebug.make
--- a/make/solaris/makefiles/fastdebug.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/solaris/makefiles/fastdebug.make Sun Feb 03 22:43:57 2013 +0100
@@ -122,7 +122,6 @@
# and mustn't be otherwise.
MAPFILE_DTRACE = $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-$(TYPE)
-G_SUFFIX = _g
VERSION = optimized
SYSDEFS += -DASSERT -DFASTDEBUG -DCHECK_UNHANDLED_OOPS
PICFLAGS = DEFAULT
diff -r 77443715ec55 -r b5cb079ecaa4 make/solaris/makefiles/gcc.make
--- a/make/solaris/makefiles/gcc.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/solaris/makefiles/gcc.make Sun Feb 03 22:43:57 2013 +0100
@@ -187,9 +187,9 @@
# Use the stabs format for debugging information (this is the default
# on gcc-2.91). It's good enough, has all the information about line
-# numbers and local variables, and libjvm_g.so is only about 16M.
+# numbers and local variables, and libjvm.so is only about 16M.
# Change this back to "-g" if you want the most expressive format.
-# (warning: that could easily inflate libjvm_g.so to 150M!)
+# (warning: that could easily inflate libjvm.so to 150M!)
# Note: The Itanium gcc compiler crashes when using -gstabs.
DEBUG_CFLAGS/ia64 = -g
DEBUG_CFLAGS/amd64 = -g
diff -r 77443715ec55 -r b5cb079ecaa4 make/solaris/makefiles/jsig.make
--- a/make/solaris/makefiles/jsig.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/solaris/makefiles/jsig.make Sun Feb 03 22:43:57 2013 +0100
@@ -24,17 +24,12 @@
# Rules to build signal interposition library, used by vm.make
-# libjsig[_g].so: signal interposition library
+# libjsig.so: signal interposition library
JSIG = jsig
LIBJSIG = lib$(JSIG).so
-JSIG_G = $(JSIG)$(G_SUFFIX)
-LIBJSIG_G = lib$(JSIG_G).so
-
LIBJSIG_DEBUGINFO = lib$(JSIG).debuginfo
LIBJSIG_DIZ = lib$(JSIG).diz
-LIBJSIG_G_DEBUGINFO = lib$(JSIG_G).debuginfo
-LIBJSIG_G_DIZ = lib$(JSIG_G).diz
JSIGSRCDIR = $(GAMMADIR)/src/os/$(Platform_os_family)/vm
@@ -56,7 +51,6 @@
@echo Making signal interposition lib...
$(QUIETLY) $(CC) $(SYMFLAG) $(ARCHFLAG) $(SHARED_FLAG) $(PICFLAG) \
$(LFLAGS_JSIG) -o $@ $(JSIGSRCDIR)/jsig.c -ldl
- [ -f $(LIBJSIG_G) ] || { ln -s $@ $(LIBJSIG_G); }
ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
# gobjcopy crashes on "empty" section headers with the SHF_ALLOC flag set.
# Clear the SHF_ALLOC flag (if set) from empty section headers.
@@ -77,11 +71,9 @@
# implied else here is no stripping at all
endif
endif
- [ -f $(LIBJSIG_G_DEBUGINFO) ] || { ln -s $(LIBJSIG_DEBUGINFO) $(LIBJSIG_G_DEBUGINFO); }
ifeq ($(ZIP_DEBUGINFO_FILES),1)
- $(ZIPEXE) -q -y $(LIBJSIG_DIZ) $(LIBJSIG_DEBUGINFO) $(LIBJSIG_G_DEBUGINFO)
- $(RM) $(LIBJSIG_DEBUGINFO) $(LIBJSIG_G_DEBUGINFO)
- [ -f $(LIBJSIG_G_DIZ) ] || { ln -s $(LIBJSIG_DIZ) $(LIBJSIG_G_DIZ); }
+ $(ZIPEXE) -q -y $(LIBJSIG_DIZ) $(LIBJSIG_DEBUGINFO)
+ $(RM) $(LIBJSIG_DEBUGINFO)
endif
endif
diff -r 77443715ec55 -r b5cb079ecaa4 make/solaris/makefiles/jvmg.make
--- a/make/solaris/makefiles/jvmg.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/solaris/makefiles/jvmg.make Sun Feb 03 22:43:57 2013 +0100
@@ -51,7 +51,6 @@
# and mustn't be otherwise.
MAPFILE_DTRACE = $(GAMMADIR)/make/solaris/makefiles/mapfile-vers-$(TYPE)
-G_SUFFIX = _g
VERSION = debug
SYSDEFS += -DASSERT -DDEBUG
PICFLAGS = DEFAULT
diff -r 77443715ec55 -r b5cb079ecaa4 make/solaris/makefiles/mapfile-vers
--- a/make/solaris/makefiles/mapfile-vers Mon Nov 05 17:03:33 2012 -0500
+++ b/make/solaris/makefiles/mapfile-vers Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -26,235 +26,236 @@
SUNWprivate_1.1 {
global:
- # JNI
+ # JNI
JNI_CreateJavaVM;
JNI_GetCreatedJavaVMs;
JNI_GetDefaultJavaVMInitArgs;
-
- # JVM
- JVM_Accept;
- JVM_ActiveProcessorCount;
- JVM_AllocateNewArray;
- JVM_AllocateNewObject;
- JVM_ArrayCopy;
- JVM_AssertionStatusDirectives;
- JVM_Available;
- JVM_Bind;
- JVM_ClassDepth;
- JVM_ClassLoaderDepth;
- JVM_Clone;
- JVM_Close;
- JVM_CX8Field;
- JVM_CompileClass;
- JVM_CompileClasses;
- JVM_CompilerCommand;
- JVM_Connect;
- JVM_ConstantPoolGetClassAt;
- JVM_ConstantPoolGetClassAtIfLoaded;
- JVM_ConstantPoolGetDoubleAt;
- JVM_ConstantPoolGetFieldAt;
- JVM_ConstantPoolGetFieldAtIfLoaded;
- JVM_ConstantPoolGetFloatAt;
- JVM_ConstantPoolGetIntAt;
- JVM_ConstantPoolGetLongAt;
- JVM_ConstantPoolGetMethodAt;
- JVM_ConstantPoolGetMethodAtIfLoaded;
- JVM_ConstantPoolGetMemberRefInfoAt;
- JVM_ConstantPoolGetSize;
- JVM_ConstantPoolGetStringAt;
- JVM_ConstantPoolGetUTF8At;
- JVM_CountStackFrames;
- JVM_CurrentClassLoader;
- JVM_CurrentLoadedClass;
- JVM_CurrentThread;
- JVM_CurrentTimeMillis;
- JVM_DefineClass;
- JVM_DefineClassWithSource;
- JVM_DefineClassWithSourceCond;
- JVM_DesiredAssertionStatus;
- JVM_DisableCompiler;
- JVM_DoPrivileged;
- JVM_DTraceGetVersion;
- JVM_DTraceActivate;
- JVM_DTraceIsProbeEnabled;
- JVM_DTraceIsSupported;
- JVM_DTraceDispose;
- JVM_DumpAllStacks;
- JVM_DumpThreads;
- JVM_EnableCompiler;
- JVM_Exit;
- JVM_FillInStackTrace;
- JVM_FindClassFromClass;
- JVM_FindClassFromClassLoader;
- JVM_FindClassFromBootLoader;
- JVM_FindLibraryEntry;
- JVM_FindLoadedClass;
- JVM_FindPrimitiveClass;
- JVM_FindSignal;
- JVM_FreeMemory;
- JVM_GC;
- JVM_GetAllThreads;
- JVM_GetArrayElement;
- JVM_GetArrayLength;
- JVM_GetCPClassNameUTF;
- JVM_GetCPFieldClassNameUTF;
- JVM_GetCPFieldModifiers;
- JVM_GetCPFieldNameUTF;
- JVM_GetCPFieldSignatureUTF;
- JVM_GetCPMethodClassNameUTF;
- JVM_GetCPMethodModifiers;
- JVM_GetCPMethodNameUTF;
- JVM_GetCPMethodSignatureUTF;
- JVM_GetCallerClass;
- JVM_GetClassAccessFlags;
- JVM_GetClassAnnotations;
- JVM_GetClassCPEntriesCount;
- JVM_GetClassCPTypes;
- JVM_GetClassConstantPool;
- JVM_GetClassContext;
- JVM_GetClassDeclaredConstructors;
- JVM_GetClassDeclaredFields;
- JVM_GetClassDeclaredMethods;
- JVM_GetClassFieldsCount;
- JVM_GetClassInterfaces;
- JVM_GetClassLoader;
- JVM_GetClassMethodsCount;
- JVM_GetClassModifiers;
- JVM_GetClassName;
- JVM_GetClassNameUTF;
- JVM_GetClassSignature;
- JVM_GetClassSigners;
- JVM_GetComponentType;
- JVM_GetDeclaredClasses;
- JVM_GetDeclaringClass;
- JVM_GetEnclosingMethodInfo;
- JVM_GetFieldAnnotations;
- JVM_GetFieldIxModifiers;
- JVM_GetHostName;
- JVM_GetInheritedAccessControlContext;
- JVM_GetInterfaceVersion;
- JVM_GetLastErrorString;
- JVM_GetManagement;
- JVM_GetMethodAnnotations;
- JVM_GetMethodDefaultAnnotationValue;
- JVM_GetMethodIxArgsSize;
- JVM_GetMethodIxByteCode;
- JVM_GetMethodIxByteCodeLength;
- JVM_GetMethodIxExceptionIndexes;
- JVM_GetMethodIxExceptionTableEntry;
- JVM_GetMethodIxExceptionTableLength;
- JVM_GetMethodIxExceptionsCount;
- JVM_GetMethodIxLocalsCount;
- JVM_GetMethodIxMaxStack;
- JVM_GetMethodIxModifiers;
- JVM_GetMethodIxNameUTF;
- JVM_GetMethodIxSignatureUTF;
- JVM_GetMethodParameterAnnotations;
- JVM_GetPrimitiveArrayElement;
- JVM_GetProtectionDomain;
- JVM_GetSockName;
- JVM_GetSockOpt;
- JVM_GetStackAccessControlContext;
- JVM_GetStackTraceDepth;
- JVM_GetStackTraceElement;
- JVM_GetSystemPackage;
- JVM_GetSystemPackages;
- JVM_GetThreadStateNames;
- JVM_GetThreadStateValues;
- JVM_GetVersionInfo;
- JVM_Halt;
- JVM_HoldsLock;
- JVM_IHashCode;
- JVM_InitAgentProperties;
- JVM_InitProperties;
- JVM_InitializeCompiler;
- JVM_InitializeSocketLibrary;
- JVM_InternString;
- JVM_Interrupt;
- JVM_InvokeMethod;
- JVM_IsArrayClass;
- JVM_IsConstructorIx;
- JVM_IsInterface;
- JVM_IsInterrupted;
- JVM_IsNaN;
- JVM_IsPrimitiveClass;
- JVM_IsSameClassPackage;
- JVM_IsSilentCompiler;
- JVM_IsSupportedJNIVersion;
- JVM_IsThreadAlive;
- JVM_LatestUserDefinedLoader;
- JVM_Listen;
- JVM_LoadClass0;
- JVM_LoadLibrary;
- JVM_Lseek;
- JVM_MaxObjectInspectionAge;
- JVM_MaxMemory;
- JVM_MonitorNotify;
- JVM_MonitorNotifyAll;
- JVM_MonitorWait;
- JVM_NativePath;
- JVM_NanoTime;
- JVM_NewArray;
- JVM_NewInstanceFromConstructor;
- JVM_NewMultiArray;
- JVM_OnExit;
- JVM_Open;
- JVM_PrintStackTrace;
- JVM_RaiseSignal;
- JVM_RawMonitorCreate;
- JVM_RawMonitorDestroy;
- JVM_RawMonitorEnter;
- JVM_RawMonitorExit;
- JVM_Read;
- JVM_Recv;
- JVM_RecvFrom;
- JVM_RegisterSignal;
- JVM_ReleaseUTF;
- JVM_ResolveClass;
- JVM_ResumeThread;
- JVM_Send;
- JVM_SendTo;
- JVM_SetArrayElement;
- JVM_SetClassSigners;
- JVM_SetLength;
+
+ # JVM
+ JVM_Accept;
+ JVM_ActiveProcessorCount;
+ JVM_AllocateNewArray;
+ JVM_AllocateNewObject;
+ JVM_ArrayCopy;
+ JVM_AssertionStatusDirectives;
+ JVM_Available;
+ JVM_Bind;
+ JVM_ClassDepth;
+ JVM_ClassLoaderDepth;
+ JVM_Clone;
+ JVM_Close;
+ JVM_CX8Field;
+ JVM_CompileClass;
+ JVM_CompileClasses;
+ JVM_CompilerCommand;
+ JVM_Connect;
+ JVM_ConstantPoolGetClassAt;
+ JVM_ConstantPoolGetClassAtIfLoaded;
+ JVM_ConstantPoolGetDoubleAt;
+ JVM_ConstantPoolGetFieldAt;
+ JVM_ConstantPoolGetFieldAtIfLoaded;
+ JVM_ConstantPoolGetFloatAt;
+ JVM_ConstantPoolGetIntAt;
+ JVM_ConstantPoolGetLongAt;
+ JVM_ConstantPoolGetMethodAt;
+ JVM_ConstantPoolGetMethodAtIfLoaded;
+ JVM_ConstantPoolGetMemberRefInfoAt;
+ JVM_ConstantPoolGetSize;
+ JVM_ConstantPoolGetStringAt;
+ JVM_ConstantPoolGetUTF8At;
+ JVM_CountStackFrames;
+ JVM_CurrentClassLoader;
+ JVM_CurrentLoadedClass;
+ JVM_CurrentThread;
+ JVM_CurrentTimeMillis;
+ JVM_DefineClass;
+ JVM_DefineClassWithSource;
+ JVM_DefineClassWithSourceCond;
+ JVM_DesiredAssertionStatus;
+ JVM_DisableCompiler;
+ JVM_DoPrivileged;
+ JVM_DTraceGetVersion;
+ JVM_DTraceActivate;
+ JVM_DTraceIsProbeEnabled;
+ JVM_DTraceIsSupported;
+ JVM_DTraceDispose;
+ JVM_DumpAllStacks;
+ JVM_DumpThreads;
+ JVM_EnableCompiler;
+ JVM_Exit;
+ JVM_FillInStackTrace;
+ JVM_FindClassFromClass;
+ JVM_FindClassFromClassLoader;
+ JVM_FindClassFromBootLoader;
+ JVM_FindLibraryEntry;
+ JVM_FindLoadedClass;
+ JVM_FindPrimitiveClass;
+ JVM_FindSignal;
+ JVM_FreeMemory;
+ JVM_GC;
+ JVM_GetAllThreads;
+ JVM_GetArrayElement;
+ JVM_GetArrayLength;
+ JVM_GetCPClassNameUTF;
+ JVM_GetCPFieldClassNameUTF;
+ JVM_GetCPFieldModifiers;
+ JVM_GetCPFieldNameUTF;
+ JVM_GetCPFieldSignatureUTF;
+ JVM_GetCPMethodClassNameUTF;
+ JVM_GetCPMethodModifiers;
+ JVM_GetCPMethodNameUTF;
+ JVM_GetCPMethodSignatureUTF;
+ JVM_GetCallerClass;
+ JVM_GetClassAccessFlags;
+ JVM_GetClassAnnotations;
+ JVM_GetClassCPEntriesCount;
+ JVM_GetClassCPTypes;
+ JVM_GetClassConstantPool;
+ JVM_GetClassContext;
+ JVM_GetClassDeclaredConstructors;
+ JVM_GetClassDeclaredFields;
+ JVM_GetClassDeclaredMethods;
+ JVM_GetClassFieldsCount;
+ JVM_GetClassInterfaces;
+ JVM_GetClassLoader;
+ JVM_GetClassMethodsCount;
+ JVM_GetClassModifiers;
+ JVM_GetClassName;
+ JVM_GetClassNameUTF;
+ JVM_GetClassSignature;
+ JVM_GetClassSigners;
+ JVM_GetComponentType;
+ JVM_GetClassTypeAnnotations;
+ JVM_GetDeclaredClasses;
+ JVM_GetDeclaringClass;
+ JVM_GetEnclosingMethodInfo;
+ JVM_GetFieldAnnotations;
+ JVM_GetFieldIxModifiers;
+ JVM_GetHostName;
+ JVM_GetInheritedAccessControlContext;
+ JVM_GetInterfaceVersion;
+ JVM_GetLastErrorString;
+ JVM_GetManagement;
+ JVM_GetMethodAnnotations;
+ JVM_GetMethodDefaultAnnotationValue;
+ JVM_GetMethodIxArgsSize;
+ JVM_GetMethodIxByteCode;
+ JVM_GetMethodIxByteCodeLength;
+ JVM_GetMethodIxExceptionIndexes;
+ JVM_GetMethodIxExceptionTableEntry;
+ JVM_GetMethodIxExceptionTableLength;
+ JVM_GetMethodIxExceptionsCount;
+ JVM_GetMethodIxLocalsCount;
+ JVM_GetMethodIxMaxStack;
+ JVM_GetMethodIxModifiers;
+ JVM_GetMethodIxNameUTF;
+ JVM_GetMethodIxSignatureUTF;
+ JVM_GetMethodParameterAnnotations;
+ JVM_GetMethodParameters;
+ JVM_GetPrimitiveArrayElement;
+ JVM_GetProtectionDomain;
+ JVM_GetSockName;
+ JVM_GetSockOpt;
+ JVM_GetStackAccessControlContext;
+ JVM_GetStackTraceDepth;
+ JVM_GetStackTraceElement;
+ JVM_GetSystemPackage;
+ JVM_GetSystemPackages;
+ JVM_GetThreadStateNames;
+ JVM_GetThreadStateValues;
+ JVM_GetVersionInfo;
+ JVM_Halt;
+ JVM_HoldsLock;
+ JVM_IHashCode;
+ JVM_InitAgentProperties;
+ JVM_InitProperties;
+ JVM_InitializeCompiler;
+ JVM_InitializeSocketLibrary;
+ JVM_InternString;
+ JVM_Interrupt;
+ JVM_InvokeMethod;
+ JVM_IsArrayClass;
+ JVM_IsConstructorIx;
+ JVM_IsInterface;
+ JVM_IsInterrupted;
+ JVM_IsNaN;
+ JVM_IsPrimitiveClass;
+ JVM_IsSameClassPackage;
+ JVM_IsSilentCompiler;
+ JVM_IsSupportedJNIVersion;
+ JVM_IsThreadAlive;
+ JVM_LatestUserDefinedLoader;
+ JVM_Listen;
+ JVM_LoadClass0;
+ JVM_LoadLibrary;
+ JVM_Lseek;
+ JVM_MaxObjectInspectionAge;
+ JVM_MaxMemory;
+ JVM_MonitorNotify;
+ JVM_MonitorNotifyAll;
+ JVM_MonitorWait;
+ JVM_NativePath;
+ JVM_NanoTime;
+ JVM_NewArray;
+ JVM_NewInstanceFromConstructor;
+ JVM_NewMultiArray;
+ JVM_OnExit;
+ JVM_Open;
+ JVM_RaiseSignal;
+ JVM_RawMonitorCreate;
+ JVM_RawMonitorDestroy;
+ JVM_RawMonitorEnter;
+ JVM_RawMonitorExit;
+ JVM_Read;
+ JVM_Recv;
+ JVM_RecvFrom;
+ JVM_RegisterSignal;
+ JVM_ReleaseUTF;
+ JVM_ResolveClass;
+ JVM_ResumeThread;
+ JVM_Send;
+ JVM_SendTo;
+ JVM_SetArrayElement;
+ JVM_SetClassSigners;
+ JVM_SetLength;
JVM_SetNativeThreadName;
- JVM_SetPrimitiveArrayElement;
- JVM_SetProtectionDomain;
- JVM_SetSockOpt;
- JVM_SetThreadPriority;
- JVM_Sleep;
- JVM_Socket;
- JVM_SocketAvailable;
- JVM_SocketClose;
- JVM_SocketShutdown;
- JVM_StartThread;
- JVM_StopThread;
- JVM_SuspendThread;
- JVM_SupportsCX8;
- JVM_Sync;
- JVM_Timeout;
- JVM_TotalMemory;
- JVM_TraceInstructions;
- JVM_TraceMethodCalls;
- JVM_UnloadLibrary;
- JVM_Write;
- JVM_Yield;
- JVM_handle_solaris_signal;
+ JVM_SetPrimitiveArrayElement;
+ JVM_SetProtectionDomain;
+ JVM_SetSockOpt;
+ JVM_SetThreadPriority;
+ JVM_Sleep;
+ JVM_Socket;
+ JVM_SocketAvailable;
+ JVM_SocketClose;
+ JVM_SocketShutdown;
+ JVM_StartThread;
+ JVM_StopThread;
+ JVM_SuspendThread;
+ JVM_SupportsCX8;
+ JVM_Sync;
+ JVM_Timeout;
+ JVM_TotalMemory;
+ JVM_TraceInstructions;
+ JVM_TraceMethodCalls;
+ JVM_UnloadLibrary;
+ JVM_Write;
+ JVM_Yield;
+ JVM_handle_solaris_signal;
- # miscellaneous functions
- jio_fprintf;
- jio_printf;
- jio_snprintf;
- jio_vfprintf;
- jio_vsnprintf;
+ # miscellaneous functions
+ jio_fprintf;
+ jio_printf;
+ jio_snprintf;
+ jio_vfprintf;
+ jio_vsnprintf;
- # Needed because there is no JVM interface for this.
- sysThreadAvailableStackWithSlack;
+ # Needed because there is no JVM interface for this.
+ sysThreadAvailableStackWithSlack;
- # This is for Forte Analyzer profiling support.
- AsyncGetCallTrace;
+ # This is for Forte Analyzer profiling support.
+ AsyncGetCallTrace;
- # INSERT VTABLE SYMBOLS HERE
+ # INSERT VTABLE SYMBOLS HERE
local:
*;
diff -r 77443715ec55 -r b5cb079ecaa4 make/solaris/makefiles/optimized.make
--- a/make/solaris/makefiles/optimized.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/solaris/makefiles/optimized.make Sun Feb 03 22:43:57 2013 +0100
@@ -62,5 +62,4 @@
# Set the environment variable HOTSPARC_GENERIC to "true"
# to inhibit the effect of the previous line on CFLAGS.
-G_SUFFIX =
VERSION = optimized
diff -r 77443715ec55 -r b5cb079ecaa4 make/solaris/makefiles/product.make
--- a/make/solaris/makefiles/product.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/solaris/makefiles/product.make Sun Feb 03 22:43:57 2013 +0100
@@ -78,6 +78,5 @@
# and this macro is not used.
# LINK_LIB.CXX/POST_HOOK += $(STRIP_LIB.CXX/POST_HOOK)
-G_SUFFIX =
SYSDEFS += -DPRODUCT
VERSION = optimized
diff -r 77443715ec55 -r b5cb079ecaa4 make/solaris/makefiles/saproc.make
--- a/make/solaris/makefiles/saproc.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/solaris/makefiles/saproc.make Sun Feb 03 22:43:57 2013 +0100
@@ -24,20 +24,15 @@
# Rules to build serviceability agent library, used by vm.make
-# libsaproc[_g].so: serviceability agent
+# libsaproc.so: serviceability agent
SAPROC = saproc
SADIS = sadis
LIBSAPROC = lib$(SAPROC).so
SADISOBJ = $(SADIS).o
-SAPROC_G = $(SAPROC)$(G_SUFFIX)
-LIBSAPROC_G = lib$(SAPROC_G).so
-
LIBSAPROC_DEBUGINFO = lib$(SAPROC).debuginfo
LIBSAPROC_DIZ = lib$(SAPROC).diz
-LIBSAPROC_G_DEBUGINFO = lib$(SAPROC_G).debuginfo
-LIBSAPROC_G_DIZ = lib$(SAPROC_G).diz
AGENT_DIR = $(GAMMADIR)/agent
@@ -113,7 +108,6 @@
$(SA_LFLAGS) \
-o $@ \
-ldl -ldemangle -lthread -lc
- [ -f $(LIBSAPROC_G) ] || { ln -s $@ $(LIBSAPROC_G); }
$(SADISOBJ): $(SADISSRCFILES)
$(QUIETLY) $(CC) \
@@ -146,11 +140,9 @@
# implied else here is no stripping at all
endif
endif
- [ -f $(LIBSAPROC_G_DEBUGINFO) ] || { ln -s $(LIBSAPROC_DEBUGINFO) $(LIBSAPROC_G_DEBUGINFO); }
ifeq ($(ZIP_DEBUGINFO_FILES),1)
- $(ZIPEXE) -q -y $(LIBSAPROC_DIZ) $(LIBSAPROC_DEBUGINFO) $(LIBSAPROC_G_DEBUGINFO)
- $(RM) $(LIBSAPROC_DEBUGINFO) $(LIBSAPROC_G_DEBUGINFO)
- [ -f $(LIBSAPROC_G_DIZ) ] || { ln -s $(LIBSAPROC_DIZ) $(LIBSAPROC_G_DIZ); }
+ $(ZIPEXE) -q -y $(LIBSAPROC_DIZ) $(LIBSAPROC_DEBUGINFO)
+ $(RM) $(LIBSAPROC_DEBUGINFO)
endif
endif
diff -r 77443715ec55 -r b5cb079ecaa4 make/solaris/makefiles/vm.make
--- a/make/solaris/makefiles/vm.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/solaris/makefiles/vm.make Sun Feb 03 22:43:57 2013 +0100
@@ -157,12 +157,9 @@
JVM = jvm
LIBJVM = lib$(JVM).so
-LIBJVM_G = lib$(JVM)$(G_SUFFIX).so
LIBJVM_DEBUGINFO = lib$(JVM).debuginfo
LIBJVM_DIZ = lib$(JVM).diz
-LIBJVM_G_DEBUGINFO = lib$(JVM)$(G_SUFFIX).debuginfo
-LIBJVM_G_DIZ = lib$(JVM)$(G_SUFFIX).diz
SPECIAL_PATHS:=adlc c1 dist gc_implementation opto shark libadt
@@ -291,8 +288,6 @@
$(QUIETLY) $(LINK_VM) $(LFLAGS_VM) -o $@ $(sort $(LIBJVM.o)) $(LIBS_VM)
$(QUIETLY) $(LINK_LIB.CXX/POST_HOOK)
$(QUIETLY) rm -f $@.1 && ln -s $@ $@.1
- $(QUIETLY) [ -f $(LIBJVM_G) ] || ln -s $@ $(LIBJVM_G)
- $(QUIETLY) [ -f $(LIBJVM_G).1 ] || ln -s $@.1 $(LIBJVM_G).1
ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
# gobjcopy crashes on "empty" section headers with the SHF_ALLOC flag set.
# Clear the SHF_ALLOC flag (if set) from empty section headers.
@@ -313,11 +308,9 @@
# implied else here is no stripping at all
endif
endif
- $(QUIETLY) [ -f $(LIBJVM_G_DEBUGINFO) ] || ln -s $(LIBJVM_DEBUGINFO) $(LIBJVM_G_DEBUGINFO)
ifeq ($(ZIP_DEBUGINFO_FILES),1)
- $(ZIPEXE) -q -y $(LIBJVM_DIZ) $(LIBJVM_DEBUGINFO) $(LIBJVM_G_DEBUGINFO)
- $(RM) $(LIBJVM_DEBUGINFO) $(LIBJVM_G_DEBUGINFO)
- [ -f $(LIBJVM_G_DIZ) ] || { ln -s $(LIBJVM_DIZ) $(LIBJVM_G_DIZ); }
+ $(ZIPEXE) -q -y $(LIBJVM_DIZ) $(LIBJVM_DEBUGINFO)
+ $(RM) $(LIBJVM_DEBUGINFO)
endif
endif
endif # filter -sbfast -xsbfast
diff -r 77443715ec55 -r b5cb079ecaa4 make/windows/build.make
--- a/make/windows/build.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/windows/build.make Sun Feb 03 22:43:57 2013 +0100
@@ -33,7 +33,7 @@
# SA components are built if BUILD_WIN_SA=1 is specified.
# See notes in README. This produces files:
# 1. sa-jdi.jar - This is built before building jvm.dll
-# 2. sawindbg[_g].dll - Native library for SA - This is built after jvm.dll
+# 2. sawindbg.dll - Native library for SA - This is built after jvm.dll
# - Also, .lib, .map, .pdb.
#
# Please refer to ./makefiles/sa.make
@@ -115,7 +115,7 @@
!endif
#########################################################################
-# Parameters for VERSIONINFO resource for jvm[_g].dll.
+# Parameters for VERSIONINFO resource for jvm.dll.
# These can be overridden via the nmake.exe command line.
# They are overridden by RE during the control builds.
#
@@ -225,11 +225,6 @@
#########################################################################
-# With the jvm_g.dll now being named jvm.dll, we can't build both and place
-# the dll's in the same directory, so we only build one at a time,
-# re-directing the output to different output directories (done by user
-# of this makefile).
-#
defaultTarget: product
# The product or release build is an optimized build, and is the default
diff -r 77443715ec55 -r b5cb079ecaa4 make/windows/makefiles/defs.make
--- a/make/windows/makefiles/defs.make Mon Nov 05 17:03:33 2012 -0500
+++ b/make/windows/makefiles/defs.make Sun Feb 03 22:43:57 2013 +0100
@@ -131,23 +131,29 @@
# overridden in some situations, e.g., a BUILD_FLAVOR != product
# build.
-ifeq ($(BUILD_FLAVOR), product)
- FULL_DEBUG_SYMBOLS ?= 1
- ENABLE_FULL_DEBUG_SYMBOLS = $(FULL_DEBUG_SYMBOLS)
-else
- # debug variants always get Full Debug Symbols (if available)
- ENABLE_FULL_DEBUG_SYMBOLS = 1
+# Due to the multiple sub-make processes that occur this logic gets
+# executed multiple times. We reduce the noise by at least checking that
+# BUILD_FLAVOR has been set.
+ifneq ($(BUILD_FLAVOR),)
+ ifeq ($(BUILD_FLAVOR), product)
+ FULL_DEBUG_SYMBOLS ?= 1
+ ENABLE_FULL_DEBUG_SYMBOLS = $(FULL_DEBUG_SYMBOLS)
+ else
+ # debug variants always get Full Debug Symbols (if available)
+ ENABLE_FULL_DEBUG_SYMBOLS = 1
+ endif
+ _JUNK_ := $(shell \
+ echo >&2 "INFO: ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS)")
+ MAKE_ARGS += ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS)
+
+ ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
+ ZIP_DEBUGINFO_FILES ?= 1
+ else
+ ZIP_DEBUGINFO_FILES=0
+ endif
+ MAKE_ARGS += ZIP_DEBUGINFO_FILES=$(ZIP_DEBUGINFO_FILES)
endif
-_JUNK_ := $(shell \
- echo >&2 "INFO: ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS)")
-MAKE_ARGS += ENABLE_FULL_DEBUG_SYMBOLS=$(ENABLE_FULL_DEBUG_SYMBOLS)
-ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
- ZIP_DEBUGINFO_FILES ?= 1
-else
- ZIP_DEBUGINFO_FILES=0
-endif
-MAKE_ARGS += ZIP_DEBUGINFO_FILES=$(ZIP_DEBUGINFO_FILES)
MAKE_ARGS += RM="$(RM)"
MAKE_ARGS += ZIPEXE=$(ZIPEXE)
diff -r 77443715ec55 -r b5cb079ecaa4 make/windows/projectfiles/common/Makefile
--- a/make/windows/projectfiles/common/Makefile Mon Nov 05 17:03:33 2012 -0500
+++ b/make/windows/projectfiles/common/Makefile Sun Feb 03 22:43:57 2013 +0100
@@ -71,41 +71,36 @@
!include $(HOTSPOTWORKSPACE)/make/hotspot_version
-!if "$(HOTSPOT_RELEASE_VERSION)" != ""
-HOTSPOT_RELEASE_VERSION="$(HOTSPOT_RELEASE_VERSION)"
+!if "$(USER_RELEASE_SUFFIX)" != ""
+HOTSPOT_BUILD_VERSION = internal-$(USER_RELEASE_SUFFIX)
!else
-HOTSPOT_RELEASE_VERSION="$(HS_MAJOR_VER).$(HS_MINOR_VER)-b$(HS_BUILD_NUMBER)"
+HOTSPOT_BUILD_VERSION = internal
!endif
-!if "$(USER_RELEASE_SUFFIX)" != ""
-HOTSPOT_BUILD_VERSION$(HOTSPOT_BUILD_VERSION) = internal-$(USER_RELEASE_SUFFIX)
+!if "$(HOTSPOT_RELEASE_VERSION)" != ""
+HOTSPOT_RELEASE_VERSION="\\\"$(HOTSPOT_RELEASE_VERSION)\\\""
!else
-HOTSPOT_BUILD_VERSION$(HOTSPOT_BUILD_VERSION) = internal
-!endif
-!if "$(HOTSPOT_BUILD_VERSION)" != ""
-HOTSPOT_RELEASE_VERSION="$(HOTSPOT_RELEASE_VERSION)-$(HOTSPOT_BUILD_VERSION)"
+HOTSPOT_RELEASE_VERSION="\\\"$(HS_MAJOR_VER).$(HS_MINOR_VER)-b$(HS_BUILD_NUMBER)-$(HOTSPOT_BUILD_VERSION)\\\""
!endif
!if "$(JRE_RELEASE_VERSION)" != ""
-JRE_RELEASE_VERSION="$(JRE_RELEASE_VERSION)"
+JRE_RELEASE_VERSION="\\\"$(JRE_RELEASE_VERSION)\\\""
!else
-JRE_RELEASE_VERSION="$(JDK_MAJOR_VER).$(JDK_MINOR_VER).$(JDK_MICRO_VER)"
+JRE_RELEASE_VERSION="\\\"$(JDK_MAJOR_VER).$(JDK_MINOR_VER).$(JDK_MICRO_VER)\\\""
!endif
# Define HOTSPOT_VM_DISTRO if HOTSPOT_VM_DISTRO is set,
# and if it is not see if we have the src/closed directory
!if "$(HOTSPOT_VM_DISTRO)" != ""
-HOTSPOT_VM_DISTRO="$(HOTSPOT_VM_DISTRO)"
+HOTSPOT_VM_DISTRO=$(HOTSPOT_VM_DISTRO)
!else
!if exists($(HOTSPOTWORKSPACE)\src\closed)
-HOTSPOT_VM_DISTRO="Java HotSpot(TM)"
+HOTSPOT_VM_DISTRO="\\\"Java HotSpot(TM)\\\""
!else
-HOTSPOT_VM_DISTRO="OpenJDK"
+HOTSPOT_VM_DISTRO="\\\"OpenJDK\\\""
!endif
!endif
-ProjectCreatorIDEOptions = $(ProjectCreatorIDEOptions) \
- -define HOTSPOT_RELEASE_VERSION=\\\"$(HOTSPOT_RELEASE_VERSION)\\\" \
- -define JRE_RELEASE_VERSION=\\\"$(JRE_RELEASE_VERSION)\\\" \
- -define HOTSPOT_VM_DISTRO=\\\"$(HOTSPOT_VM_DISTRO)\\\"
+ReleaseOptions = -define HOTSPOT_RELEASE_VERSION=$(HOTSPOT_RELEASE_VERSION) -define JRE_RELEASE_VERSION=$(JRE_RELEASE_VERSION) -define HOTSPOT_VM_DISTRO=$(HOTSPOT_VM_DISTRO)
+ProjectCreatorIDEOptions = $(ProjectCreatorIDEOptions) $(ReleaseOptions)
$(HOTSPOTBUILDSPACE)/$(ProjectFile): $(HOTSPOTBUILDSPACE)/classes/ProjectCreator.class
@$(RUN_JAVA) -Djava.class.path="$(HOTSPOTBUILDSPACE)/classes" ProjectCreator WinGammaPlatform$(VcVersion) $(ProjectCreatorIDEOptions)
diff -r 77443715ec55 -r b5cb079ecaa4 make/windows/projectfiles/compiler2/ADLCompiler.dsp
--- a/make/windows/projectfiles/compiler2/ADLCompiler.dsp Mon Nov 05 17:03:33 2012 -0500
+++ b/make/windows/projectfiles/compiler2/ADLCompiler.dsp Sun Feb 03 22:43:57 2013 +0100
@@ -72,11 +72,11 @@
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
-# ADD BSC32 /o".\adlc\Debug\adlc_g.bsc"
+# ADD BSC32 /o".\adlc\Debug\adlc.bsc"
# SUBTRACT BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib uuid.lib /nologo /subsystem:console /debug /machine:I386 /out:".\bin\adlc_g.exe"
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib uuid.lib /nologo /subsystem:console /debug /machine:I386 /out:".\bin\adlc.exe"
!ENDIF
diff -r 77443715ec55 -r b5cb079ecaa4 make/windows/projectfiles/tiered/ADLCompiler.dsp
--- a/make/windows/projectfiles/tiered/ADLCompiler.dsp Mon Nov 05 17:03:33 2012 -0500
+++ b/make/windows/projectfiles/tiered/ADLCompiler.dsp Sun Feb 03 22:43:57 2013 +0100
@@ -72,11 +72,11 @@
# ADD RSC /l 0x409
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
-# ADD BSC32 /o".\adlc\Debug\adlc_g.bsc"
+# ADD BSC32 /o".\adlc\Debug\adlc.bsc"
# SUBTRACT BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib uuid.lib /nologo /subsystem:console /debug /machine:I386 /out:".\bin\adlc_g.exe"
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib uuid.lib /nologo /subsystem:console /debug /machine:I386 /out:".\bin\adlc.exe"
!ENDIF
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/assembler_sparc.cpp
--- a/src/cpu/sparc/vm/assembler_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/assembler_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -24,4985 +24,8 @@
#include "precompiled.hpp"
#include "asm/assembler.hpp"
-#include "assembler_sparc.inline.hpp"
-#include "gc_interface/collectedHeap.inline.hpp"
-#include "interpreter/interpreter.hpp"
-#include "memory/cardTableModRefBS.hpp"
-#include "memory/resourceArea.hpp"
-#include "prims/methodHandles.hpp"
-#include "runtime/biasedLocking.hpp"
-#include "runtime/interfaceSupport.hpp"
-#include "runtime/objectMonitor.hpp"
-#include "runtime/os.hpp"
-#include "runtime/sharedRuntime.hpp"
-#include "runtime/stubRoutines.hpp"
-#ifndef SERIALGC
-#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
-#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
-#include "gc_implementation/g1/heapRegion.hpp"
-#endif
-
-#ifdef PRODUCT
-#define BLOCK_COMMENT(str) /* nothing */
-#define STOP(error) stop(error)
-#else
-#define BLOCK_COMMENT(str) block_comment(str)
-#define STOP(error) block_comment(error); stop(error)
-#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, relocInfo::relocType disp_reloc) {
- assert(scale == 0, "not supported");
- RelocationHolder rspec;
- if (disp_reloc != relocInfo::none) {
- rspec = Relocation::spec_simple(disp_reloc);
- }
-
- Register rindex = as_Register(index);
- if (rindex != G0) {
- Address madr(as_Register(base), rindex);
- madr._rspec = rspec;
- return madr;
- } else {
- Address madr(as_Register(base), disp);
- madr._rspec = rspec;
- return madr;
- }
-}
-
-Address Argument::address_in_frame() const {
- // Warning: In LP64 mode disp will occupy more than 10 bits, but
- // op codes such as ld or ldx, only access disp() to get
- // their simm13 argument.
- int disp = ((_number - Argument::n_register_parameters + frame::memory_parameter_word_sp_offset) * BytesPerWord) + STACK_BIAS;
- if (is_in())
- return Address(FP, disp); // In argument.
- else
- return Address(SP, disp); // Out argument.
-}
-
-static const char* argumentNames[][2] = {
- {"A0","P0"}, {"A1","P1"}, {"A2","P2"}, {"A3","P3"}, {"A4","P4"},
- {"A5","P5"}, {"A6","P6"}, {"A7","P7"}, {"A8","P8"}, {"A9","P9"},
- {"A(n>9)","P(n>9)"}
-};
-
-const char* Argument::name() const {
- int nofArgs = sizeof argumentNames / sizeof argumentNames[0];
- int num = number();
- if (num >= nofArgs) num = nofArgs - 1;
- return argumentNames[num][is_in() ? 1 : 0];
-}
-
-void Assembler::print_instruction(int inst) {
- const char* s;
- switch (inv_op(inst)) {
- default: s = "????"; break;
- case call_op: s = "call"; break;
- case branch_op:
- switch (inv_op2(inst)) {
- case fb_op2: s = "fb"; break;
- case fbp_op2: s = "fbp"; break;
- case br_op2: s = "br"; break;
- case bp_op2: s = "bp"; break;
- case cb_op2: s = "cb"; break;
- case bpr_op2: {
- if (is_cbcond(inst)) {
- s = is_cxb(inst) ? "cxb" : "cwb";
- } else {
- s = "bpr";
- }
- break;
- }
- default: s = "????"; break;
- }
- }
- ::tty->print("%s", s);
-}
-
-
-// Patch instruction inst at offset inst_pos to refer to dest_pos
-// and return the resulting instruction.
-// We should have pcs, not offsets, but since all is relative, it will work out
-// OK.
-int Assembler::patched_branch(int dest_pos, int inst, int inst_pos) {
-
- int m; // mask for displacement field
- int v; // new value for displacement field
- const int word_aligned_ones = -4;
- switch (inv_op(inst)) {
- default: ShouldNotReachHere();
- case call_op: m = wdisp(word_aligned_ones, 0, 30); v = wdisp(dest_pos, inst_pos, 30); break;
- case branch_op:
- switch (inv_op2(inst)) {
- case fbp_op2: m = wdisp( word_aligned_ones, 0, 19); v = wdisp( dest_pos, inst_pos, 19); break;
- case bp_op2: m = wdisp( word_aligned_ones, 0, 19); v = wdisp( dest_pos, inst_pos, 19); break;
- case fb_op2: m = wdisp( word_aligned_ones, 0, 22); v = wdisp( dest_pos, inst_pos, 22); break;
- case br_op2: m = wdisp( word_aligned_ones, 0, 22); v = wdisp( dest_pos, inst_pos, 22); break;
- case cb_op2: m = wdisp( word_aligned_ones, 0, 22); v = wdisp( dest_pos, inst_pos, 22); break;
- case bpr_op2: {
- if (is_cbcond(inst)) {
- m = wdisp10(word_aligned_ones, 0);
- v = wdisp10(dest_pos, inst_pos);
- } else {
- m = wdisp16(word_aligned_ones, 0);
- v = wdisp16(dest_pos, inst_pos);
- }
- break;
- }
- default: ShouldNotReachHere();
- }
- }
- return inst & ~m | v;
-}
-
-// Return the offset of the branch destionation of instruction inst
-// at offset pos.
-// Should have pcs, but since all is relative, it works out.
-int Assembler::branch_destination(int inst, int pos) {
- int r;
- switch (inv_op(inst)) {
- default: ShouldNotReachHere();
- case call_op: r = inv_wdisp(inst, pos, 30); break;
- case branch_op:
- switch (inv_op2(inst)) {
- case fbp_op2: r = inv_wdisp( inst, pos, 19); break;
- case bp_op2: r = inv_wdisp( inst, pos, 19); break;
- case fb_op2: r = inv_wdisp( inst, pos, 22); break;
- case br_op2: r = inv_wdisp( inst, pos, 22); break;
- case cb_op2: r = inv_wdisp( inst, pos, 22); break;
- case bpr_op2: {
- if (is_cbcond(inst)) {
- r = inv_wdisp10(inst, pos);
- } else {
- r = inv_wdisp16(inst, pos);
- }
- break;
- }
- default: ShouldNotReachHere();
- }
- }
- return r;
-}
+#include "asm/assembler.inline.hpp"
int AbstractAssembler::code_fill_byte() {
return 0x00; // illegal instruction 0x00000000
}
-
-Assembler::Condition Assembler::reg_cond_to_cc_cond(Assembler::RCondition in) {
- switch (in) {
- case rc_z: return equal;
- case rc_lez: return lessEqual;
- case rc_lz: return less;
- case rc_nz: return notEqual;
- case rc_gz: return greater;
- case rc_gez: return greaterEqual;
- default:
- ShouldNotReachHere();
- }
- return equal;
-}
-
-// Generate a bunch 'o stuff (including v9's
-#ifndef PRODUCT
-void Assembler::test_v9() {
- add( G0, G1, G2 );
- add( G3, 0, G4 );
-
- addcc( G5, G6, G7 );
- addcc( I0, 1, I1 );
- addc( I2, I3, I4 );
- addc( I5, -1, I6 );
- addccc( I7, L0, L1 );
- addccc( L2, (1 << 12) - 2, L3 );
-
- Label lbl1, lbl2, lbl3;
-
- bind(lbl1);
-
- bpr( rc_z, true, pn, L4, pc(), relocInfo::oop_type );
- delayed()->nop();
- bpr( rc_lez, false, pt, L5, lbl1);
- delayed()->nop();
-
- fb( f_never, true, pc() + 4, relocInfo::none);
- delayed()->nop();
- fb( f_notEqual, false, lbl2 );
- delayed()->nop();
-
- fbp( f_notZero, true, fcc0, pn, pc() - 4, relocInfo::none);
- delayed()->nop();
- fbp( f_lessOrGreater, false, fcc1, pt, lbl3 );
- delayed()->nop();
-
- br( equal, true, pc() + 1024, relocInfo::none);
- delayed()->nop();
- br( lessEqual, false, lbl1 );
- delayed()->nop();
- br( never, false, lbl1 );
- delayed()->nop();
-
- bp( less, true, icc, pn, pc(), relocInfo::none);
- delayed()->nop();
- bp( lessEqualUnsigned, false, xcc, pt, lbl2 );
- delayed()->nop();
-
- call( pc(), relocInfo::none);
- delayed()->nop();
- call( lbl3 );
- delayed()->nop();
-
-
- casa( L6, L7, O0 );
- casxa( O1, O2, O3, 0 );
-
- udiv( O4, O5, O7 );
- udiv( G0, (1 << 12) - 1, G1 );
- sdiv( G1, G2, G3 );
- sdiv( G4, -((1 << 12) - 1), G5 );
- udivcc( G6, G7, I0 );
- udivcc( I1, -((1 << 12) - 2), I2 );
- sdivcc( I3, I4, I5 );
- sdivcc( I6, -((1 << 12) - 0), I7 );
-
- done();
- retry();
-
- fadd( FloatRegisterImpl::S, F0, F1, F2 );
- fsub( FloatRegisterImpl::D, F34, F0, F62 );
-
- fcmp( FloatRegisterImpl::Q, fcc0, F0, F60);
- fcmpe( FloatRegisterImpl::S, fcc1, F31, F30);
-
- ftox( FloatRegisterImpl::D, F2, F4 );
- ftoi( FloatRegisterImpl::Q, F4, F8 );
-
- ftof( FloatRegisterImpl::S, FloatRegisterImpl::Q, F3, F12 );
-
- fxtof( FloatRegisterImpl::S, F4, F5 );
- fitof( FloatRegisterImpl::D, F6, F8 );
-
- fmov( FloatRegisterImpl::Q, F16, F20 );
- fneg( FloatRegisterImpl::S, F6, F7 );
- fabs( FloatRegisterImpl::D, F10, F12 );
-
- fmul( FloatRegisterImpl::Q, F24, F28, F32 );
- fmul( FloatRegisterImpl::S, FloatRegisterImpl::D, F8, F9, F14 );
- fdiv( FloatRegisterImpl::S, F10, F11, F12 );
-
- fsqrt( FloatRegisterImpl::S, F13, F14 );
-
- flush( L0, L1 );
- flush( L2, -1 );
-
- flushw();
-
- illtrap( (1 << 22) - 2);
-
- impdep1( 17, (1 << 19) - 1 );
- impdep2( 3, 0 );
-
- jmpl( L3, L4, L5 );
- delayed()->nop();
- jmpl( L6, -1, L7, Relocation::spec_simple(relocInfo::none));
- delayed()->nop();
-
-
- ldf( FloatRegisterImpl::S, O0, O1, F15 );
- ldf( FloatRegisterImpl::D, O2, -1, F14 );
-
-
- ldfsr( O3, O4 );
- ldfsr( O5, -1 );
- ldxfsr( O6, O7 );
- ldxfsr( I0, -1 );
-
- ldfa( FloatRegisterImpl::D, I1, I2, 1, F16 );
- ldfa( FloatRegisterImpl::Q, I3, -1, F36 );
-
- ldsb( I4, I5, I6 );
- ldsb( I7, -1, G0 );
- ldsh( G1, G3, G4 );
- ldsh( G5, -1, G6 );
- ldsw( G7, L0, L1 );
- ldsw( L2, -1, L3 );
- ldub( L4, L5, L6 );
- ldub( L7, -1, O0 );
- lduh( O1, O2, O3 );
- lduh( O4, -1, O5 );
- lduw( O6, O7, G0 );
- lduw( G1, -1, G2 );
- ldx( G3, G4, G5 );
- ldx( G6, -1, G7 );
- ldd( I0, I1, I2 );
- ldd( I3, -1, I4 );
-
- ldsba( I5, I6, 2, I7 );
- ldsba( L0, -1, L1 );
- ldsha( L2, L3, 3, L4 );
- ldsha( L5, -1, L6 );
- ldswa( L7, O0, (1 << 8) - 1, O1 );
- ldswa( O2, -1, O3 );
- lduba( O4, O5, 0, O6 );
- lduba( O7, -1, I0 );
- lduha( I1, I2, 1, I3 );
- lduha( I4, -1, I5 );
- lduwa( I6, I7, 2, L0 );
- lduwa( L1, -1, L2 );
- ldxa( L3, L4, 3, L5 );
- ldxa( L6, -1, L7 );
- ldda( G0, G1, 4, G2 );
- ldda( G3, -1, G4 );
-
- ldstub( G5, G6, G7 );
- ldstub( O0, -1, O1 );
-
- ldstuba( O2, O3, 5, O4 );
- ldstuba( O5, -1, O6 );
-
- and3( I0, L0, O0 );
- and3( G7, -1, O7 );
- andcc( L2, I2, G2 );
- andcc( L4, -1, G4 );
- andn( I5, I6, I7 );
- andn( I6, -1, I7 );
- andncc( I5, I6, I7 );
- andncc( I7, -1, I6 );
- or3( I5, I6, I7 );
- or3( I7, -1, I6 );
- orcc( I5, I6, I7 );
- orcc( I7, -1, I6 );
- orn( I5, I6, I7 );
- orn( I7, -1, I6 );
- orncc( I5, I6, I7 );
- orncc( I7, -1, I6 );
- xor3( I5, I6, I7 );
- xor3( I7, -1, I6 );
- xorcc( I5, I6, I7 );
- xorcc( I7, -1, I6 );
- xnor( I5, I6, I7 );
- xnor( I7, -1, I6 );
- xnorcc( I5, I6, I7 );
- xnorcc( I7, -1, I6 );
-
- membar( Membar_mask_bits(StoreStore | LoadStore | StoreLoad | LoadLoad | Sync | MemIssue | Lookaside ) );
- membar( StoreStore );
- membar( LoadStore );
- membar( StoreLoad );
- membar( LoadLoad );
- membar( Sync );
- membar( MemIssue );
- membar( Lookaside );
-
- fmov( FloatRegisterImpl::S, f_ordered, true, fcc2, F16, F17 );
- fmov( FloatRegisterImpl::D, rc_lz, L5, F18, F20 );
-
- movcc( overflowClear, false, icc, I6, L4 );
- movcc( f_unorderedOrEqual, true, fcc2, (1 << 10) - 1, O0 );
-
- movr( rc_nz, I5, I6, I7 );
- movr( rc_gz, L1, -1, L2 );
-
- mulx( I5, I6, I7 );
- mulx( I7, -1, I6 );
- sdivx( I5, I6, I7 );
- sdivx( I7, -1, I6 );
- udivx( I5, I6, I7 );
- udivx( I7, -1, I6 );
-
- umul( I5, I6, I7 );
- umul( I7, -1, I6 );
- smul( I5, I6, I7 );
- smul( I7, -1, I6 );
- umulcc( I5, I6, I7 );
- umulcc( I7, -1, I6 );
- smulcc( I5, I6, I7 );
- smulcc( I7, -1, I6 );
-
- mulscc( I5, I6, I7 );
- mulscc( I7, -1, I6 );
-
- nop();
-
-
- popc( G0, G1);
- popc( -1, G2);
-
- prefetch( L1, L2, severalReads );
- prefetch( L3, -1, oneRead );
- prefetcha( O3, O2, 6, severalWritesAndPossiblyReads );
- prefetcha( G2, -1, oneWrite );
-
- rett( I7, I7);
- delayed()->nop();
- rett( G0, -1, relocInfo::none);
- delayed()->nop();
-
- save( I5, I6, I7 );
- save( I7, -1, I6 );
- restore( I5, I6, I7 );
- restore( I7, -1, I6 );
-
- saved();
- restored();
-
- sethi( 0xaaaaaaaa, I3, Relocation::spec_simple(relocInfo::none));
-
- sll( I5, I6, I7 );
- sll( I7, 31, I6 );
- srl( I5, I6, I7 );
- srl( I7, 0, I6 );
- sra( I5, I6, I7 );
- sra( I7, 30, I6 );
- sllx( I5, I6, I7 );
- sllx( I7, 63, I6 );
- srlx( I5, I6, I7 );
- srlx( I7, 0, I6 );
- srax( I5, I6, I7 );
- srax( I7, 62, I6 );
-
- sir( -1 );
-
- stbar();
-
- stf( FloatRegisterImpl::Q, F40, G0, I7 );
- stf( FloatRegisterImpl::S, F18, I3, -1 );
-
- stfsr( L1, L2 );
- stfsr( I7, -1 );
- stxfsr( I6, I5 );
- stxfsr( L4, -1 );
-
- stfa( FloatRegisterImpl::D, F22, I6, I7, 7 );
- stfa( FloatRegisterImpl::Q, F44, G0, -1 );
-
- stb( L5, O2, I7 );
- stb( I7, I6, -1 );
- sth( L5, O2, I7 );
- sth( I7, I6, -1 );
- stw( L5, O2, I7 );
- stw( I7, I6, -1 );
- stx( L5, O2, I7 );
- stx( I7, I6, -1 );
- std( L5, O2, I7 );
- std( I7, I6, -1 );
-
- stba( L5, O2, I7, 8 );
- stba( I7, I6, -1 );
- stha( L5, O2, I7, 9 );
- stha( I7, I6, -1 );
- stwa( L5, O2, I7, 0 );
- stwa( I7, I6, -1 );
- stxa( L5, O2, I7, 11 );
- stxa( I7, I6, -1 );
- stda( L5, O2, I7, 12 );
- stda( I7, I6, -1 );
-
- sub( I5, I6, I7 );
- sub( I7, -1, I6 );
- subcc( I5, I6, I7 );
- subcc( I7, -1, I6 );
- subc( I5, I6, I7 );
- subc( I7, -1, I6 );
- subccc( I5, I6, I7 );
- subccc( I7, -1, I6 );
-
- swap( I5, I6, I7 );
- swap( I7, -1, I6 );
-
- swapa( G0, G1, 13, G2 );
- swapa( I7, -1, I6 );
-
- taddcc( I5, I6, I7 );
- taddcc( I7, -1, I6 );
- taddcctv( I5, I6, I7 );
- taddcctv( I7, -1, I6 );
-
- tsubcc( I5, I6, I7 );
- tsubcc( I7, -1, I6 );
- tsubcctv( I5, I6, I7 );
- tsubcctv( I7, -1, I6 );
-
- trap( overflowClear, xcc, G0, G1 );
- trap( lessEqual, icc, I7, 17 );
-
- bind(lbl2);
- bind(lbl3);
-
- code()->decode();
-}
-
-// Generate a bunch 'o stuff unique to V8
-void Assembler::test_v8_onlys() {
- Label lbl1;
-
- cb( cp_0or1or2, false, pc() - 4, relocInfo::none);
- delayed()->nop();
- cb( cp_never, true, lbl1);
- delayed()->nop();
-
- cpop1(1, 2, 3, 4);
- cpop2(5, 6, 7, 8);
-
- ldc( I0, I1, 31);
- ldc( I2, -1, 0);
-
- lddc( I4, I4, 30);
- lddc( I6, 0, 1 );
-
- ldcsr( L0, L1, 0);
- ldcsr( L1, (1 << 12) - 1, 17 );
-
- stc( 31, L4, L5);
- stc( 30, L6, -(1 << 12) );
-
- stdc( 0, L7, G0);
- stdc( 1, G1, 0 );
-
- stcsr( 16, G2, G3);
- stcsr( 17, G4, 1 );
-
- stdcq( 4, G5, G6);
- stdcq( 5, G7, -1 );
-
- bind(lbl1);
-
- code()->decode();
-}
-#endif
-
-// Implementation of MacroAssembler
-
-void MacroAssembler::null_check(Register reg, int offset) {
- if (needs_explicit_null_check((intptr_t)offset)) {
- // provoke OS NULL exception if reg = NULL by
- // accessing M[reg] w/o changing any registers
- ld_ptr(reg, 0, G0);
- }
- else {
- // nothing to do, (later) access of M[reg + offset]
- // will provoke OS NULL exception if reg = NULL
- }
-}
-
-// Ring buffer jumps
-
-#ifndef PRODUCT
-void MacroAssembler::ret( bool trace ) { if (trace) {
- mov(I7, O7); // traceable register
- JMP(O7, 2 * BytesPerInstWord);
- } else {
- jmpl( I7, 2 * BytesPerInstWord, G0 );
- }
- }
-
-void MacroAssembler::retl( bool trace ) { if (trace) JMP(O7, 2 * BytesPerInstWord);
- else jmpl( O7, 2 * BytesPerInstWord, G0 ); }
-#endif /* PRODUCT */
-
-
-void MacroAssembler::jmp2(Register r1, Register r2, const char* file, int line ) {
- assert_not_delayed();
- // This can only be traceable if r1 & r2 are visible after a window save
- if (TraceJumps) {
-#ifndef PRODUCT
- save_frame(0);
- verify_thread();
- ld(G2_thread, in_bytes(JavaThread::jmp_ring_index_offset()), O0);
- add(G2_thread, in_bytes(JavaThread::jmp_ring_offset()), O1);
- sll(O0, exact_log2(4*sizeof(intptr_t)), O2);
- add(O2, O1, O1);
-
- add(r1->after_save(), r2->after_save(), O2);
- set((intptr_t)file, O3);
- set(line, O4);
- Label L;
- // get nearby pc, store jmp target
- call(L, relocInfo::none); // No relocation for call to pc+0x8
- delayed()->st(O2, O1, 0);
- bind(L);
-
- // store nearby pc
- st(O7, O1, sizeof(intptr_t));
- // store file
- st(O3, O1, 2*sizeof(intptr_t));
- // store line
- st(O4, O1, 3*sizeof(intptr_t));
- add(O0, 1, O0);
- and3(O0, JavaThread::jump_ring_buffer_size - 1, O0);
- st(O0, G2_thread, in_bytes(JavaThread::jmp_ring_index_offset()));
- restore();
-#endif /* PRODUCT */
- }
- jmpl(r1, r2, G0);
-}
-void MacroAssembler::jmp(Register r1, int offset, const char* file, int line ) {
- assert_not_delayed();
- // This can only be traceable if r1 is visible after a window save
- if (TraceJumps) {
-#ifndef PRODUCT
- save_frame(0);
- verify_thread();
- ld(G2_thread, in_bytes(JavaThread::jmp_ring_index_offset()), O0);
- add(G2_thread, in_bytes(JavaThread::jmp_ring_offset()), O1);
- sll(O0, exact_log2(4*sizeof(intptr_t)), O2);
- add(O2, O1, O1);
-
- add(r1->after_save(), offset, O2);
- set((intptr_t)file, O3);
- set(line, O4);
- Label L;
- // get nearby pc, store jmp target
- call(L, relocInfo::none); // No relocation for call to pc+0x8
- delayed()->st(O2, O1, 0);
- bind(L);
-
- // store nearby pc
- st(O7, O1, sizeof(intptr_t));
- // store file
- st(O3, O1, 2*sizeof(intptr_t));
- // store line
- st(O4, O1, 3*sizeof(intptr_t));
- add(O0, 1, O0);
- and3(O0, JavaThread::jump_ring_buffer_size - 1, O0);
- st(O0, G2_thread, in_bytes(JavaThread::jmp_ring_index_offset()));
- restore();
-#endif /* PRODUCT */
- }
- jmp(r1, offset);
-}
-
-// This code sequence is relocatable to any address, even on LP64.
-void MacroAssembler::jumpl(const AddressLiteral& addrlit, Register temp, Register d, int offset, const char* file, int line) {
- assert_not_delayed();
- // Force fixed length sethi because NativeJump and NativeFarCall don't handle
- // variable length instruction streams.
- patchable_sethi(addrlit, temp);
- Address a(temp, addrlit.low10() + offset); // Add the offset to the displacement.
- if (TraceJumps) {
-#ifndef PRODUCT
- // Must do the add here so relocation can find the remainder of the
- // value to be relocated.
- add(a.base(), a.disp(), a.base(), addrlit.rspec(offset));
- save_frame(0);
- verify_thread();
- ld(G2_thread, in_bytes(JavaThread::jmp_ring_index_offset()), O0);
- add(G2_thread, in_bytes(JavaThread::jmp_ring_offset()), O1);
- sll(O0, exact_log2(4*sizeof(intptr_t)), O2);
- add(O2, O1, O1);
-
- set((intptr_t)file, O3);
- set(line, O4);
- Label L;
-
- // get nearby pc, store jmp target
- call(L, relocInfo::none); // No relocation for call to pc+0x8
- delayed()->st(a.base()->after_save(), O1, 0);
- bind(L);
-
- // store nearby pc
- st(O7, O1, sizeof(intptr_t));
- // store file
- st(O3, O1, 2*sizeof(intptr_t));
- // store line
- st(O4, O1, 3*sizeof(intptr_t));
- add(O0, 1, O0);
- and3(O0, JavaThread::jump_ring_buffer_size - 1, O0);
- st(O0, G2_thread, in_bytes(JavaThread::jmp_ring_index_offset()));
- restore();
- jmpl(a.base(), G0, d);
-#else
- jmpl(a.base(), a.disp(), d);
-#endif /* PRODUCT */
- } else {
- jmpl(a.base(), a.disp(), d);
- }
-}
-
-void MacroAssembler::jump(const AddressLiteral& addrlit, Register temp, int offset, const char* file, int line) {
- jumpl(addrlit, temp, G0, offset, file, line);
-}
-
-
-// Conditional breakpoint (for assertion checks in assembly code)
-void MacroAssembler::breakpoint_trap(Condition c, CC cc) {
- trap(c, cc, G0, ST_RESERVED_FOR_USER_0);
-}
-
-// We want to use ST_BREAKPOINT here, but the debugger is confused by it.
-void MacroAssembler::breakpoint_trap() {
- trap(ST_RESERVED_FOR_USER_0);
-}
-
-// flush windows (except current) using flushw instruction if avail.
-void MacroAssembler::flush_windows() {
- if (VM_Version::v9_instructions_work()) flushw();
- else flush_windows_trap();
-}
-
-// Write serialization page so VM thread can do a pseudo remote membar
-// We use the current thread pointer to calculate a thread specific
-// offset to write to within the page. This minimizes bus traffic
-// due to cache line collision.
-void MacroAssembler::serialize_memory(Register thread, Register tmp1, Register tmp2) {
- srl(thread, os::get_serialize_page_shift_count(), tmp2);
- if (Assembler::is_simm13(os::vm_page_size())) {
- and3(tmp2, (os::vm_page_size() - sizeof(int)), tmp2);
- }
- else {
- set((os::vm_page_size() - sizeof(int)), tmp1);
- and3(tmp2, tmp1, tmp2);
- }
- set(os::get_memory_serialize_page(), tmp1);
- st(G0, tmp1, tmp2);
-}
-
-
-
-void MacroAssembler::enter() {
- Unimplemented();
-}
-
-void MacroAssembler::leave() {
- Unimplemented();
-}
-
-void MacroAssembler::mult(Register s1, Register s2, Register d) {
- if(VM_Version::v9_instructions_work()) {
- mulx (s1, s2, d);
- } else {
- smul (s1, s2, d);
- }
-}
-
-void MacroAssembler::mult(Register s1, int simm13a, Register d) {
- if(VM_Version::v9_instructions_work()) {
- mulx (s1, simm13a, d);
- } else {
- smul (s1, simm13a, d);
- }
-}
-
-
-#ifdef ASSERT
-void MacroAssembler::read_ccr_v8_assert(Register ccr_save) {
- const Register s1 = G3_scratch;
- const Register s2 = G4_scratch;
- Label get_psr_test;
- // Get the condition codes the V8 way.
- read_ccr_trap(s1);
- mov(ccr_save, s2);
- // This is a test of V8 which has icc but not xcc
- // so mask off the xcc bits
- and3(s2, 0xf, s2);
- // Compare condition codes from the V8 and V9 ways.
- subcc(s2, s1, G0);
- br(Assembler::notEqual, true, Assembler::pt, get_psr_test);
- delayed()->breakpoint_trap();
- bind(get_psr_test);
-}
-
-void MacroAssembler::write_ccr_v8_assert(Register ccr_save) {
- const Register s1 = G3_scratch;
- const Register s2 = G4_scratch;
- Label set_psr_test;
- // Write out the saved condition codes the V8 way
- write_ccr_trap(ccr_save, s1, s2);
- // Read back the condition codes using the V9 instruction
- rdccr(s1);
- mov(ccr_save, s2);
- // This is a test of V8 which has icc but not xcc
- // so mask off the xcc bits
- and3(s2, 0xf, s2);
- and3(s1, 0xf, s1);
- // Compare the V8 way with the V9 way.
- subcc(s2, s1, G0);
- br(Assembler::notEqual, true, Assembler::pt, set_psr_test);
- delayed()->breakpoint_trap();
- bind(set_psr_test);
-}
-#else
-#define read_ccr_v8_assert(x)
-#define write_ccr_v8_assert(x)
-#endif // ASSERT
-
-void MacroAssembler::read_ccr(Register ccr_save) {
- if (VM_Version::v9_instructions_work()) {
- rdccr(ccr_save);
- // Test code sequence used on V8. Do not move above rdccr.
- read_ccr_v8_assert(ccr_save);
- } else {
- read_ccr_trap(ccr_save);
- }
-}
-
-void MacroAssembler::write_ccr(Register ccr_save) {
- if (VM_Version::v9_instructions_work()) {
- // Test code sequence used on V8. Do not move below wrccr.
- write_ccr_v8_assert(ccr_save);
- wrccr(ccr_save);
- } else {
- const Register temp_reg1 = G3_scratch;
- const Register temp_reg2 = G4_scratch;
- write_ccr_trap(ccr_save, temp_reg1, temp_reg2);
- }
-}
-
-
-// Calls to C land
-
-#ifdef ASSERT
-// a hook for debugging
-static Thread* reinitialize_thread() {
- return ThreadLocalStorage::thread();
-}
-#else
-#define reinitialize_thread ThreadLocalStorage::thread
-#endif
-
-#ifdef ASSERT
-address last_get_thread = NULL;
-#endif
-
-// call this when G2_thread is not known to be valid
-void MacroAssembler::get_thread() {
- save_frame(0); // to avoid clobbering O0
- mov(G1, L0); // avoid clobbering G1
- mov(G5_method, L1); // avoid clobbering G5
- mov(G3, L2); // avoid clobbering G3 also
- mov(G4, L5); // avoid clobbering G4
-#ifdef ASSERT
- AddressLiteral last_get_thread_addrlit(&last_get_thread);
- set(last_get_thread_addrlit, L3);
- inc(L4, get_pc(L4) + 2 * BytesPerInstWord); // skip getpc() code + inc + st_ptr to point L4 at call
- st_ptr(L4, L3, 0);
-#endif
- call(CAST_FROM_FN_PTR(address, reinitialize_thread), relocInfo::runtime_call_type);
- delayed()->nop();
- mov(L0, G1);
- mov(L1, G5_method);
- mov(L2, G3);
- mov(L5, G4);
- restore(O0, 0, G2_thread);
-}
-
-static Thread* verify_thread_subroutine(Thread* gthread_value) {
- Thread* correct_value = ThreadLocalStorage::thread();
- guarantee(gthread_value == correct_value, "G2_thread value must be the thread");
- return correct_value;
-}
-
-void MacroAssembler::verify_thread() {
- if (VerifyThread) {
- // NOTE: this chops off the heads of the 64-bit O registers.
-#ifdef CC_INTERP
- save_frame(0);
-#else
- // make sure G2_thread contains the right value
- save_frame_and_mov(0, Lmethod, Lmethod); // to avoid clobbering O0 (and propagate Lmethod for -Xprof)
- mov(G1, L1); // avoid clobbering G1
- // G2 saved below
- mov(G3, L3); // avoid clobbering G3
- mov(G4, L4); // avoid clobbering G4
- mov(G5_method, L5); // avoid clobbering G5_method
-#endif /* CC_INTERP */
-#if defined(COMPILER2) && !defined(_LP64)
- // Save & restore possible 64-bit Long arguments in G-regs
- srlx(G1,32,L0);
- srlx(G4,32,L6);
-#endif
- call(CAST_FROM_FN_PTR(address,verify_thread_subroutine), relocInfo::runtime_call_type);
- delayed()->mov(G2_thread, O0);
-
- mov(L1, G1); // Restore G1
- // G2 restored below
- mov(L3, G3); // restore G3
- mov(L4, G4); // restore G4
- mov(L5, G5_method); // restore G5_method
-#if defined(COMPILER2) && !defined(_LP64)
- // Save & restore possible 64-bit Long arguments in G-regs
- sllx(L0,32,G2); // Move old high G1 bits high in G2
- srl(G1, 0,G1); // Clear current high G1 bits
- or3 (G1,G2,G1); // Recover 64-bit G1
- sllx(L6,32,G2); // Move old high G4 bits high in G2
- srl(G4, 0,G4); // Clear current high G4 bits
- or3 (G4,G2,G4); // Recover 64-bit G4
-#endif
- restore(O0, 0, G2_thread);
- }
-}
-
-
-void MacroAssembler::save_thread(const Register thread_cache) {
- verify_thread();
- if (thread_cache->is_valid()) {
- assert(thread_cache->is_local() || thread_cache->is_in(), "bad volatile");
- mov(G2_thread, thread_cache);
- }
- if (VerifyThread) {
- // smash G2_thread, as if the VM were about to anyway
- set(0x67676767, G2_thread);
- }
-}
-
-
-void MacroAssembler::restore_thread(const Register thread_cache) {
- if (thread_cache->is_valid()) {
- assert(thread_cache->is_local() || thread_cache->is_in(), "bad volatile");
- mov(thread_cache, G2_thread);
- verify_thread();
- } else {
- // do it the slow way
- get_thread();
- }
-}
-
-
-// %%% maybe get rid of [re]set_last_Java_frame
-void MacroAssembler::set_last_Java_frame(Register last_java_sp, Register last_Java_pc) {
- assert_not_delayed();
- Address flags(G2_thread, JavaThread::frame_anchor_offset() +
- JavaFrameAnchor::flags_offset());
- Address pc_addr(G2_thread, JavaThread::last_Java_pc_offset());
-
- // Always set last_Java_pc and flags first because once last_Java_sp is visible
- // has_last_Java_frame is true and users will look at the rest of the fields.
- // (Note: flags should always be zero before we get here so doesn't need to be set.)
-
-#ifdef ASSERT
- // Verify that flags was zeroed on return to Java
- Label PcOk;
- save_frame(0); // to avoid clobbering O0
- ld_ptr(pc_addr, L0);
- br_null_short(L0, Assembler::pt, PcOk);
- STOP("last_Java_pc not zeroed before leaving Java");
- bind(PcOk);
-
- // Verify that flags was zeroed on return to Java
- Label FlagsOk;
- ld(flags, L0);
- tst(L0);
- br(Assembler::zero, false, Assembler::pt, FlagsOk);
- delayed() -> restore();
- STOP("flags not zeroed before leaving Java");
- bind(FlagsOk);
-#endif /* ASSERT */
- //
- // When returning from calling out from Java mode the frame anchor's last_Java_pc
- // will always be set to NULL. It is set here so that if we are doing a call to
- // native (not VM) that we capture the known pc and don't have to rely on the
- // native call having a standard frame linkage where we can find the pc.
-
- if (last_Java_pc->is_valid()) {
- st_ptr(last_Java_pc, pc_addr);
- }
-
-#ifdef _LP64
-#ifdef ASSERT
- // Make sure that we have an odd stack
- Label StackOk;
- andcc(last_java_sp, 0x01, G0);
- br(Assembler::notZero, false, Assembler::pt, StackOk);
- delayed()->nop();
- STOP("Stack Not Biased in set_last_Java_frame");
- bind(StackOk);
-#endif // ASSERT
- assert( last_java_sp != G4_scratch, "bad register usage in set_last_Java_frame");
- add( last_java_sp, STACK_BIAS, G4_scratch );
- st_ptr(G4_scratch, G2_thread, JavaThread::last_Java_sp_offset());
-#else
- st_ptr(last_java_sp, G2_thread, JavaThread::last_Java_sp_offset());
-#endif // _LP64
-}
-
-void MacroAssembler::reset_last_Java_frame(void) {
- assert_not_delayed();
-
- Address sp_addr(G2_thread, JavaThread::last_Java_sp_offset());
- Address pc_addr(G2_thread, JavaThread::frame_anchor_offset() + JavaFrameAnchor::last_Java_pc_offset());
- Address flags (G2_thread, JavaThread::frame_anchor_offset() + JavaFrameAnchor::flags_offset());
-
-#ifdef ASSERT
- // check that it WAS previously set
-#ifdef CC_INTERP
- save_frame(0);
-#else
- save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod to helper frame for -Xprof
-#endif /* CC_INTERP */
- ld_ptr(sp_addr, L0);
- tst(L0);
- breakpoint_trap(Assembler::zero, Assembler::ptr_cc);
- restore();
-#endif // ASSERT
-
- st_ptr(G0, sp_addr);
- // Always return last_Java_pc to zero
- st_ptr(G0, pc_addr);
- // Always null flags after return to Java
- st(G0, flags);
-}
-
-
-void MacroAssembler::call_VM_base(
- Register oop_result,
- Register thread_cache,
- Register last_java_sp,
- address entry_point,
- int number_of_arguments,
- bool check_exceptions)
-{
- assert_not_delayed();
-
- // determine last_java_sp register
- if (!last_java_sp->is_valid()) {
- last_java_sp = SP;
- }
- // debugging support
- assert(number_of_arguments >= 0 , "cannot have negative number of arguments");
-
- // 64-bit last_java_sp is biased!
- set_last_Java_frame(last_java_sp, noreg);
- if (VerifyThread) mov(G2_thread, O0); // about to be smashed; pass early
- save_thread(thread_cache);
- // do the call
- call(entry_point, relocInfo::runtime_call_type);
- if (!VerifyThread)
- delayed()->mov(G2_thread, O0); // pass thread as first argument
- else
- delayed()->nop(); // (thread already passed)
- restore_thread(thread_cache);
- reset_last_Java_frame();
-
- // check for pending exceptions. use Gtemp as scratch register.
- if (check_exceptions) {
- 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);
- }
-}
-
-void MacroAssembler::check_and_forward_exception(Register scratch_reg)
-{
- Label L;
-
- check_and_handle_popframe(scratch_reg);
- check_and_handle_earlyret(scratch_reg);
-
- Address exception_addr(G2_thread, Thread::pending_exception_offset());
- ld_ptr(exception_addr, scratch_reg);
- br_null_short(scratch_reg, pt, L);
- // we use O7 linkage so that forward_exception_entry has the issuing PC
- call(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type);
- delayed()->nop();
- bind(L);
-}
-
-
-void MacroAssembler::check_and_handle_popframe(Register scratch_reg) {
-}
-
-
-void MacroAssembler::check_and_handle_earlyret(Register scratch_reg) {
-}
-
-
-void MacroAssembler::call_VM(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) {
- call_VM_base(oop_result, noreg, noreg, entry_point, number_of_arguments, check_exceptions);
-}
-
-
-void MacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions) {
- // O0 is reserved for the thread
- mov(arg_1, O1);
- call_VM(oop_result, entry_point, 1, check_exceptions);
-}
-
-
-void MacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions) {
- // O0 is reserved for the thread
- mov(arg_1, O1);
- mov(arg_2, O2); assert(arg_2 != O1, "smashed argument");
- call_VM(oop_result, entry_point, 2, check_exceptions);
-}
-
-
-void MacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions) {
- // O0 is reserved for the thread
- mov(arg_1, O1);
- mov(arg_2, O2); assert(arg_2 != O1, "smashed argument");
- mov(arg_3, O3); assert(arg_3 != O1 && arg_3 != O2, "smashed argument");
- call_VM(oop_result, entry_point, 3, check_exceptions);
-}
-
-
-
-// Note: The following call_VM overloadings are useful when a "save"
-// has already been performed by a stub, and the last Java frame is
-// the previous one. In that case, last_java_sp must be passed as FP
-// instead of SP.
-
-
-void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, int number_of_arguments, bool check_exceptions) {
- call_VM_base(oop_result, noreg, last_java_sp, entry_point, number_of_arguments, check_exceptions);
-}
-
-
-void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, bool check_exceptions) {
- // O0 is reserved for the thread
- mov(arg_1, O1);
- call_VM(oop_result, last_java_sp, entry_point, 1, check_exceptions);
-}
-
-
-void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, bool check_exceptions) {
- // O0 is reserved for the thread
- mov(arg_1, O1);
- mov(arg_2, O2); assert(arg_2 != O1, "smashed argument");
- call_VM(oop_result, last_java_sp, entry_point, 2, check_exceptions);
-}
-
-
-void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions) {
- // O0 is reserved for the thread
- mov(arg_1, O1);
- mov(arg_2, O2); assert(arg_2 != O1, "smashed argument");
- mov(arg_3, O3); assert(arg_3 != O1 && arg_3 != O2, "smashed argument");
- call_VM(oop_result, last_java_sp, entry_point, 3, check_exceptions);
-}
-
-
-
-void MacroAssembler::call_VM_leaf_base(Register thread_cache, address entry_point, int number_of_arguments) {
- assert_not_delayed();
- save_thread(thread_cache);
- // do the call
- 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
-}
-
-
-void MacroAssembler::call_VM_leaf(Register thread_cache, address entry_point, int number_of_arguments) {
- call_VM_leaf_base(thread_cache, entry_point, number_of_arguments);
-}
-
-
-void MacroAssembler::call_VM_leaf(Register thread_cache, address entry_point, Register arg_1) {
- mov(arg_1, O0);
- call_VM_leaf(thread_cache, entry_point, 1);
-}
-
-
-void MacroAssembler::call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2) {
- mov(arg_1, O0);
- mov(arg_2, O1); assert(arg_2 != O0, "smashed argument");
- call_VM_leaf(thread_cache, entry_point, 2);
-}
-
-
-void MacroAssembler::call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2, Register arg_3) {
- mov(arg_1, O0);
- mov(arg_2, O1); assert(arg_2 != O0, "smashed argument");
- mov(arg_3, O2); assert(arg_3 != O0 && arg_3 != O1, "smashed argument");
- call_VM_leaf(thread_cache, entry_point, 3);
-}
-
-
-void MacroAssembler::get_vm_result(Register oop_result) {
- verify_thread();
- Address vm_result_addr(G2_thread, JavaThread::vm_result_offset());
- ld_ptr( vm_result_addr, oop_result);
- st_ptr(G0, vm_result_addr);
- verify_oop(oop_result);
-}
-
-
-void MacroAssembler::get_vm_result_2(Register metadata_result) {
- verify_thread();
- Address vm_result_addr_2(G2_thread, JavaThread::vm_result_2_offset());
- ld_ptr(vm_result_addr_2, metadata_result);
- st_ptr(G0, vm_result_addr_2);
-}
-
-
-// We require that C code which does not return a value in vm_result will
-// leave it undisturbed.
-void MacroAssembler::set_vm_result(Register oop_result) {
- verify_thread();
- Address vm_result_addr(G2_thread, JavaThread::vm_result_offset());
- verify_oop(oop_result);
-
-# ifdef ASSERT
- // Check that we are not overwriting any other oop.
-#ifdef CC_INTERP
- save_frame(0);
-#else
- save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod for -Xprof
-#endif /* CC_INTERP */
- ld_ptr(vm_result_addr, L0);
- tst(L0);
- restore();
- breakpoint_trap(notZero, Assembler::ptr_cc);
- // }
-# endif
-
- st_ptr(oop_result, vm_result_addr);
-}
-
-
-void MacroAssembler::ic_call(address entry, bool emit_delay) {
- RelocationHolder rspec = virtual_call_Relocation::spec(pc());
- patchable_set((intptr_t)Universe::non_oop_word(), G5_inline_cache_reg);
- relocate(rspec);
- call(entry, relocInfo::none);
- if (emit_delay) {
- delayed()->nop();
- }
-}
-
-
-void MacroAssembler::card_table_write(jbyte* byte_map_base,
- Register tmp, Register obj) {
-#ifdef _LP64
- srlx(obj, CardTableModRefBS::card_shift, obj);
-#else
- srl(obj, CardTableModRefBS::card_shift, obj);
-#endif
- assert(tmp != obj, "need separate temp reg");
- set((address) byte_map_base, tmp);
- stb(G0, tmp, obj);
-}
-
-
-void MacroAssembler::internal_sethi(const AddressLiteral& addrlit, Register d, bool ForceRelocatable) {
- address save_pc;
- int shiftcnt;
-#ifdef _LP64
-# ifdef CHECK_DELAY
- assert_not_delayed((char*) "cannot put two instructions in delay slot");
-# endif
- v9_dep();
- save_pc = pc();
-
- int msb32 = (int) (addrlit.value() >> 32);
- int lsb32 = (int) (addrlit.value());
-
- if (msb32 == 0 && lsb32 >= 0) {
- Assembler::sethi(lsb32, d, addrlit.rspec());
- }
- else if (msb32 == -1) {
- Assembler::sethi(~lsb32, d, addrlit.rspec());
- xor3(d, ~low10(~0), d);
- }
- else {
- Assembler::sethi(msb32, d, addrlit.rspec()); // msb 22-bits
- if (msb32 & 0x3ff) // Any bits?
- or3(d, msb32 & 0x3ff, d); // msb 32-bits are now in lsb 32
- if (lsb32 & 0xFFFFFC00) { // done?
- if ((lsb32 >> 20) & 0xfff) { // Any bits set?
- sllx(d, 12, d); // Make room for next 12 bits
- or3(d, (lsb32 >> 20) & 0xfff, d); // Or in next 12
- shiftcnt = 0; // We already shifted
- }
- else
- shiftcnt = 12;
- if ((lsb32 >> 10) & 0x3ff) {
- sllx(d, shiftcnt + 10, d); // Make room for last 10 bits
- or3(d, (lsb32 >> 10) & 0x3ff, d); // Or in next 10
- shiftcnt = 0;
- }
- else
- shiftcnt = 10;
- sllx(d, shiftcnt + 10, d); // Shift leaving disp field 0'd
- }
- else
- sllx(d, 32, d);
- }
- // Pad out the instruction sequence so it can be patched later.
- if (ForceRelocatable || (addrlit.rtype() != relocInfo::none &&
- addrlit.rtype() != relocInfo::runtime_call_type)) {
- while (pc() < (save_pc + (7 * BytesPerInstWord)))
- nop();
- }
-#else
- Assembler::sethi(addrlit.value(), d, addrlit.rspec());
-#endif
-}
-
-
-void MacroAssembler::sethi(const AddressLiteral& addrlit, Register d) {
- internal_sethi(addrlit, d, false);
-}
-
-
-void MacroAssembler::patchable_sethi(const AddressLiteral& addrlit, Register d) {
- internal_sethi(addrlit, d, true);
-}
-
-
-int MacroAssembler::insts_for_sethi(address a, bool worst_case) {
-#ifdef _LP64
- if (worst_case) return 7;
- intptr_t iaddr = (intptr_t) a;
- int msb32 = (int) (iaddr >> 32);
- int lsb32 = (int) (iaddr);
- int count;
- if (msb32 == 0 && lsb32 >= 0)
- count = 1;
- else if (msb32 == -1)
- count = 2;
- else {
- count = 2;
- if (msb32 & 0x3ff)
- count++;
- if (lsb32 & 0xFFFFFC00 ) {
- if ((lsb32 >> 20) & 0xfff) count += 2;
- if ((lsb32 >> 10) & 0x3ff) count += 2;
- }
- }
- return count;
-#else
- return 1;
-#endif
-}
-
-int MacroAssembler::worst_case_insts_for_set() {
- return insts_for_sethi(NULL, true) + 1;
-}
-
-
-// Keep in sync with MacroAssembler::insts_for_internal_set
-void MacroAssembler::internal_set(const AddressLiteral& addrlit, Register d, bool ForceRelocatable) {
- intptr_t value = addrlit.value();
-
- if (!ForceRelocatable && addrlit.rspec().type() == relocInfo::none) {
- // can optimize
- if (-4096 <= value && value <= 4095) {
- or3(G0, value, d); // setsw (this leaves upper 32 bits sign-extended)
- return;
- }
- if (inv_hi22(hi22(value)) == value) {
- sethi(addrlit, d);
- return;
- }
- }
- assert_not_delayed((char*) "cannot put two instructions in delay slot");
- internal_sethi(addrlit, d, ForceRelocatable);
- if (ForceRelocatable || addrlit.rspec().type() != relocInfo::none || addrlit.low10() != 0) {
- add(d, addrlit.low10(), d, addrlit.rspec());
- }
-}
-
-// Keep in sync with MacroAssembler::internal_set
-int MacroAssembler::insts_for_internal_set(intptr_t value) {
- // can optimize
- if (-4096 <= value && value <= 4095) {
- return 1;
- }
- if (inv_hi22(hi22(value)) == value) {
- return insts_for_sethi((address) value);
- }
- int count = insts_for_sethi((address) value);
- AddressLiteral al(value);
- if (al.low10() != 0) {
- count++;
- }
- return count;
-}
-
-void MacroAssembler::set(const AddressLiteral& al, Register d) {
- internal_set(al, d, false);
-}
-
-void MacroAssembler::set(intptr_t value, Register d) {
- AddressLiteral al(value);
- internal_set(al, d, false);
-}
-
-void MacroAssembler::set(address addr, Register d, RelocationHolder const& rspec) {
- AddressLiteral al(addr, rspec);
- internal_set(al, d, false);
-}
-
-void MacroAssembler::patchable_set(const AddressLiteral& al, Register d) {
- internal_set(al, d, true);
-}
-
-void MacroAssembler::patchable_set(intptr_t value, Register d) {
- AddressLiteral al(value);
- internal_set(al, d, true);
-}
-
-
-void MacroAssembler::set64(jlong value, Register d, Register tmp) {
- assert_not_delayed();
- v9_dep();
-
- int hi = (int)(value >> 32);
- int lo = (int)(value & ~0);
- // (Matcher::isSimpleConstant64 knows about the following optimizations.)
- if (Assembler::is_simm13(lo) && value == lo) {
- or3(G0, lo, d);
- } else if (hi == 0) {
- Assembler::sethi(lo, d); // hardware version zero-extends to upper 32
- if (low10(lo) != 0)
- or3(d, low10(lo), d);
- }
- else if (hi == -1) {
- Assembler::sethi(~lo, d); // hardware version zero-extends to upper 32
- xor3(d, low10(lo) ^ ~low10(~0), d);
- }
- else if (lo == 0) {
- if (Assembler::is_simm13(hi)) {
- or3(G0, hi, d);
- } else {
- Assembler::sethi(hi, d); // hardware version zero-extends to upper 32
- if (low10(hi) != 0)
- or3(d, low10(hi), d);
- }
- sllx(d, 32, d);
- }
- else {
- Assembler::sethi(hi, tmp);
- Assembler::sethi(lo, d); // macro assembler version sign-extends
- if (low10(hi) != 0)
- or3 (tmp, low10(hi), tmp);
- if (low10(lo) != 0)
- or3 ( d, low10(lo), d);
- sllx(tmp, 32, tmp);
- or3 (d, tmp, d);
- }
-}
-
-int MacroAssembler::insts_for_set64(jlong value) {
- v9_dep();
-
- int hi = (int) (value >> 32);
- int lo = (int) (value & ~0);
- int count = 0;
-
- // (Matcher::isSimpleConstant64 knows about the following optimizations.)
- if (Assembler::is_simm13(lo) && value == lo) {
- count++;
- } else if (hi == 0) {
- count++;
- if (low10(lo) != 0)
- count++;
- }
- else if (hi == -1) {
- count += 2;
- }
- else if (lo == 0) {
- if (Assembler::is_simm13(hi)) {
- count++;
- } else {
- count++;
- if (low10(hi) != 0)
- count++;
- }
- count++;
- }
- else {
- count += 2;
- if (low10(hi) != 0)
- count++;
- if (low10(lo) != 0)
- count++;
- count += 2;
- }
- return count;
-}
-
-// compute size in bytes of sparc frame, given
-// number of extraWords
-int MacroAssembler::total_frame_size_in_bytes(int extraWords) {
-
- int nWords = frame::memory_parameter_word_sp_offset;
-
- nWords += extraWords;
-
- if (nWords & 1) ++nWords; // round up to double-word
-
- return nWords * BytesPerWord;
-}
-
-
-// save_frame: given number of "extra" words in frame,
-// issue approp. save instruction (p 200, v8 manual)
-
-void MacroAssembler::save_frame(int extraWords) {
- int delta = -total_frame_size_in_bytes(extraWords);
- if (is_simm13(delta)) {
- save(SP, delta, SP);
- } else {
- set(delta, G3_scratch);
- save(SP, G3_scratch, SP);
- }
-}
-
-
-void MacroAssembler::save_frame_c1(int size_in_bytes) {
- if (is_simm13(-size_in_bytes)) {
- save(SP, -size_in_bytes, SP);
- } else {
- set(-size_in_bytes, G3_scratch);
- save(SP, G3_scratch, SP);
- }
-}
-
-
-void MacroAssembler::save_frame_and_mov(int extraWords,
- Register s1, Register d1,
- Register s2, Register d2) {
- assert_not_delayed();
-
- // The trick here is to use precisely the same memory word
- // that trap handlers also use to save the register.
- // This word cannot be used for any other purpose, but
- // it works fine to save the register's value, whether or not
- // an interrupt flushes register windows at any given moment!
- Address s1_addr;
- if (s1->is_valid() && (s1->is_in() || s1->is_local())) {
- s1_addr = s1->address_in_saved_window();
- st_ptr(s1, s1_addr);
- }
-
- Address s2_addr;
- if (s2->is_valid() && (s2->is_in() || s2->is_local())) {
- s2_addr = s2->address_in_saved_window();
- st_ptr(s2, s2_addr);
- }
-
- save_frame(extraWords);
-
- if (s1_addr.base() == SP) {
- ld_ptr(s1_addr.after_save(), d1);
- } else if (s1->is_valid()) {
- mov(s1->after_save(), d1);
- }
-
- if (s2_addr.base() == SP) {
- ld_ptr(s2_addr.after_save(), d2);
- } else if (s2->is_valid()) {
- mov(s2->after_save(), d2);
- }
-}
-
-
-AddressLiteral MacroAssembler::allocate_metadata_address(Metadata* obj) {
- assert(oop_recorder() != NULL, "this assembler needs a Recorder");
- int index = oop_recorder()->allocate_metadata_index(obj);
- RelocationHolder rspec = metadata_Relocation::spec(index);
- return AddressLiteral((address)obj, rspec);
-}
-
-AddressLiteral MacroAssembler::constant_metadata_address(Metadata* obj) {
- assert(oop_recorder() != NULL, "this assembler needs a Recorder");
- int index = oop_recorder()->find_index(obj);
- RelocationHolder rspec = metadata_Relocation::spec(index);
- return AddressLiteral((address)obj, rspec);
-}
-
-
-AddressLiteral MacroAssembler::constant_oop_address(jobject obj) {
- assert(oop_recorder() != NULL, "this assembler needs an OopRecorder");
- assert(Universe::heap()->is_in_reserved(JNIHandles::resolve(obj)), "not an oop");
- int oop_index = oop_recorder()->find_index(obj);
- return AddressLiteral(obj, oop_Relocation::spec(oop_index));
-}
-
-void MacroAssembler::set_narrow_oop(jobject obj, Register d) {
- assert(oop_recorder() != NULL, "this assembler needs an OopRecorder");
- int oop_index = oop_recorder()->find_index(obj);
- RelocationHolder rspec = oop_Relocation::spec(oop_index);
-
- assert_not_delayed();
- // Relocation with special format (see relocInfo_sparc.hpp).
- relocate(rspec, 1);
- // Assembler::sethi(0x3fffff, d);
- emit_long( op(branch_op) | rd(d) | op2(sethi_op2) | hi22(0x3fffff) );
- // Don't add relocation for 'add'. Do patching during 'sethi' processing.
- add(d, 0x3ff, d);
-
-}
-
-void MacroAssembler::set_narrow_klass(Klass* k, Register d) {
- assert(oop_recorder() != NULL, "this assembler needs an OopRecorder");
- int klass_index = oop_recorder()->find_index(k);
- RelocationHolder rspec = metadata_Relocation::spec(klass_index);
- narrowOop encoded_k = oopDesc::encode_klass(k);
-
- assert_not_delayed();
- // Relocation with special format (see relocInfo_sparc.hpp).
- relocate(rspec, 1);
- // Assembler::sethi(encoded_k, d);
- emit_long( op(branch_op) | rd(d) | op2(sethi_op2) | hi22(encoded_k) );
- // Don't add relocation for 'add'. Do patching during 'sethi' processing.
- add(d, low10(encoded_k), d);
-
-}
-
-void MacroAssembler::align(int modulus) {
- while (offset() % modulus != 0) nop();
-}
-
-
-void MacroAssembler::safepoint() {
- relocate(breakpoint_Relocation::spec(breakpoint_Relocation::safepoint));
-}
-
-
-void RegistersForDebugging::print(outputStream* s) {
- FlagSetting fs(Debugging, true);
- int j;
- for (j = 0; j < 8; ++j) {
- if (j != 6) { s->print("i%d = ", j); os::print_location(s, i[j]); }
- else { s->print( "fp = " ); os::print_location(s, i[j]); }
- }
- s->cr();
-
- for (j = 0; j < 8; ++j) {
- s->print("l%d = ", j); os::print_location(s, l[j]);
- }
- s->cr();
-
- for (j = 0; j < 8; ++j) {
- if (j != 6) { s->print("o%d = ", j); os::print_location(s, o[j]); }
- else { s->print( "sp = " ); os::print_location(s, o[j]); }
- }
- s->cr();
-
- for (j = 0; j < 8; ++j) {
- s->print("g%d = ", j); os::print_location(s, g[j]);
- }
- s->cr();
-
- // print out floats with compression
- for (j = 0; j < 32; ) {
- jfloat val = f[j];
- int last = j;
- for ( ; last+1 < 32; ++last ) {
- char b1[1024], b2[1024];
- sprintf(b1, "%f", val);
- sprintf(b2, "%f", f[last+1]);
- if (strcmp(b1, b2))
- break;
- }
- s->print("f%d", j);
- if ( j != last ) s->print(" - f%d", last);
- s->print(" = %f", val);
- s->fill_to(25);
- s->print_cr(" (0x%x)", val);
- j = last + 1;
- }
- s->cr();
-
- // and doubles (evens only)
- for (j = 0; j < 32; ) {
- jdouble val = d[j];
- int last = j;
- for ( ; last+1 < 32; ++last ) {
- char b1[1024], b2[1024];
- sprintf(b1, "%f", val);
- sprintf(b2, "%f", d[last+1]);
- if (strcmp(b1, b2))
- break;
- }
- s->print("d%d", 2 * j);
- if ( j != last ) s->print(" - d%d", last);
- s->print(" = %f", val);
- s->fill_to(30);
- s->print("(0x%x)", *(int*)&val);
- s->fill_to(42);
- s->print_cr("(0x%x)", *(1 + (int*)&val));
- j = last + 1;
- }
- s->cr();
-}
-
-void RegistersForDebugging::save_registers(MacroAssembler* a) {
- a->sub(FP, round_to(sizeof(RegistersForDebugging), sizeof(jdouble)) - STACK_BIAS, O0);
- a->flush_windows();
- int i;
- for (i = 0; i < 8; ++i) {
- a->ld_ptr(as_iRegister(i)->address_in_saved_window().after_save(), L1); a->st_ptr( L1, O0, i_offset(i));
- a->ld_ptr(as_lRegister(i)->address_in_saved_window().after_save(), L1); a->st_ptr( L1, O0, l_offset(i));
- a->st_ptr(as_oRegister(i)->after_save(), O0, o_offset(i));
- a->st_ptr(as_gRegister(i)->after_save(), O0, g_offset(i));
- }
- for (i = 0; i < 32; ++i) {
- a->stf(FloatRegisterImpl::S, as_FloatRegister(i), O0, f_offset(i));
- }
- for (i = 0; i < (VM_Version::v9_instructions_work() ? 64 : 32); i += 2) {
- a->stf(FloatRegisterImpl::D, as_FloatRegister(i), O0, d_offset(i));
- }
-}
-
-void RegistersForDebugging::restore_registers(MacroAssembler* a, Register r) {
- for (int i = 1; i < 8; ++i) {
- a->ld_ptr(r, g_offset(i), as_gRegister(i));
- }
- for (int j = 0; j < 32; ++j) {
- a->ldf(FloatRegisterImpl::S, O0, f_offset(j), as_FloatRegister(j));
- }
- for (int k = 0; k < (VM_Version::v9_instructions_work() ? 64 : 32); k += 2) {
- a->ldf(FloatRegisterImpl::D, O0, d_offset(k), as_FloatRegister(k));
- }
-}
-
-
-// pushes double TOS element of FPU stack on CPU stack; pops from FPU stack
-void MacroAssembler::push_fTOS() {
- // %%%%%% need to implement this
-}
-
-// pops double TOS element from CPU stack and pushes on FPU stack
-void MacroAssembler::pop_fTOS() {
- // %%%%%% need to implement this
-}
-
-void MacroAssembler::empty_FPU_stack() {
- // %%%%%% need to implement this
-}
-
-void MacroAssembler::_verify_oop(Register reg, const char* msg, const char * file, int line) {
- // plausibility check for oops
- if (!VerifyOops) return;
-
- if (reg == G0) return; // always NULL, which is always an oop
-
- BLOCK_COMMENT("verify_oop {");
- char buffer[64];
-#ifdef COMPILER1
- if (CommentedAssembly) {
- snprintf(buffer, sizeof(buffer), "verify_oop at %d", offset());
- block_comment(buffer);
- }
-#endif
-
- int len = strlen(file) + strlen(msg) + 1 + 4;
- sprintf(buffer, "%d", line);
- len += strlen(buffer);
- sprintf(buffer, " at offset %d ", offset());
- len += strlen(buffer);
- char * real_msg = new char[len];
- sprintf(real_msg, "%s%s(%s:%d)", msg, buffer, file, line);
-
- // Call indirectly to solve generation ordering problem
- AddressLiteral a(StubRoutines::verify_oop_subroutine_entry_address());
-
- // Make some space on stack above the current register window.
- // Enough to hold 8 64-bit registers.
- add(SP,-8*8,SP);
-
- // Save some 64-bit registers; a normal 'save' chops the heads off
- // of 64-bit longs in the 32-bit build.
- stx(O0,SP,frame::register_save_words*wordSize+STACK_BIAS+0*8);
- stx(O1,SP,frame::register_save_words*wordSize+STACK_BIAS+1*8);
- mov(reg,O0); // Move arg into O0; arg might be in O7 which is about to be crushed
- stx(O7,SP,frame::register_save_words*wordSize+STACK_BIAS+7*8);
-
- // Size of set() should stay the same
- patchable_set((intptr_t)real_msg, O1);
- // Load address to call to into O7
- load_ptr_contents(a, O7);
- // Register call to verify_oop_subroutine
- callr(O7, G0);
- 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) {
- // plausibility check for oops
- if (!VerifyOops) return;
-
- char buffer[64];
- sprintf(buffer, "%d", line);
- int len = strlen(file) + strlen(msg) + 1 + 4 + strlen(buffer);
- sprintf(buffer, " at SP+%d ", addr.disp());
- len += strlen(buffer);
- char * real_msg = new char[len];
- sprintf(real_msg, "%s at SP+%d (%s:%d)", msg, addr.disp(), file, line);
-
- // Call indirectly to solve generation ordering problem
- AddressLiteral a(StubRoutines::verify_oop_subroutine_entry_address());
-
- // Make some space on stack above the current register window.
- // Enough to hold 8 64-bit registers.
- add(SP,-8*8,SP);
-
- // Save some 64-bit registers; a normal 'save' chops the heads off
- // of 64-bit longs in the 32-bit build.
- stx(O0,SP,frame::register_save_words*wordSize+STACK_BIAS+0*8);
- stx(O1,SP,frame::register_save_words*wordSize+STACK_BIAS+1*8);
- ld_ptr(addr.base(), addr.disp() + 8*8, O0); // Load arg into O0; arg might be in O7 which is about to be crushed
- stx(O7,SP,frame::register_save_words*wordSize+STACK_BIAS+7*8);
-
- // Size of set() should stay the same
- patchable_set((intptr_t)real_msg, O1);
- // Load address to call to into O7
- load_ptr_contents(a, O7);
- // Register call to verify_oop_subroutine
- callr(O7, G0);
- delayed()->nop();
- // recover frame size
- add(SP, 8*8,SP);
-}
-
-// side-door communication with signalHandler in os_solaris.cpp
-address MacroAssembler::_verify_oop_implicit_branch[3] = { NULL };
-
-// This macro is expanded just once; it creates shared code. Contract:
-// receives an oop in O0. Must restore O0 & O7 from TLS. Must not smash ANY
-// registers, including flags. May not use a register 'save', as this blows
-// the high bits of the O-regs if they contain Long values. Acts as a 'leaf'
-// call.
-void MacroAssembler::verify_oop_subroutine() {
- assert( VM_Version::v9_instructions_work(), "VerifyOops not supported for V8" );
-
- // Leaf call; no frame.
- Label succeed, fail, null_or_fail;
-
- // O0 and O7 were saved already (O0 in O0's TLS home, O7 in O5's TLS home).
- // O0 is now the oop to be checked. O7 is the return address.
- Register O0_obj = O0;
-
- // Save some more registers for temps.
- stx(O2,SP,frame::register_save_words*wordSize+STACK_BIAS+2*8);
- stx(O3,SP,frame::register_save_words*wordSize+STACK_BIAS+3*8);
- stx(O4,SP,frame::register_save_words*wordSize+STACK_BIAS+4*8);
- stx(O5,SP,frame::register_save_words*wordSize+STACK_BIAS+5*8);
-
- // Save flags
- Register O5_save_flags = O5;
- rdccr( O5_save_flags );
-
- { // count number of verifies
- Register O2_adr = O2;
- Register O3_accum = O3;
- inc_counter(StubRoutines::verify_oop_count_addr(), O2_adr, O3_accum);
- }
-
- Register O2_mask = O2;
- Register O3_bits = O3;
- Register O4_temp = O4;
-
- // mark lower end of faulting range
- assert(_verify_oop_implicit_branch[0] == NULL, "set once");
- _verify_oop_implicit_branch[0] = pc();
-
- // We can't check the mark oop because it could be in the process of
- // locking or unlocking while this is running.
- set(Universe::verify_oop_mask (), O2_mask);
- set(Universe::verify_oop_bits (), O3_bits);
-
- // assert((obj & oop_mask) == oop_bits);
- and3(O0_obj, O2_mask, O4_temp);
- cmp_and_brx_short(O4_temp, O3_bits, notEqual, pn, null_or_fail);
-
- if ((NULL_WORD & Universe::verify_oop_mask()) == Universe::verify_oop_bits()) {
- // the null_or_fail case is useless; must test for null separately
- br_null_short(O0_obj, pn, succeed);
- }
-
- // Check the Klass* of this object for being in the right area of memory.
- // Cannot do the load in the delay above slot in case O0 is null
- load_klass(O0_obj, O0_obj);
- // assert((klass != NULL)
- br_null_short(O0_obj, pn, fail);
- // TODO: Future assert that klass is lower 4g memory for UseCompressedKlassPointers
-
- wrccr( O5_save_flags ); // Restore CCR's
-
- // mark upper end of faulting range
- _verify_oop_implicit_branch[1] = pc();
-
- //-----------------------
- // all tests pass
- bind(succeed);
-
- // Restore prior 64-bit registers
- ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+0*8,O0);
- ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+1*8,O1);
- ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+2*8,O2);
- ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+3*8,O3);
- ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+4*8,O4);
- ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+5*8,O5);
-
- retl(); // Leaf return; restore prior O7 in delay slot
- delayed()->ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+7*8,O7);
-
- //-----------------------
- bind(null_or_fail); // nulls are less common but OK
- br_null(O0_obj, false, pt, succeed);
- delayed()->wrccr( O5_save_flags ); // Restore CCR's
-
- //-----------------------
- // report failure:
- bind(fail);
- _verify_oop_implicit_branch[2] = pc();
-
- wrccr( O5_save_flags ); // Restore CCR's
-
- save_frame(::round_to(sizeof(RegistersForDebugging) / BytesPerWord, 2));
-
- // stop_subroutine expects message pointer in I1.
- mov(I1, O1);
-
- // Restore prior 64-bit registers
- ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+0*8,I0);
- ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+1*8,I1);
- ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+2*8,I2);
- ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+3*8,I3);
- ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+4*8,I4);
- ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+5*8,I5);
-
- // factor long stop-sequence into subroutine to save space
- assert(StubRoutines::Sparc::stop_subroutine_entry_address(), "hasn't been generated yet");
-
- // call indirectly to solve generation ordering problem
- AddressLiteral al(StubRoutines::Sparc::stop_subroutine_entry_address());
- load_ptr_contents(al, O5);
- jmpl(O5, 0, O7);
- delayed()->nop();
-}
-
-
-void MacroAssembler::stop(const char* msg) {
- // save frame first to get O7 for return address
- // add one word to size in case struct is odd number of words long
- // It must be doubleword-aligned for storing doubles into it.
-
- save_frame(::round_to(sizeof(RegistersForDebugging) / BytesPerWord, 2));
-
- // stop_subroutine expects message pointer in I1.
- // Size of set() should stay the same
- patchable_set((intptr_t)msg, O1);
-
- // factor long stop-sequence into subroutine to save space
- assert(StubRoutines::Sparc::stop_subroutine_entry_address(), "hasn't been generated yet");
-
- // call indirectly to solve generation ordering problem
- AddressLiteral a(StubRoutines::Sparc::stop_subroutine_entry_address());
- load_ptr_contents(a, O5);
- jmpl(O5, 0, O7);
- delayed()->nop();
-
- breakpoint_trap(); // make stop actually stop rather than writing
- // unnoticeable results in the output files.
-
- // restore(); done in callee to save space!
-}
-
-
-void MacroAssembler::warn(const char* msg) {
- save_frame(::round_to(sizeof(RegistersForDebugging) / BytesPerWord, 2));
- RegistersForDebugging::save_registers(this);
- mov(O0, L0);
- // Size of set() should stay the same
- patchable_set((intptr_t)msg, O0);
- call( CAST_FROM_FN_PTR(address, warning) );
- delayed()->nop();
-// ret();
-// delayed()->restore();
- RegistersForDebugging::restore_registers(this, L0);
- restore();
-}
-
-
-void MacroAssembler::untested(const char* what) {
- // We must be able to turn interactive prompting off
- // in order to run automated test scripts on the VM
- // Use the flag ShowMessageBoxOnError
-
- char* b = new char[1024];
- sprintf(b, "untested: %s", what);
-
- if (ShowMessageBoxOnError) { STOP(b); }
- else { warn(b); }
-}
-
-
-void MacroAssembler::stop_subroutine() {
- RegistersForDebugging::save_registers(this);
-
- // for the sake of the debugger, stick a PC on the current frame
- // (this assumes that the caller has performed an extra "save")
- mov(I7, L7);
- add(O7, -7 * BytesPerInt, I7);
-
- save_frame(); // one more save to free up another O7 register
- mov(I0, O1); // addr of reg save area
-
- // We expect pointer to message in I1. Caller must set it up in O1
- mov(I1, O0); // get msg
- call (CAST_FROM_FN_PTR(address, MacroAssembler::debug), relocInfo::runtime_call_type);
- delayed()->nop();
-
- restore();
-
- RegistersForDebugging::restore_registers(this, O0);
-
- save_frame(0);
- call(CAST_FROM_FN_PTR(address,breakpoint));
- delayed()->nop();
- restore();
-
- mov(L7, I7);
- retl();
- delayed()->restore(); // see stop above
-}
-
-
-void MacroAssembler::debug(char* msg, RegistersForDebugging* regs) {
- if ( ShowMessageBoxOnError ) {
- JavaThread* thread = JavaThread::current();
- JavaThreadState saved_state = thread->thread_state();
- thread->set_thread_state(_thread_in_vm);
- {
- // In order to get locks work, we need to fake a in_VM state
- ttyLocker ttyl;
- ::tty->print_cr("EXECUTION STOPPED: %s\n", msg);
- if (CountBytecodes || TraceBytecodes || StopInterpreterAt) {
- BytecodeCounter::print();
- }
- if (os::message_box(msg, "Execution stopped, print registers?"))
- regs->print(::tty);
- }
- BREAKPOINT;
- ThreadStateTransition::transition(JavaThread::current(), _thread_in_vm, saved_state);
- }
- else {
- ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg);
- }
- assert(false, err_msg("DEBUG MESSAGE: %s", msg));
-}
-
-#ifndef PRODUCT
-void MacroAssembler::test() {
- ResourceMark rm;
-
- CodeBuffer cb("test", 10000, 10000);
- MacroAssembler* a = new MacroAssembler(&cb);
- VM_Version::allow_all();
- a->test_v9();
- a->test_v8_onlys();
- VM_Version::revert();
-
- StubRoutines::Sparc::test_stop_entry()();
-}
-#endif
-
-
-void MacroAssembler::calc_mem_param_words(Register Rparam_words, Register Rresult) {
- subcc( Rparam_words, Argument::n_register_parameters, Rresult); // how many mem words?
- Label no_extras;
- br( negative, true, pt, no_extras ); // if neg, clear reg
- delayed()->set(0, Rresult); // annuled, so only if taken
- bind( no_extras );
-}
-
-
-void MacroAssembler::calc_frame_size(Register Rextra_words, Register Rresult) {
-#ifdef _LP64
- add(Rextra_words, frame::memory_parameter_word_sp_offset, Rresult);
-#else
- add(Rextra_words, frame::memory_parameter_word_sp_offset + 1, Rresult);
-#endif
- bclr(1, Rresult);
- sll(Rresult, LogBytesPerWord, Rresult); // Rresult has total frame bytes
-}
-
-
-void MacroAssembler::calc_frame_size_and_save(Register Rextra_words, Register Rresult) {
- calc_frame_size(Rextra_words, Rresult);
- neg(Rresult);
- save(SP, Rresult, SP);
-}
-
-
-// ---------------------------------------------------------
-Assembler::RCondition cond2rcond(Assembler::Condition c) {
- switch (c) {
- /*case zero: */
- case Assembler::equal: return Assembler::rc_z;
- case Assembler::lessEqual: return Assembler::rc_lez;
- case Assembler::less: return Assembler::rc_lz;
- /*case notZero:*/
- case Assembler::notEqual: return Assembler::rc_nz;
- case Assembler::greater: return Assembler::rc_gz;
- case Assembler::greaterEqual: return Assembler::rc_gez;
- }
- ShouldNotReachHere();
- return Assembler::rc_z;
-}
-
-// compares (32 bit) register with zero and branches. NOT FOR USE WITH 64-bit POINTERS
-void MacroAssembler::cmp_zero_and_br(Condition c, Register s1, Label& L, bool a, Predict p) {
- tst(s1);
- br (c, a, p, L);
-}
-
-// Compares a pointer register with zero and branches on null.
-// Does a test & branch on 32-bit systems and a register-branch on 64-bit.
-void MacroAssembler::br_null( Register s1, bool a, Predict p, Label& L ) {
- assert_not_delayed();
-#ifdef _LP64
- bpr( rc_z, a, p, s1, L );
-#else
- tst(s1);
- br ( zero, a, p, L );
-#endif
-}
-
-void MacroAssembler::br_notnull( Register s1, bool a, Predict p, Label& L ) {
- assert_not_delayed();
-#ifdef _LP64
- bpr( rc_nz, a, p, s1, L );
-#else
- tst(s1);
- br ( notZero, a, p, L );
-#endif
-}
-
-// Compare registers and branch with nop in delay slot or cbcond without delay slot.
-
-// Compare integer (32 bit) values (icc only).
-void MacroAssembler::cmp_and_br_short(Register s1, Register s2, Condition c,
- Predict p, Label& L) {
- assert_not_delayed();
- if (use_cbcond(L)) {
- Assembler::cbcond(c, icc, s1, s2, L);
- } else {
- cmp(s1, s2);
- br(c, false, p, L);
- delayed()->nop();
- }
-}
-
-// Compare integer (32 bit) values (icc only).
-void MacroAssembler::cmp_and_br_short(Register s1, int simm13a, Condition c,
- Predict p, Label& L) {
- assert_not_delayed();
- if (is_simm(simm13a,5) && use_cbcond(L)) {
- Assembler::cbcond(c, icc, s1, simm13a, L);
- } else {
- cmp(s1, simm13a);
- br(c, false, p, L);
- delayed()->nop();
- }
-}
-
-// Branch that tests xcc in LP64 and icc in !LP64
-void MacroAssembler::cmp_and_brx_short(Register s1, Register s2, Condition c,
- Predict p, Label& L) {
- assert_not_delayed();
- if (use_cbcond(L)) {
- Assembler::cbcond(c, ptr_cc, s1, s2, L);
- } else {
- cmp(s1, s2);
- brx(c, false, p, L);
- delayed()->nop();
- }
-}
-
-// Branch that tests xcc in LP64 and icc in !LP64
-void MacroAssembler::cmp_and_brx_short(Register s1, int simm13a, Condition c,
- Predict p, Label& L) {
- assert_not_delayed();
- if (is_simm(simm13a,5) && use_cbcond(L)) {
- Assembler::cbcond(c, ptr_cc, s1, simm13a, L);
- } else {
- cmp(s1, simm13a);
- brx(c, false, p, L);
- delayed()->nop();
- }
-}
-
-// Short branch version for compares a pointer with zero.
-
-void MacroAssembler::br_null_short(Register s1, Predict p, Label& L) {
- assert_not_delayed();
- if (use_cbcond(L)) {
- Assembler::cbcond(zero, ptr_cc, s1, 0, L);
- return;
- }
- br_null(s1, false, p, L);
- delayed()->nop();
-}
-
-void MacroAssembler::br_notnull_short(Register s1, Predict p, Label& L) {
- assert_not_delayed();
- if (use_cbcond(L)) {
- Assembler::cbcond(notZero, ptr_cc, s1, 0, L);
- return;
- }
- br_notnull(s1, false, p, L);
- delayed()->nop();
-}
-
-// Unconditional short branch
-void MacroAssembler::ba_short(Label& L) {
- if (use_cbcond(L)) {
- Assembler::cbcond(equal, icc, G0, G0, L);
- return;
- }
- br(always, false, pt, L);
- delayed()->nop();
-}
-
-// instruction sequences factored across compiler & interpreter
-
-
-void MacroAssembler::lcmp( Register Ra_hi, Register Ra_low,
- Register Rb_hi, Register Rb_low,
- Register Rresult) {
-
- Label check_low_parts, done;
-
- cmp(Ra_hi, Rb_hi ); // compare hi parts
- br(equal, true, pt, check_low_parts);
- delayed()->cmp(Ra_low, Rb_low); // test low parts
-
- // And, with an unsigned comparison, it does not matter if the numbers
- // are negative or not.
- // E.g., -2 cmp -1: the low parts are 0xfffffffe and 0xffffffff.
- // The second one is bigger (unsignedly).
-
- // Other notes: The first move in each triplet can be unconditional
- // (and therefore probably prefetchable).
- // And the equals case for the high part does not need testing,
- // since that triplet is reached only after finding the high halves differ.
-
- if (VM_Version::v9_instructions_work()) {
- mov(-1, Rresult);
- ba(done); delayed()-> movcc(greater, false, icc, 1, Rresult);
- } else {
- br(less, true, pt, done); delayed()-> set(-1, Rresult);
- br(greater, true, pt, done); delayed()-> set( 1, Rresult);
- }
-
- bind( check_low_parts );
-
- if (VM_Version::v9_instructions_work()) {
- mov( -1, Rresult);
- movcc(equal, false, icc, 0, Rresult);
- movcc(greaterUnsigned, false, icc, 1, Rresult);
- } else {
- set(-1, Rresult);
- br(equal, true, pt, done); delayed()->set( 0, Rresult);
- br(greaterUnsigned, true, pt, done); delayed()->set( 1, Rresult);
- }
- bind( done );
-}
-
-void MacroAssembler::lneg( Register Rhi, Register Rlow ) {
- subcc( G0, Rlow, Rlow );
- subc( G0, Rhi, Rhi );
-}
-
-void MacroAssembler::lshl( Register Rin_high, Register Rin_low,
- Register Rcount,
- Register Rout_high, Register Rout_low,
- Register Rtemp ) {
-
-
- Register Ralt_count = Rtemp;
- Register Rxfer_bits = Rtemp;
-
- assert( Ralt_count != Rin_high
- && Ralt_count != Rin_low
- && Ralt_count != Rcount
- && Rxfer_bits != Rin_low
- && Rxfer_bits != Rin_high
- && Rxfer_bits != Rcount
- && Rxfer_bits != Rout_low
- && Rout_low != Rin_high,
- "register alias checks");
-
- Label big_shift, done;
-
- // This code can be optimized to use the 64 bit shifts in V9.
- // Here we use the 32 bit shifts.
-
- and3( Rcount, 0x3f, Rcount); // take least significant 6 bits
- subcc(Rcount, 31, Ralt_count);
- br(greater, true, pn, big_shift);
- delayed()->dec(Ralt_count);
-
- // shift < 32 bits, Ralt_count = Rcount-31
-
- // We get the transfer bits by shifting right by 32-count the low
- // register. This is done by shifting right by 31-count and then by one
- // more to take care of the special (rare) case where count is zero
- // (shifting by 32 would not work).
-
- neg(Ralt_count);
-
- // The order of the next two instructions is critical in the case where
- // Rin and Rout are the same and should not be reversed.
-
- srl(Rin_low, Ralt_count, Rxfer_bits); // shift right by 31-count
- if (Rcount != Rout_low) {
- sll(Rin_low, Rcount, Rout_low); // low half
- }
- sll(Rin_high, Rcount, Rout_high);
- if (Rcount == Rout_low) {
- sll(Rin_low, Rcount, Rout_low); // low half
- }
- srl(Rxfer_bits, 1, Rxfer_bits ); // shift right by one more
- ba(done);
- delayed()->or3(Rout_high, Rxfer_bits, Rout_high); // new hi value: or in shifted old hi part and xfer from low
-
- // shift >= 32 bits, Ralt_count = Rcount-32
- bind(big_shift);
- sll(Rin_low, Ralt_count, Rout_high );
- clr(Rout_low);
-
- bind(done);
-}
-
-
-void MacroAssembler::lshr( Register Rin_high, Register Rin_low,
- Register Rcount,
- Register Rout_high, Register Rout_low,
- Register Rtemp ) {
-
- Register Ralt_count = Rtemp;
- Register Rxfer_bits = Rtemp;
-
- assert( Ralt_count != Rin_high
- && Ralt_count != Rin_low
- && Ralt_count != Rcount
- && Rxfer_bits != Rin_low
- && Rxfer_bits != Rin_high
- && Rxfer_bits != Rcount
- && Rxfer_bits != Rout_high
- && Rout_high != Rin_low,
- "register alias checks");
-
- Label big_shift, done;
-
- // This code can be optimized to use the 64 bit shifts in V9.
- // Here we use the 32 bit shifts.
-
- and3( Rcount, 0x3f, Rcount); // take least significant 6 bits
- subcc(Rcount, 31, Ralt_count);
- br(greater, true, pn, big_shift);
- delayed()->dec(Ralt_count);
-
- // shift < 32 bits, Ralt_count = Rcount-31
-
- // We get the transfer bits by shifting left by 32-count the high
- // register. This is done by shifting left by 31-count and then by one
- // more to take care of the special (rare) case where count is zero
- // (shifting by 32 would not work).
-
- neg(Ralt_count);
- if (Rcount != Rout_low) {
- srl(Rin_low, Rcount, Rout_low);
- }
-
- // The order of the next two instructions is critical in the case where
- // Rin and Rout are the same and should not be reversed.
-
- sll(Rin_high, Ralt_count, Rxfer_bits); // shift left by 31-count
- sra(Rin_high, Rcount, Rout_high ); // high half
- sll(Rxfer_bits, 1, Rxfer_bits); // shift left by one more
- if (Rcount == Rout_low) {
- srl(Rin_low, Rcount, Rout_low);
- }
- ba(done);
- delayed()->or3(Rout_low, Rxfer_bits, Rout_low); // new low value: or shifted old low part and xfer from high
-
- // shift >= 32 bits, Ralt_count = Rcount-32
- bind(big_shift);
-
- sra(Rin_high, Ralt_count, Rout_low);
- sra(Rin_high, 31, Rout_high); // sign into hi
-
- bind( done );
-}
-
-
-
-void MacroAssembler::lushr( Register Rin_high, Register Rin_low,
- Register Rcount,
- Register Rout_high, Register Rout_low,
- Register Rtemp ) {
-
- Register Ralt_count = Rtemp;
- Register Rxfer_bits = Rtemp;
-
- assert( Ralt_count != Rin_high
- && Ralt_count != Rin_low
- && Ralt_count != Rcount
- && Rxfer_bits != Rin_low
- && Rxfer_bits != Rin_high
- && Rxfer_bits != Rcount
- && Rxfer_bits != Rout_high
- && Rout_high != Rin_low,
- "register alias checks");
-
- Label big_shift, done;
-
- // This code can be optimized to use the 64 bit shifts in V9.
- // Here we use the 32 bit shifts.
-
- and3( Rcount, 0x3f, Rcount); // take least significant 6 bits
- subcc(Rcount, 31, Ralt_count);
- br(greater, true, pn, big_shift);
- delayed()->dec(Ralt_count);
-
- // shift < 32 bits, Ralt_count = Rcount-31
-
- // We get the transfer bits by shifting left by 32-count the high
- // register. This is done by shifting left by 31-count and then by one
- // more to take care of the special (rare) case where count is zero
- // (shifting by 32 would not work).
-
- neg(Ralt_count);
- if (Rcount != Rout_low) {
- srl(Rin_low, Rcount, Rout_low);
- }
-
- // The order of the next two instructions is critical in the case where
- // Rin and Rout are the same and should not be reversed.
-
- sll(Rin_high, Ralt_count, Rxfer_bits); // shift left by 31-count
- srl(Rin_high, Rcount, Rout_high ); // high half
- sll(Rxfer_bits, 1, Rxfer_bits); // shift left by one more
- if (Rcount == Rout_low) {
- srl(Rin_low, Rcount, Rout_low);
- }
- ba(done);
- delayed()->or3(Rout_low, Rxfer_bits, Rout_low); // new low value: or shifted old low part and xfer from high
-
- // shift >= 32 bits, Ralt_count = Rcount-32
- bind(big_shift);
-
- srl(Rin_high, Ralt_count, Rout_low);
- clr(Rout_high);
-
- bind( done );
-}
-
-#ifdef _LP64
-void MacroAssembler::lcmp( Register Ra, Register Rb, Register Rresult) {
- cmp(Ra, Rb);
- mov(-1, Rresult);
- movcc(equal, false, xcc, 0, Rresult);
- movcc(greater, false, xcc, 1, Rresult);
-}
-#endif
-
-
-void MacroAssembler::load_sized_value(Address src, Register dst, size_t size_in_bytes, bool is_signed) {
- switch (size_in_bytes) {
- case 8: ld_long(src, dst); break;
- case 4: ld( src, dst); break;
- case 2: is_signed ? ldsh(src, dst) : lduh(src, dst); break;
- case 1: is_signed ? ldsb(src, dst) : ldub(src, dst); break;
- default: ShouldNotReachHere();
- }
-}
-
-void MacroAssembler::store_sized_value(Register src, Address dst, size_t size_in_bytes) {
- switch (size_in_bytes) {
- case 8: st_long(src, dst); break;
- case 4: st( src, dst); break;
- case 2: sth( src, dst); break;
- case 1: stb( src, dst); break;
- default: ShouldNotReachHere();
- }
-}
-
-
-void MacroAssembler::float_cmp( bool is_float, int unordered_result,
- FloatRegister Fa, FloatRegister Fb,
- Register Rresult) {
-
- fcmp(is_float ? FloatRegisterImpl::S : FloatRegisterImpl::D, fcc0, Fa, Fb);
-
- Condition lt = unordered_result == -1 ? f_unorderedOrLess : f_less;
- Condition eq = f_equal;
- Condition gt = unordered_result == 1 ? f_unorderedOrGreater : f_greater;
-
- if (VM_Version::v9_instructions_work()) {
-
- mov(-1, Rresult);
- movcc(eq, true, fcc0, 0, Rresult);
- movcc(gt, true, fcc0, 1, Rresult);
-
- } else {
- Label done;
-
- set( -1, Rresult );
- //fb(lt, true, pn, done); delayed()->set( -1, Rresult );
- fb( eq, true, pn, done); delayed()->set( 0, Rresult );
- fb( gt, true, pn, done); delayed()->set( 1, Rresult );
-
- bind (done);
- }
-}
-
-
-void MacroAssembler::fneg( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d)
-{
- if (VM_Version::v9_instructions_work()) {
- Assembler::fneg(w, s, d);
- } else {
- if (w == FloatRegisterImpl::S) {
- Assembler::fneg(w, s, d);
- } else if (w == FloatRegisterImpl::D) {
- // number() does a sanity check on the alignment.
- assert(((s->encoding(FloatRegisterImpl::D) & 1) == 0) &&
- ((d->encoding(FloatRegisterImpl::D) & 1) == 0), "float register alignment check");
-
- Assembler::fneg(FloatRegisterImpl::S, s, d);
- Assembler::fmov(FloatRegisterImpl::S, s->successor(), d->successor());
- } else {
- assert(w == FloatRegisterImpl::Q, "Invalid float register width");
-
- // number() does a sanity check on the alignment.
- assert(((s->encoding(FloatRegisterImpl::D) & 3) == 0) &&
- ((d->encoding(FloatRegisterImpl::D) & 3) == 0), "float register alignment check");
-
- Assembler::fneg(FloatRegisterImpl::S, s, d);
- Assembler::fmov(FloatRegisterImpl::S, s->successor(), d->successor());
- Assembler::fmov(FloatRegisterImpl::S, s->successor()->successor(), d->successor()->successor());
- Assembler::fmov(FloatRegisterImpl::S, s->successor()->successor()->successor(), d->successor()->successor()->successor());
- }
- }
-}
-
-void MacroAssembler::fmov( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d)
-{
- if (VM_Version::v9_instructions_work()) {
- Assembler::fmov(w, s, d);
- } else {
- if (w == FloatRegisterImpl::S) {
- Assembler::fmov(w, s, d);
- } else if (w == FloatRegisterImpl::D) {
- // number() does a sanity check on the alignment.
- assert(((s->encoding(FloatRegisterImpl::D) & 1) == 0) &&
- ((d->encoding(FloatRegisterImpl::D) & 1) == 0), "float register alignment check");
-
- Assembler::fmov(FloatRegisterImpl::S, s, d);
- Assembler::fmov(FloatRegisterImpl::S, s->successor(), d->successor());
- } else {
- assert(w == FloatRegisterImpl::Q, "Invalid float register width");
-
- // number() does a sanity check on the alignment.
- assert(((s->encoding(FloatRegisterImpl::D) & 3) == 0) &&
- ((d->encoding(FloatRegisterImpl::D) & 3) == 0), "float register alignment check");
-
- Assembler::fmov(FloatRegisterImpl::S, s, d);
- Assembler::fmov(FloatRegisterImpl::S, s->successor(), d->successor());
- Assembler::fmov(FloatRegisterImpl::S, s->successor()->successor(), d->successor()->successor());
- Assembler::fmov(FloatRegisterImpl::S, s->successor()->successor()->successor(), d->successor()->successor()->successor());
- }
- }
-}
-
-void MacroAssembler::fabs( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d)
-{
- if (VM_Version::v9_instructions_work()) {
- Assembler::fabs(w, s, d);
- } else {
- if (w == FloatRegisterImpl::S) {
- Assembler::fabs(w, s, d);
- } else if (w == FloatRegisterImpl::D) {
- // number() does a sanity check on the alignment.
- assert(((s->encoding(FloatRegisterImpl::D) & 1) == 0) &&
- ((d->encoding(FloatRegisterImpl::D) & 1) == 0), "float register alignment check");
-
- Assembler::fabs(FloatRegisterImpl::S, s, d);
- Assembler::fmov(FloatRegisterImpl::S, s->successor(), d->successor());
- } else {
- assert(w == FloatRegisterImpl::Q, "Invalid float register width");
-
- // number() does a sanity check on the alignment.
- assert(((s->encoding(FloatRegisterImpl::D) & 3) == 0) &&
- ((d->encoding(FloatRegisterImpl::D) & 3) == 0), "float register alignment check");
-
- Assembler::fabs(FloatRegisterImpl::S, s, d);
- Assembler::fmov(FloatRegisterImpl::S, s->successor(), d->successor());
- Assembler::fmov(FloatRegisterImpl::S, s->successor()->successor(), d->successor()->successor());
- Assembler::fmov(FloatRegisterImpl::S, s->successor()->successor()->successor(), d->successor()->successor()->successor());
- }
- }
-}
-
-void MacroAssembler::save_all_globals_into_locals() {
- mov(G1,L1);
- mov(G2,L2);
- mov(G3,L3);
- mov(G4,L4);
- mov(G5,L5);
- mov(G6,L6);
- mov(G7,L7);
-}
-
-void MacroAssembler::restore_globals_from_locals() {
- mov(L1,G1);
- mov(L2,G2);
- mov(L3,G3);
- mov(L4,G4);
- mov(L5,G5);
- mov(L6,G6);
- mov(L7,G7);
-}
-
-// Use for 64 bit operation.
-void MacroAssembler::casx_under_lock(Register top_ptr_reg, Register top_reg, Register ptr_reg, address lock_addr, bool use_call_vm)
-{
- // store ptr_reg as the new top value
-#ifdef _LP64
- casx(top_ptr_reg, top_reg, ptr_reg);
-#else
- cas_under_lock(top_ptr_reg, top_reg, ptr_reg, lock_addr, use_call_vm);
-#endif // _LP64
-}
-
-// [RGV] This routine does not handle 64 bit operations.
-// use casx_under_lock() or casx directly!!!
-void MacroAssembler::cas_under_lock(Register top_ptr_reg, Register top_reg, Register ptr_reg, address lock_addr, bool use_call_vm)
-{
- // store ptr_reg as the new top value
- if (VM_Version::v9_instructions_work()) {
- cas(top_ptr_reg, top_reg, ptr_reg);
- } else {
-
- // If the register is not an out nor global, it is not visible
- // after the save. Allocate a register for it, save its
- // value in the register save area (the save may not flush
- // registers to the save area).
-
- Register top_ptr_reg_after_save;
- Register top_reg_after_save;
- Register ptr_reg_after_save;
-
- if (top_ptr_reg->is_out() || top_ptr_reg->is_global()) {
- top_ptr_reg_after_save = top_ptr_reg->after_save();
- } else {
- Address reg_save_addr = top_ptr_reg->address_in_saved_window();
- top_ptr_reg_after_save = L0;
- st(top_ptr_reg, reg_save_addr);
- }
-
- if (top_reg->is_out() || top_reg->is_global()) {
- top_reg_after_save = top_reg->after_save();
- } else {
- Address reg_save_addr = top_reg->address_in_saved_window();
- top_reg_after_save = L1;
- st(top_reg, reg_save_addr);
- }
-
- if (ptr_reg->is_out() || ptr_reg->is_global()) {
- ptr_reg_after_save = ptr_reg->after_save();
- } else {
- Address reg_save_addr = ptr_reg->address_in_saved_window();
- ptr_reg_after_save = L2;
- st(ptr_reg, reg_save_addr);
- }
-
- const Register& lock_reg = L3;
- const Register& lock_ptr_reg = L4;
- const Register& value_reg = L5;
- const Register& yield_reg = L6;
- const Register& yieldall_reg = L7;
-
- save_frame();
-
- if (top_ptr_reg_after_save == L0) {
- ld(top_ptr_reg->address_in_saved_window().after_save(), top_ptr_reg_after_save);
- }
-
- if (top_reg_after_save == L1) {
- ld(top_reg->address_in_saved_window().after_save(), top_reg_after_save);
- }
-
- if (ptr_reg_after_save == L2) {
- ld(ptr_reg->address_in_saved_window().after_save(), ptr_reg_after_save);
- }
-
- Label(retry_get_lock);
- Label(not_same);
- Label(dont_yield);
-
- assert(lock_addr, "lock_address should be non null for v8");
- set((intptr_t)lock_addr, lock_ptr_reg);
- // Initialize yield counter
- mov(G0,yield_reg);
- mov(G0, yieldall_reg);
- set(StubRoutines::Sparc::locked, lock_reg);
-
- bind(retry_get_lock);
- cmp_and_br_short(yield_reg, V8AtomicOperationUnderLockSpinCount, Assembler::less, Assembler::pt, dont_yield);
-
- if(use_call_vm) {
- Untested("Need to verify global reg consistancy");
- call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::yield_all), yieldall_reg);
- } else {
- // Save the regs and make space for a C call
- save(SP, -96, SP);
- save_all_globals_into_locals();
- call(CAST_FROM_FN_PTR(address,os::yield_all));
- delayed()->mov(yieldall_reg, O0);
- restore_globals_from_locals();
- restore();
- }
-
- // reset the counter
- mov(G0,yield_reg);
- add(yieldall_reg, 1, yieldall_reg);
-
- bind(dont_yield);
- // try to get lock
- swap(lock_ptr_reg, 0, lock_reg);
-
- // did we get the lock?
- cmp(lock_reg, StubRoutines::Sparc::unlocked);
- br(Assembler::notEqual, true, Assembler::pn, retry_get_lock);
- delayed()->add(yield_reg,1,yield_reg);
-
- // yes, got lock. do we have the same top?
- ld(top_ptr_reg_after_save, 0, value_reg);
- cmp_and_br_short(value_reg, top_reg_after_save, Assembler::notEqual, Assembler::pn, not_same);
-
- // yes, same top.
- st(ptr_reg_after_save, top_ptr_reg_after_save, 0);
- membar(Assembler::StoreStore);
-
- bind(not_same);
- mov(value_reg, ptr_reg_after_save);
- st(lock_reg, lock_ptr_reg, 0); // unlock
-
- restore();
- }
-}
-
-RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr,
- Register tmp,
- int offset) {
- intptr_t value = *delayed_value_addr;
- if (value != 0)
- return RegisterOrConstant(value + offset);
-
- // load indirectly to solve generation ordering problem
- AddressLiteral a(delayed_value_addr);
- load_ptr_contents(a, tmp);
-
-#ifdef ASSERT
- tst(tmp);
- breakpoint_trap(zero, xcc);
-#endif
-
- if (offset != 0)
- add(tmp, offset, tmp);
-
- return RegisterOrConstant(tmp);
-}
-
-
-RegisterOrConstant MacroAssembler::regcon_andn_ptr(RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp) {
- assert(d.register_or_noreg() != G0, "lost side effect");
- if ((s2.is_constant() && s2.as_constant() == 0) ||
- (s2.is_register() && s2.as_register() == G0)) {
- // Do nothing, just move value.
- if (s1.is_register()) {
- if (d.is_constant()) d = temp;
- mov(s1.as_register(), d.as_register());
- return d;
- } else {
- return s1;
- }
- }
-
- if (s1.is_register()) {
- assert_different_registers(s1.as_register(), temp);
- if (d.is_constant()) d = temp;
- andn(s1.as_register(), ensure_simm13_or_reg(s2, temp), d.as_register());
- return d;
- } else {
- if (s2.is_register()) {
- assert_different_registers(s2.as_register(), temp);
- if (d.is_constant()) d = temp;
- set(s1.as_constant(), temp);
- andn(temp, s2.as_register(), d.as_register());
- return d;
- } else {
- intptr_t res = s1.as_constant() & ~s2.as_constant();
- return res;
- }
- }
-}
-
-RegisterOrConstant MacroAssembler::regcon_inc_ptr(RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp) {
- assert(d.register_or_noreg() != G0, "lost side effect");
- if ((s2.is_constant() && s2.as_constant() == 0) ||
- (s2.is_register() && s2.as_register() == G0)) {
- // Do nothing, just move value.
- if (s1.is_register()) {
- if (d.is_constant()) d = temp;
- mov(s1.as_register(), d.as_register());
- return d;
- } else {
- return s1;
- }
- }
-
- if (s1.is_register()) {
- assert_different_registers(s1.as_register(), temp);
- if (d.is_constant()) d = temp;
- add(s1.as_register(), ensure_simm13_or_reg(s2, temp), d.as_register());
- return d;
- } else {
- if (s2.is_register()) {
- assert_different_registers(s2.as_register(), temp);
- if (d.is_constant()) d = temp;
- add(s2.as_register(), ensure_simm13_or_reg(s1, temp), d.as_register());
- return d;
- } else {
- intptr_t res = s1.as_constant() + s2.as_constant();
- return res;
- }
- }
-}
-
-RegisterOrConstant MacroAssembler::regcon_sll_ptr(RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp) {
- assert(d.register_or_noreg() != G0, "lost side effect");
- if (!is_simm13(s2.constant_or_zero()))
- s2 = (s2.as_constant() & 0xFF);
- if ((s2.is_constant() && s2.as_constant() == 0) ||
- (s2.is_register() && s2.as_register() == G0)) {
- // Do nothing, just move value.
- if (s1.is_register()) {
- if (d.is_constant()) d = temp;
- mov(s1.as_register(), d.as_register());
- return d;
- } else {
- return s1;
- }
- }
-
- if (s1.is_register()) {
- assert_different_registers(s1.as_register(), temp);
- if (d.is_constant()) d = temp;
- sll_ptr(s1.as_register(), ensure_simm13_or_reg(s2, temp), d.as_register());
- return d;
- } else {
- if (s2.is_register()) {
- assert_different_registers(s2.as_register(), temp);
- if (d.is_constant()) d = temp;
- set(s1.as_constant(), temp);
- sll_ptr(temp, s2.as_register(), d.as_register());
- return d;
- } else {
- intptr_t res = s1.as_constant() << s2.as_constant();
- return res;
- }
- }
-}
-
-
-// Look up the method for a megamorphic invokeinterface call.
-// The target method is determined by .
-// The receiver klass is in recv_klass.
-// On success, the result will be in method_result, and execution falls through.
-// On failure, execution transfers to the given label.
-void MacroAssembler::lookup_interface_method(Register recv_klass,
- Register intf_klass,
- RegisterOrConstant itable_index,
- Register method_result,
- Register scan_temp,
- Register sethi_temp,
- Label& L_no_such_interface) {
- assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
- assert(itable_index.is_constant() || itable_index.as_register() == method_result,
- "caller must use same register for non-constant itable index as for method");
-
- Label L_no_such_interface_restore;
- bool did_save = false;
- if (scan_temp == noreg || sethi_temp == noreg) {
- Register recv_2 = recv_klass->is_global() ? recv_klass : L0;
- Register intf_2 = intf_klass->is_global() ? intf_klass : L1;
- assert(method_result->is_global(), "must be able to return value");
- scan_temp = L2;
- sethi_temp = L3;
- save_frame_and_mov(0, recv_klass, recv_2, intf_klass, intf_2);
- recv_klass = recv_2;
- intf_klass = intf_2;
- did_save = true;
- }
-
- // Compute start of first itableOffsetEntry (which is at the end of the vtable)
- int vtable_base = InstanceKlass::vtable_start_offset() * wordSize;
- int scan_step = itableOffsetEntry::size() * wordSize;
- int vte_size = vtableEntry::size() * wordSize;
-
- lduw(recv_klass, InstanceKlass::vtable_length_offset() * wordSize, scan_temp);
- // %%% We should store the aligned, prescaled offset in the klassoop.
- // Then the next several instructions would fold away.
-
- int round_to_unit = ((HeapWordsPerLong > 1) ? BytesPerLong : 0);
- int itb_offset = vtable_base;
- if (round_to_unit != 0) {
- // hoist first instruction of round_to(scan_temp, BytesPerLong):
- itb_offset += round_to_unit - wordSize;
- }
- int itb_scale = exact_log2(vtableEntry::size() * wordSize);
- sll(scan_temp, itb_scale, scan_temp);
- add(scan_temp, itb_offset, scan_temp);
- if (round_to_unit != 0) {
- // Round up to align_object_offset boundary
- // see code for InstanceKlass::start_of_itable!
- // Was: round_to(scan_temp, BytesPerLong);
- // Hoisted: add(scan_temp, BytesPerLong-1, scan_temp);
- and3(scan_temp, -round_to_unit, scan_temp);
- }
- add(recv_klass, scan_temp, scan_temp);
-
- // Adjust recv_klass by scaled itable_index, so we can free itable_index.
- RegisterOrConstant itable_offset = itable_index;
- itable_offset = regcon_sll_ptr(itable_index, exact_log2(itableMethodEntry::size() * wordSize), itable_offset);
- itable_offset = regcon_inc_ptr(itable_offset, itableMethodEntry::method_offset_in_bytes(), itable_offset);
- add(recv_klass, ensure_simm13_or_reg(itable_offset, sethi_temp), recv_klass);
-
- // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
- // if (scan->interface() == intf) {
- // result = (klass + scan->offset() + itable_index);
- // }
- // }
- Label L_search, L_found_method;
-
- for (int peel = 1; peel >= 0; peel--) {
- // %%%% Could load both offset and interface in one ldx, if they were
- // in the opposite order. This would save a load.
- ld_ptr(scan_temp, itableOffsetEntry::interface_offset_in_bytes(), method_result);
-
- // Check that this entry is non-null. A null entry means that
- // the receiver class doesn't implement the interface, and wasn't the
- // same as when the caller was compiled.
- bpr(Assembler::rc_z, false, Assembler::pn, method_result, did_save ? L_no_such_interface_restore : L_no_such_interface);
- delayed()->cmp(method_result, intf_klass);
-
- if (peel) {
- brx(Assembler::equal, false, Assembler::pt, L_found_method);
- } else {
- brx(Assembler::notEqual, false, Assembler::pn, L_search);
- // (invert the test to fall through to found_method...)
- }
- delayed()->add(scan_temp, scan_step, scan_temp);
-
- if (!peel) break;
-
- bind(L_search);
- }
-
- bind(L_found_method);
-
- // Got a hit.
- int ito_offset = itableOffsetEntry::offset_offset_in_bytes();
- // scan_temp[-scan_step] points to the vtable offset we need
- ito_offset -= scan_step;
- lduw(scan_temp, ito_offset, scan_temp);
- ld_ptr(recv_klass, scan_temp, method_result);
-
- if (did_save) {
- Label L_done;
- ba(L_done);
- delayed()->restore();
-
- bind(L_no_such_interface_restore);
- ba(L_no_such_interface);
- delayed()->restore();
-
- bind(L_done);
- }
-}
-
-
-// virtual method calling
-void MacroAssembler::lookup_virtual_method(Register recv_klass,
- RegisterOrConstant vtable_index,
- Register method_result) {
- assert_different_registers(recv_klass, method_result, vtable_index.register_or_noreg());
- Register sethi_temp = method_result;
- const int base = (InstanceKlass::vtable_start_offset() * wordSize +
- // method pointer offset within the vtable entry:
- vtableEntry::method_offset_in_bytes());
- RegisterOrConstant vtable_offset = vtable_index;
- // Each of the following three lines potentially generates an instruction.
- // But the total number of address formation instructions will always be
- // at most two, and will often be zero. In any case, it will be optimal.
- // If vtable_index is a register, we will have (sll_ptr N,x; inc_ptr B,x; ld_ptr k,x).
- // If vtable_index is a constant, we will have at most (set B+X<is_global()) sub_2 = L0;
- if (!sup_2->is_global()) sup_2 = L1;
- bool did_save = false;
- if (temp_reg == noreg || temp2_reg == noreg) {
- temp_reg = L2;
- temp2_reg = L3;
- save_frame_and_mov(0, sub_klass, sub_2, super_klass, sup_2);
- sub_klass = sub_2;
- super_klass = sup_2;
- did_save = true;
- }
- Label L_failure, L_pop_to_failure, L_pop_to_success;
- check_klass_subtype_fast_path(sub_klass, super_klass,
- temp_reg, temp2_reg,
- (did_save ? &L_pop_to_success : &L_success),
- (did_save ? &L_pop_to_failure : &L_failure), NULL);
-
- if (!did_save)
- save_frame_and_mov(0, sub_klass, sub_2, super_klass, sup_2);
- check_klass_subtype_slow_path(sub_2, sup_2,
- L2, L3, L4, L5,
- NULL, &L_pop_to_failure);
-
- // on success:
- bind(L_pop_to_success);
- restore();
- ba_short(L_success);
-
- // on failure:
- bind(L_pop_to_failure);
- restore();
- bind(L_failure);
-}
-
-
-void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass,
- Register super_klass,
- Register temp_reg,
- Register temp2_reg,
- Label* L_success,
- Label* L_failure,
- Label* L_slow_path,
- RegisterOrConstant super_check_offset) {
- int sc_offset = in_bytes(Klass::secondary_super_cache_offset());
- int sco_offset = in_bytes(Klass::super_check_offset_offset());
-
- bool must_load_sco = (super_check_offset.constant_or_zero() == -1);
- bool need_slow_path = (must_load_sco ||
- super_check_offset.constant_or_zero() == sco_offset);
-
- assert_different_registers(sub_klass, super_klass, temp_reg);
- if (super_check_offset.is_register()) {
- assert_different_registers(sub_klass, super_klass, temp_reg,
- super_check_offset.as_register());
- } else if (must_load_sco) {
- assert(temp2_reg != noreg, "supply either a temp or a register offset");
- }
-
- Label L_fallthrough;
- int label_nulls = 0;
- if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; }
- if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; }
- if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; }
- assert(label_nulls <= 1 ||
- (L_slow_path == &L_fallthrough && label_nulls <= 2 && !need_slow_path),
- "at most one NULL in the batch, usually");
-
- // If the pointers are equal, we are done (e.g., String[] elements).
- // This self-check enables sharing of secondary supertype arrays among
- // non-primary types such as array-of-interface. Otherwise, each such
- // type would need its own customized SSA.
- // We move this check to the front of the fast path because many
- // type checks are in fact trivially successful in this manner,
- // so we get a nicely predicted branch right at the start of the check.
- cmp(super_klass, sub_klass);
- brx(Assembler::equal, false, Assembler::pn, *L_success);
- delayed()->nop();
-
- // Check the supertype display:
- if (must_load_sco) {
- // The super check offset is always positive...
- lduw(super_klass, sco_offset, temp2_reg);
- super_check_offset = RegisterOrConstant(temp2_reg);
- // super_check_offset is register.
- assert_different_registers(sub_klass, super_klass, temp_reg, super_check_offset.as_register());
- }
- ld_ptr(sub_klass, super_check_offset, temp_reg);
- cmp(super_klass, temp_reg);
-
- // This check has worked decisively for primary supers.
- // Secondary supers are sought in the super_cache ('super_cache_addr').
- // (Secondary supers are interfaces and very deeply nested subtypes.)
- // This works in the same check above because of a tricky aliasing
- // between the super_cache and the primary super display elements.
- // (The 'super_check_addr' can address either, as the case requires.)
- // Note that the cache is updated below if it does not help us find
- // what we need immediately.
- // So if it was a primary super, we can just fail immediately.
- // Otherwise, it's the slow path for us (no success at this point).
-
- // Hacked ba(), which may only be used just before L_fallthrough.
-#define FINAL_JUMP(label) \
- if (&(label) != &L_fallthrough) { \
- ba(label); delayed()->nop(); \
- }
-
- if (super_check_offset.is_register()) {
- brx(Assembler::equal, false, Assembler::pn, *L_success);
- delayed()->cmp(super_check_offset.as_register(), sc_offset);
-
- if (L_failure == &L_fallthrough) {
- brx(Assembler::equal, false, Assembler::pt, *L_slow_path);
- delayed()->nop();
- } else {
- brx(Assembler::notEqual, false, Assembler::pn, *L_failure);
- delayed()->nop();
- FINAL_JUMP(*L_slow_path);
- }
- } else if (super_check_offset.as_constant() == sc_offset) {
- // Need a slow path; fast failure is impossible.
- if (L_slow_path == &L_fallthrough) {
- brx(Assembler::equal, false, Assembler::pt, *L_success);
- delayed()->nop();
- } else {
- brx(Assembler::notEqual, false, Assembler::pn, *L_slow_path);
- delayed()->nop();
- FINAL_JUMP(*L_success);
- }
- } else {
- // No slow path; it's a fast decision.
- if (L_failure == &L_fallthrough) {
- brx(Assembler::equal, false, Assembler::pt, *L_success);
- delayed()->nop();
- } else {
- brx(Assembler::notEqual, false, Assembler::pn, *L_failure);
- delayed()->nop();
- FINAL_JUMP(*L_success);
- }
- }
-
- bind(L_fallthrough);
-
-#undef FINAL_JUMP
-}
-
-
-void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass,
- Register super_klass,
- Register count_temp,
- Register scan_temp,
- Register scratch_reg,
- Register coop_reg,
- Label* L_success,
- Label* L_failure) {
- assert_different_registers(sub_klass, super_klass,
- count_temp, scan_temp, scratch_reg, coop_reg);
-
- Label L_fallthrough, L_loop;
- int label_nulls = 0;
- if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; }
- if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; }
- assert(label_nulls <= 1, "at most one NULL in the batch");
-
- // a couple of useful fields in sub_klass:
- int ss_offset = in_bytes(Klass::secondary_supers_offset());
- int sc_offset = in_bytes(Klass::secondary_super_cache_offset());
-
- // Do a linear scan of the secondary super-klass chain.
- // This code is rarely used, so simplicity is a virtue here.
-
-#ifndef PRODUCT
- int* pst_counter = &SharedRuntime::_partial_subtype_ctr;
- inc_counter((address) pst_counter, count_temp, scan_temp);
-#endif
-
- // We will consult the secondary-super array.
- ld_ptr(sub_klass, ss_offset, scan_temp);
-
- Register search_key = super_klass;
-
- // Load the array length. (Positive movl does right thing on LP64.)
- lduw(scan_temp, Array::length_offset_in_bytes(), count_temp);
-
- // Check for empty secondary super list
- tst(count_temp);
-
- // In the array of super classes elements are pointer sized.
- int element_size = wordSize;
-
- // Top of search loop
- bind(L_loop);
- br(Assembler::equal, false, Assembler::pn, *L_failure);
- delayed()->add(scan_temp, element_size, scan_temp);
-
- // Skip the array header in all array accesses.
- int elem_offset = Array::base_offset_in_bytes();
- elem_offset -= element_size; // the scan pointer was pre-incremented also
-
- // Load next super to check
- ld_ptr( scan_temp, elem_offset, scratch_reg );
-
- // Look for Rsuper_klass on Rsub_klass's secondary super-class-overflow list
- cmp(scratch_reg, search_key);
-
- // A miss means we are NOT a subtype and need to keep looping
- brx(Assembler::notEqual, false, Assembler::pn, L_loop);
- delayed()->deccc(count_temp); // decrement trip counter in delay slot
-
- // Success. Cache the super we found and proceed in triumph.
- st_ptr(super_klass, sub_klass, sc_offset);
-
- if (L_success != &L_fallthrough) {
- ba(*L_success);
- delayed()->nop();
- }
-
- bind(L_fallthrough);
-}
-
-
-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;
- int offset = extra_slot_offset * stackElementSize;
- if (arg_slot.is_constant()) {
- offset += arg_slot.as_constant() * stackElementSize;
- return offset;
- } else {
- assert(temp_reg != noreg, "must specify");
- sll_ptr(arg_slot.as_register(), exact_log2(stackElementSize), temp_reg);
- if (offset != 0)
- 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, temp_reg, extra_slot_offset));
-}
-
-
-void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg,
- Register temp_reg,
- Label& done, Label* slow_case,
- BiasedLockingCounters* counters) {
- assert(UseBiasedLocking, "why call this otherwise?");
-
- if (PrintBiasedLockingStatistics) {
- assert_different_registers(obj_reg, mark_reg, temp_reg, O7);
- if (counters == NULL)
- counters = BiasedLocking::counters();
- }
-
- Label cas_label;
-
- // Biased locking
- // See whether the lock is currently biased toward our thread and
- // whether the epoch is still valid
- // Note that the runtime guarantees sufficient alignment of JavaThread
- // pointers to allow age to be placed into low bits
- assert(markOopDesc::age_shift == markOopDesc::lock_bits + markOopDesc::biased_lock_bits, "biased locking makes assumptions about bit layout");
- and3(mark_reg, markOopDesc::biased_lock_mask_in_place, temp_reg);
- cmp_and_brx_short(temp_reg, markOopDesc::biased_lock_pattern, Assembler::notEqual, Assembler::pn, cas_label);
-
- load_klass(obj_reg, temp_reg);
- ld_ptr(Address(temp_reg, Klass::prototype_header_offset()), temp_reg);
- or3(G2_thread, temp_reg, temp_reg);
- xor3(mark_reg, temp_reg, temp_reg);
- andcc(temp_reg, ~((int) markOopDesc::age_mask_in_place), temp_reg);
- if (counters != NULL) {
- cond_inc(Assembler::equal, (address) counters->biased_lock_entry_count_addr(), mark_reg, temp_reg);
- // Reload mark_reg as we may need it later
- ld_ptr(Address(obj_reg, oopDesc::mark_offset_in_bytes()), mark_reg);
- }
- brx(Assembler::equal, true, Assembler::pt, done);
- delayed()->nop();
-
- Label try_revoke_bias;
- Label try_rebias;
- Address mark_addr = Address(obj_reg, oopDesc::mark_offset_in_bytes());
- assert(mark_addr.disp() == 0, "cas must take a zero displacement");
-
- // At this point we know that the header has the bias pattern and
- // that we are not the bias owner in the current epoch. We need to
- // figure out more details about the state of the header in order to
- // know what operations can be legally performed on the object's
- // header.
-
- // If the low three bits in the xor result aren't clear, that means
- // the prototype header is no longer biased and we have to revoke
- // the bias on this object.
- btst(markOopDesc::biased_lock_mask_in_place, temp_reg);
- brx(Assembler::notZero, false, Assembler::pn, try_revoke_bias);
-
- // Biasing is still enabled for this data type. See whether the
- // epoch of the current bias is still valid, meaning that the epoch
- // bits of the mark word are equal to the epoch bits of the
- // prototype header. (Note that the prototype header's epoch bits
- // only change at a safepoint.) If not, attempt to rebias the object
- // toward the current thread. Note that we must be absolutely sure
- // that the current epoch is invalid in order to do this because
- // otherwise the manipulations it performs on the mark word are
- // illegal.
- delayed()->btst(markOopDesc::epoch_mask_in_place, temp_reg);
- brx(Assembler::notZero, false, Assembler::pn, try_rebias);
-
- // The epoch of the current bias is still valid but we know nothing
- // about the owner; it might be set or it might be clear. Try to
- // acquire the bias of the object using an atomic operation. If this
- // fails we will go in to the runtime to revoke the object's bias.
- // Note that we first construct the presumed unbiased header so we
- // don't accidentally blow away another thread's valid bias.
- delayed()->and3(mark_reg,
- markOopDesc::biased_lock_mask_in_place | markOopDesc::age_mask_in_place | markOopDesc::epoch_mask_in_place,
- mark_reg);
- or3(G2_thread, mark_reg, temp_reg);
- casn(mark_addr.base(), mark_reg, temp_reg);
- // If the biasing toward our thread failed, this means that
- // another thread succeeded in biasing it toward itself and we
- // need to revoke that bias. The revocation will occur in the
- // interpreter runtime in the slow case.
- cmp(mark_reg, temp_reg);
- if (counters != NULL) {
- cond_inc(Assembler::zero, (address) counters->anonymously_biased_lock_entry_count_addr(), mark_reg, temp_reg);
- }
- if (slow_case != NULL) {
- brx(Assembler::notEqual, true, Assembler::pn, *slow_case);
- delayed()->nop();
- }
- ba_short(done);
-
- bind(try_rebias);
- // At this point we know the epoch has expired, meaning that the
- // current "bias owner", if any, is actually invalid. Under these
- // circumstances _only_, we are allowed to use the current header's
- // value as the comparison value when doing the cas to acquire the
- // bias in the current epoch. In other words, we allow transfer of
- // the bias from one thread to another directly in this situation.
- //
- // FIXME: due to a lack of registers we currently blow away the age
- // bits in this situation. Should attempt to preserve them.
- load_klass(obj_reg, temp_reg);
- ld_ptr(Address(temp_reg, Klass::prototype_header_offset()), temp_reg);
- or3(G2_thread, temp_reg, temp_reg);
- casn(mark_addr.base(), mark_reg, temp_reg);
- // If the biasing toward our thread failed, this means that
- // another thread succeeded in biasing it toward itself and we
- // need to revoke that bias. The revocation will occur in the
- // interpreter runtime in the slow case.
- cmp(mark_reg, temp_reg);
- if (counters != NULL) {
- cond_inc(Assembler::zero, (address) counters->rebiased_lock_entry_count_addr(), mark_reg, temp_reg);
- }
- if (slow_case != NULL) {
- brx(Assembler::notEqual, true, Assembler::pn, *slow_case);
- delayed()->nop();
- }
- ba_short(done);
-
- bind(try_revoke_bias);
- // The prototype mark in the klass doesn't have the bias bit set any
- // more, indicating that objects of this data type are not supposed
- // to be biased any more. We are going to try to reset the mark of
- // this object to the prototype value and fall through to the
- // CAS-based locking scheme. Note that if our CAS fails, it means
- // that another thread raced us for the privilege of revoking the
- // bias of this particular object, so it's okay to continue in the
- // normal locking code.
- //
- // FIXME: due to a lack of registers we currently blow away the age
- // bits in this situation. Should attempt to preserve them.
- load_klass(obj_reg, temp_reg);
- ld_ptr(Address(temp_reg, Klass::prototype_header_offset()), temp_reg);
- casn(mark_addr.base(), mark_reg, temp_reg);
- // Fall through to the normal CAS-based lock, because no matter what
- // the result of the above CAS, some thread must have succeeded in
- // removing the bias bit from the object's header.
- if (counters != NULL) {
- cmp(mark_reg, temp_reg);
- cond_inc(Assembler::zero, (address) counters->revoked_lock_entry_count_addr(), mark_reg, temp_reg);
- }
-
- bind(cas_label);
-}
-
-void MacroAssembler::biased_locking_exit (Address mark_addr, Register temp_reg, Label& done,
- bool allow_delay_slot_filling) {
- // Check for biased locking unlock case, which is a no-op
- // Note: we do not have to check the thread ID for two reasons.
- // First, the interpreter checks for IllegalMonitorStateException at
- // a higher level. Second, if the bias was revoked while we held the
- // lock, the object could not be rebiased toward another thread, so
- // the bias bit would be clear.
- ld_ptr(mark_addr, temp_reg);
- and3(temp_reg, markOopDesc::biased_lock_mask_in_place, temp_reg);
- cmp(temp_reg, markOopDesc::biased_lock_pattern);
- brx(Assembler::equal, allow_delay_slot_filling, Assembler::pt, done);
- delayed();
- if (!allow_delay_slot_filling) {
- nop();
- }
-}
-
-
-// CASN -- 32-64 bit switch hitter similar to the synthetic CASN provided by
-// Solaris/SPARC's "as". Another apt name would be cas_ptr()
-
-void MacroAssembler::casn (Register addr_reg, Register cmp_reg, Register set_reg ) {
- casx_under_lock (addr_reg, cmp_reg, set_reg, (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr());
-}
-
-
-
-// compiler_lock_object() and compiler_unlock_object() are direct transliterations
-// of i486.ad fast_lock() and fast_unlock(). See those methods for detailed comments.
-// The code could be tightened up considerably.
-//
-// box->dhw disposition - post-conditions at DONE_LABEL.
-// - Successful inflated lock: box->dhw != 0.
-// Any non-zero value suffices.
-// Consider G2_thread, rsp, boxReg, or unused_mark()
-// - Successful Stack-lock: box->dhw == mark.
-// box->dhw must contain the displaced mark word value
-// - Failure -- icc.ZFlag == 0 and box->dhw is undefined.
-// The slow-path fast_enter() and slow_enter() operators
-// are responsible for setting box->dhw = NonZero (typically ::unused_mark).
-// - Biased: box->dhw is undefined
-//
-// SPARC refworkload performance - specifically jetstream and scimark - are
-// extremely sensitive to the size of the code emitted by compiler_lock_object
-// and compiler_unlock_object. Critically, the key factor is code size, not path
-// length. (Simply experiments to pad CLO with unexecuted NOPs demonstrte the
-// effect).
-
-
-void MacroAssembler::compiler_lock_object(Register Roop, Register Rmark,
- Register Rbox, Register Rscratch,
- BiasedLockingCounters* counters,
- bool try_bias) {
- Address mark_addr(Roop, oopDesc::mark_offset_in_bytes());
-
- verify_oop(Roop);
- Label done ;
-
- if (counters != NULL) {
- inc_counter((address) counters->total_entry_count_addr(), Rmark, Rscratch);
- }
-
- if (EmitSync & 1) {
- mov(3, Rscratch);
- st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
- cmp(SP, G0);
- return ;
- }
-
- if (EmitSync & 2) {
-
- // Fetch object's markword
- ld_ptr(mark_addr, Rmark);
-
- if (try_bias) {
- biased_locking_enter(Roop, Rmark, Rscratch, done, NULL, counters);
- }
-
- // Save Rbox in Rscratch to be used for the cas operation
- mov(Rbox, Rscratch);
-
- // set Rmark to markOop | markOopDesc::unlocked_value
- or3(Rmark, markOopDesc::unlocked_value, Rmark);
-
- // Initialize the box. (Must happen before we update the object mark!)
- st_ptr(Rmark, Rbox, BasicLock::displaced_header_offset_in_bytes());
-
- // compare object markOop with Rmark and if equal exchange Rscratch with object markOop
- assert(mark_addr.disp() == 0, "cas must take a zero displacement");
- casx_under_lock(mark_addr.base(), Rmark, Rscratch,
- (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr());
-
- // if compare/exchange succeeded we found an unlocked object and we now have locked it
- // hence we are done
- cmp(Rmark, Rscratch);
-#ifdef _LP64
- sub(Rscratch, STACK_BIAS, Rscratch);
-#endif
- brx(Assembler::equal, false, Assembler::pt, done);
- delayed()->sub(Rscratch, SP, Rscratch); //pull next instruction into delay slot
-
- // we did not find an unlocked object so see if this is a recursive case
- // sub(Rscratch, SP, Rscratch);
- assert(os::vm_page_size() > 0xfff, "page size too small - change the constant");
- andcc(Rscratch, 0xfffff003, Rscratch);
- st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
- bind (done);
- return ;
- }
-
- Label Egress ;
-
- if (EmitSync & 256) {
- Label IsInflated ;
-
- ld_ptr(mark_addr, Rmark); // fetch obj->mark
- // Triage: biased, stack-locked, neutral, inflated
- if (try_bias) {
- biased_locking_enter(Roop, Rmark, Rscratch, done, NULL, counters);
- // Invariant: if control reaches this point in the emitted stream
- // then Rmark has not been modified.
- }
-
- // Store mark into displaced mark field in the on-stack basic-lock "box"
- // Critically, this must happen before the CAS
- // Maximize the ST-CAS distance to minimize the ST-before-CAS penalty.
- st_ptr(Rmark, Rbox, BasicLock::displaced_header_offset_in_bytes());
- andcc(Rmark, 2, G0);
- brx(Assembler::notZero, false, Assembler::pn, IsInflated);
- delayed()->
-
- // Try stack-lock acquisition.
- // Beware: the 1st instruction is in a delay slot
- mov(Rbox, Rscratch);
- or3(Rmark, markOopDesc::unlocked_value, Rmark);
- assert(mark_addr.disp() == 0, "cas must take a zero displacement");
- casn(mark_addr.base(), Rmark, Rscratch);
- cmp(Rmark, Rscratch);
- brx(Assembler::equal, false, Assembler::pt, done);
- delayed()->sub(Rscratch, SP, Rscratch);
-
- // Stack-lock attempt failed - check for recursive stack-lock.
- // See the comments below about how we might remove this case.
-#ifdef _LP64
- sub(Rscratch, STACK_BIAS, Rscratch);
-#endif
- assert(os::vm_page_size() > 0xfff, "page size too small - change the constant");
- andcc(Rscratch, 0xfffff003, Rscratch);
- br(Assembler::always, false, Assembler::pt, done);
- delayed()-> st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
-
- bind(IsInflated);
- if (EmitSync & 64) {
- // If m->owner != null goto IsLocked
- // Pessimistic form: Test-and-CAS vs CAS
- // The optimistic form avoids RTS->RTO cache line upgrades.
- ld_ptr(Rmark, ObjectMonitor::owner_offset_in_bytes() - 2, Rscratch);
- andcc(Rscratch, Rscratch, G0);
- brx(Assembler::notZero, false, Assembler::pn, done);
- delayed()->nop();
- // m->owner == null : it's unlocked.
- }
-
- // Try to CAS m->owner from null to Self
- // Invariant: if we acquire the lock then _recursions should be 0.
- add(Rmark, ObjectMonitor::owner_offset_in_bytes()-2, Rmark);
- mov(G2_thread, Rscratch);
- casn(Rmark, G0, Rscratch);
- cmp(Rscratch, G0);
- // Intentional fall-through into done
- } else {
- // Aggressively avoid the Store-before-CAS penalty
- // Defer the store into box->dhw until after the CAS
- Label IsInflated, Recursive ;
-
-// Anticipate CAS -- Avoid RTS->RTO upgrade
-// prefetch (mark_addr, Assembler::severalWritesAndPossiblyReads);
-
- ld_ptr(mark_addr, Rmark); // fetch obj->mark
- // Triage: biased, stack-locked, neutral, inflated
-
- if (try_bias) {
- biased_locking_enter(Roop, Rmark, Rscratch, done, NULL, counters);
- // Invariant: if control reaches this point in the emitted stream
- // then Rmark has not been modified.
- }
- andcc(Rmark, 2, G0);
- brx(Assembler::notZero, false, Assembler::pn, IsInflated);
- delayed()-> // Beware - dangling delay-slot
-
- // Try stack-lock acquisition.
- // Transiently install BUSY (0) encoding in the mark word.
- // if the CAS of 0 into the mark was successful then we execute:
- // ST box->dhw = mark -- save fetched mark in on-stack basiclock box
- // ST obj->mark = box -- overwrite transient 0 value
- // This presumes TSO, of course.
-
- mov(0, Rscratch);
- or3(Rmark, markOopDesc::unlocked_value, Rmark);
- assert(mark_addr.disp() == 0, "cas must take a zero displacement");
- casn(mark_addr.base(), Rmark, Rscratch);
-// prefetch (mark_addr, Assembler::severalWritesAndPossiblyReads);
- cmp(Rscratch, Rmark);
- brx(Assembler::notZero, false, Assembler::pn, Recursive);
- delayed()->st_ptr(Rmark, Rbox, BasicLock::displaced_header_offset_in_bytes());
- if (counters != NULL) {
- cond_inc(Assembler::equal, (address) counters->fast_path_entry_count_addr(), Rmark, Rscratch);
- }
- ba(done);
- delayed()->st_ptr(Rbox, mark_addr);
-
- bind(Recursive);
- // Stack-lock attempt failed - check for recursive stack-lock.
- // Tests show that we can remove the recursive case with no impact
- // on refworkload 0.83. If we need to reduce the size of the code
- // emitted by compiler_lock_object() the recursive case is perfect
- // candidate.
- //
- // A more extreme idea is to always inflate on stack-lock recursion.
- // This lets us eliminate the recursive checks in compiler_lock_object
- // and compiler_unlock_object and the (box->dhw == 0) encoding.
- // A brief experiment - requiring changes to synchronizer.cpp, interpreter,
- // and showed a performance *increase*. In the same experiment I eliminated
- // the fast-path stack-lock code from the interpreter and always passed
- // control to the "slow" operators in synchronizer.cpp.
-
- // RScratch contains the fetched obj->mark value from the failed CASN.
-#ifdef _LP64
- sub(Rscratch, STACK_BIAS, Rscratch);
-#endif
- sub(Rscratch, SP, Rscratch);
- assert(os::vm_page_size() > 0xfff, "page size too small - change the constant");
- andcc(Rscratch, 0xfffff003, Rscratch);
- if (counters != NULL) {
- // Accounting needs the Rscratch register
- st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
- cond_inc(Assembler::equal, (address) counters->fast_path_entry_count_addr(), Rmark, Rscratch);
- ba_short(done);
- } else {
- ba(done);
- delayed()->st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
- }
-
- bind (IsInflated);
- if (EmitSync & 64) {
- // If m->owner != null goto IsLocked
- // Test-and-CAS vs CAS
- // Pessimistic form avoids futile (doomed) CAS attempts
- // The optimistic form avoids RTS->RTO cache line upgrades.
- ld_ptr(Rmark, ObjectMonitor::owner_offset_in_bytes() - 2, Rscratch);
- andcc(Rscratch, Rscratch, G0);
- brx(Assembler::notZero, false, Assembler::pn, done);
- delayed()->nop();
- // m->owner == null : it's unlocked.
- }
-
- // Try to CAS m->owner from null to Self
- // Invariant: if we acquire the lock then _recursions should be 0.
- add(Rmark, ObjectMonitor::owner_offset_in_bytes()-2, Rmark);
- mov(G2_thread, Rscratch);
- casn(Rmark, G0, Rscratch);
- cmp(Rscratch, G0);
- // ST box->displaced_header = NonZero.
- // Any non-zero value suffices:
- // unused_mark(), G2_thread, RBox, RScratch, rsp, etc.
- st_ptr(Rbox, Rbox, BasicLock::displaced_header_offset_in_bytes());
- // Intentional fall-through into done
- }
-
- bind (done);
-}
-
-void MacroAssembler::compiler_unlock_object(Register Roop, Register Rmark,
- Register Rbox, Register Rscratch,
- bool try_bias) {
- Address mark_addr(Roop, oopDesc::mark_offset_in_bytes());
-
- Label done ;
-
- if (EmitSync & 4) {
- cmp(SP, G0);
- return ;
- }
-
- if (EmitSync & 8) {
- if (try_bias) {
- biased_locking_exit(mark_addr, Rscratch, done);
- }
-
- // Test first if it is a fast recursive unlock
- ld_ptr(Rbox, BasicLock::displaced_header_offset_in_bytes(), Rmark);
- br_null_short(Rmark, Assembler::pt, done);
-
- // Check if it is still a light weight lock, this is is true if we see
- // the stack address of the basicLock in the markOop of the object
- assert(mark_addr.disp() == 0, "cas must take a zero displacement");
- casx_under_lock(mark_addr.base(), Rbox, Rmark,
- (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr());
- ba(done);
- delayed()->cmp(Rbox, Rmark);
- bind(done);
- return ;
- }
-
- // Beware ... If the aggregate size of the code emitted by CLO and CUO is
- // is too large performance rolls abruptly off a cliff.
- // This could be related to inlining policies, code cache management, or
- // I$ effects.
- Label LStacked ;
-
- if (try_bias) {
- // TODO: eliminate redundant LDs of obj->mark
- biased_locking_exit(mark_addr, Rscratch, done);
- }
-
- ld_ptr(Roop, oopDesc::mark_offset_in_bytes(), Rmark);
- ld_ptr(Rbox, BasicLock::displaced_header_offset_in_bytes(), Rscratch);
- andcc(Rscratch, Rscratch, G0);
- brx(Assembler::zero, false, Assembler::pn, done);
- delayed()->nop(); // consider: relocate fetch of mark, above, into this DS
- andcc(Rmark, 2, G0);
- brx(Assembler::zero, false, Assembler::pt, LStacked);
- delayed()->nop();
-
- // It's inflated
- // Conceptually we need a #loadstore|#storestore "release" MEMBAR before
- // the ST of 0 into _owner which releases the lock. This prevents loads
- // and stores within the critical section from reordering (floating)
- // past the store that releases the lock. But TSO is a strong memory model
- // and that particular flavor of barrier is a noop, so we can safely elide it.
- // Note that we use 1-0 locking by default for the inflated case. We
- // close the resultant (and rare) race by having contented threads in
- // monitorenter periodically poll _owner.
- ld_ptr(Rmark, ObjectMonitor::owner_offset_in_bytes() - 2, Rscratch);
- ld_ptr(Rmark, ObjectMonitor::recursions_offset_in_bytes() - 2, Rbox);
- xor3(Rscratch, G2_thread, Rscratch);
- orcc(Rbox, Rscratch, Rbox);
- brx(Assembler::notZero, false, Assembler::pn, done);
- delayed()->
- ld_ptr(Rmark, ObjectMonitor::EntryList_offset_in_bytes() - 2, Rscratch);
- ld_ptr(Rmark, ObjectMonitor::cxq_offset_in_bytes() - 2, Rbox);
- orcc(Rbox, Rscratch, G0);
- if (EmitSync & 65536) {
- Label LSucc ;
- brx(Assembler::notZero, false, Assembler::pn, LSucc);
- delayed()->nop();
- ba(done);
- delayed()->st_ptr(G0, Rmark, ObjectMonitor::owner_offset_in_bytes() - 2);
-
- bind(LSucc);
- st_ptr(G0, Rmark, ObjectMonitor::owner_offset_in_bytes() - 2);
- if (os::is_MP()) { membar (StoreLoad); }
- ld_ptr(Rmark, ObjectMonitor::succ_offset_in_bytes() - 2, Rscratch);
- andcc(Rscratch, Rscratch, G0);
- brx(Assembler::notZero, false, Assembler::pt, done);
- delayed()->andcc(G0, G0, G0);
- add(Rmark, ObjectMonitor::owner_offset_in_bytes()-2, Rmark);
- mov(G2_thread, Rscratch);
- casn(Rmark, G0, Rscratch);
- // invert icc.zf and goto done
- br_notnull(Rscratch, false, Assembler::pt, done);
- delayed()->cmp(G0, G0);
- ba(done);
- delayed()->cmp(G0, 1);
- } else {
- brx(Assembler::notZero, false, Assembler::pn, done);
- delayed()->nop();
- ba(done);
- delayed()->st_ptr(G0, Rmark, ObjectMonitor::owner_offset_in_bytes() - 2);
- }
-
- bind (LStacked);
- // Consider: we could replace the expensive CAS in the exit
- // path with a simple ST of the displaced mark value fetched from
- // the on-stack basiclock box. That admits a race where a thread T2
- // in the slow lock path -- inflating with monitor M -- could race a
- // thread T1 in the fast unlock path, resulting in a missed wakeup for T2.
- // More precisely T1 in the stack-lock unlock path could "stomp" the
- // inflated mark value M installed by T2, resulting in an orphan
- // object monitor M and T2 becoming stranded. We can remedy that situation
- // by having T2 periodically poll the object's mark word using timed wait
- // operations. If T2 discovers that a stomp has occurred it vacates
- // the monitor M and wakes any other threads stranded on the now-orphan M.
- // In addition the monitor scavenger, which performs deflation,
- // would also need to check for orpan monitors and stranded threads.
- //
- // Finally, inflation is also used when T2 needs to assign a hashCode
- // to O and O is stack-locked by T1. The "stomp" race could cause
- // an assigned hashCode value to be lost. We can avoid that condition
- // and provide the necessary hashCode stability invariants by ensuring
- // that hashCode generation is idempotent between copying GCs.
- // For example we could compute the hashCode of an object O as
- // O's heap address XOR some high quality RNG value that is refreshed
- // at GC-time. The monitor scavenger would install the hashCode
- // found in any orphan monitors. Again, the mechanism admits a
- // lost-update "stomp" WAW race but detects and recovers as needed.
- //
- // A prototype implementation showed excellent results, although
- // the scavenger and timeout code was rather involved.
-
- casn(mark_addr.base(), Rbox, Rscratch);
- cmp(Rbox, Rscratch);
- // Intentional fall through into done ...
-
- bind(done);
-}
-
-
-
-void MacroAssembler::print_CPU_state() {
- // %%%%% need to implement this
-}
-
-void MacroAssembler::verify_FPU(int stack_depth, const char* s) {
- // %%%%% need to implement this
-}
-
-void MacroAssembler::push_IU_state() {
- // %%%%% need to implement this
-}
-
-
-void MacroAssembler::pop_IU_state() {
- // %%%%% need to implement this
-}
-
-
-void MacroAssembler::push_FPU_state() {
- // %%%%% need to implement this
-}
-
-
-void MacroAssembler::pop_FPU_state() {
- // %%%%% need to implement this
-}
-
-
-void MacroAssembler::push_CPU_state() {
- // %%%%% need to implement this
-}
-
-
-void MacroAssembler::pop_CPU_state() {
- // %%%%% need to implement this
-}
-
-
-
-void MacroAssembler::verify_tlab() {
-#ifdef ASSERT
- if (UseTLAB && VerifyOops) {
- Label next, next2, ok;
- Register t1 = L0;
- Register t2 = L1;
- Register t3 = L2;
-
- save_frame(0);
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), t1);
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_start_offset()), t2);
- or3(t1, t2, t3);
- cmp_and_br_short(t1, t2, Assembler::greaterEqual, Assembler::pn, next);
- STOP("assert(top >= start)");
- should_not_reach_here();
-
- bind(next);
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), t1);
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_end_offset()), t2);
- or3(t3, t2, t3);
- cmp_and_br_short(t1, t2, Assembler::lessEqual, Assembler::pn, next2);
- STOP("assert(top <= end)");
- should_not_reach_here();
-
- bind(next2);
- and3(t3, MinObjAlignmentInBytesMask, t3);
- cmp_and_br_short(t3, 0, Assembler::lessEqual, Assembler::pn, ok);
- STOP("assert(aligned)");
- should_not_reach_here();
-
- bind(ok);
- restore();
- }
-#endif
-}
-
-
-void MacroAssembler::eden_allocate(
- Register obj, // result: pointer to object after successful allocation
- Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
- int con_size_in_bytes, // object size in bytes if known at compile time
- Register t1, // temp register
- Register t2, // temp register
- Label& slow_case // continuation point if fast allocation fails
-){
- // make sure arguments make sense
- assert_different_registers(obj, var_size_in_bytes, t1, t2);
- assert(0 <= con_size_in_bytes && Assembler::is_simm13(con_size_in_bytes), "illegal object size");
- assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0, "object size is not multiple of alignment");
-
- if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) {
- // No allocation in the shared eden.
- ba_short(slow_case);
- } else {
- // get eden boundaries
- // note: we need both top & top_addr!
- const Register top_addr = t1;
- const Register end = t2;
-
- CollectedHeap* ch = Universe::heap();
- set((intx)ch->top_addr(), top_addr);
- intx delta = (intx)ch->end_addr() - (intx)ch->top_addr();
- ld_ptr(top_addr, delta, end);
- ld_ptr(top_addr, 0, obj);
-
- // try to allocate
- Label retry;
- bind(retry);
-#ifdef ASSERT
- // make sure eden top is properly aligned
- {
- Label L;
- btst(MinObjAlignmentInBytesMask, obj);
- br(Assembler::zero, false, Assembler::pt, L);
- delayed()->nop();
- STOP("eden top is not properly aligned");
- bind(L);
- }
-#endif // ASSERT
- const Register free = end;
- sub(end, obj, free); // compute amount of free space
- if (var_size_in_bytes->is_valid()) {
- // size is unknown at compile time
- cmp(free, var_size_in_bytes);
- br(Assembler::lessUnsigned, false, Assembler::pn, slow_case); // if there is not enough space go the slow case
- delayed()->add(obj, var_size_in_bytes, end);
- } else {
- // size is known at compile time
- cmp(free, con_size_in_bytes);
- br(Assembler::lessUnsigned, false, Assembler::pn, slow_case); // if there is not enough space go the slow case
- delayed()->add(obj, con_size_in_bytes, end);
- }
- // Compare obj with the value at top_addr; if still equal, swap the value of
- // end with the value at top_addr. If not equal, read the value at top_addr
- // into end.
- casx_under_lock(top_addr, obj, end, (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr());
- // if someone beat us on the allocation, try again, otherwise continue
- cmp(obj, end);
- brx(Assembler::notEqual, false, Assembler::pn, retry);
- delayed()->mov(end, obj); // nop if successfull since obj == end
-
-#ifdef ASSERT
- // make sure eden top is properly aligned
- {
- Label L;
- const Register top_addr = t1;
-
- set((intx)ch->top_addr(), top_addr);
- ld_ptr(top_addr, 0, top_addr);
- btst(MinObjAlignmentInBytesMask, top_addr);
- br(Assembler::zero, false, Assembler::pt, L);
- delayed()->nop();
- STOP("eden top is not properly aligned");
- bind(L);
- }
-#endif // ASSERT
- }
-}
-
-
-void MacroAssembler::tlab_allocate(
- Register obj, // result: pointer to object after successful allocation
- Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
- int con_size_in_bytes, // object size in bytes if known at compile time
- Register t1, // temp register
- Label& slow_case // continuation point if fast allocation fails
-){
- // make sure arguments make sense
- assert_different_registers(obj, var_size_in_bytes, t1);
- assert(0 <= con_size_in_bytes && is_simm13(con_size_in_bytes), "illegal object size");
- assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0, "object size is not multiple of alignment");
-
- const Register free = t1;
-
- verify_tlab();
-
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), obj);
-
- // calculate amount of free space
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_end_offset()), free);
- sub(free, obj, free);
-
- Label done;
- if (var_size_in_bytes == noreg) {
- cmp(free, con_size_in_bytes);
- } else {
- cmp(free, var_size_in_bytes);
- }
- br(Assembler::less, false, Assembler::pn, slow_case);
- // calculate the new top pointer
- if (var_size_in_bytes == noreg) {
- delayed()->add(obj, con_size_in_bytes, free);
- } else {
- delayed()->add(obj, var_size_in_bytes, free);
- }
-
- bind(done);
-
-#ifdef ASSERT
- // make sure new free pointer is properly aligned
- {
- Label L;
- btst(MinObjAlignmentInBytesMask, free);
- br(Assembler::zero, false, Assembler::pt, L);
- delayed()->nop();
- STOP("updated TLAB free is not properly aligned");
- bind(L);
- }
-#endif // ASSERT
-
- // update the tlab top pointer
- st_ptr(free, G2_thread, in_bytes(JavaThread::tlab_top_offset()));
- verify_tlab();
-}
-
-
-void MacroAssembler::tlab_refill(Label& retry, Label& try_eden, Label& slow_case) {
- Register top = O0;
- Register t1 = G1;
- Register t2 = G3;
- Register t3 = O1;
- assert_different_registers(top, t1, t2, t3, G4, G5 /* preserve G4 and G5 */);
- Label do_refill, discard_tlab;
-
- if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) {
- // No allocation in the shared eden.
- ba_short(slow_case);
- }
-
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), top);
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_end_offset()), t1);
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_refill_waste_limit_offset()), t2);
-
- // calculate amount of free space
- sub(t1, top, t1);
- srl_ptr(t1, LogHeapWordSize, t1);
-
- // Retain tlab and allocate object in shared space if
- // the amount free in the tlab is too large to discard.
- cmp(t1, t2);
- brx(Assembler::lessEqual, false, Assembler::pt, discard_tlab);
-
- // increment waste limit to prevent getting stuck on this slow path
- delayed()->add(t2, ThreadLocalAllocBuffer::refill_waste_limit_increment(), t2);
- st_ptr(t2, G2_thread, in_bytes(JavaThread::tlab_refill_waste_limit_offset()));
- if (TLABStats) {
- // increment number of slow_allocations
- ld(G2_thread, in_bytes(JavaThread::tlab_slow_allocations_offset()), t2);
- add(t2, 1, t2);
- stw(t2, G2_thread, in_bytes(JavaThread::tlab_slow_allocations_offset()));
- }
- ba_short(try_eden);
-
- bind(discard_tlab);
- if (TLABStats) {
- // increment number of refills
- ld(G2_thread, in_bytes(JavaThread::tlab_number_of_refills_offset()), t2);
- add(t2, 1, t2);
- stw(t2, G2_thread, in_bytes(JavaThread::tlab_number_of_refills_offset()));
- // accumulate wastage
- ld(G2_thread, in_bytes(JavaThread::tlab_fast_refill_waste_offset()), t2);
- add(t2, t1, t2);
- stw(t2, G2_thread, in_bytes(JavaThread::tlab_fast_refill_waste_offset()));
- }
-
- // if tlab is currently allocated (top or end != null) then
- // fill [top, end + alignment_reserve) with array object
- br_null_short(top, Assembler::pn, do_refill);
-
- set((intptr_t)markOopDesc::prototype()->copy_set_hash(0x2), t2);
- st_ptr(t2, top, oopDesc::mark_offset_in_bytes()); // set up the mark word
- // set klass to intArrayKlass
- sub(t1, typeArrayOopDesc::header_size(T_INT), t1);
- add(t1, ThreadLocalAllocBuffer::alignment_reserve(), t1);
- sll_ptr(t1, log2_intptr(HeapWordSize/sizeof(jint)), t1);
- st(t1, top, arrayOopDesc::length_offset_in_bytes());
- set((intptr_t)Universe::intArrayKlassObj_addr(), t2);
- ld_ptr(t2, 0, t2);
- // store klass last. concurrent gcs assumes klass length is valid if
- // klass field is not null.
- store_klass(t2, top);
- verify_oop(top);
-
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_start_offset()), t1);
- sub(top, t1, t1); // size of tlab's allocated portion
- incr_allocated_bytes(t1, t2, t3);
-
- // refill the tlab with an eden allocation
- bind(do_refill);
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_size_offset()), t1);
- sll_ptr(t1, LogHeapWordSize, t1);
- // allocate new tlab, address returned in top
- eden_allocate(top, t1, 0, t2, t3, slow_case);
-
- st_ptr(top, G2_thread, in_bytes(JavaThread::tlab_start_offset()));
- st_ptr(top, G2_thread, in_bytes(JavaThread::tlab_top_offset()));
-#ifdef ASSERT
- // check that tlab_size (t1) is still valid
- {
- Label ok;
- ld_ptr(G2_thread, in_bytes(JavaThread::tlab_size_offset()), t2);
- sll_ptr(t2, LogHeapWordSize, t2);
- cmp_and_br_short(t1, t2, Assembler::equal, Assembler::pt, ok);
- STOP("assert(t1 == tlab_size)");
- should_not_reach_here();
-
- bind(ok);
- }
-#endif // ASSERT
- add(top, t1, top); // t1 is tlab_size
- sub(top, ThreadLocalAllocBuffer::alignment_reserve_in_bytes(), top);
- st_ptr(top, G2_thread, in_bytes(JavaThread::tlab_end_offset()));
- verify_tlab();
- ba_short(retry);
-}
-
-void MacroAssembler::incr_allocated_bytes(RegisterOrConstant size_in_bytes,
- Register t1, Register t2) {
- // Bump total bytes allocated by this thread
- assert(t1->is_global(), "must be global reg"); // so all 64 bits are saved on a context switch
- assert_different_registers(size_in_bytes.register_or_noreg(), t1, t2);
- // v8 support has gone the way of the dodo
- ldx(G2_thread, in_bytes(JavaThread::allocated_bytes_offset()), t1);
- add(t1, ensure_simm13_or_reg(size_in_bytes, t2), t1);
- stx(t1, G2_thread, in_bytes(JavaThread::allocated_bytes_offset()));
-}
-
-Assembler::Condition MacroAssembler::negate_condition(Assembler::Condition cond) {
- switch (cond) {
- // Note some conditions are synonyms for others
- case Assembler::never: return Assembler::always;
- case Assembler::zero: return Assembler::notZero;
- case Assembler::lessEqual: return Assembler::greater;
- case Assembler::less: return Assembler::greaterEqual;
- case Assembler::lessEqualUnsigned: return Assembler::greaterUnsigned;
- case Assembler::lessUnsigned: return Assembler::greaterEqualUnsigned;
- case Assembler::negative: return Assembler::positive;
- case Assembler::overflowSet: return Assembler::overflowClear;
- case Assembler::always: return Assembler::never;
- case Assembler::notZero: return Assembler::zero;
- case Assembler::greater: return Assembler::lessEqual;
- case Assembler::greaterEqual: return Assembler::less;
- case Assembler::greaterUnsigned: return Assembler::lessEqualUnsigned;
- case Assembler::greaterEqualUnsigned: return Assembler::lessUnsigned;
- case Assembler::positive: return Assembler::negative;
- case Assembler::overflowClear: return Assembler::overflowSet;
- }
-
- ShouldNotReachHere(); return Assembler::overflowClear;
-}
-
-void MacroAssembler::cond_inc(Assembler::Condition cond, address counter_ptr,
- Register Rtmp1, Register Rtmp2 /*, Register Rtmp3, Register Rtmp4 */) {
- Condition negated_cond = negate_condition(cond);
- Label L;
- brx(negated_cond, false, Assembler::pt, L);
- delayed()->nop();
- inc_counter(counter_ptr, Rtmp1, Rtmp2);
- bind(L);
-}
-
-void MacroAssembler::inc_counter(address counter_addr, Register Rtmp1, Register Rtmp2) {
- AddressLiteral addrlit(counter_addr);
- sethi(addrlit, Rtmp1); // Move hi22 bits into temporary register.
- Address addr(Rtmp1, addrlit.low10()); // Build an address with low10 bits.
- ld(addr, Rtmp2);
- inc(Rtmp2);
- st(Rtmp2, addr);
-}
-
-void MacroAssembler::inc_counter(int* counter_addr, Register Rtmp1, Register Rtmp2) {
- inc_counter((address) counter_addr, Rtmp1, Rtmp2);
-}
-
-SkipIfEqual::SkipIfEqual(
- MacroAssembler* masm, Register temp, const bool* flag_addr,
- Assembler::Condition condition) {
- _masm = masm;
- AddressLiteral flag(flag_addr);
- _masm->sethi(flag, temp);
- _masm->ldub(temp, flag.low10(), temp);
- _masm->tst(temp);
- _masm->br(condition, false, Assembler::pt, _label);
- _masm->delayed()->nop();
-}
-
-SkipIfEqual::~SkipIfEqual() {
- _masm->bind(_label);
-}
-
-
-// Writes to stack successive pages until offset reached to check for
-// stack overflow + shadow pages. This clobbers tsp and scratch.
-void MacroAssembler::bang_stack_size(Register Rsize, Register Rtsp,
- Register Rscratch) {
- // Use stack pointer in temp stack pointer
- mov(SP, Rtsp);
-
- // Bang stack for total size given plus stack shadow page size.
- // Bang one page at a time because a large size can overflow yellow and
- // red zones (the bang will fail but stack overflow handling can't tell that
- // it was a stack overflow bang vs a regular segv).
- int offset = os::vm_page_size();
- Register Roffset = Rscratch;
-
- Label loop;
- bind(loop);
- set((-offset)+STACK_BIAS, Rscratch);
- st(G0, Rtsp, Rscratch);
- set(offset, Roffset);
- sub(Rsize, Roffset, Rsize);
- cmp(Rsize, G0);
- br(Assembler::greater, false, Assembler::pn, loop);
- delayed()->sub(Rtsp, Roffset, Rtsp);
-
- // Bang down shadow pages too.
- // The -1 because we already subtracted 1 page.
- for (int i = 0; i< StackShadowPages-1; i++) {
- set((-i*offset)+STACK_BIAS, Rscratch);
- st(G0, Rtsp, Rscratch);
- }
-}
-
-///////////////////////////////////////////////////////////////////////////////////
-#ifndef SERIALGC
-
-static address satb_log_enqueue_with_frame = NULL;
-static u_char* satb_log_enqueue_with_frame_end = NULL;
-
-static address satb_log_enqueue_frameless = NULL;
-static u_char* satb_log_enqueue_frameless_end = NULL;
-
-static int EnqueueCodeSize = 128 DEBUG_ONLY( + 256); // Instructions?
-
-static void generate_satb_log_enqueue(bool with_frame) {
- BufferBlob* bb = BufferBlob::create("enqueue_with_frame", EnqueueCodeSize);
- CodeBuffer buf(bb);
- MacroAssembler masm(&buf);
-
-#define __ masm.
-
- address start = __ pc();
- Register pre_val;
-
- Label refill, restart;
- if (with_frame) {
- __ save_frame(0);
- pre_val = I0; // Was O0 before the save.
- } else {
- pre_val = O0;
- }
-
- int satb_q_index_byte_offset =
- in_bytes(JavaThread::satb_mark_queue_offset() +
- PtrQueue::byte_offset_of_index());
-
- int satb_q_buf_byte_offset =
- in_bytes(JavaThread::satb_mark_queue_offset() +
- PtrQueue::byte_offset_of_buf());
-
- assert(in_bytes(PtrQueue::byte_width_of_index()) == sizeof(intptr_t) &&
- in_bytes(PtrQueue::byte_width_of_buf()) == sizeof(intptr_t),
- "check sizes in assembly below");
-
- __ bind(restart);
-
- // Load the index into the SATB buffer. PtrQueue::_index is a size_t
- // so ld_ptr is appropriate.
- __ ld_ptr(G2_thread, satb_q_index_byte_offset, L0);
-
- // index == 0?
- __ cmp_and_brx_short(L0, G0, Assembler::equal, Assembler::pn, refill);
-
- __ ld_ptr(G2_thread, satb_q_buf_byte_offset, L1);
- __ sub(L0, oopSize, L0);
-
- __ st_ptr(pre_val, L1, L0); // [_buf + index] := I0
- if (!with_frame) {
- // Use return-from-leaf
- __ retl();
- __ delayed()->st_ptr(L0, G2_thread, satb_q_index_byte_offset);
- } else {
- // Not delayed.
- __ st_ptr(L0, G2_thread, satb_q_index_byte_offset);
- }
- if (with_frame) {
- __ ret();
- __ delayed()->restore();
- }
- __ bind(refill);
-
- address handle_zero =
- CAST_FROM_FN_PTR(address,
- &SATBMarkQueueSet::handle_zero_index_for_thread);
- // This should be rare enough that we can afford to save all the
- // scratch registers that the calling context might be using.
- __ mov(G1_scratch, L0);
- __ mov(G3_scratch, L1);
- __ mov(G4, L2);
- // We need the value of O0 above (for the write into the buffer), so we
- // save and restore it.
- __ mov(O0, L3);
- // Since the call will overwrite O7, we save and restore that, as well.
- __ mov(O7, L4);
- __ call_VM_leaf(L5, handle_zero, G2_thread);
- __ mov(L0, G1_scratch);
- __ mov(L1, G3_scratch);
- __ mov(L2, G4);
- __ mov(L3, O0);
- __ br(Assembler::always, /*annul*/false, Assembler::pt, restart);
- __ delayed()->mov(L4, O7);
-
- if (with_frame) {
- satb_log_enqueue_with_frame = start;
- satb_log_enqueue_with_frame_end = __ pc();
- } else {
- satb_log_enqueue_frameless = start;
- satb_log_enqueue_frameless_end = __ pc();
- }
-
-#undef __
-}
-
-static inline void generate_satb_log_enqueue_if_necessary(bool with_frame) {
- if (with_frame) {
- if (satb_log_enqueue_with_frame == 0) {
- generate_satb_log_enqueue(with_frame);
- assert(satb_log_enqueue_with_frame != 0, "postcondition.");
- if (G1SATBPrintStubs) {
- tty->print_cr("Generated with-frame satb enqueue:");
- Disassembler::decode((u_char*)satb_log_enqueue_with_frame,
- satb_log_enqueue_with_frame_end,
- tty);
- }
- }
- } else {
- if (satb_log_enqueue_frameless == 0) {
- generate_satb_log_enqueue(with_frame);
- assert(satb_log_enqueue_frameless != 0, "postcondition.");
- if (G1SATBPrintStubs) {
- tty->print_cr("Generated frameless satb enqueue:");
- Disassembler::decode((u_char*)satb_log_enqueue_frameless,
- satb_log_enqueue_frameless_end,
- tty);
- }
- }
- }
-}
-
-void MacroAssembler::g1_write_barrier_pre(Register obj,
- Register index,
- int offset,
- Register pre_val,
- Register tmp,
- bool preserve_o_regs) {
- Label filtered;
-
- if (obj == noreg) {
- // We are not loading the previous value so make
- // sure that we don't trash the value in pre_val
- // with the code below.
- assert_different_registers(pre_val, tmp);
- } else {
- // We will be loading the previous value
- // in this code so...
- assert(offset == 0 || index == noreg, "choose one");
- assert(pre_val == noreg, "check this code");
- }
-
- // Is marking active?
- if (in_bytes(PtrQueue::byte_width_of_active()) == 4) {
- ld(G2,
- in_bytes(JavaThread::satb_mark_queue_offset() +
- PtrQueue::byte_offset_of_active()),
- tmp);
- } else {
- guarantee(in_bytes(PtrQueue::byte_width_of_active()) == 1,
- "Assumption");
- ldsb(G2,
- in_bytes(JavaThread::satb_mark_queue_offset() +
- PtrQueue::byte_offset_of_active()),
- tmp);
- }
-
- // Is marking active?
- cmp_and_br_short(tmp, G0, Assembler::equal, Assembler::pt, filtered);
-
- // Do we need to load the previous value?
- if (obj != noreg) {
- // Load the previous value...
- if (index == noreg) {
- if (Assembler::is_simm13(offset)) {
- load_heap_oop(obj, offset, tmp);
- } else {
- set(offset, tmp);
- load_heap_oop(obj, tmp, tmp);
- }
- } else {
- load_heap_oop(obj, index, tmp);
- }
- // Previous value has been loaded into tmp
- pre_val = tmp;
- }
-
- assert(pre_val != noreg, "must have a real register");
-
- // Is the previous value null?
- cmp_and_brx_short(pre_val, G0, Assembler::equal, Assembler::pt, filtered);
-
- // OK, it's not filtered, so we'll need to call enqueue. In the normal
- // case, pre_val will be a scratch G-reg, but there are some cases in
- // which it's an O-reg. In the first case, do a normal call. In the
- // latter, do a save here and call the frameless version.
-
- guarantee(pre_val->is_global() || pre_val->is_out(),
- "Or we need to think harder.");
-
- if (pre_val->is_global() && !preserve_o_regs) {
- generate_satb_log_enqueue_if_necessary(true); // with frame
-
- call(satb_log_enqueue_with_frame);
- delayed()->mov(pre_val, O0);
- } else {
- generate_satb_log_enqueue_if_necessary(false); // frameless
-
- save_frame(0);
- call(satb_log_enqueue_frameless);
- delayed()->mov(pre_val->after_save(), O0);
- restore();
- }
-
- bind(filtered);
-}
-
-static address dirty_card_log_enqueue = 0;
-static u_char* dirty_card_log_enqueue_end = 0;
-
-// This gets to assume that o0 contains the object address.
-static void generate_dirty_card_log_enqueue(jbyte* byte_map_base) {
- BufferBlob* bb = BufferBlob::create("dirty_card_enqueue", EnqueueCodeSize*2);
- CodeBuffer buf(bb);
- MacroAssembler masm(&buf);
-#define __ masm.
- address start = __ pc();
-
- Label not_already_dirty, restart, refill;
-
-#ifdef _LP64
- __ srlx(O0, CardTableModRefBS::card_shift, O0);
-#else
- __ srl(O0, CardTableModRefBS::card_shift, O0);
-#endif
- AddressLiteral addrlit(byte_map_base);
- __ set(addrlit, O1); // O1 :=
- __ ldub(O0, O1, O2); // O2 := [O0 + O1]
-
- assert(CardTableModRefBS::dirty_card_val() == 0, "otherwise check this code");
- __ cmp_and_br_short(O2, G0, Assembler::notEqual, Assembler::pt, not_already_dirty);
-
- // We didn't take the branch, so we're already dirty: return.
- // Use return-from-leaf
- __ retl();
- __ delayed()->nop();
-
- // Not dirty.
- __ bind(not_already_dirty);
-
- // Get O0 + O1 into a reg by itself
- __ add(O0, O1, O3);
-
- // First, dirty it.
- __ stb(G0, O3, G0); // [cardPtr] := 0 (i.e., dirty).
-
- int dirty_card_q_index_byte_offset =
- in_bytes(JavaThread::dirty_card_queue_offset() +
- PtrQueue::byte_offset_of_index());
- int dirty_card_q_buf_byte_offset =
- in_bytes(JavaThread::dirty_card_queue_offset() +
- PtrQueue::byte_offset_of_buf());
- __ bind(restart);
-
- // Load the index into the update buffer. PtrQueue::_index is
- // a size_t so ld_ptr is appropriate here.
- __ ld_ptr(G2_thread, dirty_card_q_index_byte_offset, L0);
-
- // index == 0?
- __ cmp_and_brx_short(L0, G0, Assembler::equal, Assembler::pn, refill);
-
- __ ld_ptr(G2_thread, dirty_card_q_buf_byte_offset, L1);
- __ sub(L0, oopSize, L0);
-
- __ st_ptr(O3, L1, L0); // [_buf + index] := I0
- // Use return-from-leaf
- __ retl();
- __ delayed()->st_ptr(L0, G2_thread, dirty_card_q_index_byte_offset);
-
- __ bind(refill);
- address handle_zero =
- CAST_FROM_FN_PTR(address,
- &DirtyCardQueueSet::handle_zero_index_for_thread);
- // This should be rare enough that we can afford to save all the
- // scratch registers that the calling context might be using.
- __ mov(G1_scratch, L3);
- __ mov(G3_scratch, L5);
- // We need the value of O3 above (for the write into the buffer), so we
- // save and restore it.
- __ mov(O3, L6);
- // Since the call will overwrite O7, we save and restore that, as well.
- __ mov(O7, L4);
-
- __ call_VM_leaf(L7_thread_cache, handle_zero, G2_thread);
- __ mov(L3, G1_scratch);
- __ mov(L5, G3_scratch);
- __ mov(L6, O3);
- __ br(Assembler::always, /*annul*/false, Assembler::pt, restart);
- __ delayed()->mov(L4, O7);
-
- dirty_card_log_enqueue = start;
- dirty_card_log_enqueue_end = __ pc();
- // XXX Should have a guarantee here about not going off the end!
- // Does it already do so? Do an experiment...
-
-#undef __
-
-}
-
-static inline void
-generate_dirty_card_log_enqueue_if_necessary(jbyte* byte_map_base) {
- if (dirty_card_log_enqueue == 0) {
- generate_dirty_card_log_enqueue(byte_map_base);
- assert(dirty_card_log_enqueue != 0, "postcondition.");
- if (G1SATBPrintStubs) {
- tty->print_cr("Generated dirty_card enqueue:");
- Disassembler::decode((u_char*)dirty_card_log_enqueue,
- dirty_card_log_enqueue_end,
- tty);
- }
- }
-}
-
-
-void MacroAssembler::g1_write_barrier_post(Register store_addr, Register new_val, Register tmp) {
-
- Label filtered;
- MacroAssembler* post_filter_masm = this;
-
- if (new_val == G0) return;
-
- G1SATBCardTableModRefBS* bs = (G1SATBCardTableModRefBS*) Universe::heap()->barrier_set();
- assert(bs->kind() == BarrierSet::G1SATBCT ||
- bs->kind() == BarrierSet::G1SATBCTLogging, "wrong barrier");
-
- if (G1RSBarrierRegionFilter) {
- xor3(store_addr, new_val, tmp);
-#ifdef _LP64
- srlx(tmp, HeapRegion::LogOfHRGrainBytes, tmp);
-#else
- srl(tmp, HeapRegion::LogOfHRGrainBytes, tmp);
-#endif
-
- // XXX Should I predict this taken or not? Does it matter?
- cmp_and_brx_short(tmp, G0, Assembler::equal, Assembler::pt, filtered);
- }
-
- // If the "store_addr" register is an "in" or "local" register, move it to
- // a scratch reg so we can pass it as an argument.
- bool use_scr = !(store_addr->is_global() || store_addr->is_out());
- // Pick a scratch register different from "tmp".
- Register scr = (tmp == G1_scratch ? G3_scratch : G1_scratch);
- // Make sure we use up the delay slot!
- if (use_scr) {
- post_filter_masm->mov(store_addr, scr);
- } else {
- post_filter_masm->nop();
- }
- generate_dirty_card_log_enqueue_if_necessary(bs->byte_map_base);
- save_frame(0);
- call(dirty_card_log_enqueue);
- if (use_scr) {
- delayed()->mov(scr, O0);
- } else {
- delayed()->mov(store_addr->after_save(), O0);
- }
- restore();
-
- bind(filtered);
-}
-
-#endif // SERIALGC
-///////////////////////////////////////////////////////////////////////////////////
-
-void MacroAssembler::card_write_barrier_post(Register store_addr, Register new_val, Register tmp) {
- // If we're writing constant NULL, we can skip the write barrier.
- if (new_val == G0) return;
- CardTableModRefBS* bs = (CardTableModRefBS*) Universe::heap()->barrier_set();
- assert(bs->kind() == BarrierSet::CardTableModRef ||
- bs->kind() == BarrierSet::CardTableExtension, "wrong barrier");
- card_table_write(bs->byte_map_base, tmp, store_addr);
-}
-
-void MacroAssembler::load_klass(Register src_oop, Register klass) {
- // The number of bytes in this code is used by
- // MachCallDynamicJavaNode::ret_addr_offset()
- // if this changes, change that.
- if (UseCompressedKlassPointers) {
- lduw(src_oop, oopDesc::klass_offset_in_bytes(), klass);
- decode_klass_not_null(klass);
- } else {
- ld_ptr(src_oop, oopDesc::klass_offset_in_bytes(), klass);
- }
-}
-
-void MacroAssembler::store_klass(Register klass, Register dst_oop) {
- if (UseCompressedKlassPointers) {
- assert(dst_oop != klass, "not enough registers");
- encode_klass_not_null(klass);
- st(klass, dst_oop, oopDesc::klass_offset_in_bytes());
- } else {
- st_ptr(klass, dst_oop, oopDesc::klass_offset_in_bytes());
- }
-}
-
-void MacroAssembler::store_klass_gap(Register s, Register d) {
- if (UseCompressedKlassPointers) {
- assert(s != d, "not enough registers");
- st(s, d, oopDesc::klass_gap_offset_in_bytes());
- }
-}
-
-void MacroAssembler::load_heap_oop(const Address& s, Register d) {
- if (UseCompressedOops) {
- lduw(s, d);
- decode_heap_oop(d);
- } else {
- ld_ptr(s, d);
- }
-}
-
-void MacroAssembler::load_heap_oop(Register s1, Register s2, Register d) {
- if (UseCompressedOops) {
- lduw(s1, s2, d);
- decode_heap_oop(d, d);
- } else {
- ld_ptr(s1, s2, d);
- }
-}
-
-void MacroAssembler::load_heap_oop(Register s1, int simm13a, Register d) {
- if (UseCompressedOops) {
- lduw(s1, simm13a, d);
- decode_heap_oop(d, d);
- } else {
- ld_ptr(s1, simm13a, d);
- }
-}
-
-void MacroAssembler::load_heap_oop(Register s1, RegisterOrConstant s2, Register d) {
- if (s2.is_constant()) load_heap_oop(s1, s2.as_constant(), d);
- else load_heap_oop(s1, s2.as_register(), d);
-}
-
-void MacroAssembler::store_heap_oop(Register d, Register s1, Register s2) {
- if (UseCompressedOops) {
- assert(s1 != d && s2 != d, "not enough registers");
- encode_heap_oop(d);
- st(d, s1, s2);
- } else {
- st_ptr(d, s1, s2);
- }
-}
-
-void MacroAssembler::store_heap_oop(Register d, Register s1, int simm13a) {
- if (UseCompressedOops) {
- assert(s1 != d, "not enough registers");
- encode_heap_oop(d);
- st(d, s1, simm13a);
- } else {
- st_ptr(d, s1, simm13a);
- }
-}
-
-void MacroAssembler::store_heap_oop(Register d, const Address& a, int offset) {
- if (UseCompressedOops) {
- assert(a.base() != d, "not enough registers");
- encode_heap_oop(d);
- st(d, a, offset);
- } else {
- st_ptr(d, a, offset);
- }
-}
-
-
-void MacroAssembler::encode_heap_oop(Register src, Register dst) {
- assert (UseCompressedOops, "must be compressed");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
- verify_oop(src);
- if (Universe::narrow_oop_base() == NULL) {
- srlx(src, LogMinObjAlignmentInBytes, dst);
- return;
- }
- Label done;
- if (src == dst) {
- // optimize for frequent case src == dst
- bpr(rc_nz, true, Assembler::pt, src, done);
- delayed() -> sub(src, G6_heapbase, dst); // annuled if not taken
- bind(done);
- srlx(src, LogMinObjAlignmentInBytes, dst);
- } else {
- bpr(rc_z, false, Assembler::pn, src, done);
- delayed() -> mov(G0, dst);
- // could be moved before branch, and annulate delay,
- // but may add some unneeded work decoding null
- sub(src, G6_heapbase, dst);
- srlx(dst, LogMinObjAlignmentInBytes, dst);
- bind(done);
- }
-}
-
-
-void MacroAssembler::encode_heap_oop_not_null(Register r) {
- assert (UseCompressedOops, "must be compressed");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
- verify_oop(r);
- if (Universe::narrow_oop_base() != NULL)
- sub(r, G6_heapbase, r);
- srlx(r, LogMinObjAlignmentInBytes, r);
-}
-
-void MacroAssembler::encode_heap_oop_not_null(Register src, Register dst) {
- assert (UseCompressedOops, "must be compressed");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
- verify_oop(src);
- if (Universe::narrow_oop_base() == NULL) {
- srlx(src, LogMinObjAlignmentInBytes, dst);
- } else {
- sub(src, G6_heapbase, dst);
- srlx(dst, LogMinObjAlignmentInBytes, dst);
- }
-}
-
-// Same algorithm as oops.inline.hpp decode_heap_oop.
-void MacroAssembler::decode_heap_oop(Register src, Register dst) {
- assert (UseCompressedOops, "must be compressed");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
- sllx(src, LogMinObjAlignmentInBytes, dst);
- if (Universe::narrow_oop_base() != NULL) {
- Label done;
- bpr(rc_nz, true, Assembler::pt, dst, done);
- delayed() -> add(dst, G6_heapbase, dst); // annuled if not taken
- bind(done);
- }
- verify_oop(dst);
-}
-
-void MacroAssembler::decode_heap_oop_not_null(Register r) {
- // Do not add assert code to this unless you change vtableStubs_sparc.cpp
- // pd_code_size_limit.
- // Also do not verify_oop as this is called by verify_oop.
- assert (UseCompressedOops, "must be compressed");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
- sllx(r, LogMinObjAlignmentInBytes, r);
- if (Universe::narrow_oop_base() != NULL)
- add(r, G6_heapbase, r);
-}
-
-void MacroAssembler::decode_heap_oop_not_null(Register src, Register dst) {
- // Do not add assert code to this unless you change vtableStubs_sparc.cpp
- // pd_code_size_limit.
- // Also do not verify_oop as this is called by verify_oop.
- assert (UseCompressedOops, "must be compressed");
- assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
- sllx(src, LogMinObjAlignmentInBytes, dst);
- if (Universe::narrow_oop_base() != NULL)
- add(dst, G6_heapbase, dst);
-}
-
-void MacroAssembler::encode_klass_not_null(Register r) {
- assert(Metaspace::is_initialized(), "metaspace should be initialized");
- assert (UseCompressedKlassPointers, "must be compressed");
- assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
- if (Universe::narrow_klass_base() != NULL)
- sub(r, G6_heapbase, r);
- srlx(r, LogKlassAlignmentInBytes, r);
-}
-
-void MacroAssembler::encode_klass_not_null(Register src, Register dst) {
- assert(Metaspace::is_initialized(), "metaspace should be initialized");
- assert (UseCompressedKlassPointers, "must be compressed");
- assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
- if (Universe::narrow_klass_base() == NULL) {
- srlx(src, LogKlassAlignmentInBytes, dst);
- } else {
- sub(src, G6_heapbase, dst);
- srlx(dst, LogKlassAlignmentInBytes, dst);
- }
-}
-
-void MacroAssembler::decode_klass_not_null(Register r) {
- assert(Metaspace::is_initialized(), "metaspace should be initialized");
- // Do not add assert code to this unless you change vtableStubs_sparc.cpp
- // pd_code_size_limit.
- assert (UseCompressedKlassPointers, "must be compressed");
- assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
- sllx(r, LogKlassAlignmentInBytes, r);
- if (Universe::narrow_klass_base() != NULL)
- add(r, G6_heapbase, r);
-}
-
-void MacroAssembler::decode_klass_not_null(Register src, Register dst) {
- assert(Metaspace::is_initialized(), "metaspace should be initialized");
- // Do not add assert code to this unless you change vtableStubs_sparc.cpp
- // pd_code_size_limit.
- assert (UseCompressedKlassPointers, "must be compressed");
- assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
- sllx(src, LogKlassAlignmentInBytes, dst);
- if (Universe::narrow_klass_base() != NULL)
- add(dst, G6_heapbase, dst);
-}
-
-void MacroAssembler::reinit_heapbase() {
- if (UseCompressedOops || UseCompressedKlassPointers) {
- AddressLiteral base(Universe::narrow_ptrs_base_addr());
- load_ptr_contents(base, G6_heapbase);
- }
-}
-
-// Compare char[] arrays aligned to 4 bytes.
-void MacroAssembler::char_arrays_equals(Register ary1, Register ary2,
- Register limit, Register result,
- Register chr1, Register chr2, Label& Ldone) {
- Label Lvector, Lloop;
- assert(chr1 == result, "should be the same");
-
- // Note: limit contains number of bytes (2*char_elements) != 0.
- andcc(limit, 0x2, chr1); // trailing character ?
- br(Assembler::zero, false, Assembler::pt, Lvector);
- delayed()->nop();
-
- // compare the trailing char
- sub(limit, sizeof(jchar), limit);
- lduh(ary1, limit, chr1);
- lduh(ary2, limit, chr2);
- cmp(chr1, chr2);
- br(Assembler::notEqual, true, Assembler::pt, Ldone);
- delayed()->mov(G0, result); // not equal
-
- // only one char ?
- cmp_zero_and_br(zero, limit, Ldone, true, Assembler::pn);
- delayed()->add(G0, 1, result); // zero-length arrays are equal
-
- // word by word compare, dont't need alignment check
- bind(Lvector);
- // Shift ary1 and ary2 to the end of the arrays, negate limit
- add(ary1, limit, ary1);
- add(ary2, limit, ary2);
- neg(limit, limit);
-
- lduw(ary1, limit, chr1);
- bind(Lloop);
- lduw(ary2, limit, chr2);
- cmp(chr1, chr2);
- br(Assembler::notEqual, true, Assembler::pt, Ldone);
- delayed()->mov(G0, result); // not equal
- inccc(limit, 2*sizeof(jchar));
- // annul LDUW if branch is not taken to prevent access past end of array
- br(Assembler::notZero, true, Assembler::pt, Lloop);
- delayed()->lduw(ary1, limit, chr1); // hoisted
-
- // Caller should set it:
- // add(G0, 1, result); // equals
-}
-
-// Use BIS for zeroing (count is in bytes).
-void MacroAssembler::bis_zeroing(Register to, Register count, Register temp, Label& Ldone) {
- assert(UseBlockZeroing && VM_Version::has_block_zeroing(), "only works with BIS zeroing");
- Register end = count;
- int cache_line_size = VM_Version::prefetch_data_size();
- // Minimum count when BIS zeroing can be used since
- // it needs membar which is expensive.
- int block_zero_size = MAX2(cache_line_size*3, (int)BlockZeroingLowLimit);
-
- Label small_loop;
- // Check if count is negative (dead code) or zero.
- // Note, count uses 64bit in 64 bit VM.
- cmp_and_brx_short(count, 0, Assembler::lessEqual, Assembler::pn, Ldone);
-
- // Use BIS zeroing only for big arrays since it requires membar.
- if (Assembler::is_simm13(block_zero_size)) { // < 4096
- cmp(count, block_zero_size);
- } else {
- set(block_zero_size, temp);
- cmp(count, temp);
- }
- br(Assembler::lessUnsigned, false, Assembler::pt, small_loop);
- delayed()->add(to, count, end);
-
- // Note: size is >= three (32 bytes) cache lines.
-
- // Clean the beginning of space up to next cache line.
- for (int offs = 0; offs < cache_line_size; offs += 8) {
- stx(G0, to, offs);
- }
-
- // align to next cache line
- add(to, cache_line_size, to);
- and3(to, -cache_line_size, to);
-
- // Note: size left >= two (32 bytes) cache lines.
-
- // BIS should not be used to zero tail (64 bytes)
- // to avoid zeroing a header of the following object.
- sub(end, (cache_line_size*2)-8, end);
-
- Label bis_loop;
- bind(bis_loop);
- stxa(G0, to, G0, Assembler::ASI_ST_BLKINIT_PRIMARY);
- add(to, cache_line_size, to);
- cmp_and_brx_short(to, end, Assembler::lessUnsigned, Assembler::pt, bis_loop);
-
- // BIS needs membar.
- membar(Assembler::StoreLoad);
-
- add(end, (cache_line_size*2)-8, end); // restore end
- cmp_and_brx_short(to, end, Assembler::greaterEqualUnsigned, Assembler::pn, Ldone);
-
- // Clean the tail.
- bind(small_loop);
- stx(G0, to, 0);
- add(to, 8, to);
- cmp_and_brx_short(to, end, Assembler::lessUnsigned, Assembler::pt, small_loop);
- nop(); // Separate short branches
-}
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/assembler_sparc.hpp
--- a/src/cpu/sparc/vm/assembler_sparc.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/assembler_sparc.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,554 +25,13 @@
#ifndef CPU_SPARC_VM_ASSEMBLER_SPARC_HPP
#define CPU_SPARC_VM_ASSEMBLER_SPARC_HPP
-class BiasedLockingCounters;
-
-// promises that the system will not use traps 16-31
-#define ST_RESERVED_FOR_USER_0 0x10
-
-/* Written: David Ungar 4/19/97 */
-
-// Contains all the definitions needed for sparc assembly code generation.
-
-// Register aliases for parts of the system:
-
-// 64 bit values can be kept in g1-g5, o1-o5 and o7 and all 64 bits are safe
-// across context switches in V8+ ABI. Of course, there are no 64 bit regs
-// in V8 ABI. All 64 bits are preserved in V9 ABI for all registers.
-
-// g2-g4 are scratch registers called "application globals". Their
-// meaning is reserved to the "compilation system"--which means us!
-// They are are not supposed to be touched by ordinary C code, although
-// highly-optimized C code might steal them for temps. They are safe
-// across thread switches, and the ABI requires that they be safe
-// across function calls.
-//
-// g1 and g3 are touched by more modules. V8 allows g1 to be clobbered
-// across func calls, and V8+ also allows g5 to be clobbered across
-// func calls. Also, g1 and g5 can get touched while doing shared
-// library loading.
-//
-// We must not touch g7 (it is the thread-self register) and g6 is
-// reserved for certain tools. g0, of course, is always zero.
-//
-// (Sources: SunSoft Compilers Group, thread library engineers.)
-
-// %%%% The interpreter should be revisited to reduce global scratch regs.
-
-// This global always holds the current JavaThread pointer:
-
-REGISTER_DECLARATION(Register, G2_thread , G2);
-REGISTER_DECLARATION(Register, G6_heapbase , G6);
-
-// The following globals are part of the Java calling convention:
-
-REGISTER_DECLARATION(Register, G5_method , G5);
-REGISTER_DECLARATION(Register, G5_megamorphic_method , G5_method);
-REGISTER_DECLARATION(Register, G5_inline_cache_reg , G5_method);
-
-// The following globals are used for the new C1 & interpreter calling convention:
-REGISTER_DECLARATION(Register, Gargs , G4); // pointing to the last argument
-
-// This local is used to preserve G2_thread in the interpreter and in stubs:
-REGISTER_DECLARATION(Register, L7_thread_cache , L7);
-
-// These globals are used as scratch registers in the interpreter:
-
-REGISTER_DECLARATION(Register, Gframe_size , G1); // SAME REG as G1_scratch
-REGISTER_DECLARATION(Register, G1_scratch , G1); // also SAME
-REGISTER_DECLARATION(Register, G3_scratch , G3);
-REGISTER_DECLARATION(Register, G4_scratch , G4);
-
-// These globals are used as short-lived scratch registers in the compiler:
-
-REGISTER_DECLARATION(Register, Gtemp , G5);
-
-// JSR 292 fixed register usages:
-REGISTER_DECLARATION(Register, G5_method_type , G5);
-REGISTER_DECLARATION(Register, G3_method_handle , G3);
-REGISTER_DECLARATION(Register, L7_mh_SP_save , L7);
-
-// The compiler requires that G5_megamorphic_method is G5_inline_cache_klass,
-// because a single patchable "set" instruction (NativeMovConstReg,
-// or NativeMovConstPatching for compiler1) instruction
-// serves to set up either quantity, depending on whether the compiled
-// call site is an inline cache or is megamorphic. See the function
-// CompiledIC::set_to_megamorphic.
-//
-// If a inline cache targets an interpreted method, then the
-// G5 register will be used twice during the call. First,
-// the call site will be patched to load a compiledICHolder
-// into G5. (This is an ordered pair of ic_klass, method.)
-// The c2i adapter will first check the ic_klass, then load
-// G5_method with the method part of the pair just before
-// jumping into the interpreter.
-//
-// Note that G5_method is only the method-self for the interpreter,
-// and is logically unrelated to G5_megamorphic_method.
-//
-// Invariants on G2_thread (the JavaThread pointer):
-// - it should not be used for any other purpose anywhere
-// - it must be re-initialized by StubRoutines::call_stub()
-// - it must be preserved around every use of call_VM
-
-// We can consider using g2/g3/g4 to cache more values than the
-// JavaThread, such as the card-marking base or perhaps pointers into
-// Eden. It's something of a waste to use them as scratch temporaries,
-// since they are not supposed to be volatile. (Of course, if we find
-// that Java doesn't benefit from application globals, then we can just
-// use them as ordinary temporaries.)
-//
-// Since g1 and g5 (and/or g6) are the volatile (caller-save) registers,
-// it makes sense to use them routinely for procedure linkage,
-// whenever the On registers are not applicable. Examples: G5_method,
-// G5_inline_cache_klass, and a double handful of miscellaneous compiler
-// stubs. This means that compiler stubs, etc., should be kept to a
-// maximum of two or three G-register arguments.
-
-
-// stub frames
-
-REGISTER_DECLARATION(Register, Lentry_args , L0); // pointer to args passed to callee (interpreter) not stub itself
-
-// Interpreter frames
-
-#ifdef CC_INTERP
-REGISTER_DECLARATION(Register, Lstate , L0); // interpreter state object pointer
-REGISTER_DECLARATION(Register, L1_scratch , L1); // scratch
-REGISTER_DECLARATION(Register, Lmirror , L1); // mirror (for native methods only)
-REGISTER_DECLARATION(Register, L2_scratch , L2);
-REGISTER_DECLARATION(Register, L3_scratch , L3);
-REGISTER_DECLARATION(Register, L4_scratch , L4);
-REGISTER_DECLARATION(Register, Lscratch , L5); // C1 uses
-REGISTER_DECLARATION(Register, Lscratch2 , L6); // C1 uses
-REGISTER_DECLARATION(Register, L7_scratch , L7); // constant pool cache
-REGISTER_DECLARATION(Register, O5_savedSP , O5);
-REGISTER_DECLARATION(Register, I5_savedSP , I5); // Saved SP before bumping for locals. This is simply
- // a copy SP, so in 64-bit it's a biased value. The bias
- // is added and removed as needed in the frame code.
-// Interface to signature handler
-REGISTER_DECLARATION(Register, Llocals , L7); // pointer to locals for signature handler
-REGISTER_DECLARATION(Register, Lmethod , L6); // Method* when calling signature handler
-
-#else
-REGISTER_DECLARATION(Register, Lesp , L0); // expression stack pointer
-REGISTER_DECLARATION(Register, Lbcp , L1); // pointer to next bytecode
-REGISTER_DECLARATION(Register, Lmethod , L2);
-REGISTER_DECLARATION(Register, Llocals , L3);
-REGISTER_DECLARATION(Register, Largs , L3); // pointer to locals for signature handler
- // must match Llocals in asm interpreter
-REGISTER_DECLARATION(Register, Lmonitors , L4);
-REGISTER_DECLARATION(Register, Lbyte_code , L5);
-// When calling out from the interpreter we record SP so that we can remove any extra stack
-// space allocated during adapter transitions. This register is only live from the point
-// of the call until we return.
-REGISTER_DECLARATION(Register, Llast_SP , L5);
-REGISTER_DECLARATION(Register, Lscratch , L5);
-REGISTER_DECLARATION(Register, Lscratch2 , L6);
-REGISTER_DECLARATION(Register, LcpoolCache , L6); // constant pool cache
-
-REGISTER_DECLARATION(Register, O5_savedSP , O5);
-REGISTER_DECLARATION(Register, I5_savedSP , I5); // Saved SP before bumping for locals. This is simply
- // a copy SP, so in 64-bit it's a biased value. The bias
- // is added and removed as needed in the frame code.
-REGISTER_DECLARATION(Register, IdispatchTables , I4); // Base address of the bytecode dispatch tables
-REGISTER_DECLARATION(Register, IdispatchAddress , I3); // Register which saves the dispatch address for each bytecode
-REGISTER_DECLARATION(Register, ImethodDataPtr , I2); // Pointer to the current method data
-#endif /* CC_INTERP */
-
-// NOTE: Lscratch2 and LcpoolCache point to the same registers in
-// the interpreter code. If Lscratch2 needs to be used for some
-// purpose than LcpoolCache should be restore after that for
-// the interpreter to work right
-// (These assignments must be compatible with L7_thread_cache; see above.)
-
-// Since Lbcp points into the middle of the method object,
-// it is temporarily converted into a "bcx" during GC.
-
-// Exception processing
-// These registers are passed into exception handlers.
-// All exception handlers require the exception object being thrown.
-// In addition, an nmethod's exception handler must be passed
-// the address of the call site within the nmethod, to allow
-// proper selection of the applicable catch block.
-// (Interpreter frames use their own bcp() for this purpose.)
-//
-// The Oissuing_pc value is not always needed. When jumping to a
-// handler that is known to be interpreted, the Oissuing_pc value can be
-// omitted. An actual catch block in compiled code receives (from its
-// nmethod's exception handler) the thrown exception in the Oexception,
-// but it doesn't need the Oissuing_pc.
-//
-// If an exception handler (either interpreted or compiled)
-// discovers there is no applicable catch block, it updates
-// the Oissuing_pc to the continuation PC of its own caller,
-// pops back to that caller's stack frame, and executes that
-// caller's exception handler. Obviously, this process will
-// iterate until the control stack is popped back to a method
-// containing an applicable catch block. A key invariant is
-// that the Oissuing_pc value is always a value local to
-// the method whose exception handler is currently executing.
-//
-// Note: The issuing PC value is __not__ a raw return address (I7 value).
-// It is a "return pc", the address __following__ the call.
-// Raw return addresses are converted to issuing PCs by frame::pc(),
-// or by stubs. Issuing PCs can be used directly with PC range tables.
-//
-REGISTER_DECLARATION(Register, Oexception , O0); // exception being thrown
-REGISTER_DECLARATION(Register, Oissuing_pc , O1); // where the exception is coming from
-
-
-// These must occur after the declarations above
-#ifndef DONT_USE_REGISTER_DEFINES
-
-#define Gthread AS_REGISTER(Register, Gthread)
-#define Gmethod AS_REGISTER(Register, Gmethod)
-#define Gmegamorphic_method AS_REGISTER(Register, Gmegamorphic_method)
-#define Ginline_cache_reg AS_REGISTER(Register, Ginline_cache_reg)
-#define Gargs AS_REGISTER(Register, Gargs)
-#define Lthread_cache AS_REGISTER(Register, Lthread_cache)
-#define Gframe_size AS_REGISTER(Register, Gframe_size)
-#define Gtemp AS_REGISTER(Register, Gtemp)
-
-#ifdef CC_INTERP
-#define Lstate AS_REGISTER(Register, Lstate)
-#define Lesp AS_REGISTER(Register, Lesp)
-#define L1_scratch AS_REGISTER(Register, L1_scratch)
-#define Lmirror AS_REGISTER(Register, Lmirror)
-#define L2_scratch AS_REGISTER(Register, L2_scratch)
-#define L3_scratch AS_REGISTER(Register, L3_scratch)
-#define L4_scratch AS_REGISTER(Register, L4_scratch)
-#define Lscratch AS_REGISTER(Register, Lscratch)
-#define Lscratch2 AS_REGISTER(Register, Lscratch2)
-#define L7_scratch AS_REGISTER(Register, L7_scratch)
-#define Ostate AS_REGISTER(Register, Ostate)
-#else
-#define Lesp AS_REGISTER(Register, Lesp)
-#define Lbcp AS_REGISTER(Register, Lbcp)
-#define Lmethod AS_REGISTER(Register, Lmethod)
-#define Llocals AS_REGISTER(Register, Llocals)
-#define Lmonitors AS_REGISTER(Register, Lmonitors)
-#define Lbyte_code AS_REGISTER(Register, Lbyte_code)
-#define Lscratch AS_REGISTER(Register, Lscratch)
-#define Lscratch2 AS_REGISTER(Register, Lscratch2)
-#define LcpoolCache AS_REGISTER(Register, LcpoolCache)
-#endif /* ! CC_INTERP */
-
-#define Lentry_args AS_REGISTER(Register, Lentry_args)
-#define I5_savedSP AS_REGISTER(Register, I5_savedSP)
-#define O5_savedSP AS_REGISTER(Register, O5_savedSP)
-#define IdispatchAddress AS_REGISTER(Register, IdispatchAddress)
-#define ImethodDataPtr AS_REGISTER(Register, ImethodDataPtr)
-#define IdispatchTables AS_REGISTER(Register, IdispatchTables)
-
-#define Oexception AS_REGISTER(Register, Oexception)
-#define Oissuing_pc AS_REGISTER(Register, Oissuing_pc)
-
-
-#endif
-
-// Address is an abstraction used to represent a memory location.
-//
-// Note: A register location is represented via a Register, not
-// via an address for efficiency & simplicity reasons.
-
-class Address VALUE_OBJ_CLASS_SPEC {
- private:
- Register _base; // Base register.
- RegisterOrConstant _index_or_disp; // Index register or constant displacement.
- RelocationHolder _rspec;
-
- public:
- Address() : _base(noreg), _index_or_disp(noreg) {}
-
- Address(Register base, RegisterOrConstant index_or_disp)
- : _base(base),
- _index_or_disp(index_or_disp) {
- }
-
- Address(Register base, Register index)
- : _base(base),
- _index_or_disp(index) {
- }
-
- Address(Register base, int disp)
- : _base(base),
- _index_or_disp(disp) {
- }
-
-#ifdef ASSERT
- // ByteSize is only a class when ASSERT is defined, otherwise it's an int.
- Address(Register base, ByteSize disp)
- : _base(base),
- _index_or_disp(in_bytes(disp)) {
- }
-#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(); }
-
- 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; }
-
- RelocationHolder rspec(int offset) const {
- return offset == 0 ? _rspec : _rspec.plus(offset);
- }
-
- inline bool is_simm13(int offset = 0); // check disp+offset for overflow
-
- Address plus_disp(int plusdisp) const { // bump disp by a small amount
- assert(_index_or_disp.is_constant(), "must have a displacement");
- 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);
- a._base = a._base->after_save();
- return a;
- }
-
- Address after_restore() const {
- Address a = (*this);
- a._base = a._base->after_restore();
- return a;
- }
-
- // Convert the raw encoding form into the form expected by the
- // constructor for Address.
- static Address make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc);
-
- friend class Assembler;
-};
-
-
-class AddressLiteral VALUE_OBJ_CLASS_SPEC {
- private:
- address _address;
- RelocationHolder _rspec;
-
- RelocationHolder rspec_from_rtype(relocInfo::relocType rtype, address addr) {
- switch (rtype) {
- case relocInfo::external_word_type:
- return external_word_Relocation::spec(addr);
- case relocInfo::internal_word_type:
- return internal_word_Relocation::spec(addr);
-#ifdef _LP64
- case relocInfo::opt_virtual_call_type:
- return opt_virtual_call_Relocation::spec();
- case relocInfo::static_call_type:
- return static_call_Relocation::spec();
- case relocInfo::runtime_call_type:
- return runtime_call_Relocation::spec();
-#endif
- case relocInfo::none:
- return RelocationHolder();
- default:
- ShouldNotReachHere();
- return RelocationHolder();
- }
- }
-
- protected:
- // creation
- AddressLiteral() : _address(NULL), _rspec(NULL) {}
-
- public:
- AddressLiteral(address addr, RelocationHolder const& rspec)
- : _address(addr),
- _rspec(rspec) {}
-
- // Some constructors to avoid casting at the call site.
- AddressLiteral(jobject obj, RelocationHolder const& rspec)
- : _address((address) obj),
- _rspec(rspec) {}
-
- AddressLiteral(intptr_t value, RelocationHolder const& rspec)
- : _address((address) value),
- _rspec(rspec) {}
-
- AddressLiteral(address addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- // Some constructors to avoid casting at the call site.
- AddressLiteral(address* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- AddressLiteral(bool* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- AddressLiteral(const bool* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- AddressLiteral(signed char* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- AddressLiteral(int* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- AddressLiteral(intptr_t addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
-#ifdef _LP64
- // 32-bit complains about a multiple declaration for int*.
- AddressLiteral(intptr_t* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-#endif
-
- AddressLiteral(Metadata* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- AddressLiteral(Metadata** 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)) {}
-
- AddressLiteral(double* addr, relocInfo::relocType rtype = relocInfo::none)
- : _address((address) addr),
- _rspec(rspec_from_rtype(rtype, (address) addr)) {}
-
- intptr_t value() const { return (intptr_t) _address; }
- int low10() const;
-
- const relocInfo::relocType rtype() const { return _rspec.type(); }
- const RelocationHolder& rspec() const { return _rspec; }
-
- RelocationHolder rspec(int offset) const {
- return offset == 0 ? _rspec : _rspec.plus(offset);
- }
-};
-
-// 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(Metadata** 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));
-}
-
-
-
-// Argument is an abstraction used to represent an outgoing
-// actual argument or an incoming formal parameter, whether
-// it resides in memory or in a register, in a manner consistent
-// with the SPARC Application Binary Interface, or ABI. This is
-// often referred to as the native or C calling convention.
-
-class Argument VALUE_OBJ_CLASS_SPEC {
- private:
- int _number;
- bool _is_in;
-
- public:
-#ifdef _LP64
- enum {
- n_register_parameters = 6, // only 6 registers may contain integer parameters
- n_float_register_parameters = 16 // Can have up to 16 floating registers
- };
-#else
- enum {
- n_register_parameters = 6 // only 6 registers may contain integer parameters
- };
-#endif
-
- // creation
- Argument(int number, bool is_in) : _number(number), _is_in(is_in) {}
-
- int number() const { return _number; }
- bool is_in() const { return _is_in; }
- bool is_out() const { return !is_in(); }
-
- Argument successor() const { return Argument(number() + 1, is_in()); }
- Argument as_in() const { return Argument(number(), true ); }
- Argument as_out() const { return Argument(number(), false); }
-
- // locating register-based arguments:
- bool is_register() const { return _number < n_register_parameters; }
-
-#ifdef _LP64
- // locating Floating Point register-based arguments:
- bool is_float_register() const { return _number < n_float_register_parameters; }
-
- FloatRegister as_float_register() const {
- assert(is_float_register(), "must be a register argument");
- return as_FloatRegister(( number() *2 ) + 1);
- }
- FloatRegister as_double_register() const {
- assert(is_float_register(), "must be a register argument");
- return as_FloatRegister(( number() *2 ));
- }
-#endif
-
- Register as_register() const {
- assert(is_register(), "must be a register argument");
- return is_in() ? as_iRegister(number()) : as_oRegister(number());
- }
-
- // locating memory-based arguments
- Address as_address() const {
- assert(!is_register(), "must be a memory argument");
- return address_in_frame();
- }
-
- // When applied to a register-based argument, give the corresponding address
- // into the 6-word area "into which callee may store register arguments"
- // (This is a different place than the corresponding register-save area location.)
- Address address_in_frame() const;
-
- // debugging
- const char* name() const;
-
- friend class Assembler;
-};
-
+#include "asm/register.hpp"
// The SPARC Assembler: Pure assembler doing NO optimizations on the instruction
// level; i.e., what you write
// is what you get. The Assembler is generating code into a CodeBuffer.
class Assembler : public AbstractAssembler {
- protected:
-
- static void print_instruction(int inst);
- static int patched_branch(int dest_pos, int inst, int inst_pos);
- static int branch_destination(int inst, int pos);
-
-
friend class AbstractAssembler;
friend class AddressLiteral;
@@ -1216,8 +675,8 @@
AbstractAssembler::flush();
}
- inline void emit_long(int); // shadows AbstractAssembler::emit_long
- inline void emit_data(int x) { emit_long(x); }
+ inline void emit_int32(int); // shadows AbstractAssembler::emit_int32
+ inline void emit_data(int x) { emit_int32(x); }
inline void emit_data(int, RelocationHolder const&);
inline void emit_data(int, relocInfo::relocType rtype);
// helper for above fcns
@@ -1230,17 +689,14 @@
// pp 135 (addc was addx in v8)
inline void add(Register s1, Register s2, Register d );
- inline void add(Register s1, int simm13a, Register d, relocInfo::relocType rtype = relocInfo::none);
- inline void add(Register s1, int simm13a, Register d, RelocationHolder const& rspec);
- inline void add(Register s1, RegisterOrConstant s2, Register d, int offset = 0);
- inline void add(const Address& a, Register d, int offset = 0);
+ inline void add(Register s1, int simm13a, Register d );
- void addcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
- void addcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void addc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(addc_op3 ) | rs1(s1) | rs2(s2) ); }
- void addc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(addc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void addccc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(addc_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
- void addccc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(addc_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void addcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
+ void addcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void addc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 ) | rs1(s1) | rs2(s2) ); }
+ void addc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void addccc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
+ void addccc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(addc_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// pp 136
@@ -1293,76 +749,76 @@
// at address s1 is swapped with the data in d. If the values are not equal,
// the the contents of memory at s1 is loaded into d, without the swap.
- void casa( Register s1, Register s2, Register d, int ia = -1 ) { v9_only(); emit_long( op(ldst_op) | rd(d) | op3(casa_op3 ) | rs1(s1) | (ia == -1 ? immed(true) : imm_asi(ia)) | rs2(s2)); }
- void casxa( Register s1, Register s2, Register d, int ia = -1 ) { v9_only(); emit_long( op(ldst_op) | rd(d) | op3(casxa_op3) | rs1(s1) | (ia == -1 ? immed(true) : imm_asi(ia)) | rs2(s2)); }
+ void casa( Register s1, Register s2, Register d, int ia = -1 ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(casa_op3 ) | rs1(s1) | (ia == -1 ? immed(true) : imm_asi(ia)) | rs2(s2)); }
+ void casxa( Register s1, Register s2, Register d, int ia = -1 ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(casxa_op3) | rs1(s1) | (ia == -1 ? immed(true) : imm_asi(ia)) | rs2(s2)); }
// pp 152
- void udiv( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(udiv_op3 ) | rs1(s1) | rs2(s2)); }
- void udiv( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(udiv_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void sdiv( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sdiv_op3 ) | rs1(s1) | rs2(s2)); }
- void sdiv( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sdiv_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void udivcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(udiv_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); }
- void udivcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(udiv_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void sdivcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sdiv_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); }
- void sdivcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sdiv_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void udiv( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 ) | rs1(s1) | rs2(s2)); }
+ void udiv( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void sdiv( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 ) | rs1(s1) | rs2(s2)); }
+ void sdiv( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void udivcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); }
+ void udivcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(udiv_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void sdivcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 | cc_bit_op3) | rs1(s1) | rs2(s2)); }
+ void sdivcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sdiv_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// pp 155
- void done() { v9_only(); cti(); emit_long( op(arith_op) | fcn(0) | op3(done_op3) ); }
- void retry() { v9_only(); cti(); emit_long( op(arith_op) | fcn(1) | op3(retry_op3) ); }
+ void done() { v9_only(); cti(); emit_int32( op(arith_op) | fcn(0) | op3(done_op3) ); }
+ void retry() { v9_only(); cti(); emit_int32( op(arith_op) | fcn(1) | op3(retry_op3) ); }
// pp 156
- void fadd( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x40 + w) | fs2(s2, w)); }
- void fsub( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x44 + w) | fs2(s2, w)); }
+ void fadd( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x40 + w) | fs2(s2, w)); }
+ void fsub( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x44 + w) | fs2(s2, w)); }
// pp 157
- void fcmp( FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2) { v8_no_cc(cc); emit_long( op(arith_op) | cmpcc(cc) | op3(fpop2_op3) | fs1(s1, w) | opf(0x50 + w) | fs2(s2, w)); }
- void fcmpe( FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2) { v8_no_cc(cc); emit_long( op(arith_op) | cmpcc(cc) | op3(fpop2_op3) | fs1(s1, w) | opf(0x54 + w) | fs2(s2, w)); }
+ void fcmp( FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2) { v8_no_cc(cc); emit_int32( op(arith_op) | cmpcc(cc) | op3(fpop2_op3) | fs1(s1, w) | opf(0x50 + w) | fs2(s2, w)); }
+ void fcmpe( FloatRegisterImpl::Width w, CC cc, FloatRegister s1, FloatRegister s2) { v8_no_cc(cc); emit_int32( op(arith_op) | cmpcc(cc) | op3(fpop2_op3) | fs1(s1, w) | opf(0x54 + w) | fs2(s2, w)); }
// pp 159
- 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)); }
+ void ftox( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_int32( 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_int32( op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(fpop1_op3) | opf(0xd0 + w) | fs2(s, w)); }
// pp 160
- void ftof( FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s, FloatRegister d ) { emit_long( op(arith_op) | fd(d, dw) | op3(fpop1_op3) | opf(0xc0 + sw + dw*4) | fs2(s, sw)); }
+ void ftof( FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, dw) | op3(fpop1_op3) | opf(0xc0 + sw + dw*4) | fs2(s, sw)); }
// 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, 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)); }
+ void fxtof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_int32( 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_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0xc0 + w*4) | fs2(s, FloatRegisterImpl::S)); }
// pp 162
- void fmov( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v8_s_only(w); emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x00 + w) | fs2(s, w)); }
+ void fmov( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v8_s_only(w); emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x00 + w) | fs2(s, w)); }
- void fneg( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v8_s_only(w); emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x04 + w) | fs2(s, w)); }
+ void fneg( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v8_s_only(w); emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x04 + w) | fs2(s, w)); }
// page 144 sparc v8 architecture (double prec works on v8 if the source and destination registers are the same). fnegs is the only instruction available
// on v8 to do negation of single, double and quad precision floats.
- void fneg( FloatRegisterImpl::Width w, FloatRegister sd ) { if (VM_Version::v9_instructions_work()) emit_long( op(arith_op) | fd(sd, w) | op3(fpop1_op3) | opf(0x04 + w) | fs2(sd, w)); else emit_long( op(arith_op) | fd(sd, w) | op3(fpop1_op3) | opf(0x05) | fs2(sd, w)); }
+ void fneg( FloatRegisterImpl::Width w, FloatRegister sd ) { if (VM_Version::v9_instructions_work()) emit_int32( op(arith_op) | fd(sd, w) | op3(fpop1_op3) | opf(0x04 + w) | fs2(sd, w)); else emit_int32( op(arith_op) | fd(sd, w) | op3(fpop1_op3) | opf(0x05) | fs2(sd, w)); }
- void fabs( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v8_s_only(w); emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x08 + w) | fs2(s, w)); }
+ void fabs( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v8_s_only(w); emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x08 + w) | fs2(s, w)); }
// page 144 sparc v8 architecture (double prec works on v8 if the source and destination registers are the same). fabss is the only instruction available
// on v8 to do abs operation on single/double/quad precision floats.
- void fabs( FloatRegisterImpl::Width w, FloatRegister sd ) { if (VM_Version::v9_instructions_work()) emit_long( op(arith_op) | fd(sd, w) | op3(fpop1_op3) | opf(0x08 + w) | fs2(sd, w)); else emit_long( op(arith_op) | fd(sd, w) | op3(fpop1_op3) | opf(0x09) | fs2(sd, w)); }
+ void fabs( FloatRegisterImpl::Width w, FloatRegister sd ) { if (VM_Version::v9_instructions_work()) emit_int32( op(arith_op) | fd(sd, w) | op3(fpop1_op3) | opf(0x08 + w) | fs2(sd, w)); else emit_int32( op(arith_op) | fd(sd, w) | op3(fpop1_op3) | opf(0x09) | fs2(sd, w)); }
// pp 163
- void fmul( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x48 + w) | fs2(s2, w)); }
- void fmul( FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_long( op(arith_op) | fd(d, dw) | op3(fpop1_op3) | fs1(s1, sw) | opf(0x60 + sw + dw*4) | fs2(s2, sw)); }
- void fdiv( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x4c + w) | fs2(s2, w)); }
+ void fmul( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x48 + w) | fs2(s2, w)); }
+ void fmul( FloatRegisterImpl::Width sw, FloatRegisterImpl::Width dw, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, dw) | op3(fpop1_op3) | fs1(s1, sw) | opf(0x60 + sw + dw*4) | fs2(s2, sw)); }
+ void fdiv( FloatRegisterImpl::Width w, FloatRegister s1, FloatRegister s2, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | fs1(s1, w) | opf(0x4c + w) | fs2(s2, w)); }
// pp 164
- void fsqrt( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x28 + w) | fs2(s, w)); }
+ void fsqrt( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_int32( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x28 + w) | fs2(s, w)); }
// pp 165
@@ -1371,22 +827,22 @@
// pp 167
- void flushw() { v9_only(); emit_long( op(arith_op) | op3(flushw_op3) ); }
+ void flushw() { v9_only(); emit_int32( op(arith_op) | op3(flushw_op3) ); }
// pp 168
- void illtrap( int const22a) { if (const22a != 0) v9_only(); emit_long( op(branch_op) | u_field(const22a, 21, 0) ); }
+ void illtrap( int const22a) { if (const22a != 0) v9_only(); emit_int32( op(branch_op) | u_field(const22a, 21, 0) ); }
// v8 unimp == illtrap(0)
// pp 169
- void impdep1( int id1, int const19a ) { v9_only(); emit_long( op(arith_op) | fcn(id1) | op3(impdep1_op3) | u_field(const19a, 18, 0)); }
- void impdep2( int id1, int const19a ) { v9_only(); emit_long( op(arith_op) | fcn(id1) | op3(impdep2_op3) | u_field(const19a, 18, 0)); }
+ void impdep1( int id1, int const19a ) { v9_only(); emit_int32( op(arith_op) | fcn(id1) | op3(impdep1_op3) | u_field(const19a, 18, 0)); }
+ void impdep2( int id1, int const19a ) { v9_only(); emit_int32( op(arith_op) | fcn(id1) | op3(impdep2_op3) | u_field(const19a, 18, 0)); }
// pp 149 (v8)
- void cpop1( int opc, int cr1, int cr2, int crd ) { v8_only(); emit_long( op(arith_op) | fcn(crd) | op3(impdep1_op3) | u_field(cr1, 18, 14) | opf(opc) | u_field(cr2, 4, 0)); }
- void cpop2( int opc, int cr1, int cr2, int crd ) { v8_only(); emit_long( op(arith_op) | fcn(crd) | op3(impdep2_op3) | u_field(cr1, 18, 14) | opf(opc) | u_field(cr2, 4, 0)); }
+ void cpop1( int opc, int cr1, int cr2, int crd ) { v8_only(); emit_int32( op(arith_op) | fcn(crd) | op3(impdep1_op3) | u_field(cr1, 18, 14) | opf(opc) | u_field(cr2, 4, 0)); }
+ void cpop2( int opc, int cr1, int cr2, int crd ) { v8_only(); emit_int32( op(arith_op) | fcn(crd) | op3(impdep2_op3) | u_field(cr1, 18, 14) | opf(opc) | u_field(cr2, 4, 0)); }
// pp 170
@@ -1395,12 +851,9 @@
// 171
- inline void ldf(FloatRegisterImpl::Width w, Register s1, RegisterOrConstant s2, FloatRegister d);
inline void ldf(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d);
inline void ldf(FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d, RelocationHolder const& rspec = RelocationHolder());
- inline void ldf(FloatRegisterImpl::Width w, const Address& a, FloatRegister d, int offset = 0);
-
inline void ldfsr( Register s1, Register s2 );
inline void ldfsr( Register s1, int simm13a);
@@ -1419,8 +872,8 @@
// 173
- void ldfa( FloatRegisterImpl::Width w, Register s1, Register s2, int ia, FloatRegister d ) { v9_only(); emit_long( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3 | alt_bit_op3, w) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void ldfa( FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d ) { v9_only(); emit_long( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3 | alt_bit_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void ldfa( FloatRegisterImpl::Width w, Register s1, Register s2, int ia, FloatRegister d ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3 | alt_bit_op3, w) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void ldfa( FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3 | alt_bit_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// pp 175, lduw is ld on v8
@@ -1438,54 +891,27 @@
inline void lduw( Register s1, int simm13a, Register d);
inline void ldx( Register s1, Register s2, Register d );
inline void ldx( Register s1, int simm13a, Register d);
- inline void ld( Register s1, Register s2, Register d );
- inline void ld( Register s1, int simm13a, Register d);
inline void ldd( Register s1, Register s2, Register d );
inline void ldd( Register s1, int simm13a, Register d);
-#ifdef ASSERT
- // ByteSize is only a class when ASSERT is defined, otherwise it's an int.
- inline void ld( Register s1, ByteSize simm13a, Register d);
-#endif
-
- inline void ldsb(const Address& a, Register d, int offset = 0);
- inline void ldsh(const Address& a, Register d, int offset = 0);
- inline void ldsw(const Address& a, Register d, int offset = 0);
- inline void ldub(const Address& a, Register d, int offset = 0);
- inline void lduh(const Address& a, Register d, int offset = 0);
- inline void lduw(const Address& a, Register d, int offset = 0);
- inline void ldx( const Address& a, Register d, int offset = 0);
- inline void ld( const Address& a, Register d, int offset = 0);
- inline void ldd( const Address& a, Register d, int offset = 0);
-
- inline void ldub( Register s1, RegisterOrConstant s2, Register d );
- inline void ldsb( Register s1, RegisterOrConstant s2, Register d );
- inline void lduh( Register s1, RegisterOrConstant s2, Register d );
- inline void ldsh( Register s1, RegisterOrConstant s2, Register d );
- inline void lduw( Register s1, RegisterOrConstant s2, Register d );
- inline void ldsw( Register s1, RegisterOrConstant s2, Register d );
- inline void ldx( Register s1, RegisterOrConstant s2, Register d );
- inline void ld( Register s1, RegisterOrConstant s2, Register d );
- inline void ldd( Register s1, RegisterOrConstant s2, Register d );
-
// pp 177
- void ldsba( Register s1, Register s2, int ia, Register d ) { emit_long( op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void ldsba( Register s1, int simm13a, Register d ) { emit_long( op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void ldsha( Register s1, Register s2, int ia, Register d ) { emit_long( op(ldst_op) | rd(d) | op3(ldsh_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void ldsha( Register s1, int simm13a, Register d ) { emit_long( op(ldst_op) | rd(d) | op3(ldsh_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void ldswa( Register s1, Register s2, int ia, Register d ) { v9_only(); emit_long( op(ldst_op) | rd(d) | op3(ldsw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void ldswa( Register s1, int simm13a, Register d ) { v9_only(); emit_long( op(ldst_op) | rd(d) | op3(ldsw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void lduba( Register s1, Register s2, int ia, Register d ) { emit_long( op(ldst_op) | rd(d) | op3(ldub_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void lduba( Register s1, int simm13a, Register d ) { emit_long( op(ldst_op) | rd(d) | op3(ldub_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void lduha( Register s1, Register s2, int ia, Register d ) { emit_long( op(ldst_op) | rd(d) | op3(lduh_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void lduha( Register s1, int simm13a, Register d ) { emit_long( op(ldst_op) | rd(d) | op3(lduh_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void lduwa( Register s1, Register s2, int ia, Register d ) { emit_long( op(ldst_op) | rd(d) | op3(lduw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void lduwa( Register s1, int simm13a, Register d ) { emit_long( op(ldst_op) | rd(d) | op3(lduw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void ldxa( Register s1, Register s2, int ia, Register d ) { v9_only(); emit_long( op(ldst_op) | rd(d) | op3(ldx_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void ldxa( Register s1, int simm13a, Register d ) { v9_only(); emit_long( op(ldst_op) | rd(d) | op3(ldx_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void ldda( Register s1, Register s2, int ia, Register d ) { v9_dep(); emit_long( op(ldst_op) | rd(d) | op3(ldd_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void ldda( Register s1, int simm13a, Register d ) { v9_dep(); emit_long( op(ldst_op) | rd(d) | op3(ldd_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void ldsba( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void ldsba( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsb_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void ldsha( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsh_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void ldsha( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldsh_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void ldswa( Register s1, Register s2, int ia, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldsw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void ldswa( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldsw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void lduba( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldub_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void lduba( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldub_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void lduha( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduh_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void lduha( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduh_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void lduwa( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void lduwa( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(lduw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void ldxa( Register s1, Register s2, int ia, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldx_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void ldxa( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldx_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void ldda( Register s1, Register s2, int ia, Register d ) { v9_dep(); emit_int32( op(ldst_op) | rd(d) | op3(ldd_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void ldda( Register s1, int simm13a, Register d ) { v9_dep(); emit_int32( op(ldst_op) | rd(d) | op3(ldd_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// pp 179
@@ -1494,113 +920,111 @@
// pp 180
- void ldstuba( Register s1, Register s2, int ia, Register d ) { emit_long( op(ldst_op) | rd(d) | op3(ldstub_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void ldstuba( Register s1, int simm13a, Register d ) { emit_long( op(ldst_op) | rd(d) | op3(ldstub_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void ldstuba( Register s1, Register s2, int ia, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldstub_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void ldstuba( Register s1, int simm13a, Register d ) { emit_int32( op(ldst_op) | rd(d) | op3(ldstub_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// pp 181
- void and3( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(and_op3 ) | rs1(s1) | rs2(s2) ); }
- void and3( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(and_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void andcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(and_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
- void andcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(and_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void andn( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(andn_op3 ) | rs1(s1) | rs2(s2) ); }
- void andn( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(andn_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void andn( Register s1, RegisterOrConstant s2, Register d);
- void andncc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(andn_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
- void andncc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(andn_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void or3( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(or_op3 ) | rs1(s1) | rs2(s2) ); }
- void or3( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(or_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void orcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(or_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
- void orcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(or_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void orn( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(orn_op3) | rs1(s1) | rs2(s2) ); }
- void orn( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(orn_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void orncc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(orn_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
- void orncc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(orn_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void xor3( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(xor_op3 ) | rs1(s1) | rs2(s2) ); }
- void xor3( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(xor_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void xorcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(xor_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
- void xorcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(xor_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void xnor( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(xnor_op3 ) | rs1(s1) | rs2(s2) ); }
- void xnor( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(xnor_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void xnorcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(xnor_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
- void xnorcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(xnor_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void and3( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 ) | rs1(s1) | rs2(s2) ); }
+ void and3( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void andcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
+ void andcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(and_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void andn( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 ) | rs1(s1) | rs2(s2) ); }
+ void andn( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void andncc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
+ void andncc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(andn_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void or3( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 ) | rs1(s1) | rs2(s2) ); }
+ void or3( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void orcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
+ void orcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(or_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void orn( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3) | rs1(s1) | rs2(s2) ); }
+ void orn( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void orncc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
+ void orncc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(orn_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void xor3( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 ) | rs1(s1) | rs2(s2) ); }
+ void xor3( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void xorcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
+ void xorcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xor_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void xnor( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 ) | rs1(s1) | rs2(s2) ); }
+ void xnor( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void xnorcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
+ void xnorcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(xnor_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// pp 183
- void membar( Membar_mask_bits const7a ) { v9_only(); emit_long( op(arith_op) | op3(membar_op3) | rs1(O7) | immed(true) | u_field( int(const7a), 6, 0)); }
+ void membar( Membar_mask_bits const7a ) { v9_only(); emit_int32( op(arith_op) | op3(membar_op3) | rs1(O7) | immed(true) | u_field( int(const7a), 6, 0)); }
// pp 185
- void fmov( FloatRegisterImpl::Width w, Condition c, bool floatCC, CC cca, FloatRegister s2, FloatRegister d ) { v9_only(); emit_long( op(arith_op) | fd(d, w) | op3(fpop2_op3) | cond_mov(c) | opf_cc(cca, floatCC) | opf_low6(w) | fs2(s2, w)); }
+ void fmov( FloatRegisterImpl::Width w, Condition c, bool floatCC, CC cca, FloatRegister s2, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fpop2_op3) | cond_mov(c) | opf_cc(cca, floatCC) | opf_low6(w) | fs2(s2, w)); }
// pp 189
- void fmov( FloatRegisterImpl::Width w, RCondition c, Register s1, FloatRegister s2, FloatRegister d ) { v9_only(); emit_long( op(arith_op) | fd(d, w) | op3(fpop2_op3) | rs1(s1) | rcond(c) | opf_low5(4 + w) | fs2(s2, w)); }
+ void fmov( FloatRegisterImpl::Width w, RCondition c, Register s1, FloatRegister s2, FloatRegister d ) { v9_only(); emit_int32( op(arith_op) | fd(d, w) | op3(fpop2_op3) | rs1(s1) | rcond(c) | opf_low5(4 + w) | fs2(s2, w)); }
// pp 191
- void movcc( Condition c, bool floatCC, CC cca, Register s2, Register d ) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(movcc_op3) | mov_cc(cca, floatCC) | cond_mov(c) | rs2(s2) ); }
- void movcc( Condition c, bool floatCC, CC cca, int simm11a, Register d ) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(movcc_op3) | mov_cc(cca, floatCC) | cond_mov(c) | immed(true) | simm(simm11a, 11) ); }
+ void movcc( Condition c, bool floatCC, CC cca, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movcc_op3) | mov_cc(cca, floatCC) | cond_mov(c) | rs2(s2) ); }
+ void movcc( Condition c, bool floatCC, CC cca, int simm11a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movcc_op3) | mov_cc(cca, floatCC) | cond_mov(c) | immed(true) | simm(simm11a, 11) ); }
// pp 195
- void movr( RCondition c, Register s1, Register s2, Register d ) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(movr_op3) | rs1(s1) | rcond(c) | rs2(s2) ); }
- void movr( RCondition c, Register s1, int simm10a, Register d ) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(movr_op3) | rs1(s1) | rcond(c) | immed(true) | simm(simm10a, 10) ); }
+ void movr( RCondition c, Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movr_op3) | rs1(s1) | rcond(c) | rs2(s2) ); }
+ void movr( RCondition c, Register s1, int simm10a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(movr_op3) | rs1(s1) | rcond(c) | immed(true) | simm(simm10a, 10) ); }
// pp 196
- void mulx( Register s1, Register s2, Register d ) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(mulx_op3 ) | rs1(s1) | rs2(s2) ); }
- void mulx( Register s1, int simm13a, Register d ) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(mulx_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void sdivx( Register s1, Register s2, Register d ) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(sdivx_op3) | rs1(s1) | rs2(s2) ); }
- void sdivx( Register s1, int simm13a, Register d ) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(sdivx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void udivx( Register s1, Register s2, Register d ) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(udivx_op3) | rs1(s1) | rs2(s2) ); }
- void udivx( Register s1, int simm13a, Register d ) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(udivx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void mulx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(mulx_op3 ) | rs1(s1) | rs2(s2) ); }
+ void mulx( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(mulx_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void sdivx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sdivx_op3) | rs1(s1) | rs2(s2) ); }
+ void sdivx( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sdivx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void udivx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(udivx_op3) | rs1(s1) | rs2(s2) ); }
+ void udivx( Register s1, int simm13a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(udivx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// pp 197
- void umul( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(umul_op3 ) | rs1(s1) | rs2(s2) ); }
- void umul( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(umul_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void smul( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(smul_op3 ) | rs1(s1) | rs2(s2) ); }
- void smul( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(smul_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void umulcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(umul_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
- void umulcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(umul_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void smulcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(smul_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
- void smulcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(smul_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void umul( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 ) | rs1(s1) | rs2(s2) ); }
+ void umul( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void smul( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 ) | rs1(s1) | rs2(s2) ); }
+ void smul( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void umulcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
+ void umulcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(umul_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void smulcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
+ void smulcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(smul_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// pp 199
- void mulscc( Register s1, Register s2, Register d ) { v9_dep(); emit_long( op(arith_op) | rd(d) | op3(mulscc_op3) | rs1(s1) | rs2(s2) ); }
- void mulscc( Register s1, int simm13a, Register d ) { v9_dep(); emit_long( op(arith_op) | rd(d) | op3(mulscc_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void mulscc( Register s1, Register s2, Register d ) { v9_dep(); emit_int32( op(arith_op) | rd(d) | op3(mulscc_op3) | rs1(s1) | rs2(s2) ); }
+ void mulscc( Register s1, int simm13a, Register d ) { v9_dep(); emit_int32( op(arith_op) | rd(d) | op3(mulscc_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// pp 201
- void nop() { emit_long( op(branch_op) | op2(sethi_op2) ); }
+ void nop() { emit_int32( op(branch_op) | op2(sethi_op2) ); }
// pp 202
- void popc( Register s, Register d) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(popc_op3) | rs2(s)); }
- void popc( int simm13a, Register d) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(popc_op3) | immed(true) | simm(simm13a, 13)); }
+ void popc( Register s, Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(popc_op3) | rs2(s)); }
+ void popc( int simm13a, Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(popc_op3) | immed(true) | simm(simm13a, 13)); }
// pp 203
- void prefetch( Register s1, Register s2, PrefetchFcn f);
- void prefetch( Register s1, int simm13a, PrefetchFcn f);
- void prefetcha( Register s1, Register s2, int ia, PrefetchFcn f ) { v9_only(); emit_long( op(ldst_op) | fcn(f) | op3(prefetch_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void prefetcha( Register s1, int simm13a, PrefetchFcn f ) { v9_only(); emit_long( op(ldst_op) | fcn(f) | op3(prefetch_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void prefetch( Register s1, Register s2, PrefetchFcn f) { v9_only(); emit_int32( op(ldst_op) | fcn(f) | op3(prefetch_op3) | rs1(s1) | rs2(s2) ); }
+ void prefetch( Register s1, int simm13a, PrefetchFcn f) { v9_only(); emit_data( op(ldst_op) | fcn(f) | op3(prefetch_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
- inline void prefetch(const Address& a, PrefetchFcn F, int offset = 0);
+ void prefetcha( Register s1, Register s2, int ia, PrefetchFcn f ) { v9_only(); emit_int32( op(ldst_op) | fcn(f) | op3(prefetch_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void prefetcha( Register s1, int simm13a, PrefetchFcn f ) { v9_only(); emit_int32( op(ldst_op) | fcn(f) | op3(prefetch_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// pp 208
// not implementing read privileged register
- inline void rdy( Register d) { v9_dep(); emit_long( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(0, 18, 14)); }
- inline void rdccr( Register d) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(2, 18, 14)); }
- inline void rdasi( Register d) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(3, 18, 14)); }
- inline void rdtick( Register d) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(4, 18, 14)); } // Spoon!
- inline void rdpc( Register d) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(5, 18, 14)); }
- inline void rdfprs( Register d) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(6, 18, 14)); }
+ inline void rdy( Register d) { v9_dep(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(0, 18, 14)); }
+ inline void rdccr( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(2, 18, 14)); }
+ inline void rdasi( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(3, 18, 14)); }
+ inline void rdtick( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(4, 18, 14)); } // Spoon!
+ inline void rdpc( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(5, 18, 14)); }
+ inline void rdfprs( Register d) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(rdreg_op3) | u_field(6, 18, 14)); }
// pp 213
@@ -1609,54 +1033,52 @@
// pp 214
- void save( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(save_op3) | rs1(s1) | rs2(s2) ); }
+ void save( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(save_op3) | rs1(s1) | rs2(s2) ); }
void save( Register s1, int simm13a, Register d ) {
// make sure frame is at least large enough for the register save area
assert(-simm13a >= 16 * wordSize, "frame too small");
- emit_long( op(arith_op) | rd(d) | op3(save_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) );
+ emit_int32( op(arith_op) | rd(d) | op3(save_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) );
}
- void restore( Register s1 = G0, Register s2 = G0, Register d = G0 ) { emit_long( op(arith_op) | rd(d) | op3(restore_op3) | rs1(s1) | rs2(s2) ); }
- void restore( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(restore_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void restore( Register s1 = G0, Register s2 = G0, Register d = G0 ) { emit_int32( op(arith_op) | rd(d) | op3(restore_op3) | rs1(s1) | rs2(s2) ); }
+ void restore( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(restore_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// pp 216
- void saved() { v9_only(); emit_long( op(arith_op) | fcn(0) | op3(saved_op3)); }
- void restored() { v9_only(); emit_long( op(arith_op) | fcn(1) | op3(saved_op3)); }
+ void saved() { v9_only(); emit_int32( op(arith_op) | fcn(0) | op3(saved_op3)); }
+ void restored() { v9_only(); emit_int32( op(arith_op) | fcn(1) | op3(saved_op3)); }
// pp 217
inline void sethi( int imm22a, Register d, RelocationHolder const& rspec = RelocationHolder() );
// pp 218
- void sll( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(0) | rs2(s2) ); }
- void sll( Register s1, int imm5a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); }
- void srl( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(0) | rs2(s2) ); }
- void srl( Register s1, int imm5a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); }
- void sra( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(0) | rs2(s2) ); }
- void sra( Register s1, int imm5a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); }
+ void sll( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(0) | rs2(s2) ); }
+ void sll( Register s1, int imm5a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); }
+ void srl( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(0) | rs2(s2) ); }
+ void srl( Register s1, int imm5a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); }
+ void sra( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(0) | rs2(s2) ); }
+ void sra( Register s1, int imm5a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(0) | immed(true) | u_field(imm5a, 4, 0) ); }
- void sllx( Register s1, Register s2, Register d ) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(1) | rs2(s2) ); }
- void sllx( Register s1, int imm6a, Register d ) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); }
- void srlx( Register s1, Register s2, Register d ) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(1) | rs2(s2) ); }
- void srlx( Register s1, int imm6a, Register d ) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); }
- void srax( Register s1, Register s2, Register d ) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(1) | rs2(s2) ); }
- void srax( Register s1, int imm6a, Register d ) { v9_only(); emit_long( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); }
+ void sllx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(1) | rs2(s2) ); }
+ void sllx( Register s1, int imm6a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sll_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); }
+ void srlx( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(1) | rs2(s2) ); }
+ void srlx( Register s1, int imm6a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(srl_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); }
+ void srax( Register s1, Register s2, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(1) | rs2(s2) ); }
+ void srax( Register s1, int imm6a, Register d ) { v9_only(); emit_int32( op(arith_op) | rd(d) | op3(sra_op3) | rs1(s1) | sx(1) | immed(true) | u_field(imm6a, 5, 0) ); }
// pp 220
- void sir( int simm13a ) { emit_long( op(arith_op) | fcn(15) | op3(sir_op3) | immed(true) | simm(simm13a, 13)); }
+ void sir( int simm13a ) { emit_int32( op(arith_op) | fcn(15) | op3(sir_op3) | immed(true) | simm(simm13a, 13)); }
// pp 221
- void stbar() { emit_long( op(arith_op) | op3(membar_op3) | u_field(15, 18, 14)); }
+ void stbar() { emit_int32( op(arith_op) | op3(membar_op3) | u_field(15, 18, 14)); }
// pp 222
- inline void stf( FloatRegisterImpl::Width w, FloatRegister d, Register s1, RegisterOrConstant s2);
inline void stf( FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2);
inline void stf( FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a);
- inline void stf( FloatRegisterImpl::Width w, FloatRegister d, const Address& a, int offset = 0);
inline void stfsr( Register s1, Register s2 );
inline void stfsr( Register s1, int simm13a);
@@ -1665,8 +1087,8 @@
// pp 224
- void stfa( FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2, int ia ) { v9_only(); emit_long( op(ldst_op) | fd(d, w) | alt_op3(stf_op3 | alt_bit_op3, w) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void stfa( FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a ) { v9_only(); emit_long( op(ldst_op) | fd(d, w) | alt_op3(stf_op3 | alt_bit_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void stfa( FloatRegisterImpl::Width w, FloatRegister d, Register s1, Register s2, int ia ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(stf_op3 | alt_bit_op3, w) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void stfa( FloatRegisterImpl::Width w, FloatRegister d, Register s1, int simm13a ) { v9_only(); emit_int32( op(ldst_op) | fd(d, w) | alt_op3(stf_op3 | alt_bit_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// p 226
@@ -1676,44 +1098,23 @@
inline void sth( Register d, Register s1, int simm13a);
inline void stw( Register d, Register s1, Register s2 );
inline void stw( Register d, Register s1, int simm13a);
- inline void st( Register d, Register s1, Register s2 );
- inline void st( Register d, Register s1, int simm13a);
inline void stx( Register d, Register s1, Register s2 );
inline void stx( Register d, Register s1, int simm13a);
inline void std( Register d, Register s1, Register s2 );
inline void std( Register d, Register s1, int simm13a);
-#ifdef ASSERT
- // ByteSize is only a class when ASSERT is defined, otherwise it's an int.
- inline void st( Register d, Register s1, ByteSize simm13a);
-#endif
-
- inline void stb( Register d, const Address& a, int offset = 0 );
- inline void sth( Register d, const Address& a, int offset = 0 );
- inline void stw( Register d, const Address& a, int offset = 0 );
- inline void stx( Register d, const Address& a, int offset = 0 );
- inline void st( Register d, const Address& a, int offset = 0 );
- inline void std( Register d, const Address& a, int offset = 0 );
-
- inline void stb( Register d, Register s1, RegisterOrConstant s2 );
- inline void sth( Register d, Register s1, RegisterOrConstant s2 );
- inline void stw( Register d, Register s1, RegisterOrConstant s2 );
- inline void stx( Register d, Register s1, RegisterOrConstant s2 );
- inline void std( Register d, Register s1, RegisterOrConstant s2 );
- inline void st( Register d, Register s1, RegisterOrConstant s2 );
-
// pp 177
- void stba( Register d, Register s1, Register s2, int ia ) { emit_long( op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void stba( Register d, Register s1, int simm13a ) { emit_long( op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void stha( Register d, Register s1, Register s2, int ia ) { emit_long( op(ldst_op) | rd(d) | op3(sth_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void stha( Register d, Register s1, int simm13a ) { emit_long( op(ldst_op) | rd(d) | op3(sth_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void stwa( Register d, Register s1, Register s2, int ia ) { emit_long( op(ldst_op) | rd(d) | op3(stw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void stwa( Register d, Register s1, int simm13a ) { emit_long( op(ldst_op) | rd(d) | op3(stw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void stxa( Register d, Register s1, Register s2, int ia ) { v9_only(); emit_long( op(ldst_op) | rd(d) | op3(stx_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void stxa( Register d, Register s1, int simm13a ) { v9_only(); emit_long( op(ldst_op) | rd(d) | op3(stx_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void stda( Register d, Register s1, Register s2, int ia ) { emit_long( op(ldst_op) | rd(d) | op3(std_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void stda( Register d, Register s1, int simm13a ) { emit_long( op(ldst_op) | rd(d) | op3(std_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void stba( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void stba( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(stb_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void stha( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(sth_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void stha( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(sth_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void stwa( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(stw_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void stwa( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(stw_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void stxa( Register d, Register s1, Register s2, int ia ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(stx_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void stxa( Register d, Register s1, int simm13a ) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(stx_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void stda( Register d, Register s1, Register s2, int ia ) { emit_int32( op(ldst_op) | rd(d) | op3(std_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void stda( Register d, Register s1, int simm13a ) { emit_int32( op(ldst_op) | rd(d) | op3(std_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// pp 97 (v8)
@@ -1728,85 +1129,72 @@
// pp 230
- void sub( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sub_op3 ) | rs1(s1) | rs2(s2) ); }
- void sub( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sub_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
-
- // Note: offset is added to s2.
- inline void sub(Register s1, RegisterOrConstant s2, Register d, int offset = 0);
+ void sub( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 ) | rs1(s1) | rs2(s2) ); }
+ void sub( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void subcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3 ) | rs1(s1) | rs2(s2) ); }
- void subcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void subc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(subc_op3 ) | rs1(s1) | rs2(s2) ); }
- void subc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(subc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void subccc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(subc_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
- void subccc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(subc_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void subcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3 ) | rs1(s1) | rs2(s2) ); }
+ void subcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(sub_op3 | cc_bit_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void subc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 ) | rs1(s1) | rs2(s2) ); }
+ void subc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void subccc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 | cc_bit_op3) | rs1(s1) | rs2(s2) ); }
+ void subccc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(subc_op3 | cc_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// pp 231
inline void swap( Register s1, Register s2, Register d );
inline void swap( Register s1, int simm13a, Register d);
- inline void swap( Address& a, Register d, int offset = 0 );
// pp 232
- void swapa( Register s1, Register s2, int ia, Register d ) { v9_dep(); emit_long( op(ldst_op) | rd(d) | op3(swap_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
- void swapa( Register s1, int simm13a, Register d ) { v9_dep(); emit_long( op(ldst_op) | rd(d) | op3(swap_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void swapa( Register s1, Register s2, int ia, Register d ) { v9_dep(); emit_int32( op(ldst_op) | rd(d) | op3(swap_op3 | alt_bit_op3) | rs1(s1) | imm_asi(ia) | rs2(s2) ); }
+ void swapa( Register s1, int simm13a, Register d ) { v9_dep(); emit_int32( op(ldst_op) | rd(d) | op3(swap_op3 | alt_bit_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// pp 234, note op in book is wrong, see pp 268
- void taddcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(taddcc_op3 ) | rs1(s1) | rs2(s2) ); }
- void taddcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(taddcc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void taddcctv( Register s1, Register s2, Register d ) { v9_dep(); emit_long( op(arith_op) | rd(d) | op3(taddcctv_op3) | rs1(s1) | rs2(s2) ); }
- void taddcctv( Register s1, int simm13a, Register d ) { v9_dep(); emit_long( op(arith_op) | rd(d) | op3(taddcctv_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void taddcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(taddcc_op3 ) | rs1(s1) | rs2(s2) ); }
+ void taddcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(taddcc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void taddcctv( Register s1, Register s2, Register d ) { v9_dep(); emit_int32( op(arith_op) | rd(d) | op3(taddcctv_op3) | rs1(s1) | rs2(s2) ); }
+ void taddcctv( Register s1, int simm13a, Register d ) { v9_dep(); emit_int32( op(arith_op) | rd(d) | op3(taddcctv_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// pp 235
- void tsubcc( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(tsubcc_op3 ) | rs1(s1) | rs2(s2) ); }
- void tsubcc( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(tsubcc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
- void tsubcctv( Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(tsubcctv_op3) | rs1(s1) | rs2(s2) ); }
- void tsubcctv( Register s1, int simm13a, Register d ) { emit_long( op(arith_op) | rd(d) | op3(tsubcctv_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void tsubcc( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(tsubcc_op3 ) | rs1(s1) | rs2(s2) ); }
+ void tsubcc( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(tsubcc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
+ void tsubcctv( Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(tsubcctv_op3) | rs1(s1) | rs2(s2) ); }
+ void tsubcctv( Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(tsubcctv_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
// pp 237
- void trap( Condition c, CC cc, Register s1, Register s2 ) { v8_no_cc(cc); emit_long( op(arith_op) | cond(c) | op3(trap_op3) | rs1(s1) | trapcc(cc) | rs2(s2)); }
- void trap( Condition c, CC cc, Register s1, int trapa ) { v8_no_cc(cc); emit_long( op(arith_op) | cond(c) | op3(trap_op3) | rs1(s1) | trapcc(cc) | immed(true) | u_field(trapa, 6, 0)); }
+ void trap( Condition c, CC cc, Register s1, Register s2 ) { v8_no_cc(cc); emit_int32( op(arith_op) | cond(c) | op3(trap_op3) | rs1(s1) | trapcc(cc) | rs2(s2)); }
+ void trap( Condition c, CC cc, Register s1, int trapa ) { v8_no_cc(cc); emit_int32( op(arith_op) | cond(c) | op3(trap_op3) | rs1(s1) | trapcc(cc) | immed(true) | u_field(trapa, 6, 0)); }
// simple uncond. trap
void trap( int trapa ) { trap( always, icc, G0, trapa ); }
// pp 239 omit write priv register for now
- inline void wry( Register d) { v9_dep(); emit_long( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(0, 29, 25)); }
- inline void wrccr(Register s) { v9_only(); emit_long( op(arith_op) | rs1(s) | op3(wrreg_op3) | u_field(2, 29, 25)); }
- inline void wrccr(Register s, int simm13a) { v9_only(); emit_long( op(arith_op) |
+ inline void wry( Register d) { v9_dep(); emit_int32( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(0, 29, 25)); }
+ inline void wrccr(Register s) { v9_only(); emit_int32( op(arith_op) | rs1(s) | op3(wrreg_op3) | u_field(2, 29, 25)); }
+ inline void wrccr(Register s, int simm13a) { v9_only(); emit_int32( op(arith_op) |
rs1(s) |
op3(wrreg_op3) |
u_field(2, 29, 25) |
immed(true) |
simm(simm13a, 13)); }
- inline void wrasi(Register d) { v9_only(); emit_long( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(3, 29, 25)); }
+ inline void wrasi(Register d) { v9_only(); emit_int32( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(3, 29, 25)); }
// wrasi(d, imm) stores (d xor imm) to asi
- inline void wrasi(Register d, int simm13a) { v9_only(); emit_long( op(arith_op) | rs1(d) | op3(wrreg_op3) |
+ inline void wrasi(Register d, int simm13a) { v9_only(); emit_int32( op(arith_op) | rs1(d) | op3(wrreg_op3) |
u_field(3, 29, 25) | immed(true) | simm(simm13a, 13)); }
- inline void wrfprs( Register d) { v9_only(); emit_long( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(6, 29, 25)); }
+ inline void wrfprs( Register d) { v9_only(); emit_int32( 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)); }
-
+ void movstosw( FloatRegister s, Register d ) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstosw_opf) | fs2(s, FloatRegisterImpl::S)); }
+ void movstouw( FloatRegister s, Register d ) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstouw_opf) | fs2(s, FloatRegisterImpl::S)); }
+ void movdtox( FloatRegister s, Register d ) { vis3_only(); emit_int32( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mdtox_opf) | fs2(s, FloatRegisterImpl::D)); }
-
-
- // 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.)
- Assembler::Condition reg_cond_to_cc_cond(RCondition in);
-
+ void movwtos( Register s, FloatRegister d ) { vis3_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(mftoi_op3) | opf(mwtos_opf) | rs2(s)); }
+ void movxtod( Register s, FloatRegister d ) { vis3_only(); emit_int32( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(mftoi_op3) | opf(mxtod_opf) | rs2(s)); }
// Creation
Assembler(CodeBuffer* code) : AbstractAssembler(code) {
@@ -1814,864 +1202,6 @@
delay_state = no_delay;
#endif
}
-
- // Testing
-#ifndef PRODUCT
- void test_v9();
- void test_v8_onlys();
-#endif
-};
-
-
-class RegistersForDebugging : public StackObj {
- public:
- intptr_t i[8], l[8], o[8], g[8];
- float f[32];
- double d[32];
-
- void print(outputStream* s);
-
- static int i_offset(int j) { return offset_of(RegistersForDebugging, i[j]); }
- static int l_offset(int j) { return offset_of(RegistersForDebugging, l[j]); }
- static int o_offset(int j) { return offset_of(RegistersForDebugging, o[j]); }
- static int g_offset(int j) { return offset_of(RegistersForDebugging, g[j]); }
- static int f_offset(int j) { return offset_of(RegistersForDebugging, f[j]); }
- static int d_offset(int j) { return offset_of(RegistersForDebugging, d[j / 2]); }
-
- // gen asm code to save regs
- static void save_registers(MacroAssembler* a);
-
- // restore global registers in case C code disturbed them
- static void restore_registers(MacroAssembler* a, Register r);
-
-
};
-
-// MacroAssembler extends Assembler by a few frequently used macros.
-//
-// Most of the standard SPARC synthetic ops are defined here.
-// Instructions for which a 'better' code sequence exists depending
-// on arguments should also go in here.
-
-#define JMP2(r1, r2) jmp(r1, r2, __FILE__, __LINE__)
-#define JMP(r1, off) jmp(r1, off, __FILE__, __LINE__)
-#define JUMP(a, temp, off) jump(a, temp, off, __FILE__, __LINE__)
-#define JUMPL(a, temp, d, off) jumpl(a, temp, d, off, __FILE__, __LINE__)
-
-
-class MacroAssembler: public Assembler {
- protected:
- // Support for VM calls
- // This is the base routine called by the different versions of call_VM_leaf. The interpreter
- // may customize this version by overriding it for its purposes (e.g., to save/restore
- // additional registers when doing a VM call).
-#ifdef CC_INTERP
- #define VIRTUAL
-#else
- #define VIRTUAL virtual
-#endif
-
- VIRTUAL void call_VM_leaf_base(Register thread_cache, address entry_point, int number_of_arguments);
-
- //
- // It is imperative that all calls into the VM are handled via the call_VM macros.
- // They make sure that the stack linkage is setup correctly. call_VM's correspond
- // to ENTRY/ENTRY_X entry points while call_VM_leaf's correspond to LEAF entry points.
- //
- // This is the base routine called by the different versions of call_VM. The interpreter
- // may customize this version by overriding it for its purposes (e.g., to save/restore
- // additional registers when doing a VM call).
- //
- // A non-volatile java_thread_cache register should be specified so
- // that the G2_thread value can be preserved across the call.
- // (If java_thread_cache is noreg, then a slow get_thread call
- // will re-initialize the G2_thread.) call_VM_base returns the register that contains the
- // thread.
- //
- // If no last_java_sp is specified (noreg) than SP will be used instead.
-
- virtual void call_VM_base(
- Register oop_result, // where an oop-result ends up if any; use noreg otherwise
- Register java_thread_cache, // the thread if computed before ; use noreg otherwise
- Register last_java_sp, // to set up last_Java_frame in stubs; use noreg otherwise
- address entry_point, // the entry point
- int number_of_arguments, // the number of arguments (w/o thread) to pop after call
- bool check_exception=true // flag which indicates if exception should be checked
- );
-
- // This routine should emit JVMTI PopFrame and ForceEarlyReturn handling code.
- // The implementation is only non-empty for the InterpreterMacroAssembler,
- // as only the interpreter handles and ForceEarlyReturn PopFrame requests.
- virtual void check_and_handle_popframe(Register scratch_reg);
- virtual void check_and_handle_earlyret(Register scratch_reg);
-
- public:
- MacroAssembler(CodeBuffer* code) : Assembler(code) {}
-
- // Support for NULL-checks
- //
- // Generates code that causes a NULL OS exception if the content of reg is NULL.
- // If the accessed location is M[reg + offset] and the offset is known, provide the
- // offset. No explicit code generation is needed if the offset is within a certain
- // range (0 <= offset <= page_size).
- //
- // %%%%%% Currently not done for SPARC
-
- void null_check(Register reg, int offset = -1);
- static bool needs_explicit_null_check(intptr_t offset);
-
- // support for delayed instructions
- MacroAssembler* delayed() { Assembler::delayed(); return this; }
-
- // branches that use right instruction for v8 vs. v9
- inline void br( Condition c, bool a, Predict p, address d, relocInfo::relocType rt = relocInfo::none );
- inline void br( Condition c, bool a, Predict p, Label& L );
-
- inline void fb( Condition c, bool a, Predict p, address d, relocInfo::relocType rt = relocInfo::none );
- inline void fb( Condition c, bool a, Predict p, Label& L );
-
- // compares register with zero (32 bit) and branches (V9 and V8 instructions)
- void cmp_zero_and_br( Condition c, Register s1, Label& L, bool a = false, Predict p = pn );
- // Compares a pointer register with zero and branches on (not)null.
- // Does a test & branch on 32-bit systems and a register-branch on 64-bit.
- void br_null ( Register s1, bool a, Predict p, Label& L );
- void br_notnull( Register s1, bool a, Predict p, Label& L );
-
- //
- // Compare registers and branch with nop in delay slot or cbcond without delay slot.
- //
- // ATTENTION: use these instructions with caution because cbcond instruction
- // has very short distance: 512 instructions (2Kbyte).
-
- // Compare integer (32 bit) values (icc only).
- void cmp_and_br_short(Register s1, Register s2, Condition c, Predict p, Label& L);
- void cmp_and_br_short(Register s1, int simm13a, Condition c, Predict p, Label& L);
- // Platform depending version for pointer compare (icc on !LP64 and xcc on LP64).
- void cmp_and_brx_short(Register s1, Register s2, Condition c, Predict p, Label& L);
- void cmp_and_brx_short(Register s1, int simm13a, Condition c, Predict p, Label& L);
-
- // Short branch version for compares a pointer pwith zero.
- void br_null_short ( Register s1, Predict p, Label& L );
- void br_notnull_short( Register s1, Predict p, Label& L );
-
- // unconditional short branch
- void ba_short(Label& L);
-
- inline void bp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt = relocInfo::none );
- inline void bp( Condition c, bool a, CC cc, Predict p, Label& L );
-
- // Branch that tests xcc in LP64 and icc in !LP64
- inline void brx( Condition c, bool a, Predict p, address d, relocInfo::relocType rt = relocInfo::none );
- inline void brx( Condition c, bool a, Predict p, Label& L );
-
- // unconditional branch
- inline void ba( Label& L );
-
- // Branch that tests fp condition codes
- inline void fbp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt = relocInfo::none );
- inline void fbp( Condition c, bool a, CC cc, Predict p, Label& L );
-
- // get PC the best way
- inline int get_pc( Register d );
-
- // Sparc shorthands(pp 85, V8 manual, pp 289 V9 manual)
- inline void cmp( Register s1, Register s2 ) { subcc( s1, s2, G0 ); }
- inline void cmp( Register s1, int simm13a ) { subcc( s1, simm13a, G0 ); }
-
- inline void jmp( Register s1, Register s2 );
- inline void jmp( Register s1, int simm13a, RelocationHolder const& rspec = RelocationHolder() );
-
- // Check if the call target is out of wdisp30 range (relative to the code cache)
- static inline bool is_far_target(address d);
- inline void call( address d, relocInfo::relocType rt = relocInfo::runtime_call_type );
- inline void call( Label& L, relocInfo::relocType rt = relocInfo::runtime_call_type );
- inline void callr( Register s1, Register s2 );
- inline void callr( Register s1, int simm13a, RelocationHolder const& rspec = RelocationHolder() );
-
- // Emits nothing on V8
- inline void iprefetch( address d, relocInfo::relocType rt = relocInfo::none );
- inline void iprefetch( Label& L);
-
- inline void tst( Register s ) { orcc( G0, s, G0 ); }
-
-#ifdef PRODUCT
- inline void ret( bool trace = TraceJumps ) { if (trace) {
- mov(I7, O7); // traceable register
- JMP(O7, 2 * BytesPerInstWord);
- } else {
- jmpl( I7, 2 * BytesPerInstWord, G0 );
- }
- }
-
- inline void retl( bool trace = TraceJumps ) { if (trace) JMP(O7, 2 * BytesPerInstWord);
- else jmpl( O7, 2 * BytesPerInstWord, G0 ); }
-#else
- void ret( bool trace = TraceJumps );
- void retl( bool trace = TraceJumps );
-#endif /* PRODUCT */
-
- // Required platform-specific helpers for Label::patch_instructions.
- // They _shadow_ the declarations in AbstractAssembler, which are undefined.
- void pd_patch_instruction(address branch, address target);
-#ifndef PRODUCT
- static void pd_print_patched_instruction(address branch);
-#endif
-
- // sethi Macro handles optimizations and relocations
-private:
- void internal_sethi(const AddressLiteral& addrlit, Register d, bool ForceRelocatable);
-public:
- void sethi(const AddressLiteral& addrlit, Register d);
- void patchable_sethi(const AddressLiteral& addrlit, Register d);
-
- // compute the number of instructions for a sethi/set
- static int insts_for_sethi( address a, bool worst_case = false );
- static int worst_case_insts_for_set();
-
- // set may be either setsw or setuw (high 32 bits may be zero or sign)
-private:
- void internal_set(const AddressLiteral& al, Register d, bool ForceRelocatable);
- static int insts_for_internal_set(intptr_t value);
-public:
- void set(const AddressLiteral& addrlit, Register d);
- void set(intptr_t value, Register d);
- void set(address addr, Register d, RelocationHolder const& rspec);
- static int insts_for_set(intptr_t value) { return insts_for_internal_set(value); }
-
- void patchable_set(const AddressLiteral& addrlit, Register d);
- void patchable_set(intptr_t value, Register d);
- void set64(jlong value, Register d, Register tmp);
- static int insts_for_set64(jlong value);
-
- // sign-extend 32 to 64
- inline void signx( Register s, Register d ) { sra( s, G0, d); }
- inline void signx( Register d ) { sra( d, G0, d); }
-
- inline void not1( Register s, Register d ) { xnor( s, G0, d ); }
- inline void not1( Register d ) { xnor( d, G0, d ); }
-
- inline void neg( Register s, Register d ) { sub( G0, s, d ); }
- inline void neg( Register d ) { sub( G0, d, d ); }
-
- inline void cas( Register s1, Register s2, Register d) { casa( s1, s2, d, ASI_PRIMARY); }
- inline void casx( Register s1, Register s2, Register d) { casxa(s1, s2, d, ASI_PRIMARY); }
- // Functions for isolating 64 bit atomic swaps for LP64
- // cas_ptr will perform cas for 32 bit VM's and casx for 64 bit VM's
- inline void cas_ptr( Register s1, Register s2, Register d) {
-#ifdef _LP64
- casx( s1, s2, d );
-#else
- cas( s1, s2, d );
-#endif
- }
-
- // Functions for isolating 64 bit shifts for LP64
- inline void sll_ptr( Register s1, Register s2, Register d );
- inline void sll_ptr( Register s1, int imm6a, Register d );
- inline void sll_ptr( Register s1, RegisterOrConstant s2, Register d );
- inline void srl_ptr( Register s1, Register s2, Register d );
- inline void srl_ptr( Register s1, int imm6a, Register d );
-
- // little-endian
- inline void casl( Register s1, Register s2, Register d) { casa( s1, s2, d, ASI_PRIMARY_LITTLE); }
- inline void casxl( Register s1, Register s2, Register d) { casxa(s1, s2, d, ASI_PRIMARY_LITTLE); }
-
- inline void inc( Register d, int const13 = 1 ) { add( d, const13, d); }
- inline void inccc( Register d, int const13 = 1 ) { addcc( d, const13, d); }
-
- inline void dec( Register d, int const13 = 1 ) { sub( d, const13, d); }
- inline void deccc( Register d, int const13 = 1 ) { subcc( d, const13, d); }
-
- inline void btst( Register s1, Register s2 ) { andcc( s1, s2, G0 ); }
- inline void btst( int simm13a, Register s ) { andcc( s, simm13a, G0 ); }
-
- inline void bset( Register s1, Register s2 ) { or3( s1, s2, s2 ); }
- inline void bset( int simm13a, Register s ) { or3( s, simm13a, s ); }
-
- inline void bclr( Register s1, Register s2 ) { andn( s1, s2, s2 ); }
- inline void bclr( int simm13a, Register s ) { andn( s, simm13a, s ); }
-
- inline void btog( Register s1, Register s2 ) { xor3( s1, s2, s2 ); }
- inline void btog( int simm13a, Register s ) { xor3( s, simm13a, s ); }
-
- inline void clr( Register d ) { or3( G0, G0, d ); }
-
- inline void clrb( Register s1, Register s2);
- inline void clrh( Register s1, Register s2);
- inline void clr( Register s1, Register s2);
- inline void clrx( Register s1, Register s2);
-
- inline void clrb( Register s1, int simm13a);
- inline void clrh( Register s1, int simm13a);
- inline void clr( Register s1, int simm13a);
- inline void clrx( Register s1, int simm13a);
-
- // copy & clear upper word
- inline void clruw( Register s, Register d ) { srl( s, G0, d); }
- // clear upper word
- inline void clruwu( Register d ) { srl( d, G0, d); }
-
- // membar psuedo instruction. takes into account target memory model.
- inline void membar( Assembler::Membar_mask_bits const7a );
-
- // returns if membar generates anything.
- inline bool membar_has_effect( Assembler::Membar_mask_bits const7a );
-
- // mov pseudo instructions
- inline void mov( Register s, Register d) {
- if ( s != d ) or3( G0, s, d);
- else assert_not_delayed(); // Put something useful in the delay slot!
- }
-
- inline void mov_or_nop( Register s, Register d) {
- if ( s != d ) or3( G0, s, d);
- else nop();
- }
-
- inline void mov( int simm13a, Register d) { or3( G0, simm13a, d); }
-
- // address pseudos: make these names unlike instruction names to avoid confusion
- inline intptr_t load_pc_address( Register reg, int bytes_to_skip );
- inline void load_contents(const AddressLiteral& addrlit, Register d, int offset = 0);
- inline void load_bool_contents(const AddressLiteral& addrlit, Register d, int offset = 0);
- inline void load_ptr_contents(const AddressLiteral& addrlit, Register d, int offset = 0);
- inline void store_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset = 0);
- inline void store_ptr_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset = 0);
- inline void jumpl_to(const AddressLiteral& addrlit, Register temp, Register d, int offset = 0);
- inline void jump_to(const AddressLiteral& addrlit, Register temp, int offset = 0);
- inline void jump_indirect_to(Address& a, Register temp, int ld_offset = 0, int jmp_offset = 0);
-
- // ring buffer traceable jumps
-
- void jmp2( Register r1, Register r2, const char* file, int line );
- void jmp ( Register r1, int offset, const char* file, int line );
-
- void jumpl(const AddressLiteral& addrlit, Register temp, Register d, int offset, const char* file, int line);
- void jump (const AddressLiteral& addrlit, Register temp, int offset, const char* file, int line);
-
-
- // argument pseudos:
-
- inline void load_argument( Argument& a, Register d );
- inline void store_argument( Register s, Argument& a );
- inline void store_ptr_argument( Register s, Argument& a );
- inline void store_float_argument( FloatRegister s, Argument& a );
- inline void store_double_argument( FloatRegister s, Argument& a );
- inline void store_long_argument( Register s, Argument& a );
-
- // handy macros:
-
- inline void round_to( Register r, int modulus ) {
- assert_not_delayed();
- inc( r, modulus - 1 );
- and3( r, -modulus, r );
- }
-
- // --------------------------------------------------
-
- // Functions for isolating 64 bit loads for LP64
- // ld_ptr will perform ld for 32 bit VM's and ldx for 64 bit VM's
- // st_ptr will perform st for 32 bit VM's and stx for 64 bit VM's
- inline void ld_ptr(Register s1, Register s2, Register d);
- inline void ld_ptr(Register s1, int simm13a, Register d);
- inline void ld_ptr(Register s1, RegisterOrConstant s2, Register d);
- inline void ld_ptr(const Address& a, Register d, int offset = 0);
- inline void st_ptr(Register d, Register s1, Register s2);
- inline void st_ptr(Register d, Register s1, int simm13a);
- inline void st_ptr(Register d, Register s1, RegisterOrConstant s2);
- inline void st_ptr(Register d, const Address& a, int offset = 0);
-
-#ifdef ASSERT
- // ByteSize is only a class when ASSERT is defined, otherwise it's an int.
- inline void ld_ptr(Register s1, ByteSize simm13a, Register d);
- inline void st_ptr(Register d, Register s1, ByteSize simm13a);
-#endif
-
- // ld_long will perform ldd for 32 bit VM's and ldx for 64 bit VM's
- // st_long will perform std for 32 bit VM's and stx for 64 bit VM's
- inline void ld_long(Register s1, Register s2, Register d);
- inline void ld_long(Register s1, int simm13a, Register d);
- inline void ld_long(Register s1, RegisterOrConstant s2, Register d);
- inline void ld_long(const Address& a, Register d, int offset = 0);
- inline void st_long(Register d, Register s1, Register s2);
- inline void st_long(Register d, Register s1, int simm13a);
- inline void st_long(Register d, Register s1, RegisterOrConstant s2);
- inline void st_long(Register d, const Address& a, int offset = 0);
-
- // Helpers for address formation.
- // - They emit only a move if s2 is a constant zero.
- // - If dest is a constant and either s1 or s2 is a register, the temp argument is required and becomes the result.
- // - If dest is a register and either s1 or s2 is a non-simm13 constant, the temp argument is required and used to materialize the constant.
- RegisterOrConstant regcon_andn_ptr(RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp = noreg);
- RegisterOrConstant regcon_inc_ptr( RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp = noreg);
- RegisterOrConstant regcon_sll_ptr( RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp = noreg);
-
- RegisterOrConstant ensure_simm13_or_reg(RegisterOrConstant src, Register temp) {
- if (is_simm13(src.constant_or_zero()))
- return src; // register or short constant
- guarantee(temp != noreg, "constant offset overflow");
- set(src.as_constant(), temp);
- return temp;
- }
-
- // --------------------------------------------------
-
- public:
- // traps as per trap.h (SPARC ABI?)
-
- void breakpoint_trap();
- void breakpoint_trap(Condition c, CC cc);
- void flush_windows_trap();
- void clean_windows_trap();
- void get_psr_trap();
- void set_psr_trap();
-
- // V8/V9 flush_windows
- void flush_windows();
-
- // Support for serializing memory accesses between threads
- void serialize_memory(Register thread, Register tmp1, Register tmp2);
-
- // Stack frame creation/removal
- void enter();
- void leave();
-
- // V8/V9 integer multiply
- void mult(Register s1, Register s2, Register d);
- void mult(Register s1, int simm13a, Register d);
-
- // V8/V9 read and write of condition codes.
- void read_ccr(Register d);
- void write_ccr(Register s);
-
- // Manipulation of C++ bools
- // These are idioms to flag the need for care with accessing bools but on
- // this platform we assume byte size
-
- inline void stbool(Register d, const Address& a) { stb(d, a); }
- inline void ldbool(const Address& a, Register d) { ldub(a, d); }
- inline void movbool( bool boolconst, Register d) { mov( (int) boolconst, d); }
-
- // klass oop manipulations if compressed
- void load_klass(Register src_oop, Register klass);
- void store_klass(Register klass, Register dst_oop);
- void store_klass_gap(Register s, Register dst_oop);
-
- // oop manipulations
- void load_heap_oop(const Address& s, Register d);
- void load_heap_oop(Register s1, Register s2, Register d);
- void load_heap_oop(Register s1, int simm13a, Register d);
- void load_heap_oop(Register s1, RegisterOrConstant s2, Register d);
- void store_heap_oop(Register d, Register s1, Register s2);
- void store_heap_oop(Register d, Register s1, int simm13a);
- void store_heap_oop(Register d, const Address& a, int offset = 0);
-
- void encode_heap_oop(Register src, Register dst);
- void encode_heap_oop(Register r) {
- encode_heap_oop(r, r);
- }
- void decode_heap_oop(Register src, Register dst);
- void decode_heap_oop(Register r) {
- decode_heap_oop(r, r);
- }
- void encode_heap_oop_not_null(Register r);
- void decode_heap_oop_not_null(Register r);
- void encode_heap_oop_not_null(Register src, Register dst);
- void decode_heap_oop_not_null(Register src, Register dst);
-
- void encode_klass_not_null(Register r);
- void decode_klass_not_null(Register r);
- void encode_klass_not_null(Register src, Register dst);
- void decode_klass_not_null(Register src, Register dst);
-
- // Support for managing the JavaThread pointer (i.e.; the reference to
- // thread-local information).
- void get_thread(); // load G2_thread
- void verify_thread(); // verify G2_thread contents
- void save_thread (const Register threache); // save to cache
- void restore_thread(const Register thread_cache); // restore from cache
-
- // Support for last Java frame (but use call_VM instead where possible)
- void set_last_Java_frame(Register last_java_sp, Register last_Java_pc);
- void reset_last_Java_frame(void);
-
- // Call into the VM.
- // Passes the thread pointer (in O0) as a prepended argument.
- // Makes sure oop return values are visible to the GC.
- void call_VM(Register oop_result, address entry_point, int number_of_arguments = 0, bool check_exceptions = true);
- void call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions = true);
- void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true);
- void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true);
-
- // these overloadings are not presently used on SPARC:
- void call_VM(Register oop_result, Register last_java_sp, address entry_point, int number_of_arguments = 0, bool check_exceptions = true);
- void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, bool check_exceptions = true);
- void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true);
- void 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 call_VM_leaf(Register thread_cache, address entry_point, int number_of_arguments = 0);
- void call_VM_leaf(Register thread_cache, address entry_point, Register arg_1);
- void call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2);
- void call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2, Register arg_3);
-
- void get_vm_result (Register oop_result);
- void get_vm_result_2(Register metadata_result);
-
- // vm result is currently getting hijacked to for oop preservation
- void set_vm_result(Register oop_result);
-
- // Emit the CompiledIC call idiom
- void ic_call(address entry, bool emit_delay = true);
-
- // if call_VM_base was called with check_exceptions=false, then call
- // check_and_forward_exception to handle exceptions when it is safe
- void check_and_forward_exception(Register scratch_reg);
-
- private:
- // For V8
- void read_ccr_trap(Register ccr_save);
- void write_ccr_trap(Register ccr_save1, Register scratch1, Register scratch2);
-
-#ifdef ASSERT
- // For V8 debugging. Uses V8 instruction sequence and checks
- // result with V9 insturctions rdccr and wrccr.
- // Uses Gscatch and Gscatch2
- void read_ccr_v8_assert(Register ccr_save);
- void write_ccr_v8_assert(Register ccr_save);
-#endif // ASSERT
-
- public:
-
- // Write to card table for - register is destroyed afterwards.
- void card_table_write(jbyte* byte_map_base, Register tmp, Register obj);
-
- void card_write_barrier_post(Register store_addr, Register new_val, Register tmp);
-
-#ifndef SERIALGC
- // General G1 pre-barrier generator.
- void g1_write_barrier_pre(Register obj, Register index, int offset, Register pre_val, Register tmp, bool preserve_o_regs);
-
- // General G1 post-barrier generator
- void g1_write_barrier_post(Register store_addr, Register new_val, Register tmp);
-#endif // SERIALGC
-
- // pushes double TOS element of FPU stack on CPU stack; pops from FPU stack
- void push_fTOS();
-
- // pops double TOS element from CPU stack and pushes on FPU stack
- void pop_fTOS();
-
- void empty_FPU_stack();
-
- void push_IU_state();
- void pop_IU_state();
-
- void push_FPU_state();
- void pop_FPU_state();
-
- void push_CPU_state();
- void pop_CPU_state();
-
- // if heap base register is used - reinit it with the correct value
- void reinit_heapbase();
-
- // Debugging
- void _verify_oop(Register reg, const char * msg, const char * file, int line);
- void _verify_oop_addr(Address addr, const char * msg, const char * file, int line);
-
- // TODO: verify_method and klass metadata (compare against vptr?)
- void _verify_method_ptr(Register reg, const char * msg, const char * file, int line) {}
- void _verify_klass_ptr(Register reg, const char * msg, const char * file, int line){}
-
-#define verify_oop(reg) _verify_oop(reg, "broken oop " #reg, __FILE__, __LINE__)
-#define verify_oop_addr(addr) _verify_oop_addr(addr, "broken oop addr ", __FILE__, __LINE__)
-#define verify_method_ptr(reg) _verify_method_ptr(reg, "broken method " #reg, __FILE__, __LINE__)
-#define verify_klass_ptr(reg) _verify_klass_ptr(reg, "broken klass " #reg, __FILE__, __LINE__)
-
- // only if +VerifyOops
- void verify_FPU(int stack_depth, const char* s = "illegal FPU state");
- // only if +VerifyFPU
- void stop(const char* msg); // prints msg, dumps registers and stops execution
- void warn(const char* msg); // prints msg, but don't stop
- void untested(const char* what = "");
- void unimplemented(const char* what = "") { char* b = new char[1024]; jio_snprintf(b, 1024, "unimplemented: %s", what); stop(b); }
- void should_not_reach_here() { stop("should not reach here"); }
- void print_CPU_state();
-
- // oops in code
- AddressLiteral allocate_oop_address(jobject obj); // allocate_index
- AddressLiteral constant_oop_address(jobject obj); // find_index
- inline void set_oop (jobject obj, Register d); // uses allocate_oop_address
- inline void set_oop_constant (jobject obj, Register d); // uses constant_oop_address
- inline void set_oop (const AddressLiteral& obj_addr, Register d); // same as load_address
-
- // metadata in code that we have to keep track of
- AddressLiteral allocate_metadata_address(Metadata* obj); // allocate_index
- AddressLiteral constant_metadata_address(Metadata* obj); // find_index
- inline void set_metadata (Metadata* obj, Register d); // uses allocate_metadata_address
- inline void set_metadata_constant (Metadata* obj, Register d); // uses constant_metadata_address
- inline void set_metadata (const AddressLiteral& obj_addr, Register d); // same as load_address
-
- void set_narrow_oop( jobject obj, Register d );
- void set_narrow_klass( Klass* k, Register d );
-
- // nop padding
- void align(int modulus);
-
- // declare a safepoint
- void safepoint();
-
- // factor out part of stop into subroutine to save space
- void stop_subroutine();
- // factor out part of verify_oop into subroutine to save space
- void verify_oop_subroutine();
-
- // side-door communication with signalHandler in os_solaris.cpp
- static address _verify_oop_implicit_branch[3];
-
-#ifndef PRODUCT
- static void test();
-#endif
-
- int total_frame_size_in_bytes(int extraWords);
-
- // used when extraWords known statically
- 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
- void save_frame_and_mov(int extraWords, Register s1, Register d1, Register s2 = Register(), Register d2 = Register());
-
- // give no. (outgoing) params, calc # of words will need on frame
- void calc_mem_param_words(Register Rparam_words, Register Rresult);
-
- // used to calculate frame size dynamically
- // result is in bytes and must be negated for save inst
- void calc_frame_size(Register extraWords, Register resultReg);
-
- // calc and also save
- void calc_frame_size_and_save(Register extraWords, Register resultReg);
-
- static void debug(char* msg, RegistersForDebugging* outWindow);
-
- // implementations of bytecodes used by both interpreter and compiler
-
- void lcmp( Register Ra_hi, Register Ra_low,
- Register Rb_hi, Register Rb_low,
- Register Rresult);
-
- void lneg( Register Rhi, Register Rlow );
-
- void lshl( Register Rin_high, Register Rin_low, Register Rcount,
- Register Rout_high, Register Rout_low, Register Rtemp );
-
- void lshr( Register Rin_high, Register Rin_low, Register Rcount,
- Register Rout_high, Register Rout_low, Register Rtemp );
-
- void lushr( Register Rin_high, Register Rin_low, Register Rcount,
- Register Rout_high, Register Rout_low, Register Rtemp );
-
-#ifdef _LP64
- void lcmp( Register Ra, Register Rb, Register Rresult);
-#endif
-
- // Load and store values by size and signed-ness
- void load_sized_value( Address src, Register dst, size_t size_in_bytes, bool is_signed);
- void store_sized_value(Register src, Address dst, size_t size_in_bytes);
-
- void float_cmp( bool is_float, int unordered_result,
- FloatRegister Fa, FloatRegister Fb,
- Register Rresult);
-
- void fneg( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d);
- void fneg( FloatRegisterImpl::Width w, FloatRegister sd ) { Assembler::fneg(w, sd); }
- void fmov( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d);
- void fabs( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d);
-
- void save_all_globals_into_locals();
- void restore_globals_from_locals();
-
- void casx_under_lock(Register top_ptr_reg, Register top_reg, Register ptr_reg,
- address lock_addr=0, bool use_call_vm=false);
- void cas_under_lock(Register top_ptr_reg, Register top_reg, Register ptr_reg,
- address lock_addr=0, bool use_call_vm=false);
- void casn (Register addr_reg, Register cmp_reg, Register set_reg) ;
-
- // These set the icc condition code to equal if the lock succeeded
- // and notEqual if it failed and requires a slow case
- void compiler_lock_object(Register Roop, Register Rmark, Register Rbox,
- Register Rscratch,
- BiasedLockingCounters* counters = NULL,
- bool try_bias = UseBiasedLocking);
- void compiler_unlock_object(Register Roop, Register Rmark, Register Rbox,
- Register Rscratch,
- bool try_bias = UseBiasedLocking);
-
- // Biased locking support
- // Upon entry, lock_reg must point to the lock record on the stack,
- // obj_reg must contain the target object, and mark_reg must contain
- // the target object's header.
- // Destroys mark_reg if an attempt is made to bias an anonymously
- // biased lock. In this case a failure will go either to the slow
- // case or fall through with the notEqual condition code set with
- // the expectation that the slow case in the runtime will be called.
- // In the fall-through case where the CAS-based lock is done,
- // mark_reg is not destroyed.
- void biased_locking_enter(Register obj_reg, Register mark_reg, Register temp_reg,
- Label& done, Label* slow_case = NULL,
- BiasedLockingCounters* counters = NULL);
- // Upon entry, the base register of mark_addr must contain the oop.
- // Destroys temp_reg.
-
- // If allow_delay_slot_filling is set to true, the next instruction
- // emitted after this one will go in an annulled delay slot if the
- // biased locking exit case failed.
- void biased_locking_exit(Address mark_addr, Register temp_reg, Label& done, bool allow_delay_slot_filling = false);
-
- // allocation
- void eden_allocate(
- Register obj, // result: pointer to object after successful allocation
- Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
- int con_size_in_bytes, // object size in bytes if known at compile time
- Register t1, // temp register
- Register t2, // temp register
- Label& slow_case // continuation point if fast allocation fails
- );
- void tlab_allocate(
- Register obj, // result: pointer to object after successful allocation
- Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
- int con_size_in_bytes, // object size in bytes if known at compile time
- Register t1, // temp register
- Label& slow_case // continuation point if fast allocation fails
- );
- void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case);
- void incr_allocated_bytes(RegisterOrConstant size_in_bytes,
- Register t1, Register t2);
-
- // interface method calling
- void lookup_interface_method(Register recv_klass,
- Register intf_klass,
- RegisterOrConstant itable_index,
- Register method_result,
- Register temp_reg, Register temp2_reg,
- Label& no_such_interface);
-
- // virtual method calling
- void lookup_virtual_method(Register recv_klass,
- RegisterOrConstant vtable_index,
- Register method_result);
-
- // Test sub_klass against super_klass, with fast and slow paths.
-
- // The fast path produces a tri-state answer: yes / no / maybe-slow.
- // One of the three labels can be NULL, meaning take the fall-through.
- // If super_check_offset is -1, the value is loaded up from super_klass.
- // No registers are killed, except temp_reg and temp2_reg.
- // If super_check_offset is not -1, temp2_reg is not used and can be noreg.
- void check_klass_subtype_fast_path(Register sub_klass,
- Register super_klass,
- Register temp_reg,
- Register temp2_reg,
- Label* L_success,
- Label* L_failure,
- Label* L_slow_path,
- RegisterOrConstant super_check_offset = RegisterOrConstant(-1));
-
- // The rest of the type check; must be wired to a corresponding fast path.
- // It does not repeat the fast path logic, so don't use it standalone.
- // The temp_reg can be noreg, if no temps are available.
- // It can also be sub_klass or super_klass, meaning it's OK to kill that one.
- // Updates the sub's secondary super cache as necessary.
- void check_klass_subtype_slow_path(Register sub_klass,
- Register super_klass,
- Register temp_reg,
- Register temp2_reg,
- Register temp3_reg,
- Register temp4_reg,
- Label* L_success,
- Label* L_failure);
-
- // Simplified, combined version, good for typical uses.
- // Falls through on failure.
- void check_klass_subtype(Register sub_klass,
- Register super_klass,
- Register temp_reg,
- Register temp2_reg,
- Label& L_success);
-
- // method handles (JSR 292)
- // 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 = noreg,
- int extra_slot_offset = 0);
-
- // Stack overflow checking
-
- // Note: this clobbers G3_scratch
- void bang_stack_with_offset(int offset) {
- // stack grows down, caller passes positive offset
- assert(offset > 0, "must bang with negative offset");
- set((-offset)+STACK_BIAS, G3_scratch);
- st(G0, SP, G3_scratch);
- }
-
- // Writes to stack successive pages until offset reached to check for
- // stack overflow + shadow pages. Clobbers tsp and scratch registers.
- void bang_stack_size(Register Rsize, Register Rtsp, Register Rscratch);
-
- virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset);
-
- void verify_tlab();
-
- Condition negate_condition(Condition cond);
-
- // Helper functions for statistics gathering.
- // Conditionally (non-atomically) increments passed counter address, preserving condition codes.
- void cond_inc(Condition cond, address counter_addr, Register Rtemp1, Register Rtemp2);
- // Unconditional increment.
- void inc_counter(address counter_addr, Register Rtmp1, Register Rtmp2);
- void inc_counter(int* counter_addr, Register Rtmp1, Register Rtmp2);
-
- // Compare char[] arrays aligned to 4 bytes.
- void char_arrays_equals(Register ary1, Register ary2,
- Register limit, Register result,
- Register chr1, Register chr2, Label& Ldone);
- // Use BIS for zeroing
- void bis_zeroing(Register to, Register count, Register temp, Label& Ldone);
-
-#undef VIRTUAL
-
-};
-
-/**
- * class SkipIfEqual:
- *
- * Instantiating this class will result in assembly code being output that will
- * jump around any code emitted between the creation of the instance and it's
- * automatic destruction at the end of a scope block, depending on the value of
- * the flag passed to the constructor, which will be checked at run-time.
- */
-class SkipIfEqual : public StackObj {
- private:
- MacroAssembler* _masm;
- Label _label;
-
- public:
- // 'temp' is a temp register that this object can use (and trash)
- SkipIfEqual(MacroAssembler*, Register temp,
- const bool* flag_addr, Assembler::Condition condition);
- ~SkipIfEqual();
-};
-
-#ifdef ASSERT
-// On RISC, there's no benefit to verifying instruction boundaries.
-inline bool AbstractAssembler::pd_check_instruction_mark() { return false; }
-#endif
-
#endif // CPU_SPARC_VM_ASSEMBLER_SPARC_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/assembler_sparc.inline.hpp
--- a/src/cpu/sparc/vm/assembler_sparc.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/assembler_sparc.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,33 +25,8 @@
#ifndef CPU_SPARC_VM_ASSEMBLER_SPARC_INLINE_HPP
#define CPU_SPARC_VM_ASSEMBLER_SPARC_INLINE_HPP
-#include "asm/assembler.inline.hpp"
-#include "asm/codeBuffer.hpp"
-#include "code/codeCache.hpp"
-#include "runtime/handles.inline.hpp"
-
-inline void MacroAssembler::pd_patch_instruction(address branch, address target) {
- jint& stub_inst = *(jint*) branch;
- stub_inst = patched_branch(target - branch, stub_inst, 0);
-}
+#include "asm/assembler.hpp"
-#ifndef PRODUCT
-inline void MacroAssembler::pd_print_patched_instruction(address branch) {
- jint stub_inst = *(jint*) branch;
- print_instruction(stub_inst);
- ::tty->print("%s", " (unresolved)");
-}
-#endif // PRODUCT
-
-inline bool Address::is_simm13(int offset) { return Assembler::is_simm13(disp() + offset); }
-
-
-inline int AddressLiteral::low10() const {
- return Assembler::low10(value());
-}
-
-
-// inlines for SPARC assembler -- dmu 5/97
inline void Assembler::check_delay() {
# ifdef CHECK_DELAY
@@ -60,25 +35,24 @@
# endif
}
-inline void Assembler::emit_long(int x) {
+inline void Assembler::emit_int32(int x) {
check_delay();
- AbstractAssembler::emit_long(x);
+ AbstractAssembler::emit_int32(x);
}
inline void Assembler::emit_data(int x, relocInfo::relocType rtype) {
relocate(rtype);
- emit_long(x);
+ emit_int32(x);
}
inline void Assembler::emit_data(int x, RelocationHolder const& rspec) {
relocate(rspec);
- emit_long(x);
+ emit_int32(x);
}
-inline void Assembler::add(Register s1, Register s2, Register d ) { emit_long( op(arith_op) | rd(d) | op3(add_op3) | rs1(s1) | rs2(s2) ); }
-inline void Assembler::add(Register s1, int simm13a, Register d, relocInfo::relocType rtype ) { emit_data( op(arith_op) | rd(d) | op3(add_op3) | rs1(s1) | immed(true) | simm(simm13a, 13), rtype ); }
-inline void Assembler::add(Register s1, int simm13a, Register d, RelocationHolder const& rspec ) { emit_data( op(arith_op) | rd(d) | op3(add_op3) | rs1(s1) | immed(true) | simm(simm13a, 13), rspec ); }
+inline void Assembler::add(Register s1, Register s2, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::add(Register s1, int simm13a, Register d ) { emit_int32( op(arith_op) | rd(d) | op3(add_op3) | rs1(s1) | immed(true) | simm(simm13a, 13) ); }
inline void Assembler::bpr( RCondition c, bool a, Predict p, Register s1, address d, relocInfo::relocType rt ) { v9_only(); cti(); emit_data( op(branch_op) | annul(a) | cond(c) | op2(bpr_op2) | wdisp16(intptr_t(d), intptr_t(pc())) | predict(p) | rs1(s1), rt); has_delay_slot(); }
inline void Assembler::bpr( RCondition c, bool a, Predict p, Register s1, Label& L) { bpr( c, a, p, s1, target(L)); }
@@ -105,792 +79,93 @@
inline void Assembler::call( address d, relocInfo::relocType rt ) { cti(); emit_data( op(call_op) | wdisp(intptr_t(d), intptr_t(pc()), 30), rt); has_delay_slot(); assert(rt != relocInfo::virtual_call_type, "must use virtual_call_Relocation::spec"); }
inline void Assembler::call( Label& L, relocInfo::relocType rt ) { call( target(L), rt); }
-inline void Assembler::flush( Register s1, Register s2) { emit_long( op(arith_op) | op3(flush_op3) | rs1(s1) | rs2(s2)); }
+inline void Assembler::flush( Register s1, Register s2) { emit_int32( op(arith_op) | op3(flush_op3) | rs1(s1) | rs2(s2)); }
inline void Assembler::flush( Register s1, int simm13a) { emit_data( op(arith_op) | op3(flush_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::jmpl( Register s1, Register s2, Register d ) { cti(); emit_long( op(arith_op) | rd(d) | op3(jmpl_op3) | rs1(s1) | rs2(s2)); has_delay_slot(); }
+inline void Assembler::jmpl( Register s1, Register s2, Register d ) { cti(); emit_int32( op(arith_op) | rd(d) | op3(jmpl_op3) | rs1(s1) | rs2(s2)); has_delay_slot(); }
inline void Assembler::jmpl( Register s1, int simm13a, Register d, RelocationHolder const& rspec ) { cti(); emit_data( op(arith_op) | rd(d) | op3(jmpl_op3) | rs1(s1) | immed(true) | simm(simm13a, 13), rspec); has_delay_slot(); }
-inline void Assembler::ldf(FloatRegisterImpl::Width w, Register s1, RegisterOrConstant s2, FloatRegister d) {
- if (s2.is_register()) ldf(w, s1, s2.as_register(), d);
- else ldf(w, s1, s2.as_constant(), d);
-}
-
-inline void Assembler::ldf(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d) { emit_long( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3, w) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::ldf(FloatRegisterImpl::Width w, Register s1, Register s2, FloatRegister d) { emit_int32( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3, w) | rs1(s1) | rs2(s2) ); }
inline void Assembler::ldf(FloatRegisterImpl::Width w, Register s1, int simm13a, FloatRegister d, RelocationHolder const& rspec) { emit_data( op(ldst_op) | fd(d, w) | alt_op3(ldf_op3, w) | rs1(s1) | immed(true) | simm(simm13a, 13), rspec); }
-inline void Assembler::ldf(FloatRegisterImpl::Width w, const Address& a, FloatRegister d, int offset) { relocate(a.rspec(offset)); ldf( w, a.base(), a.disp() + offset, d); }
-
-inline void Assembler::ldfsr( Register s1, Register s2) { v9_dep(); emit_long( op(ldst_op) | op3(ldfsr_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::ldfsr( Register s1, Register s2) { v9_dep(); emit_int32( op(ldst_op) | op3(ldfsr_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::ldfsr( Register s1, int simm13a) { v9_dep(); emit_data( op(ldst_op) | op3(ldfsr_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::ldxfsr( Register s1, Register s2) { v9_only(); emit_long( op(ldst_op) | rd(G1) | op3(ldfsr_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::ldxfsr( Register s1, Register s2) { v9_only(); emit_int32( op(ldst_op) | rd(G1) | op3(ldfsr_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::ldxfsr( Register s1, int simm13a) { v9_only(); emit_data( op(ldst_op) | rd(G1) | op3(ldfsr_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::ldc( Register s1, Register s2, int crd) { v8_only(); emit_long( op(ldst_op) | fcn(crd) | op3(ldc_op3 ) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::ldc( Register s1, Register s2, int crd) { v8_only(); emit_int32( op(ldst_op) | fcn(crd) | op3(ldc_op3 ) | rs1(s1) | rs2(s2) ); }
inline void Assembler::ldc( Register s1, int simm13a, int crd) { v8_only(); emit_data( op(ldst_op) | fcn(crd) | op3(ldc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::lddc( Register s1, Register s2, int crd) { v8_only(); emit_long( op(ldst_op) | fcn(crd) | op3(lddc_op3 ) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::lddc( Register s1, Register s2, int crd) { v8_only(); emit_int32( op(ldst_op) | fcn(crd) | op3(lddc_op3 ) | rs1(s1) | rs2(s2) ); }
inline void Assembler::lddc( Register s1, int simm13a, int crd) { v8_only(); emit_data( op(ldst_op) | fcn(crd) | op3(lddc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::ldcsr( Register s1, Register s2, int crd) { v8_only(); emit_long( op(ldst_op) | fcn(crd) | op3(ldcsr_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::ldcsr( Register s1, Register s2, int crd) { v8_only(); emit_int32( op(ldst_op) | fcn(crd) | op3(ldcsr_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::ldcsr( Register s1, int simm13a, int crd) { v8_only(); emit_data( op(ldst_op) | fcn(crd) | op3(ldcsr_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::ldsb( Register s1, Register s2, Register d) { emit_long( op(ldst_op) | rd(d) | op3(ldsb_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::ldsb( Register s1, Register s2, Register d) { emit_int32( op(ldst_op) | rd(d) | op3(ldsb_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::ldsb( Register s1, int simm13a, Register d) { emit_data( op(ldst_op) | rd(d) | op3(ldsb_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::ldsh( Register s1, Register s2, Register d) { emit_long( op(ldst_op) | rd(d) | op3(ldsh_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::ldsh( Register s1, Register s2, Register d) { emit_int32( op(ldst_op) | rd(d) | op3(ldsh_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::ldsh( Register s1, int simm13a, Register d) { emit_data( op(ldst_op) | rd(d) | op3(ldsh_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::ldsw( Register s1, Register s2, Register d) { emit_long( op(ldst_op) | rd(d) | op3(ldsw_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::ldsw( Register s1, Register s2, Register d) { emit_int32( op(ldst_op) | rd(d) | op3(ldsw_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::ldsw( Register s1, int simm13a, Register d) { emit_data( op(ldst_op) | rd(d) | op3(ldsw_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::ldub( Register s1, Register s2, Register d) { emit_long( op(ldst_op) | rd(d) | op3(ldub_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::ldub( Register s1, Register s2, Register d) { emit_int32( op(ldst_op) | rd(d) | op3(ldub_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::ldub( Register s1, int simm13a, Register d) { emit_data( op(ldst_op) | rd(d) | op3(ldub_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::lduh( Register s1, Register s2, Register d) { emit_long( op(ldst_op) | rd(d) | op3(lduh_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::lduh( Register s1, Register s2, Register d) { emit_int32( op(ldst_op) | rd(d) | op3(lduh_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::lduh( Register s1, int simm13a, Register d) { emit_data( op(ldst_op) | rd(d) | op3(lduh_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::lduw( Register s1, Register s2, Register d) { emit_long( op(ldst_op) | rd(d) | op3(lduw_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::lduw( Register s1, Register s2, Register d) { emit_int32( op(ldst_op) | rd(d) | op3(lduw_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::lduw( Register s1, int simm13a, Register d) { emit_data( op(ldst_op) | rd(d) | op3(lduw_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::ldx( Register s1, Register s2, Register d) { v9_only(); emit_long( op(ldst_op) | rd(d) | op3(ldx_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::ldx( Register s1, Register s2, Register d) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(ldx_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::ldx( Register s1, int simm13a, Register d) { v9_only(); emit_data( op(ldst_op) | rd(d) | op3(ldx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::ldd( Register s1, Register s2, Register d) { v9_dep(); assert(d->is_even(), "not even"); emit_long( op(ldst_op) | rd(d) | op3(ldd_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::ldd( Register s1, Register s2, Register d) { v9_dep(); assert(d->is_even(), "not even"); emit_int32( op(ldst_op) | rd(d) | op3(ldd_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::ldd( Register s1, int simm13a, Register d) { v9_dep(); assert(d->is_even(), "not even"); emit_data( op(ldst_op) | rd(d) | op3(ldd_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-#ifdef _LP64
-// Make all 32 bit loads signed so 64 bit registers maintain proper sign
-inline void Assembler::ld( Register s1, Register s2, Register d) { ldsw( s1, s2, d); }
-inline void Assembler::ld( Register s1, int simm13a, Register d) { ldsw( s1, simm13a, d); }
-#else
-inline void Assembler::ld( Register s1, Register s2, Register d) { lduw( s1, s2, d); }
-inline void Assembler::ld( Register s1, int simm13a, Register d) { lduw( s1, simm13a, d); }
-#endif
-
-#ifdef ASSERT
- // ByteSize is only a class when ASSERT is defined, otherwise it's an int.
-# ifdef _LP64
-inline void Assembler::ld( Register s1, ByteSize simm13a, Register d) { ldsw( s1, in_bytes(simm13a), d); }
-# else
-inline void Assembler::ld( Register s1, ByteSize simm13a, Register d) { lduw( s1, in_bytes(simm13a), d); }
-# endif
-#endif
-
-inline void Assembler::ld( const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); ld( a.base(), a.index(), d); }
- else { ld( a.base(), a.disp() + offset, d); }
-}
-inline void Assembler::ldsb(const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); ldsb(a.base(), a.index(), d); }
- else { ldsb(a.base(), a.disp() + offset, d); }
-}
-inline void Assembler::ldsh(const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); ldsh(a.base(), a.index(), d); }
- else { ldsh(a.base(), a.disp() + offset, d); }
-}
-inline void Assembler::ldsw(const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); ldsw(a.base(), a.index(), d); }
- else { ldsw(a.base(), a.disp() + offset, d); }
-}
-inline void Assembler::ldub(const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); ldub(a.base(), a.index(), d); }
- else { ldub(a.base(), a.disp() + offset, d); }
-}
-inline void Assembler::lduh(const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); lduh(a.base(), a.index(), d); }
- else { lduh(a.base(), a.disp() + offset, d); }
-}
-inline void Assembler::lduw(const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); lduw(a.base(), a.index(), d); }
- else { lduw(a.base(), a.disp() + offset, d); }
-}
-inline void Assembler::ldd( const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); ldd( a.base(), a.index(), d); }
- else { ldd( a.base(), a.disp() + offset, d); }
-}
-inline void Assembler::ldx( const Address& a, Register d, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); ldx( a.base(), a.index(), d); }
- else { ldx( a.base(), a.disp() + offset, d); }
-}
-
-inline void Assembler::ldub(Register s1, RegisterOrConstant s2, Register d) { ldub(Address(s1, s2), d); }
-inline void Assembler::ldsb(Register s1, RegisterOrConstant s2, Register d) { ldsb(Address(s1, s2), d); }
-inline void Assembler::lduh(Register s1, RegisterOrConstant s2, Register d) { lduh(Address(s1, s2), d); }
-inline void Assembler::ldsh(Register s1, RegisterOrConstant s2, Register d) { ldsh(Address(s1, s2), d); }
-inline void Assembler::lduw(Register s1, RegisterOrConstant s2, Register d) { lduw(Address(s1, s2), d); }
-inline void Assembler::ldsw(Register s1, RegisterOrConstant s2, Register d) { ldsw(Address(s1, s2), d); }
-inline void Assembler::ldx( Register s1, RegisterOrConstant s2, Register d) { ldx( Address(s1, s2), d); }
-inline void Assembler::ld( Register s1, RegisterOrConstant s2, Register d) { ld( Address(s1, s2), d); }
-inline void Assembler::ldd( Register s1, RegisterOrConstant s2, Register d) { ldd( Address(s1, s2), d); }
-
-// form effective addresses this way:
-inline void Assembler::add(const Address& a, Register d, int offset) {
- if (a.has_index()) add(a.base(), a.index(), d);
- else { add(a.base(), a.disp() + offset, d, a.rspec(offset)); offset = 0; }
- if (offset != 0) add(d, offset, d);
-}
-inline void Assembler::add(Register s1, RegisterOrConstant s2, Register d, int offset) {
- if (s2.is_register()) add(s1, s2.as_register(), d);
- else { add(s1, s2.as_constant() + offset, d); offset = 0; }
- if (offset != 0) add(d, offset, d);
-}
-
-inline void Assembler::andn(Register s1, RegisterOrConstant s2, Register d) {
- if (s2.is_register()) andn(s1, s2.as_register(), d);
- else andn(s1, s2.as_constant(), d);
-}
-
-inline void Assembler::ldstub( Register s1, Register s2, Register d) { emit_long( op(ldst_op) | rd(d) | op3(ldstub_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::ldstub( Register s1, Register s2, Register d) { emit_int32( op(ldst_op) | rd(d) | op3(ldstub_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::ldstub( Register s1, int simm13a, Register d) { emit_data( op(ldst_op) | rd(d) | op3(ldstub_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-
-inline void Assembler::prefetch(Register s1, Register s2, PrefetchFcn f) { v9_only(); emit_long( op(ldst_op) | fcn(f) | op3(prefetch_op3) | rs1(s1) | rs2(s2) ); }
-inline void Assembler::prefetch(Register s1, int simm13a, PrefetchFcn f) { v9_only(); emit_data( op(ldst_op) | fcn(f) | op3(prefetch_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-
-inline void Assembler::prefetch(const Address& a, PrefetchFcn f, int offset) { v9_only(); relocate(a.rspec(offset)); prefetch(a.base(), a.disp() + offset, f); }
-
-
-inline void Assembler::rett( Register s1, Register s2 ) { cti(); emit_long( op(arith_op) | op3(rett_op3) | rs1(s1) | rs2(s2)); has_delay_slot(); }
+inline void Assembler::rett( Register s1, Register s2 ) { cti(); emit_int32( op(arith_op) | op3(rett_op3) | rs1(s1) | rs2(s2)); has_delay_slot(); }
inline void Assembler::rett( Register s1, int simm13a, relocInfo::relocType rt) { cti(); emit_data( op(arith_op) | op3(rett_op3) | rs1(s1) | immed(true) | simm(simm13a, 13), rt); has_delay_slot(); }
inline void Assembler::sethi( int imm22a, Register d, RelocationHolder const& rspec ) { emit_data( op(branch_op) | rd(d) | op2(sethi_op2) | hi22(imm22a), rspec); }
// pp 222
-inline void Assembler::stf( FloatRegisterImpl::Width w, FloatRegister d, Register s1, RegisterOrConstant s2) {
- if (s2.is_register()) stf(w, d, s1, s2.as_register());
- else stf(w, d, s1, s2.as_constant());
-}
-
-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, Register s2) { emit_int32( 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));
- 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, Register s2) { v9_dep(); emit_int32( 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)); }
-inline void Assembler::stxfsr( Register s1, Register s2) { v9_only(); emit_long( op(ldst_op) | rd(G1) | op3(stfsr_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::stxfsr( Register s1, Register s2) { v9_only(); emit_int32( op(ldst_op) | rd(G1) | op3(stfsr_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::stxfsr( Register s1, int simm13a) { v9_only(); emit_data( op(ldst_op) | rd(G1) | op3(stfsr_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
// p 226
-inline void Assembler::stb( Register d, Register s1, Register s2) { emit_long( op(ldst_op) | rd(d) | op3(stb_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::stb( Register d, Register s1, Register s2) { emit_int32( op(ldst_op) | rd(d) | op3(stb_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::stb( Register d, Register s1, int simm13a) { emit_data( op(ldst_op) | rd(d) | op3(stb_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::sth( Register d, Register s1, Register s2) { emit_long( op(ldst_op) | rd(d) | op3(sth_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::sth( Register d, Register s1, Register s2) { emit_int32( op(ldst_op) | rd(d) | op3(sth_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::sth( Register d, Register s1, int simm13a) { emit_data( op(ldst_op) | rd(d) | op3(sth_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::stw( Register d, Register s1, Register s2) { emit_long( op(ldst_op) | rd(d) | op3(stw_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::stw( Register d, Register s1, Register s2) { emit_int32( op(ldst_op) | rd(d) | op3(stw_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::stw( Register d, Register s1, int simm13a) { emit_data( op(ldst_op) | rd(d) | op3(stw_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::stx( Register d, Register s1, Register s2) { v9_only(); emit_long( op(ldst_op) | rd(d) | op3(stx_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::stx( Register d, Register s1, Register s2) { v9_only(); emit_int32( op(ldst_op) | rd(d) | op3(stx_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::stx( Register d, Register s1, int simm13a) { v9_only(); emit_data( op(ldst_op) | rd(d) | op3(stx_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::std( Register d, Register s1, Register s2) { v9_dep(); assert(d->is_even(), "not even"); emit_long( op(ldst_op) | rd(d) | op3(std_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::std( Register d, Register s1, Register s2) { v9_dep(); assert(d->is_even(), "not even"); emit_int32( op(ldst_op) | rd(d) | op3(std_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::std( Register d, Register s1, int simm13a) { v9_dep(); assert(d->is_even(), "not even"); emit_data( op(ldst_op) | rd(d) | op3(std_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::st( Register d, Register s1, Register s2) { stw(d, s1, s2); }
-inline void Assembler::st( Register d, Register s1, int simm13a) { stw(d, s1, simm13a); }
-
-#ifdef ASSERT
-// ByteSize is only a class when ASSERT is defined, otherwise it's an int.
-inline void Assembler::st( Register d, Register s1, ByteSize simm13a) { stw(d, s1, in_bytes(simm13a)); }
-#endif
-
-inline void Assembler::stb(Register d, const Address& a, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); stb(d, a.base(), a.index() ); }
- else { stb(d, a.base(), a.disp() + offset); }
-}
-inline void Assembler::sth(Register d, const Address& a, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); sth(d, a.base(), a.index() ); }
- else { sth(d, a.base(), a.disp() + offset); }
-}
-inline void Assembler::stw(Register d, const Address& a, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); stw(d, a.base(), a.index() ); }
- else { stw(d, a.base(), a.disp() + offset); }
-}
-inline void Assembler::st( Register d, const Address& a, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); st( d, a.base(), a.index() ); }
- else { st( d, a.base(), a.disp() + offset); }
-}
-inline void Assembler::std(Register d, const Address& a, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); std(d, a.base(), a.index() ); }
- else { std(d, a.base(), a.disp() + offset); }
-}
-inline void Assembler::stx(Register d, const Address& a, int offset) {
- if (a.has_index()) { assert(offset == 0, ""); stx(d, a.base(), a.index() ); }
- else { stx(d, a.base(), a.disp() + offset); }
-}
-
-inline void Assembler::stb(Register d, Register s1, RegisterOrConstant s2) { stb(d, Address(s1, s2)); }
-inline void Assembler::sth(Register d, Register s1, RegisterOrConstant s2) { sth(d, Address(s1, s2)); }
-inline void Assembler::stw(Register d, Register s1, RegisterOrConstant s2) { stw(d, Address(s1, s2)); }
-inline void Assembler::stx(Register d, Register s1, RegisterOrConstant s2) { stx(d, Address(s1, s2)); }
-inline void Assembler::std(Register d, Register s1, RegisterOrConstant s2) { std(d, Address(s1, s2)); }
-inline void Assembler::st( Register d, Register s1, RegisterOrConstant s2) { st( d, Address(s1, s2)); }
-
// v8 p 99
-inline void Assembler::stc( int crd, Register s1, Register s2) { v8_only(); emit_long( op(ldst_op) | fcn(crd) | op3(stc_op3 ) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::stc( int crd, Register s1, Register s2) { v8_only(); emit_int32( op(ldst_op) | fcn(crd) | op3(stc_op3 ) | rs1(s1) | rs2(s2) ); }
inline void Assembler::stc( int crd, Register s1, int simm13a) { v8_only(); emit_data( op(ldst_op) | fcn(crd) | op3(stc_op3 ) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::stdc( int crd, Register s1, Register s2) { v8_only(); emit_long( op(ldst_op) | fcn(crd) | op3(stdc_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::stdc( int crd, Register s1, Register s2) { v8_only(); emit_int32( op(ldst_op) | fcn(crd) | op3(stdc_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::stdc( int crd, Register s1, int simm13a) { v8_only(); emit_data( op(ldst_op) | fcn(crd) | op3(stdc_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::stcsr( int crd, Register s1, Register s2) { v8_only(); emit_long( op(ldst_op) | fcn(crd) | op3(stcsr_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::stcsr( int crd, Register s1, Register s2) { v8_only(); emit_int32( op(ldst_op) | fcn(crd) | op3(stcsr_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::stcsr( int crd, Register s1, int simm13a) { v8_only(); emit_data( op(ldst_op) | fcn(crd) | op3(stcsr_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::stdcq( int crd, Register s1, Register s2) { v8_only(); emit_long( op(ldst_op) | fcn(crd) | op3(stdcq_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::stdcq( int crd, Register s1, Register s2) { v8_only(); emit_int32( op(ldst_op) | fcn(crd) | op3(stdcq_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::stdcq( int crd, Register s1, int simm13a) { v8_only(); emit_data( op(ldst_op) | fcn(crd) | op3(stdcq_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::sub(Register s1, RegisterOrConstant s2, Register d, int offset) {
- if (s2.is_register()) sub(s1, s2.as_register(), d);
- else { sub(s1, s2.as_constant() + offset, d); offset = 0; }
- if (offset != 0) sub(d, offset, d);
-}
-
// pp 231
-inline void Assembler::swap( Register s1, Register s2, Register d) { v9_dep(); emit_long( op(ldst_op) | rd(d) | op3(swap_op3) | rs1(s1) | rs2(s2) ); }
+inline void Assembler::swap( Register s1, Register s2, Register d) { v9_dep(); emit_int32( op(ldst_op) | rd(d) | op3(swap_op3) | rs1(s1) | rs2(s2) ); }
inline void Assembler::swap( Register s1, int simm13a, Register d) { v9_dep(); emit_data( op(ldst_op) | rd(d) | op3(swap_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); }
-inline void Assembler::swap( Address& a, Register d, int offset ) {
- relocate(a.rspec(offset));
- if (a.has_index()) { assert(offset == 0, ""); swap( a.base(), a.index(), d ); }
- else { swap( a.base(), a.disp() + offset, d ); }
-}
-
-
-// Use the right loads/stores for the platform
-inline void MacroAssembler::ld_ptr( Register s1, Register s2, Register d ) {
-#ifdef _LP64
- Assembler::ldx(s1, s2, d);
-#else
- Assembler::ld( s1, s2, d);
-#endif
-}
-
-inline void MacroAssembler::ld_ptr( Register s1, int simm13a, Register d ) {
-#ifdef _LP64
- Assembler::ldx(s1, simm13a, d);
-#else
- Assembler::ld( s1, simm13a, d);
-#endif
-}
-
-#ifdef ASSERT
-// ByteSize is only a class when ASSERT is defined, otherwise it's an int.
-inline void MacroAssembler::ld_ptr( Register s1, ByteSize simm13a, Register d ) {
- ld_ptr(s1, in_bytes(simm13a), d);
-}
-#endif
-
-inline void MacroAssembler::ld_ptr( Register s1, RegisterOrConstant s2, Register d ) {
-#ifdef _LP64
- Assembler::ldx(s1, s2, d);
-#else
- Assembler::ld( s1, s2, d);
-#endif
-}
-
-inline void MacroAssembler::ld_ptr(const Address& a, Register d, int offset) {
-#ifdef _LP64
- Assembler::ldx(a, d, offset);
-#else
- Assembler::ld( a, d, offset);
-#endif
-}
-
-inline void MacroAssembler::st_ptr( Register d, Register s1, Register s2 ) {
-#ifdef _LP64
- Assembler::stx(d, s1, s2);
-#else
- Assembler::st( d, s1, s2);
-#endif
-}
-
-inline void MacroAssembler::st_ptr( Register d, Register s1, int simm13a ) {
-#ifdef _LP64
- Assembler::stx(d, s1, simm13a);
-#else
- Assembler::st( d, s1, simm13a);
-#endif
-}
-
-#ifdef ASSERT
-// ByteSize is only a class when ASSERT is defined, otherwise it's an int.
-inline void MacroAssembler::st_ptr( Register d, Register s1, ByteSize simm13a ) {
- st_ptr(d, s1, in_bytes(simm13a));
-}
-#endif
-
-inline void MacroAssembler::st_ptr( Register d, Register s1, RegisterOrConstant s2 ) {
-#ifdef _LP64
- Assembler::stx(d, s1, s2);
-#else
- Assembler::st( d, s1, s2);
-#endif
-}
-
-inline void MacroAssembler::st_ptr(Register d, const Address& a, int offset) {
-#ifdef _LP64
- Assembler::stx(d, a, offset);
-#else
- Assembler::st( d, a, offset);
-#endif
-}
-
-// Use the right loads/stores for the platform
-inline void MacroAssembler::ld_long( Register s1, Register s2, Register d ) {
-#ifdef _LP64
- Assembler::ldx(s1, s2, d);
-#else
- Assembler::ldd(s1, s2, d);
-#endif
-}
-
-inline void MacroAssembler::ld_long( Register s1, int simm13a, Register d ) {
-#ifdef _LP64
- Assembler::ldx(s1, simm13a, d);
-#else
- Assembler::ldd(s1, simm13a, d);
-#endif
-}
-
-inline void MacroAssembler::ld_long( Register s1, RegisterOrConstant s2, Register d ) {
-#ifdef _LP64
- Assembler::ldx(s1, s2, d);
-#else
- Assembler::ldd(s1, s2, d);
-#endif
-}
-
-inline void MacroAssembler::ld_long(const Address& a, Register d, int offset) {
-#ifdef _LP64
- Assembler::ldx(a, d, offset);
-#else
- Assembler::ldd(a, d, offset);
-#endif
-}
-
-inline void MacroAssembler::st_long( Register d, Register s1, Register s2 ) {
-#ifdef _LP64
- Assembler::stx(d, s1, s2);
-#else
- Assembler::std(d, s1, s2);
-#endif
-}
-
-inline void MacroAssembler::st_long( Register d, Register s1, int simm13a ) {
-#ifdef _LP64
- Assembler::stx(d, s1, simm13a);
-#else
- Assembler::std(d, s1, simm13a);
-#endif
-}
-
-inline void MacroAssembler::st_long( Register d, Register s1, RegisterOrConstant s2 ) {
-#ifdef _LP64
- Assembler::stx(d, s1, s2);
-#else
- Assembler::std(d, s1, s2);
-#endif
-}
-
-inline void MacroAssembler::st_long( Register d, const Address& a, int offset ) {
-#ifdef _LP64
- Assembler::stx(d, a, offset);
-#else
- Assembler::std(d, a, offset);
-#endif
-}
-
-// Functions for isolating 64 bit shifts for LP64
-
-inline void MacroAssembler::sll_ptr( Register s1, Register s2, Register d ) {
-#ifdef _LP64
- Assembler::sllx(s1, s2, d);
-#else
- Assembler::sll( s1, s2, d);
-#endif
-}
-
-inline void MacroAssembler::sll_ptr( Register s1, int imm6a, Register d ) {
-#ifdef _LP64
- Assembler::sllx(s1, imm6a, d);
-#else
- Assembler::sll( s1, imm6a, d);
-#endif
-}
-
-inline void MacroAssembler::srl_ptr( Register s1, Register s2, Register d ) {
-#ifdef _LP64
- Assembler::srlx(s1, s2, d);
-#else
- Assembler::srl( s1, s2, d);
-#endif
-}
-
-inline void MacroAssembler::srl_ptr( Register s1, int imm6a, Register d ) {
-#ifdef _LP64
- Assembler::srlx(s1, imm6a, d);
-#else
- Assembler::srl( s1, imm6a, d);
-#endif
-}
-
-inline void MacroAssembler::sll_ptr( Register s1, RegisterOrConstant s2, Register d ) {
- if (s2.is_register()) sll_ptr(s1, s2.as_register(), d);
- else sll_ptr(s1, s2.as_constant(), d);
-}
-
-// Use the right branch for the platform
-
-inline void MacroAssembler::br( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) {
- if (VM_Version::v9_instructions_work())
- Assembler::bp(c, a, icc, p, d, rt);
- else
- Assembler::br(c, a, d, rt);
-}
-
-inline void MacroAssembler::br( Condition c, bool a, Predict p, Label& L ) {
- br(c, a, p, target(L));
-}
-
-
-// Branch that tests either xcc or icc depending on the
-// architecture compiled (LP64 or not)
-inline void MacroAssembler::brx( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) {
-#ifdef _LP64
- Assembler::bp(c, a, xcc, p, d, rt);
-#else
- MacroAssembler::br(c, a, p, d, rt);
-#endif
-}
-
-inline void MacroAssembler::brx( Condition c, bool a, Predict p, Label& L ) {
- brx(c, a, p, target(L));
-}
-
-inline void MacroAssembler::ba( Label& L ) {
- br(always, false, pt, L);
-}
-
-// Warning: V9 only functions
-inline void MacroAssembler::bp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt ) {
- Assembler::bp(c, a, cc, p, d, rt);
-}
-
-inline void MacroAssembler::bp( Condition c, bool a, CC cc, Predict p, Label& L ) {
- Assembler::bp(c, a, cc, p, L);
-}
-
-inline void MacroAssembler::fb( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) {
- if (VM_Version::v9_instructions_work())
- fbp(c, a, fcc0, p, d, rt);
- else
- Assembler::fb(c, a, d, rt);
-}
-
-inline void MacroAssembler::fb( Condition c, bool a, Predict p, Label& L ) {
- fb(c, a, p, target(L));
-}
-
-inline void MacroAssembler::fbp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt ) {
- Assembler::fbp(c, a, cc, p, d, rt);
-}
-
-inline void MacroAssembler::fbp( Condition c, bool a, CC cc, Predict p, Label& L ) {
- Assembler::fbp(c, a, cc, p, L);
-}
-
-inline void MacroAssembler::jmp( Register s1, Register s2 ) { jmpl( s1, s2, G0 ); }
-inline void MacroAssembler::jmp( Register s1, int simm13a, RelocationHolder const& rspec ) { jmpl( s1, simm13a, G0, rspec); }
-
-inline bool MacroAssembler::is_far_target(address d) {
- if (ForceUnreachable) {
- // References outside the code cache should be treated as far
- return d < CodeCache::low_bound() || d > CodeCache::high_bound();
- }
- return !is_in_wdisp30_range(d, CodeCache::low_bound()) || !is_in_wdisp30_range(d, CodeCache::high_bound());
-}
-
-// Call with a check to see if we need to deal with the added
-// expense of relocation and if we overflow the displacement
-// of the quick call instruction.
-inline void MacroAssembler::call( address d, relocInfo::relocType rt ) {
-#ifdef _LP64
- intptr_t disp;
- // NULL is ok because it will be relocated later.
- // Must change NULL to a reachable address in order to
- // pass asserts here and in wdisp.
- if ( d == NULL )
- d = pc();
-
- // Is this address within range of the call instruction?
- // If not, use the expensive instruction sequence
- if (is_far_target(d)) {
- relocate(rt);
- AddressLiteral dest(d);
- jumpl_to(dest, O7, O7);
- } else {
- Assembler::call(d, rt);
- }
-#else
- Assembler::call( d, rt );
-#endif
-}
-
-inline void MacroAssembler::call( Label& L, relocInfo::relocType rt ) {
- MacroAssembler::call( target(L), rt);
-}
-
-
-
-inline void MacroAssembler::callr( Register s1, Register s2 ) { jmpl( s1, s2, O7 ); }
-inline void MacroAssembler::callr( Register s1, int simm13a, RelocationHolder const& rspec ) { jmpl( s1, simm13a, O7, rspec); }
-
-// prefetch instruction
-inline void MacroAssembler::iprefetch( address d, relocInfo::relocType rt ) {
- if (VM_Version::v9_instructions_work())
- Assembler::bp( never, true, xcc, pt, d, rt );
-}
-inline void MacroAssembler::iprefetch( Label& L) { iprefetch( target(L) ); }
-
-
-// clobbers o7 on V8!!
-// returns delta from gotten pc to addr after
-inline int MacroAssembler::get_pc( Register d ) {
- int x = offset();
- if (VM_Version::v9_instructions_work())
- rdpc(d);
- else {
- Label lbl;
- Assembler::call(lbl, relocInfo::none); // No relocation as this is call to pc+0x8
- if (d == O7) delayed()->nop();
- else delayed()->mov(O7, d);
- bind(lbl);
- }
- return offset() - x;
-}
-
-
-// Note: All MacroAssembler::set_foo functions are defined out-of-line.
-
-
-// Loads the current PC of the following instruction as an immediate value in
-// 2 instructions. All PCs in the CodeCache are within 2 Gig of each other.
-inline intptr_t MacroAssembler::load_pc_address( Register reg, int bytes_to_skip ) {
- intptr_t thepc = (intptr_t)pc() + 2*BytesPerInstWord + bytes_to_skip;
-#ifdef _LP64
- Unimplemented();
-#else
- Assembler::sethi( thepc & ~0x3ff, reg, internal_word_Relocation::spec((address)thepc));
- Assembler::add(reg,thepc & 0x3ff, reg, internal_word_Relocation::spec((address)thepc));
-#endif
- return thepc;
-}
-
-
-inline void MacroAssembler::load_contents(const AddressLiteral& addrlit, Register d, int offset) {
- assert_not_delayed();
- if (ForceUnreachable) {
- patchable_sethi(addrlit, d);
- } else {
- sethi(addrlit, d);
- }
- ld(d, addrlit.low10() + offset, d);
-}
-
-
-inline void MacroAssembler::load_bool_contents(const AddressLiteral& addrlit, Register d, int offset) {
- assert_not_delayed();
- if (ForceUnreachable) {
- patchable_sethi(addrlit, d);
- } else {
- sethi(addrlit, d);
- }
- ldub(d, addrlit.low10() + offset, d);
-}
-
-
-inline void MacroAssembler::load_ptr_contents(const AddressLiteral& addrlit, Register d, int offset) {
- assert_not_delayed();
- if (ForceUnreachable) {
- patchable_sethi(addrlit, d);
- } else {
- sethi(addrlit, d);
- }
- ld_ptr(d, addrlit.low10() + offset, d);
-}
-
-
-inline void MacroAssembler::store_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset) {
- assert_not_delayed();
- if (ForceUnreachable) {
- patchable_sethi(addrlit, temp);
- } else {
- sethi(addrlit, temp);
- }
- st(s, temp, addrlit.low10() + offset);
-}
-
-
-inline void MacroAssembler::store_ptr_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset) {
- assert_not_delayed();
- if (ForceUnreachable) {
- patchable_sethi(addrlit, temp);
- } else {
- sethi(addrlit, temp);
- }
- st_ptr(s, temp, addrlit.low10() + offset);
-}
-
-
-// This code sequence is relocatable to any address, even on LP64.
-inline void MacroAssembler::jumpl_to(const AddressLiteral& addrlit, Register temp, Register d, int offset) {
- assert_not_delayed();
- // Force fixed length sethi because NativeJump and NativeFarCall don't handle
- // variable length instruction streams.
- patchable_sethi(addrlit, temp);
- jmpl(temp, addrlit.low10() + offset, d);
-}
-
-
-inline void MacroAssembler::jump_to(const AddressLiteral& addrlit, Register temp, int offset) {
- jumpl_to(addrlit, temp, G0, offset);
-}
-
-
-inline void MacroAssembler::jump_indirect_to(Address& a, Register temp,
- int ld_offset, int jmp_offset) {
- assert_not_delayed();
- //sethi(al); // sethi is caller responsibility for this one
- ld_ptr(a, temp, ld_offset);
- jmp(temp, jmp_offset);
-}
-
-
-inline void MacroAssembler::set_metadata(Metadata* obj, Register d) {
- set_metadata(allocate_metadata_address(obj), d);
-}
-
-inline void MacroAssembler::set_metadata_constant(Metadata* obj, Register d) {
- set_metadata(constant_metadata_address(obj), d);
-}
-
-inline void MacroAssembler::set_metadata(const AddressLiteral& obj_addr, Register d) {
- assert(obj_addr.rspec().type() == relocInfo::metadata_type, "must be a metadata reloc");
- set(obj_addr, d);
-}
-
-inline void MacroAssembler::set_oop(jobject obj, Register d) {
- set_oop(allocate_oop_address(obj), d);
-}
-
-
-inline void MacroAssembler::set_oop_constant(jobject obj, Register d) {
- set_oop(constant_oop_address(obj), d);
-}
-
-
-inline void MacroAssembler::set_oop(const AddressLiteral& obj_addr, Register d) {
- assert(obj_addr.rspec().type() == relocInfo::oop_type, "must be an oop reloc");
- set(obj_addr, d);
-}
-
-
-inline void MacroAssembler::load_argument( Argument& a, Register d ) {
- if (a.is_register())
- mov(a.as_register(), d);
- else
- ld (a.as_address(), d);
-}
-
-inline void MacroAssembler::store_argument( Register s, Argument& a ) {
- if (a.is_register())
- mov(s, a.as_register());
- else
- st_ptr (s, a.as_address()); // ABI says everything is right justified.
-}
-
-inline void MacroAssembler::store_ptr_argument( Register s, Argument& a ) {
- if (a.is_register())
- mov(s, a.as_register());
- else
- st_ptr (s, a.as_address());
-}
-
-
-#ifdef _LP64
-inline void MacroAssembler::store_float_argument( FloatRegister s, Argument& a ) {
- if (a.is_float_register())
-// V9 ABI has F1, F3, F5 are used to pass instead of O0, O1, O2
- fmov(FloatRegisterImpl::S, s, a.as_float_register() );
- else
- // Floats are stored in the high half of the stack entry
- // The low half is undefined per the ABI.
- stf(FloatRegisterImpl::S, s, a.as_address(), sizeof(jfloat));
-}
-
-inline void MacroAssembler::store_double_argument( FloatRegister s, Argument& a ) {
- if (a.is_float_register())
-// V9 ABI has D0, D2, D4 are used to pass instead of O0, O1, O2
- fmov(FloatRegisterImpl::D, s, a.as_double_register() );
- else
- stf(FloatRegisterImpl::D, s, a.as_address());
-}
-
-inline void MacroAssembler::store_long_argument( Register s, Argument& a ) {
- if (a.is_register())
- mov(s, a.as_register());
- else
- stx(s, a.as_address());
-}
-#endif
-
-inline void MacroAssembler::clrb( Register s1, Register s2) { stb( G0, s1, s2 ); }
-inline void MacroAssembler::clrh( Register s1, Register s2) { sth( G0, s1, s2 ); }
-inline void MacroAssembler::clr( Register s1, Register s2) { stw( G0, s1, s2 ); }
-inline void MacroAssembler::clrx( Register s1, Register s2) { stx( G0, s1, s2 ); }
-
-inline void MacroAssembler::clrb( Register s1, int simm13a) { stb( G0, s1, simm13a); }
-inline void MacroAssembler::clrh( Register s1, int simm13a) { sth( G0, s1, simm13a); }
-inline void MacroAssembler::clr( Register s1, int simm13a) { stw( G0, s1, simm13a); }
-inline void MacroAssembler::clrx( Register s1, int simm13a) { stx( G0, s1, simm13a); }
-
-// returns if membar generates anything, obviously this code should mirror
-// membar below.
-inline bool MacroAssembler::membar_has_effect( Membar_mask_bits const7a ) {
- if( !os::is_MP() ) return false; // Not needed on single CPU
- if( VM_Version::v9_instructions_work() ) {
- const Membar_mask_bits effective_mask =
- Membar_mask_bits(const7a & ~(LoadLoad | LoadStore | StoreStore));
- return (effective_mask != 0);
- } else {
- return true;
- }
-}
-
-inline void MacroAssembler::membar( Membar_mask_bits const7a ) {
- // Uniprocessors do not need memory barriers
- if (!os::is_MP()) return;
- // Weakened for current Sparcs and TSO. See the v9 manual, sections 8.4.3,
- // 8.4.4.3, a.31 and a.50.
- if( VM_Version::v9_instructions_work() ) {
- // Under TSO, setting bit 3, 2, or 0 is redundant, so the only value
- // of the mmask subfield of const7a that does anything that isn't done
- // implicitly is StoreLoad.
- const Membar_mask_bits effective_mask =
- Membar_mask_bits(const7a & ~(LoadLoad | LoadStore | StoreStore));
- if ( effective_mask != 0 ) {
- Assembler::membar( effective_mask );
- }
- } else {
- // stbar is the closest there is on v8. Equivalent to membar(StoreStore). We
- // do not issue the stbar because to my knowledge all v8 machines implement TSO,
- // which guarantees that all stores behave as if an stbar were issued just after
- // each one of them. On these machines, stbar ought to be a nop. There doesn't
- // appear to be an equivalent of membar(StoreLoad) on v8: TSO doesn't require it,
- // it can't be specified by stbar, nor have I come up with a way to simulate it.
- //
- // Addendum. Dave says that ldstub guarantees a write buffer flush to coherent
- // space. Put one here to be on the safe side.
- Assembler::ldstub(SP, 0, G0);
- }
-}
-
#endif // CPU_SPARC_VM_ASSEMBLER_SPARC_INLINE_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp
--- a/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/c1_CodeStubs_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -298,7 +298,7 @@
for (int i = 0; i < _bytes_to_copy; i++) {
address ptr = (address)(_pc_start + i);
int a_byte = (*ptr) & 0xFF;
- __ a_byte (a_byte);
+ __ emit_int8 (a_byte);
}
}
@@ -340,10 +340,10 @@
int being_initialized_entry_offset = __ offset() - being_initialized_entry + sizeof_patch_record;
// Emit the patch record. We need to emit a full word, so emit an extra empty byte
- __ a_byte(0);
- __ a_byte(being_initialized_entry_offset);
- __ a_byte(bytes_to_skip);
- __ a_byte(_bytes_to_copy);
+ __ emit_int8(0);
+ __ emit_int8(being_initialized_entry_offset);
+ __ emit_int8(bytes_to_skip);
+ __ emit_int8(_bytes_to_copy);
address patch_info_pc = __ pc();
assert(patch_info_pc - end_of_patch == bytes_to_skip, "incorrect patch info");
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/codeBuffer_sparc.hpp
--- a/src/cpu/sparc/vm/codeBuffer_sparc.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/codeBuffer_sparc.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -31,9 +31,4 @@
public:
void flush_bundle(bool start_new_bundle) {}
- // Heuristic for pre-packing the pt/pn bit of a predicted branch.
- bool is_backward_branch(Label& L) {
- return L.is_bound() && insts_end() <= locator_address(L.loc());
- }
-
#endif // CPU_SPARC_VM_CODEBUFFER_SPARC_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/cppInterpreter_sparc.cpp
--- a/src/cpu/sparc/vm/cppInterpreter_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/cppInterpreter_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -137,7 +137,7 @@
}
__ ret(); // return from interpreter activation
__ delayed()->restore(I5_savedSP, G0, SP); // remove interpreter frame
- NOT_PRODUCT(__ emit_long(0);) // marker for disassembly
+ NOT_PRODUCT(__ emit_int32(0);) // marker for disassembly
return entry;
}
@@ -232,7 +232,7 @@
}
__ retl(); // return from interpreter activation
__ delayed()->nop(); // schedule this better
- NOT_PRODUCT(__ emit_long(0);) // marker for disassembly
+ NOT_PRODUCT(__ emit_int32(0);) // marker for disassembly
return entry;
}
@@ -582,7 +582,9 @@
// the following temporary registers are used during frame creation
const Register Gtmp1 = G3_scratch ;
const Register Gtmp2 = G1_scratch;
- const Address size_of_parameters(G5_method, 0, in_bytes(Method::size_of_parameters_offset()));
+ const Register RconstMethod = Gtmp1;
+ const Address constMethod(G5_method, 0, in_bytes(Method::const_offset()));
+ const Address size_of_parameters(RconstMethod, 0, in_bytes(ConstMethod::size_of_parameters_offset()));
bool inc_counter = UseCompiler || CountCompiledCalls;
@@ -618,6 +620,7 @@
}
#endif // ASSERT
+ __ ld_ptr(constMethod, RconstMethod);
__ lduh(size_of_parameters, Gtmp1);
__ sll(Gtmp1, LogBytesPerWord, Gtmp2); // parameter size in bytes
__ add(Gargs, Gtmp2, Gargs); // points to first local + BytesPerWord
@@ -1047,9 +1050,6 @@
const Register Gtmp = G3_scratch;
const Address constMethod (G5_method, 0, in_bytes(Method::const_offset()));
const Address access_flags (G5_method, 0, in_bytes(Method::access_flags_offset()));
- const Address size_of_parameters(G5_method, 0, in_bytes(Method::size_of_parameters_offset()));
- const Address max_stack (G5_method, 0, in_bytes(Method::max_stack_offset()));
- const Address size_of_locals (G5_method, 0, in_bytes(Method::size_of_locals_offset()));
// slop factor is two extra slots on the expression stack so that
// we always have room to store a result when returning from a call without parameters
@@ -1067,10 +1067,15 @@
// Now compute new frame size
if (native) {
+ const Register RconstMethod = Gtmp;
+ const Address size_of_parameters(RconstMethod, 0, in_bytes(ConstMethod::size_of_parameters_offset()));
+ __ ld_ptr(constMethod, RconstMethod);
__ lduh( size_of_parameters, Gtmp );
__ calc_mem_param_words(Gtmp, Gtmp); // space for native call parameters passed on the stack in words
} else {
- __ lduh(max_stack, Gtmp); // Full size expression stack
+ // Full size expression stack
+ __ ld_ptr(constMethod, Gtmp);
+ __ lduh(Gtmp, in_bytes(ConstMethod::max_stack_offset()), Gtmp);
}
__ add(Gtmp, fixed_size, Gtmp); // plus the fixed portion
@@ -1206,7 +1211,9 @@
__ sub(O2, wordSize, O2); // prepush
__ st_ptr(O2, XXX_STATE(_stack)); // PREPUSH
- __ lduh(max_stack, O3); // Full size expression stack
+ // Full size expression stack
+ __ ld_ptr(constMethod, O3);
+ __ lduh(O3, in_bytes(ConstMethod::max_stack_offset()), O3);
guarantee(!EnableInvokeDynamic, "no support yet for java.lang.invoke.MethodHandle"); //6815692
//6815692//if (EnableInvokeDynamic)
//6815692// __ inc(O3, Method::extra_stack_entries());
@@ -1233,9 +1240,13 @@
}
if (init_value != noreg) {
Label clear_loop;
+ const Register RconstMethod = O1;
+ const Address size_of_parameters(RconstMethod, 0, in_bytes(ConstMethod::size_of_parameters_offset()));
+ const Address size_of_locals (RconstMethod, 0, in_bytes(ConstMethod::size_of_locals_offset()));
// NOTE: If you change the frame layout, this code will need to
// be updated!
+ __ ld_ptr( constMethod, RconstMethod );
__ lduh( size_of_locals, O2 );
__ lduh( size_of_parameters, O1 );
__ sll( O2, LogBytesPerWord, O2);
@@ -1462,7 +1473,7 @@
__ brx(Assembler::equal, false, Assembler::pt, skip); \
__ delayed()->nop(); \
__ breakpoint_trap(); \
- __ emit_long(marker); \
+ __ emit_int32(marker); \
__ bind(skip); \
}
#else
@@ -1480,13 +1491,16 @@
//
// assert_different_registers(state, prev_state);
const Register Gtmp = G3_scratch;
+ const RconstMethod = G3_scratch;
const Register tmp = O2;
- const Address size_of_parameters(G5_method, 0, in_bytes(Method::size_of_parameters_offset()));
- const Address size_of_locals (G5_method, 0, in_bytes(Method::size_of_locals_offset()));
+ const Address constMethod(G5_method, 0, in_bytes(Method::const_offset()));
+ const Address size_of_parameters(RconstMethod, 0, in_bytes(ConstMethod::size_of_parameters_offset()));
+ const Address size_of_locals (RconstMethod, 0, in_bytes(ConstMethod::size_of_locals_offset()));
+ __ ld_ptr(constMethod, RconstMethod);
__ lduh(size_of_parameters, tmp);
- __ sll(tmp, LogBytesPerWord, Gtmp); // parameter size in bytes
- __ add(args, Gtmp, Gargs); // points to first local + BytesPerWord
+ __ sll(tmp, LogBytesPerWord, Gargs); // parameter size in bytes
+ __ add(args, Gargs, Gargs); // points to first local + BytesPerWord
// NEW
__ add(Gargs, -wordSize, Gargs); // points to first local[0]
// determine extra space for non-argument locals & adjust caller's SP
@@ -1538,9 +1552,6 @@
const Address constMethod (G5_method, 0, in_bytes(Method::const_offset()));
const Address access_flags (G5_method, 0, in_bytes(Method::access_flags_offset()));
- const Address size_of_parameters(G5_method, 0, in_bytes(Method::size_of_parameters_offset()));
- const Address max_stack (G5_method, 0, in_bytes(Method::max_stack_offset()));
- const Address size_of_locals (G5_method, 0, in_bytes(Method::size_of_locals_offset()));
address entry_point = __ pc();
__ mov(G0, prevState); // no current activation
@@ -1748,7 +1759,9 @@
__ ld_ptr(STATE(_result._to_call._callee), L4_scratch); // called method
__ ld_ptr(STATE(_stack), L1_scratch); // get top of java expr stack
- __ lduh(L4_scratch, in_bytes(Method::size_of_parameters_offset()), L2_scratch); // get parameter size
+ // get parameter size
+ __ ld_ptr(L4_scratch, in_bytes(Method::const_offset()), L2_scratch);
+ __ lduh(L2_scratch, in_bytes(ConstMethod::size_of_parameters_offset()), L2_scratch);
__ sll(L2_scratch, LogBytesPerWord, L2_scratch ); // parameter size in bytes
__ add(L1_scratch, L2_scratch, L1_scratch); // stack destination for result
__ ld(L4_scratch, in_bytes(Method::result_index_offset()), L3_scratch); // called method result type index
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/frame_sparc.cpp
--- a/src/cpu/sparc/vm/frame_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/frame_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -648,7 +648,7 @@
Method* m = *interpreter_frame_method_addr();
// validate the method we'd find in this potential sender
- if (!Universe::heap()->is_valid_method(m)) return false;
+ if (!m->is_valid_method()) return false;
// stack frames shouldn't be much larger than max_stack elements
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/frame_sparc.hpp
--- a/src/cpu/sparc/vm/frame_sparc.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/frame_sparc.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -204,25 +204,6 @@
intptr_t* out_register_addr(Register reg) const {
return younger_sp_addr_at(reg->after_save()->sp_offset_in_saved_window());
}
- intptr_t* memory_param_addr(int param_ix, bool is_in) const {
- int offset = callee_register_argument_save_area_sp_offset + param_ix;
- if (is_in)
- return fp_addr_at(offset);
- else
- return sp_addr_at(offset);
- }
- intptr_t* param_addr(int param_ix, bool is_in) const {
- if (param_ix >= callee_register_argument_save_area_words)
- return memory_param_addr(param_ix, is_in);
- else if (is_in)
- return register_addr(Argument(param_ix, true).as_register());
- else {
- // the registers are stored in the next younger frame
- // %%% is this really necessary?
- ShouldNotReachHere();
- return NULL;
- }
- }
// Interpreter frames
@@ -269,12 +250,8 @@
#ifndef CC_INTERP
// where Lmonitors is saved:
- BasicObjectLock** interpreter_frame_monitors_addr() const {
- return (BasicObjectLock**) sp_addr_at(Lmonitors->sp_offset_in_saved_window());
- }
- intptr_t** interpreter_frame_esp_addr() const {
- return (intptr_t**)sp_addr_at(Lesp->sp_offset_in_saved_window());
- }
+ inline BasicObjectLock** interpreter_frame_monitors_addr() const;
+ inline intptr_t** interpreter_frame_esp_addr() const;
inline void interpreter_frame_set_tos_address(intptr_t* x);
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/frame_sparc.inline.hpp
--- a/src/cpu/sparc/vm/frame_sparc.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/frame_sparc.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,6 +25,8 @@
#ifndef CPU_SPARC_VM_FRAME_SPARC_INLINE_HPP
#define CPU_SPARC_VM_FRAME_SPARC_INLINE_HPP
+#include "asm/macroAssembler.hpp"
+
// Inline functions for SPARC frames:
// Constructors
@@ -185,6 +187,13 @@
return *interpreter_frame_esp_addr() + 1;
}
+inline BasicObjectLock** frame::interpreter_frame_monitors_addr() const {
+ return (BasicObjectLock**) sp_addr_at(Lmonitors->sp_offset_in_saved_window());
+}
+inline intptr_t** frame::interpreter_frame_esp_addr() const {
+ return (intptr_t**)sp_addr_at(Lesp->sp_offset_in_saved_window());
+}
+
inline void frame::interpreter_frame_set_tos_address( intptr_t* x ) {
*interpreter_frame_esp_addr() = x - 1;
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/icBuffer_sparc.cpp
--- a/src/cpu/sparc/vm/icBuffer_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/icBuffer_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_sparc.inline.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "code/icBuffer.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "interpreter/bytecodes.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/icache_sparc.cpp
--- a/src/cpu/sparc/vm/icache_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/icache_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "assembler_sparc.inline.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "runtime/icache.hpp"
#define __ _masm->
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/interp_masm_sparc.cpp
--- a/src/cpu/sparc/vm/interp_masm_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/interp_masm_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -36,12 +36,7 @@
#include "runtime/basicLock.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/sharedRuntime.hpp"
-#ifdef TARGET_OS_FAMILY_linux
-# include "thread_linux.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_solaris
-# include "thread_solaris.inline.hpp"
-#endif
+#include "runtime/thread.inline.hpp"
#ifndef CC_INTERP
#ifndef FAST_DISPATCH
@@ -523,7 +518,8 @@
delayed()->nop();
// Compute max expression stack+register save area
- lduh(Lmethod, in_bytes(Method::max_stack_offset()), Gframe_size); // Load max stack.
+ ld_ptr(Lmethod, in_bytes(Method::const_offset()), Gframe_size);
+ lduh(Gframe_size, in_bytes(ConstMethod::max_stack_offset()), Gframe_size); // Load max stack.
add( Gframe_size, frame::memory_parameter_word_sp_offset, Gframe_size );
//
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/interp_masm_sparc.hpp
--- a/src/cpu/sparc/vm/interp_masm_sparc.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/interp_masm_sparc.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,7 +25,7 @@
#ifndef CPU_SPARC_VM_INTERP_MASM_SPARC_HPP
#define CPU_SPARC_VM_INTERP_MASM_SPARC_HPP
-#include "assembler_sparc.inline.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "interpreter/invocationCounter.hpp"
// This file specializes the assember with interpreter-specific macros
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/interpreter_sparc.cpp
--- a/src/cpu/sparc/vm/interpreter_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/interpreter_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
+#include "asm/macroAssembler.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterGenerator.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/jniFastGetField_sparc.cpp
--- a/src/cpu/sparc/vm/jniFastGetField_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/jniFastGetField_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "assembler_sparc.inline.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "memory/resourceArea.hpp"
#include "prims/jniFastGetField.hpp"
#include "prims/jvm_misc.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/macroAssembler_sparc.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cpu/sparc/vm/macroAssembler_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -0,0 +1,4582 @@
+/*
+ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/assembler.inline.hpp"
+#include "compiler/disassembler.hpp"
+#include "gc_interface/collectedHeap.inline.hpp"
+#include "interpreter/interpreter.hpp"
+#include "memory/cardTableModRefBS.hpp"
+#include "memory/resourceArea.hpp"
+#include "prims/methodHandles.hpp"
+#include "runtime/biasedLocking.hpp"
+#include "runtime/interfaceSupport.hpp"
+#include "runtime/objectMonitor.hpp"
+#include "runtime/os.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#ifndef SERIALGC
+#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
+#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
+#include "gc_implementation/g1/heapRegion.hpp"
+#endif
+
+#ifdef PRODUCT
+#define BLOCK_COMMENT(str) /* nothing */
+#define STOP(error) stop(error)
+#else
+#define BLOCK_COMMENT(str) block_comment(str)
+#define STOP(error) block_comment(error); stop(error)
+#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, relocInfo::relocType disp_reloc) {
+ assert(scale == 0, "not supported");
+ RelocationHolder rspec;
+ if (disp_reloc != relocInfo::none) {
+ rspec = Relocation::spec_simple(disp_reloc);
+ }
+
+ Register rindex = as_Register(index);
+ if (rindex != G0) {
+ Address madr(as_Register(base), rindex);
+ madr._rspec = rspec;
+ return madr;
+ } else {
+ Address madr(as_Register(base), disp);
+ madr._rspec = rspec;
+ return madr;
+ }
+}
+
+Address Argument::address_in_frame() const {
+ // Warning: In LP64 mode disp will occupy more than 10 bits, but
+ // op codes such as ld or ldx, only access disp() to get
+ // their simm13 argument.
+ int disp = ((_number - Argument::n_register_parameters + frame::memory_parameter_word_sp_offset) * BytesPerWord) + STACK_BIAS;
+ if (is_in())
+ return Address(FP, disp); // In argument.
+ else
+ return Address(SP, disp); // Out argument.
+}
+
+static const char* argumentNames[][2] = {
+ {"A0","P0"}, {"A1","P1"}, {"A2","P2"}, {"A3","P3"}, {"A4","P4"},
+ {"A5","P5"}, {"A6","P6"}, {"A7","P7"}, {"A8","P8"}, {"A9","P9"},
+ {"A(n>9)","P(n>9)"}
+};
+
+const char* Argument::name() const {
+ int nofArgs = sizeof argumentNames / sizeof argumentNames[0];
+ int num = number();
+ if (num >= nofArgs) num = nofArgs - 1;
+ return argumentNames[num][is_in() ? 1 : 0];
+}
+
+#ifdef ASSERT
+// On RISC, there's no benefit to verifying instruction boundaries.
+bool AbstractAssembler::pd_check_instruction_mark() { return false; }
+#endif
+
+// Patch instruction inst at offset inst_pos to refer to dest_pos
+// and return the resulting instruction.
+// We should have pcs, not offsets, but since all is relative, it will work out
+// OK.
+int MacroAssembler::patched_branch(int dest_pos, int inst, int inst_pos) {
+ int m; // mask for displacement field
+ int v; // new value for displacement field
+ const int word_aligned_ones = -4;
+ switch (inv_op(inst)) {
+ default: ShouldNotReachHere();
+ case call_op: m = wdisp(word_aligned_ones, 0, 30); v = wdisp(dest_pos, inst_pos, 30); break;
+ case branch_op:
+ switch (inv_op2(inst)) {
+ case fbp_op2: m = wdisp( word_aligned_ones, 0, 19); v = wdisp( dest_pos, inst_pos, 19); break;
+ case bp_op2: m = wdisp( word_aligned_ones, 0, 19); v = wdisp( dest_pos, inst_pos, 19); break;
+ case fb_op2: m = wdisp( word_aligned_ones, 0, 22); v = wdisp( dest_pos, inst_pos, 22); break;
+ case br_op2: m = wdisp( word_aligned_ones, 0, 22); v = wdisp( dest_pos, inst_pos, 22); break;
+ case cb_op2: m = wdisp( word_aligned_ones, 0, 22); v = wdisp( dest_pos, inst_pos, 22); break;
+ case bpr_op2: {
+ if (is_cbcond(inst)) {
+ m = wdisp10(word_aligned_ones, 0);
+ v = wdisp10(dest_pos, inst_pos);
+ } else {
+ m = wdisp16(word_aligned_ones, 0);
+ v = wdisp16(dest_pos, inst_pos);
+ }
+ break;
+ }
+ default: ShouldNotReachHere();
+ }
+ }
+ return inst & ~m | v;
+}
+
+// Return the offset of the branch destionation of instruction inst
+// at offset pos.
+// Should have pcs, but since all is relative, it works out.
+int MacroAssembler::branch_destination(int inst, int pos) {
+ int r;
+ switch (inv_op(inst)) {
+ default: ShouldNotReachHere();
+ case call_op: r = inv_wdisp(inst, pos, 30); break;
+ case branch_op:
+ switch (inv_op2(inst)) {
+ case fbp_op2: r = inv_wdisp( inst, pos, 19); break;
+ case bp_op2: r = inv_wdisp( inst, pos, 19); break;
+ case fb_op2: r = inv_wdisp( inst, pos, 22); break;
+ case br_op2: r = inv_wdisp( inst, pos, 22); break;
+ case cb_op2: r = inv_wdisp( inst, pos, 22); break;
+ case bpr_op2: {
+ if (is_cbcond(inst)) {
+ r = inv_wdisp10(inst, pos);
+ } else {
+ r = inv_wdisp16(inst, pos);
+ }
+ break;
+ }
+ default: ShouldNotReachHere();
+ }
+ }
+ return r;
+}
+
+void MacroAssembler::null_check(Register reg, int offset) {
+ if (needs_explicit_null_check((intptr_t)offset)) {
+ // provoke OS NULL exception if reg = NULL by
+ // accessing M[reg] w/o changing any registers
+ ld_ptr(reg, 0, G0);
+ }
+ else {
+ // nothing to do, (later) access of M[reg + offset]
+ // will provoke OS NULL exception if reg = NULL
+ }
+}
+
+// Ring buffer jumps
+
+#ifndef PRODUCT
+void MacroAssembler::ret( bool trace ) { if (trace) {
+ mov(I7, O7); // traceable register
+ JMP(O7, 2 * BytesPerInstWord);
+ } else {
+ jmpl( I7, 2 * BytesPerInstWord, G0 );
+ }
+ }
+
+void MacroAssembler::retl( bool trace ) { if (trace) JMP(O7, 2 * BytesPerInstWord);
+ else jmpl( O7, 2 * BytesPerInstWord, G0 ); }
+#endif /* PRODUCT */
+
+
+void MacroAssembler::jmp2(Register r1, Register r2, const char* file, int line ) {
+ assert_not_delayed();
+ // This can only be traceable if r1 & r2 are visible after a window save
+ if (TraceJumps) {
+#ifndef PRODUCT
+ save_frame(0);
+ verify_thread();
+ ld(G2_thread, in_bytes(JavaThread::jmp_ring_index_offset()), O0);
+ add(G2_thread, in_bytes(JavaThread::jmp_ring_offset()), O1);
+ sll(O0, exact_log2(4*sizeof(intptr_t)), O2);
+ add(O2, O1, O1);
+
+ add(r1->after_save(), r2->after_save(), O2);
+ set((intptr_t)file, O3);
+ set(line, O4);
+ Label L;
+ // get nearby pc, store jmp target
+ call(L, relocInfo::none); // No relocation for call to pc+0x8
+ delayed()->st(O2, O1, 0);
+ bind(L);
+
+ // store nearby pc
+ st(O7, O1, sizeof(intptr_t));
+ // store file
+ st(O3, O1, 2*sizeof(intptr_t));
+ // store line
+ st(O4, O1, 3*sizeof(intptr_t));
+ add(O0, 1, O0);
+ and3(O0, JavaThread::jump_ring_buffer_size - 1, O0);
+ st(O0, G2_thread, in_bytes(JavaThread::jmp_ring_index_offset()));
+ restore();
+#endif /* PRODUCT */
+ }
+ jmpl(r1, r2, G0);
+}
+void MacroAssembler::jmp(Register r1, int offset, const char* file, int line ) {
+ assert_not_delayed();
+ // This can only be traceable if r1 is visible after a window save
+ if (TraceJumps) {
+#ifndef PRODUCT
+ save_frame(0);
+ verify_thread();
+ ld(G2_thread, in_bytes(JavaThread::jmp_ring_index_offset()), O0);
+ add(G2_thread, in_bytes(JavaThread::jmp_ring_offset()), O1);
+ sll(O0, exact_log2(4*sizeof(intptr_t)), O2);
+ add(O2, O1, O1);
+
+ add(r1->after_save(), offset, O2);
+ set((intptr_t)file, O3);
+ set(line, O4);
+ Label L;
+ // get nearby pc, store jmp target
+ call(L, relocInfo::none); // No relocation for call to pc+0x8
+ delayed()->st(O2, O1, 0);
+ bind(L);
+
+ // store nearby pc
+ st(O7, O1, sizeof(intptr_t));
+ // store file
+ st(O3, O1, 2*sizeof(intptr_t));
+ // store line
+ st(O4, O1, 3*sizeof(intptr_t));
+ add(O0, 1, O0);
+ and3(O0, JavaThread::jump_ring_buffer_size - 1, O0);
+ st(O0, G2_thread, in_bytes(JavaThread::jmp_ring_index_offset()));
+ restore();
+#endif /* PRODUCT */
+ }
+ jmp(r1, offset);
+}
+
+// This code sequence is relocatable to any address, even on LP64.
+void MacroAssembler::jumpl(const AddressLiteral& addrlit, Register temp, Register d, int offset, const char* file, int line) {
+ assert_not_delayed();
+ // Force fixed length sethi because NativeJump and NativeFarCall don't handle
+ // variable length instruction streams.
+ patchable_sethi(addrlit, temp);
+ Address a(temp, addrlit.low10() + offset); // Add the offset to the displacement.
+ if (TraceJumps) {
+#ifndef PRODUCT
+ // Must do the add here so relocation can find the remainder of the
+ // value to be relocated.
+ add(a.base(), a.disp(), a.base(), addrlit.rspec(offset));
+ save_frame(0);
+ verify_thread();
+ ld(G2_thread, in_bytes(JavaThread::jmp_ring_index_offset()), O0);
+ add(G2_thread, in_bytes(JavaThread::jmp_ring_offset()), O1);
+ sll(O0, exact_log2(4*sizeof(intptr_t)), O2);
+ add(O2, O1, O1);
+
+ set((intptr_t)file, O3);
+ set(line, O4);
+ Label L;
+
+ // get nearby pc, store jmp target
+ call(L, relocInfo::none); // No relocation for call to pc+0x8
+ delayed()->st(a.base()->after_save(), O1, 0);
+ bind(L);
+
+ // store nearby pc
+ st(O7, O1, sizeof(intptr_t));
+ // store file
+ st(O3, O1, 2*sizeof(intptr_t));
+ // store line
+ st(O4, O1, 3*sizeof(intptr_t));
+ add(O0, 1, O0);
+ and3(O0, JavaThread::jump_ring_buffer_size - 1, O0);
+ st(O0, G2_thread, in_bytes(JavaThread::jmp_ring_index_offset()));
+ restore();
+ jmpl(a.base(), G0, d);
+#else
+ jmpl(a.base(), a.disp(), d);
+#endif /* PRODUCT */
+ } else {
+ jmpl(a.base(), a.disp(), d);
+ }
+}
+
+void MacroAssembler::jump(const AddressLiteral& addrlit, Register temp, int offset, const char* file, int line) {
+ jumpl(addrlit, temp, G0, offset, file, line);
+}
+
+
+// Conditional breakpoint (for assertion checks in assembly code)
+void MacroAssembler::breakpoint_trap(Condition c, CC cc) {
+ trap(c, cc, G0, ST_RESERVED_FOR_USER_0);
+}
+
+// We want to use ST_BREAKPOINT here, but the debugger is confused by it.
+void MacroAssembler::breakpoint_trap() {
+ trap(ST_RESERVED_FOR_USER_0);
+}
+
+// flush windows (except current) using flushw instruction if avail.
+void MacroAssembler::flush_windows() {
+ if (VM_Version::v9_instructions_work()) flushw();
+ else flush_windows_trap();
+}
+
+// Write serialization page so VM thread can do a pseudo remote membar
+// We use the current thread pointer to calculate a thread specific
+// offset to write to within the page. This minimizes bus traffic
+// due to cache line collision.
+void MacroAssembler::serialize_memory(Register thread, Register tmp1, Register tmp2) {
+ srl(thread, os::get_serialize_page_shift_count(), tmp2);
+ if (Assembler::is_simm13(os::vm_page_size())) {
+ and3(tmp2, (os::vm_page_size() - sizeof(int)), tmp2);
+ }
+ else {
+ set((os::vm_page_size() - sizeof(int)), tmp1);
+ and3(tmp2, tmp1, tmp2);
+ }
+ set(os::get_memory_serialize_page(), tmp1);
+ st(G0, tmp1, tmp2);
+}
+
+
+
+void MacroAssembler::enter() {
+ Unimplemented();
+}
+
+void MacroAssembler::leave() {
+ Unimplemented();
+}
+
+void MacroAssembler::mult(Register s1, Register s2, Register d) {
+ if(VM_Version::v9_instructions_work()) {
+ mulx (s1, s2, d);
+ } else {
+ smul (s1, s2, d);
+ }
+}
+
+void MacroAssembler::mult(Register s1, int simm13a, Register d) {
+ if(VM_Version::v9_instructions_work()) {
+ mulx (s1, simm13a, d);
+ } else {
+ smul (s1, simm13a, d);
+ }
+}
+
+
+#ifdef ASSERT
+void MacroAssembler::read_ccr_v8_assert(Register ccr_save) {
+ const Register s1 = G3_scratch;
+ const Register s2 = G4_scratch;
+ Label get_psr_test;
+ // Get the condition codes the V8 way.
+ read_ccr_trap(s1);
+ mov(ccr_save, s2);
+ // This is a test of V8 which has icc but not xcc
+ // so mask off the xcc bits
+ and3(s2, 0xf, s2);
+ // Compare condition codes from the V8 and V9 ways.
+ subcc(s2, s1, G0);
+ br(Assembler::notEqual, true, Assembler::pt, get_psr_test);
+ delayed()->breakpoint_trap();
+ bind(get_psr_test);
+}
+
+void MacroAssembler::write_ccr_v8_assert(Register ccr_save) {
+ const Register s1 = G3_scratch;
+ const Register s2 = G4_scratch;
+ Label set_psr_test;
+ // Write out the saved condition codes the V8 way
+ write_ccr_trap(ccr_save, s1, s2);
+ // Read back the condition codes using the V9 instruction
+ rdccr(s1);
+ mov(ccr_save, s2);
+ // This is a test of V8 which has icc but not xcc
+ // so mask off the xcc bits
+ and3(s2, 0xf, s2);
+ and3(s1, 0xf, s1);
+ // Compare the V8 way with the V9 way.
+ subcc(s2, s1, G0);
+ br(Assembler::notEqual, true, Assembler::pt, set_psr_test);
+ delayed()->breakpoint_trap();
+ bind(set_psr_test);
+}
+#else
+#define read_ccr_v8_assert(x)
+#define write_ccr_v8_assert(x)
+#endif // ASSERT
+
+void MacroAssembler::read_ccr(Register ccr_save) {
+ if (VM_Version::v9_instructions_work()) {
+ rdccr(ccr_save);
+ // Test code sequence used on V8. Do not move above rdccr.
+ read_ccr_v8_assert(ccr_save);
+ } else {
+ read_ccr_trap(ccr_save);
+ }
+}
+
+void MacroAssembler::write_ccr(Register ccr_save) {
+ if (VM_Version::v9_instructions_work()) {
+ // Test code sequence used on V8. Do not move below wrccr.
+ write_ccr_v8_assert(ccr_save);
+ wrccr(ccr_save);
+ } else {
+ const Register temp_reg1 = G3_scratch;
+ const Register temp_reg2 = G4_scratch;
+ write_ccr_trap(ccr_save, temp_reg1, temp_reg2);
+ }
+}
+
+
+// Calls to C land
+
+#ifdef ASSERT
+// a hook for debugging
+static Thread* reinitialize_thread() {
+ return ThreadLocalStorage::thread();
+}
+#else
+#define reinitialize_thread ThreadLocalStorage::thread
+#endif
+
+#ifdef ASSERT
+address last_get_thread = NULL;
+#endif
+
+// call this when G2_thread is not known to be valid
+void MacroAssembler::get_thread() {
+ save_frame(0); // to avoid clobbering O0
+ mov(G1, L0); // avoid clobbering G1
+ mov(G5_method, L1); // avoid clobbering G5
+ mov(G3, L2); // avoid clobbering G3 also
+ mov(G4, L5); // avoid clobbering G4
+#ifdef ASSERT
+ AddressLiteral last_get_thread_addrlit(&last_get_thread);
+ set(last_get_thread_addrlit, L3);
+ inc(L4, get_pc(L4) + 2 * BytesPerInstWord); // skip getpc() code + inc + st_ptr to point L4 at call
+ st_ptr(L4, L3, 0);
+#endif
+ call(CAST_FROM_FN_PTR(address, reinitialize_thread), relocInfo::runtime_call_type);
+ delayed()->nop();
+ mov(L0, G1);
+ mov(L1, G5_method);
+ mov(L2, G3);
+ mov(L5, G4);
+ restore(O0, 0, G2_thread);
+}
+
+static Thread* verify_thread_subroutine(Thread* gthread_value) {
+ Thread* correct_value = ThreadLocalStorage::thread();
+ guarantee(gthread_value == correct_value, "G2_thread value must be the thread");
+ return correct_value;
+}
+
+void MacroAssembler::verify_thread() {
+ if (VerifyThread) {
+ // NOTE: this chops off the heads of the 64-bit O registers.
+#ifdef CC_INTERP
+ save_frame(0);
+#else
+ // make sure G2_thread contains the right value
+ save_frame_and_mov(0, Lmethod, Lmethod); // to avoid clobbering O0 (and propagate Lmethod for -Xprof)
+ mov(G1, L1); // avoid clobbering G1
+ // G2 saved below
+ mov(G3, L3); // avoid clobbering G3
+ mov(G4, L4); // avoid clobbering G4
+ mov(G5_method, L5); // avoid clobbering G5_method
+#endif /* CC_INTERP */
+#if defined(COMPILER2) && !defined(_LP64)
+ // Save & restore possible 64-bit Long arguments in G-regs
+ srlx(G1,32,L0);
+ srlx(G4,32,L6);
+#endif
+ call(CAST_FROM_FN_PTR(address,verify_thread_subroutine), relocInfo::runtime_call_type);
+ delayed()->mov(G2_thread, O0);
+
+ mov(L1, G1); // Restore G1
+ // G2 restored below
+ mov(L3, G3); // restore G3
+ mov(L4, G4); // restore G4
+ mov(L5, G5_method); // restore G5_method
+#if defined(COMPILER2) && !defined(_LP64)
+ // Save & restore possible 64-bit Long arguments in G-regs
+ sllx(L0,32,G2); // Move old high G1 bits high in G2
+ srl(G1, 0,G1); // Clear current high G1 bits
+ or3 (G1,G2,G1); // Recover 64-bit G1
+ sllx(L6,32,G2); // Move old high G4 bits high in G2
+ srl(G4, 0,G4); // Clear current high G4 bits
+ or3 (G4,G2,G4); // Recover 64-bit G4
+#endif
+ restore(O0, 0, G2_thread);
+ }
+}
+
+
+void MacroAssembler::save_thread(const Register thread_cache) {
+ verify_thread();
+ if (thread_cache->is_valid()) {
+ assert(thread_cache->is_local() || thread_cache->is_in(), "bad volatile");
+ mov(G2_thread, thread_cache);
+ }
+ if (VerifyThread) {
+ // smash G2_thread, as if the VM were about to anyway
+ set(0x67676767, G2_thread);
+ }
+}
+
+
+void MacroAssembler::restore_thread(const Register thread_cache) {
+ if (thread_cache->is_valid()) {
+ assert(thread_cache->is_local() || thread_cache->is_in(), "bad volatile");
+ mov(thread_cache, G2_thread);
+ verify_thread();
+ } else {
+ // do it the slow way
+ get_thread();
+ }
+}
+
+
+// %%% maybe get rid of [re]set_last_Java_frame
+void MacroAssembler::set_last_Java_frame(Register last_java_sp, Register last_Java_pc) {
+ assert_not_delayed();
+ Address flags(G2_thread, JavaThread::frame_anchor_offset() +
+ JavaFrameAnchor::flags_offset());
+ Address pc_addr(G2_thread, JavaThread::last_Java_pc_offset());
+
+ // Always set last_Java_pc and flags first because once last_Java_sp is visible
+ // has_last_Java_frame is true and users will look at the rest of the fields.
+ // (Note: flags should always be zero before we get here so doesn't need to be set.)
+
+#ifdef ASSERT
+ // Verify that flags was zeroed on return to Java
+ Label PcOk;
+ save_frame(0); // to avoid clobbering O0
+ ld_ptr(pc_addr, L0);
+ br_null_short(L0, Assembler::pt, PcOk);
+ STOP("last_Java_pc not zeroed before leaving Java");
+ bind(PcOk);
+
+ // Verify that flags was zeroed on return to Java
+ Label FlagsOk;
+ ld(flags, L0);
+ tst(L0);
+ br(Assembler::zero, false, Assembler::pt, FlagsOk);
+ delayed() -> restore();
+ STOP("flags not zeroed before leaving Java");
+ bind(FlagsOk);
+#endif /* ASSERT */
+ //
+ // When returning from calling out from Java mode the frame anchor's last_Java_pc
+ // will always be set to NULL. It is set here so that if we are doing a call to
+ // native (not VM) that we capture the known pc and don't have to rely on the
+ // native call having a standard frame linkage where we can find the pc.
+
+ if (last_Java_pc->is_valid()) {
+ st_ptr(last_Java_pc, pc_addr);
+ }
+
+#ifdef _LP64
+#ifdef ASSERT
+ // Make sure that we have an odd stack
+ Label StackOk;
+ andcc(last_java_sp, 0x01, G0);
+ br(Assembler::notZero, false, Assembler::pt, StackOk);
+ delayed()->nop();
+ STOP("Stack Not Biased in set_last_Java_frame");
+ bind(StackOk);
+#endif // ASSERT
+ assert( last_java_sp != G4_scratch, "bad register usage in set_last_Java_frame");
+ add( last_java_sp, STACK_BIAS, G4_scratch );
+ st_ptr(G4_scratch, G2_thread, JavaThread::last_Java_sp_offset());
+#else
+ st_ptr(last_java_sp, G2_thread, JavaThread::last_Java_sp_offset());
+#endif // _LP64
+}
+
+void MacroAssembler::reset_last_Java_frame(void) {
+ assert_not_delayed();
+
+ Address sp_addr(G2_thread, JavaThread::last_Java_sp_offset());
+ Address pc_addr(G2_thread, JavaThread::frame_anchor_offset() + JavaFrameAnchor::last_Java_pc_offset());
+ Address flags (G2_thread, JavaThread::frame_anchor_offset() + JavaFrameAnchor::flags_offset());
+
+#ifdef ASSERT
+ // check that it WAS previously set
+#ifdef CC_INTERP
+ save_frame(0);
+#else
+ save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod to helper frame for -Xprof
+#endif /* CC_INTERP */
+ ld_ptr(sp_addr, L0);
+ tst(L0);
+ breakpoint_trap(Assembler::zero, Assembler::ptr_cc);
+ restore();
+#endif // ASSERT
+
+ st_ptr(G0, sp_addr);
+ // Always return last_Java_pc to zero
+ st_ptr(G0, pc_addr);
+ // Always null flags after return to Java
+ st(G0, flags);
+}
+
+
+void MacroAssembler::call_VM_base(
+ Register oop_result,
+ Register thread_cache,
+ Register last_java_sp,
+ address entry_point,
+ int number_of_arguments,
+ bool check_exceptions)
+{
+ assert_not_delayed();
+
+ // determine last_java_sp register
+ if (!last_java_sp->is_valid()) {
+ last_java_sp = SP;
+ }
+ // debugging support
+ assert(number_of_arguments >= 0 , "cannot have negative number of arguments");
+
+ // 64-bit last_java_sp is biased!
+ set_last_Java_frame(last_java_sp, noreg);
+ if (VerifyThread) mov(G2_thread, O0); // about to be smashed; pass early
+ save_thread(thread_cache);
+ // do the call
+ call(entry_point, relocInfo::runtime_call_type);
+ if (!VerifyThread)
+ delayed()->mov(G2_thread, O0); // pass thread as first argument
+ else
+ delayed()->nop(); // (thread already passed)
+ restore_thread(thread_cache);
+ reset_last_Java_frame();
+
+ // check for pending exceptions. use Gtemp as scratch register.
+ if (check_exceptions) {
+ 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);
+ }
+}
+
+void MacroAssembler::check_and_forward_exception(Register scratch_reg)
+{
+ Label L;
+
+ check_and_handle_popframe(scratch_reg);
+ check_and_handle_earlyret(scratch_reg);
+
+ Address exception_addr(G2_thread, Thread::pending_exception_offset());
+ ld_ptr(exception_addr, scratch_reg);
+ br_null_short(scratch_reg, pt, L);
+ // we use O7 linkage so that forward_exception_entry has the issuing PC
+ call(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type);
+ delayed()->nop();
+ bind(L);
+}
+
+
+void MacroAssembler::check_and_handle_popframe(Register scratch_reg) {
+}
+
+
+void MacroAssembler::check_and_handle_earlyret(Register scratch_reg) {
+}
+
+
+void MacroAssembler::call_VM(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) {
+ call_VM_base(oop_result, noreg, noreg, entry_point, number_of_arguments, check_exceptions);
+}
+
+
+void MacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions) {
+ // O0 is reserved for the thread
+ mov(arg_1, O1);
+ call_VM(oop_result, entry_point, 1, check_exceptions);
+}
+
+
+void MacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions) {
+ // O0 is reserved for the thread
+ mov(arg_1, O1);
+ mov(arg_2, O2); assert(arg_2 != O1, "smashed argument");
+ call_VM(oop_result, entry_point, 2, check_exceptions);
+}
+
+
+void MacroAssembler::call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions) {
+ // O0 is reserved for the thread
+ mov(arg_1, O1);
+ mov(arg_2, O2); assert(arg_2 != O1, "smashed argument");
+ mov(arg_3, O3); assert(arg_3 != O1 && arg_3 != O2, "smashed argument");
+ call_VM(oop_result, entry_point, 3, check_exceptions);
+}
+
+
+
+// Note: The following call_VM overloadings are useful when a "save"
+// has already been performed by a stub, and the last Java frame is
+// the previous one. In that case, last_java_sp must be passed as FP
+// instead of SP.
+
+
+void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, int number_of_arguments, bool check_exceptions) {
+ call_VM_base(oop_result, noreg, last_java_sp, entry_point, number_of_arguments, check_exceptions);
+}
+
+
+void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, bool check_exceptions) {
+ // O0 is reserved for the thread
+ mov(arg_1, O1);
+ call_VM(oop_result, last_java_sp, entry_point, 1, check_exceptions);
+}
+
+
+void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, bool check_exceptions) {
+ // O0 is reserved for the thread
+ mov(arg_1, O1);
+ mov(arg_2, O2); assert(arg_2 != O1, "smashed argument");
+ call_VM(oop_result, last_java_sp, entry_point, 2, check_exceptions);
+}
+
+
+void MacroAssembler::call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions) {
+ // O0 is reserved for the thread
+ mov(arg_1, O1);
+ mov(arg_2, O2); assert(arg_2 != O1, "smashed argument");
+ mov(arg_3, O3); assert(arg_3 != O1 && arg_3 != O2, "smashed argument");
+ call_VM(oop_result, last_java_sp, entry_point, 3, check_exceptions);
+}
+
+
+
+void MacroAssembler::call_VM_leaf_base(Register thread_cache, address entry_point, int number_of_arguments) {
+ assert_not_delayed();
+ save_thread(thread_cache);
+ // do the call
+ 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
+}
+
+
+void MacroAssembler::call_VM_leaf(Register thread_cache, address entry_point, int number_of_arguments) {
+ call_VM_leaf_base(thread_cache, entry_point, number_of_arguments);
+}
+
+
+void MacroAssembler::call_VM_leaf(Register thread_cache, address entry_point, Register arg_1) {
+ mov(arg_1, O0);
+ call_VM_leaf(thread_cache, entry_point, 1);
+}
+
+
+void MacroAssembler::call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2) {
+ mov(arg_1, O0);
+ mov(arg_2, O1); assert(arg_2 != O0, "smashed argument");
+ call_VM_leaf(thread_cache, entry_point, 2);
+}
+
+
+void MacroAssembler::call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2, Register arg_3) {
+ mov(arg_1, O0);
+ mov(arg_2, O1); assert(arg_2 != O0, "smashed argument");
+ mov(arg_3, O2); assert(arg_3 != O0 && arg_3 != O1, "smashed argument");
+ call_VM_leaf(thread_cache, entry_point, 3);
+}
+
+
+void MacroAssembler::get_vm_result(Register oop_result) {
+ verify_thread();
+ Address vm_result_addr(G2_thread, JavaThread::vm_result_offset());
+ ld_ptr( vm_result_addr, oop_result);
+ st_ptr(G0, vm_result_addr);
+ verify_oop(oop_result);
+}
+
+
+void MacroAssembler::get_vm_result_2(Register metadata_result) {
+ verify_thread();
+ Address vm_result_addr_2(G2_thread, JavaThread::vm_result_2_offset());
+ ld_ptr(vm_result_addr_2, metadata_result);
+ st_ptr(G0, vm_result_addr_2);
+}
+
+
+// We require that C code which does not return a value in vm_result will
+// leave it undisturbed.
+void MacroAssembler::set_vm_result(Register oop_result) {
+ verify_thread();
+ Address vm_result_addr(G2_thread, JavaThread::vm_result_offset());
+ verify_oop(oop_result);
+
+# ifdef ASSERT
+ // Check that we are not overwriting any other oop.
+#ifdef CC_INTERP
+ save_frame(0);
+#else
+ save_frame_and_mov(0, Lmethod, Lmethod); // Propagate Lmethod for -Xprof
+#endif /* CC_INTERP */
+ ld_ptr(vm_result_addr, L0);
+ tst(L0);
+ restore();
+ breakpoint_trap(notZero, Assembler::ptr_cc);
+ // }
+# endif
+
+ st_ptr(oop_result, vm_result_addr);
+}
+
+
+void MacroAssembler::ic_call(address entry, bool emit_delay) {
+ RelocationHolder rspec = virtual_call_Relocation::spec(pc());
+ patchable_set((intptr_t)Universe::non_oop_word(), G5_inline_cache_reg);
+ relocate(rspec);
+ call(entry, relocInfo::none);
+ if (emit_delay) {
+ delayed()->nop();
+ }
+}
+
+
+void MacroAssembler::card_table_write(jbyte* byte_map_base,
+ Register tmp, Register obj) {
+#ifdef _LP64
+ srlx(obj, CardTableModRefBS::card_shift, obj);
+#else
+ srl(obj, CardTableModRefBS::card_shift, obj);
+#endif
+ assert(tmp != obj, "need separate temp reg");
+ set((address) byte_map_base, tmp);
+ stb(G0, tmp, obj);
+}
+
+
+void MacroAssembler::internal_sethi(const AddressLiteral& addrlit, Register d, bool ForceRelocatable) {
+ address save_pc;
+ int shiftcnt;
+#ifdef _LP64
+# ifdef CHECK_DELAY
+ assert_not_delayed((char*) "cannot put two instructions in delay slot");
+# endif
+ v9_dep();
+ save_pc = pc();
+
+ int msb32 = (int) (addrlit.value() >> 32);
+ int lsb32 = (int) (addrlit.value());
+
+ if (msb32 == 0 && lsb32 >= 0) {
+ Assembler::sethi(lsb32, d, addrlit.rspec());
+ }
+ else if (msb32 == -1) {
+ Assembler::sethi(~lsb32, d, addrlit.rspec());
+ xor3(d, ~low10(~0), d);
+ }
+ else {
+ Assembler::sethi(msb32, d, addrlit.rspec()); // msb 22-bits
+ if (msb32 & 0x3ff) // Any bits?
+ or3(d, msb32 & 0x3ff, d); // msb 32-bits are now in lsb 32
+ if (lsb32 & 0xFFFFFC00) { // done?
+ if ((lsb32 >> 20) & 0xfff) { // Any bits set?
+ sllx(d, 12, d); // Make room for next 12 bits
+ or3(d, (lsb32 >> 20) & 0xfff, d); // Or in next 12
+ shiftcnt = 0; // We already shifted
+ }
+ else
+ shiftcnt = 12;
+ if ((lsb32 >> 10) & 0x3ff) {
+ sllx(d, shiftcnt + 10, d); // Make room for last 10 bits
+ or3(d, (lsb32 >> 10) & 0x3ff, d); // Or in next 10
+ shiftcnt = 0;
+ }
+ else
+ shiftcnt = 10;
+ sllx(d, shiftcnt + 10, d); // Shift leaving disp field 0'd
+ }
+ else
+ sllx(d, 32, d);
+ }
+ // Pad out the instruction sequence so it can be patched later.
+ if (ForceRelocatable || (addrlit.rtype() != relocInfo::none &&
+ addrlit.rtype() != relocInfo::runtime_call_type)) {
+ while (pc() < (save_pc + (7 * BytesPerInstWord)))
+ nop();
+ }
+#else
+ Assembler::sethi(addrlit.value(), d, addrlit.rspec());
+#endif
+}
+
+
+void MacroAssembler::sethi(const AddressLiteral& addrlit, Register d) {
+ internal_sethi(addrlit, d, false);
+}
+
+
+void MacroAssembler::patchable_sethi(const AddressLiteral& addrlit, Register d) {
+ internal_sethi(addrlit, d, true);
+}
+
+
+int MacroAssembler::insts_for_sethi(address a, bool worst_case) {
+#ifdef _LP64
+ if (worst_case) return 7;
+ intptr_t iaddr = (intptr_t) a;
+ int msb32 = (int) (iaddr >> 32);
+ int lsb32 = (int) (iaddr);
+ int count;
+ if (msb32 == 0 && lsb32 >= 0)
+ count = 1;
+ else if (msb32 == -1)
+ count = 2;
+ else {
+ count = 2;
+ if (msb32 & 0x3ff)
+ count++;
+ if (lsb32 & 0xFFFFFC00 ) {
+ if ((lsb32 >> 20) & 0xfff) count += 2;
+ if ((lsb32 >> 10) & 0x3ff) count += 2;
+ }
+ }
+ return count;
+#else
+ return 1;
+#endif
+}
+
+int MacroAssembler::worst_case_insts_for_set() {
+ return insts_for_sethi(NULL, true) + 1;
+}
+
+
+// Keep in sync with MacroAssembler::insts_for_internal_set
+void MacroAssembler::internal_set(const AddressLiteral& addrlit, Register d, bool ForceRelocatable) {
+ intptr_t value = addrlit.value();
+
+ if (!ForceRelocatable && addrlit.rspec().type() == relocInfo::none) {
+ // can optimize
+ if (-4096 <= value && value <= 4095) {
+ or3(G0, value, d); // setsw (this leaves upper 32 bits sign-extended)
+ return;
+ }
+ if (inv_hi22(hi22(value)) == value) {
+ sethi(addrlit, d);
+ return;
+ }
+ }
+ assert_not_delayed((char*) "cannot put two instructions in delay slot");
+ internal_sethi(addrlit, d, ForceRelocatable);
+ if (ForceRelocatable || addrlit.rspec().type() != relocInfo::none || addrlit.low10() != 0) {
+ add(d, addrlit.low10(), d, addrlit.rspec());
+ }
+}
+
+// Keep in sync with MacroAssembler::internal_set
+int MacroAssembler::insts_for_internal_set(intptr_t value) {
+ // can optimize
+ if (-4096 <= value && value <= 4095) {
+ return 1;
+ }
+ if (inv_hi22(hi22(value)) == value) {
+ return insts_for_sethi((address) value);
+ }
+ int count = insts_for_sethi((address) value);
+ AddressLiteral al(value);
+ if (al.low10() != 0) {
+ count++;
+ }
+ return count;
+}
+
+void MacroAssembler::set(const AddressLiteral& al, Register d) {
+ internal_set(al, d, false);
+}
+
+void MacroAssembler::set(intptr_t value, Register d) {
+ AddressLiteral al(value);
+ internal_set(al, d, false);
+}
+
+void MacroAssembler::set(address addr, Register d, RelocationHolder const& rspec) {
+ AddressLiteral al(addr, rspec);
+ internal_set(al, d, false);
+}
+
+void MacroAssembler::patchable_set(const AddressLiteral& al, Register d) {
+ internal_set(al, d, true);
+}
+
+void MacroAssembler::patchable_set(intptr_t value, Register d) {
+ AddressLiteral al(value);
+ internal_set(al, d, true);
+}
+
+
+void MacroAssembler::set64(jlong value, Register d, Register tmp) {
+ assert_not_delayed();
+ v9_dep();
+
+ int hi = (int)(value >> 32);
+ int lo = (int)(value & ~0);
+ // (Matcher::isSimpleConstant64 knows about the following optimizations.)
+ if (Assembler::is_simm13(lo) && value == lo) {
+ or3(G0, lo, d);
+ } else if (hi == 0) {
+ Assembler::sethi(lo, d); // hardware version zero-extends to upper 32
+ if (low10(lo) != 0)
+ or3(d, low10(lo), d);
+ }
+ else if (hi == -1) {
+ Assembler::sethi(~lo, d); // hardware version zero-extends to upper 32
+ xor3(d, low10(lo) ^ ~low10(~0), d);
+ }
+ else if (lo == 0) {
+ if (Assembler::is_simm13(hi)) {
+ or3(G0, hi, d);
+ } else {
+ Assembler::sethi(hi, d); // hardware version zero-extends to upper 32
+ if (low10(hi) != 0)
+ or3(d, low10(hi), d);
+ }
+ sllx(d, 32, d);
+ }
+ else {
+ Assembler::sethi(hi, tmp);
+ Assembler::sethi(lo, d); // macro assembler version sign-extends
+ if (low10(hi) != 0)
+ or3 (tmp, low10(hi), tmp);
+ if (low10(lo) != 0)
+ or3 ( d, low10(lo), d);
+ sllx(tmp, 32, tmp);
+ or3 (d, tmp, d);
+ }
+}
+
+int MacroAssembler::insts_for_set64(jlong value) {
+ v9_dep();
+
+ int hi = (int) (value >> 32);
+ int lo = (int) (value & ~0);
+ int count = 0;
+
+ // (Matcher::isSimpleConstant64 knows about the following optimizations.)
+ if (Assembler::is_simm13(lo) && value == lo) {
+ count++;
+ } else if (hi == 0) {
+ count++;
+ if (low10(lo) != 0)
+ count++;
+ }
+ else if (hi == -1) {
+ count += 2;
+ }
+ else if (lo == 0) {
+ if (Assembler::is_simm13(hi)) {
+ count++;
+ } else {
+ count++;
+ if (low10(hi) != 0)
+ count++;
+ }
+ count++;
+ }
+ else {
+ count += 2;
+ if (low10(hi) != 0)
+ count++;
+ if (low10(lo) != 0)
+ count++;
+ count += 2;
+ }
+ return count;
+}
+
+// compute size in bytes of sparc frame, given
+// number of extraWords
+int MacroAssembler::total_frame_size_in_bytes(int extraWords) {
+
+ int nWords = frame::memory_parameter_word_sp_offset;
+
+ nWords += extraWords;
+
+ if (nWords & 1) ++nWords; // round up to double-word
+
+ return nWords * BytesPerWord;
+}
+
+
+// save_frame: given number of "extra" words in frame,
+// issue approp. save instruction (p 200, v8 manual)
+
+void MacroAssembler::save_frame(int extraWords) {
+ int delta = -total_frame_size_in_bytes(extraWords);
+ if (is_simm13(delta)) {
+ save(SP, delta, SP);
+ } else {
+ set(delta, G3_scratch);
+ save(SP, G3_scratch, SP);
+ }
+}
+
+
+void MacroAssembler::save_frame_c1(int size_in_bytes) {
+ if (is_simm13(-size_in_bytes)) {
+ save(SP, -size_in_bytes, SP);
+ } else {
+ set(-size_in_bytes, G3_scratch);
+ save(SP, G3_scratch, SP);
+ }
+}
+
+
+void MacroAssembler::save_frame_and_mov(int extraWords,
+ Register s1, Register d1,
+ Register s2, Register d2) {
+ assert_not_delayed();
+
+ // The trick here is to use precisely the same memory word
+ // that trap handlers also use to save the register.
+ // This word cannot be used for any other purpose, but
+ // it works fine to save the register's value, whether or not
+ // an interrupt flushes register windows at any given moment!
+ Address s1_addr;
+ if (s1->is_valid() && (s1->is_in() || s1->is_local())) {
+ s1_addr = s1->address_in_saved_window();
+ st_ptr(s1, s1_addr);
+ }
+
+ Address s2_addr;
+ if (s2->is_valid() && (s2->is_in() || s2->is_local())) {
+ s2_addr = s2->address_in_saved_window();
+ st_ptr(s2, s2_addr);
+ }
+
+ save_frame(extraWords);
+
+ if (s1_addr.base() == SP) {
+ ld_ptr(s1_addr.after_save(), d1);
+ } else if (s1->is_valid()) {
+ mov(s1->after_save(), d1);
+ }
+
+ if (s2_addr.base() == SP) {
+ ld_ptr(s2_addr.after_save(), d2);
+ } else if (s2->is_valid()) {
+ mov(s2->after_save(), d2);
+ }
+}
+
+
+AddressLiteral MacroAssembler::allocate_metadata_address(Metadata* obj) {
+ assert(oop_recorder() != NULL, "this assembler needs a Recorder");
+ int index = oop_recorder()->allocate_metadata_index(obj);
+ RelocationHolder rspec = metadata_Relocation::spec(index);
+ return AddressLiteral((address)obj, rspec);
+}
+
+AddressLiteral MacroAssembler::constant_metadata_address(Metadata* obj) {
+ assert(oop_recorder() != NULL, "this assembler needs a Recorder");
+ int index = oop_recorder()->find_index(obj);
+ RelocationHolder rspec = metadata_Relocation::spec(index);
+ return AddressLiteral((address)obj, rspec);
+}
+
+
+AddressLiteral MacroAssembler::constant_oop_address(jobject obj) {
+ assert(oop_recorder() != NULL, "this assembler needs an OopRecorder");
+ assert(Universe::heap()->is_in_reserved(JNIHandles::resolve(obj)), "not an oop");
+ int oop_index = oop_recorder()->find_index(obj);
+ return AddressLiteral(obj, oop_Relocation::spec(oop_index));
+}
+
+void MacroAssembler::set_narrow_oop(jobject obj, Register d) {
+ assert(oop_recorder() != NULL, "this assembler needs an OopRecorder");
+ int oop_index = oop_recorder()->find_index(obj);
+ RelocationHolder rspec = oop_Relocation::spec(oop_index);
+
+ assert_not_delayed();
+ // Relocation with special format (see relocInfo_sparc.hpp).
+ relocate(rspec, 1);
+ // Assembler::sethi(0x3fffff, d);
+ emit_int32( op(branch_op) | rd(d) | op2(sethi_op2) | hi22(0x3fffff) );
+ // Don't add relocation for 'add'. Do patching during 'sethi' processing.
+ add(d, 0x3ff, d);
+
+}
+
+void MacroAssembler::set_narrow_klass(Klass* k, Register d) {
+ assert(oop_recorder() != NULL, "this assembler needs an OopRecorder");
+ int klass_index = oop_recorder()->find_index(k);
+ RelocationHolder rspec = metadata_Relocation::spec(klass_index);
+ narrowOop encoded_k = oopDesc::encode_klass(k);
+
+ assert_not_delayed();
+ // Relocation with special format (see relocInfo_sparc.hpp).
+ relocate(rspec, 1);
+ // Assembler::sethi(encoded_k, d);
+ emit_int32( op(branch_op) | rd(d) | op2(sethi_op2) | hi22(encoded_k) );
+ // Don't add relocation for 'add'. Do patching during 'sethi' processing.
+ add(d, low10(encoded_k), d);
+
+}
+
+void MacroAssembler::align(int modulus) {
+ while (offset() % modulus != 0) nop();
+}
+
+
+void MacroAssembler::safepoint() {
+ relocate(breakpoint_Relocation::spec(breakpoint_Relocation::safepoint));
+}
+
+
+void RegistersForDebugging::print(outputStream* s) {
+ FlagSetting fs(Debugging, true);
+ int j;
+ for (j = 0; j < 8; ++j) {
+ if (j != 6) { s->print("i%d = ", j); os::print_location(s, i[j]); }
+ else { s->print( "fp = " ); os::print_location(s, i[j]); }
+ }
+ s->cr();
+
+ for (j = 0; j < 8; ++j) {
+ s->print("l%d = ", j); os::print_location(s, l[j]);
+ }
+ s->cr();
+
+ for (j = 0; j < 8; ++j) {
+ if (j != 6) { s->print("o%d = ", j); os::print_location(s, o[j]); }
+ else { s->print( "sp = " ); os::print_location(s, o[j]); }
+ }
+ s->cr();
+
+ for (j = 0; j < 8; ++j) {
+ s->print("g%d = ", j); os::print_location(s, g[j]);
+ }
+ s->cr();
+
+ // print out floats with compression
+ for (j = 0; j < 32; ) {
+ jfloat val = f[j];
+ int last = j;
+ for ( ; last+1 < 32; ++last ) {
+ char b1[1024], b2[1024];
+ sprintf(b1, "%f", val);
+ sprintf(b2, "%f", f[last+1]);
+ if (strcmp(b1, b2))
+ break;
+ }
+ s->print("f%d", j);
+ if ( j != last ) s->print(" - f%d", last);
+ s->print(" = %f", val);
+ s->fill_to(25);
+ s->print_cr(" (0x%x)", val);
+ j = last + 1;
+ }
+ s->cr();
+
+ // and doubles (evens only)
+ for (j = 0; j < 32; ) {
+ jdouble val = d[j];
+ int last = j;
+ for ( ; last+1 < 32; ++last ) {
+ char b1[1024], b2[1024];
+ sprintf(b1, "%f", val);
+ sprintf(b2, "%f", d[last+1]);
+ if (strcmp(b1, b2))
+ break;
+ }
+ s->print("d%d", 2 * j);
+ if ( j != last ) s->print(" - d%d", last);
+ s->print(" = %f", val);
+ s->fill_to(30);
+ s->print("(0x%x)", *(int*)&val);
+ s->fill_to(42);
+ s->print_cr("(0x%x)", *(1 + (int*)&val));
+ j = last + 1;
+ }
+ s->cr();
+}
+
+void RegistersForDebugging::save_registers(MacroAssembler* a) {
+ a->sub(FP, round_to(sizeof(RegistersForDebugging), sizeof(jdouble)) - STACK_BIAS, O0);
+ a->flush_windows();
+ int i;
+ for (i = 0; i < 8; ++i) {
+ a->ld_ptr(as_iRegister(i)->address_in_saved_window().after_save(), L1); a->st_ptr( L1, O0, i_offset(i));
+ a->ld_ptr(as_lRegister(i)->address_in_saved_window().after_save(), L1); a->st_ptr( L1, O0, l_offset(i));
+ a->st_ptr(as_oRegister(i)->after_save(), O0, o_offset(i));
+ a->st_ptr(as_gRegister(i)->after_save(), O0, g_offset(i));
+ }
+ for (i = 0; i < 32; ++i) {
+ a->stf(FloatRegisterImpl::S, as_FloatRegister(i), O0, f_offset(i));
+ }
+ for (i = 0; i < (VM_Version::v9_instructions_work() ? 64 : 32); i += 2) {
+ a->stf(FloatRegisterImpl::D, as_FloatRegister(i), O0, d_offset(i));
+ }
+}
+
+void RegistersForDebugging::restore_registers(MacroAssembler* a, Register r) {
+ for (int i = 1; i < 8; ++i) {
+ a->ld_ptr(r, g_offset(i), as_gRegister(i));
+ }
+ for (int j = 0; j < 32; ++j) {
+ a->ldf(FloatRegisterImpl::S, O0, f_offset(j), as_FloatRegister(j));
+ }
+ for (int k = 0; k < (VM_Version::v9_instructions_work() ? 64 : 32); k += 2) {
+ a->ldf(FloatRegisterImpl::D, O0, d_offset(k), as_FloatRegister(k));
+ }
+}
+
+
+// pushes double TOS element of FPU stack on CPU stack; pops from FPU stack
+void MacroAssembler::push_fTOS() {
+ // %%%%%% need to implement this
+}
+
+// pops double TOS element from CPU stack and pushes on FPU stack
+void MacroAssembler::pop_fTOS() {
+ // %%%%%% need to implement this
+}
+
+void MacroAssembler::empty_FPU_stack() {
+ // %%%%%% need to implement this
+}
+
+void MacroAssembler::_verify_oop(Register reg, const char* msg, const char * file, int line) {
+ // plausibility check for oops
+ if (!VerifyOops) return;
+
+ if (reg == G0) return; // always NULL, which is always an oop
+
+ BLOCK_COMMENT("verify_oop {");
+ char buffer[64];
+#ifdef COMPILER1
+ if (CommentedAssembly) {
+ snprintf(buffer, sizeof(buffer), "verify_oop at %d", offset());
+ block_comment(buffer);
+ }
+#endif
+
+ int len = strlen(file) + strlen(msg) + 1 + 4;
+ sprintf(buffer, "%d", line);
+ len += strlen(buffer);
+ sprintf(buffer, " at offset %d ", offset());
+ len += strlen(buffer);
+ char * real_msg = new char[len];
+ sprintf(real_msg, "%s%s(%s:%d)", msg, buffer, file, line);
+
+ // Call indirectly to solve generation ordering problem
+ AddressLiteral a(StubRoutines::verify_oop_subroutine_entry_address());
+
+ // Make some space on stack above the current register window.
+ // Enough to hold 8 64-bit registers.
+ add(SP,-8*8,SP);
+
+ // Save some 64-bit registers; a normal 'save' chops the heads off
+ // of 64-bit longs in the 32-bit build.
+ stx(O0,SP,frame::register_save_words*wordSize+STACK_BIAS+0*8);
+ stx(O1,SP,frame::register_save_words*wordSize+STACK_BIAS+1*8);
+ mov(reg,O0); // Move arg into O0; arg might be in O7 which is about to be crushed
+ stx(O7,SP,frame::register_save_words*wordSize+STACK_BIAS+7*8);
+
+ // Size of set() should stay the same
+ patchable_set((intptr_t)real_msg, O1);
+ // Load address to call to into O7
+ load_ptr_contents(a, O7);
+ // Register call to verify_oop_subroutine
+ callr(O7, G0);
+ 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) {
+ // plausibility check for oops
+ if (!VerifyOops) return;
+
+ char buffer[64];
+ sprintf(buffer, "%d", line);
+ int len = strlen(file) + strlen(msg) + 1 + 4 + strlen(buffer);
+ sprintf(buffer, " at SP+%d ", addr.disp());
+ len += strlen(buffer);
+ char * real_msg = new char[len];
+ sprintf(real_msg, "%s at SP+%d (%s:%d)", msg, addr.disp(), file, line);
+
+ // Call indirectly to solve generation ordering problem
+ AddressLiteral a(StubRoutines::verify_oop_subroutine_entry_address());
+
+ // Make some space on stack above the current register window.
+ // Enough to hold 8 64-bit registers.
+ add(SP,-8*8,SP);
+
+ // Save some 64-bit registers; a normal 'save' chops the heads off
+ // of 64-bit longs in the 32-bit build.
+ stx(O0,SP,frame::register_save_words*wordSize+STACK_BIAS+0*8);
+ stx(O1,SP,frame::register_save_words*wordSize+STACK_BIAS+1*8);
+ ld_ptr(addr.base(), addr.disp() + 8*8, O0); // Load arg into O0; arg might be in O7 which is about to be crushed
+ stx(O7,SP,frame::register_save_words*wordSize+STACK_BIAS+7*8);
+
+ // Size of set() should stay the same
+ patchable_set((intptr_t)real_msg, O1);
+ // Load address to call to into O7
+ load_ptr_contents(a, O7);
+ // Register call to verify_oop_subroutine
+ callr(O7, G0);
+ delayed()->nop();
+ // recover frame size
+ add(SP, 8*8,SP);
+}
+
+// side-door communication with signalHandler in os_solaris.cpp
+address MacroAssembler::_verify_oop_implicit_branch[3] = { NULL };
+
+// This macro is expanded just once; it creates shared code. Contract:
+// receives an oop in O0. Must restore O0 & O7 from TLS. Must not smash ANY
+// registers, including flags. May not use a register 'save', as this blows
+// the high bits of the O-regs if they contain Long values. Acts as a 'leaf'
+// call.
+void MacroAssembler::verify_oop_subroutine() {
+ assert( VM_Version::v9_instructions_work(), "VerifyOops not supported for V8" );
+
+ // Leaf call; no frame.
+ Label succeed, fail, null_or_fail;
+
+ // O0 and O7 were saved already (O0 in O0's TLS home, O7 in O5's TLS home).
+ // O0 is now the oop to be checked. O7 is the return address.
+ Register O0_obj = O0;
+
+ // Save some more registers for temps.
+ stx(O2,SP,frame::register_save_words*wordSize+STACK_BIAS+2*8);
+ stx(O3,SP,frame::register_save_words*wordSize+STACK_BIAS+3*8);
+ stx(O4,SP,frame::register_save_words*wordSize+STACK_BIAS+4*8);
+ stx(O5,SP,frame::register_save_words*wordSize+STACK_BIAS+5*8);
+
+ // Save flags
+ Register O5_save_flags = O5;
+ rdccr( O5_save_flags );
+
+ { // count number of verifies
+ Register O2_adr = O2;
+ Register O3_accum = O3;
+ inc_counter(StubRoutines::verify_oop_count_addr(), O2_adr, O3_accum);
+ }
+
+ Register O2_mask = O2;
+ Register O3_bits = O3;
+ Register O4_temp = O4;
+
+ // mark lower end of faulting range
+ assert(_verify_oop_implicit_branch[0] == NULL, "set once");
+ _verify_oop_implicit_branch[0] = pc();
+
+ // We can't check the mark oop because it could be in the process of
+ // locking or unlocking while this is running.
+ set(Universe::verify_oop_mask (), O2_mask);
+ set(Universe::verify_oop_bits (), O3_bits);
+
+ // assert((obj & oop_mask) == oop_bits);
+ and3(O0_obj, O2_mask, O4_temp);
+ cmp_and_brx_short(O4_temp, O3_bits, notEqual, pn, null_or_fail);
+
+ if ((NULL_WORD & Universe::verify_oop_mask()) == Universe::verify_oop_bits()) {
+ // the null_or_fail case is useless; must test for null separately
+ br_null_short(O0_obj, pn, succeed);
+ }
+
+ // Check the Klass* of this object for being in the right area of memory.
+ // Cannot do the load in the delay above slot in case O0 is null
+ load_klass(O0_obj, O0_obj);
+ // assert((klass != NULL)
+ br_null_short(O0_obj, pn, fail);
+ // TODO: Future assert that klass is lower 4g memory for UseCompressedKlassPointers
+
+ wrccr( O5_save_flags ); // Restore CCR's
+
+ // mark upper end of faulting range
+ _verify_oop_implicit_branch[1] = pc();
+
+ //-----------------------
+ // all tests pass
+ bind(succeed);
+
+ // Restore prior 64-bit registers
+ ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+0*8,O0);
+ ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+1*8,O1);
+ ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+2*8,O2);
+ ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+3*8,O3);
+ ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+4*8,O4);
+ ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+5*8,O5);
+
+ retl(); // Leaf return; restore prior O7 in delay slot
+ delayed()->ldx(SP,frame::register_save_words*wordSize+STACK_BIAS+7*8,O7);
+
+ //-----------------------
+ bind(null_or_fail); // nulls are less common but OK
+ br_null(O0_obj, false, pt, succeed);
+ delayed()->wrccr( O5_save_flags ); // Restore CCR's
+
+ //-----------------------
+ // report failure:
+ bind(fail);
+ _verify_oop_implicit_branch[2] = pc();
+
+ wrccr( O5_save_flags ); // Restore CCR's
+
+ save_frame(::round_to(sizeof(RegistersForDebugging) / BytesPerWord, 2));
+
+ // stop_subroutine expects message pointer in I1.
+ mov(I1, O1);
+
+ // Restore prior 64-bit registers
+ ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+0*8,I0);
+ ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+1*8,I1);
+ ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+2*8,I2);
+ ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+3*8,I3);
+ ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+4*8,I4);
+ ldx(FP,frame::register_save_words*wordSize+STACK_BIAS+5*8,I5);
+
+ // factor long stop-sequence into subroutine to save space
+ assert(StubRoutines::Sparc::stop_subroutine_entry_address(), "hasn't been generated yet");
+
+ // call indirectly to solve generation ordering problem
+ AddressLiteral al(StubRoutines::Sparc::stop_subroutine_entry_address());
+ load_ptr_contents(al, O5);
+ jmpl(O5, 0, O7);
+ delayed()->nop();
+}
+
+
+void MacroAssembler::stop(const char* msg) {
+ // save frame first to get O7 for return address
+ // add one word to size in case struct is odd number of words long
+ // It must be doubleword-aligned for storing doubles into it.
+
+ save_frame(::round_to(sizeof(RegistersForDebugging) / BytesPerWord, 2));
+
+ // stop_subroutine expects message pointer in I1.
+ // Size of set() should stay the same
+ patchable_set((intptr_t)msg, O1);
+
+ // factor long stop-sequence into subroutine to save space
+ assert(StubRoutines::Sparc::stop_subroutine_entry_address(), "hasn't been generated yet");
+
+ // call indirectly to solve generation ordering problem
+ AddressLiteral a(StubRoutines::Sparc::stop_subroutine_entry_address());
+ load_ptr_contents(a, O5);
+ jmpl(O5, 0, O7);
+ delayed()->nop();
+
+ breakpoint_trap(); // make stop actually stop rather than writing
+ // unnoticeable results in the output files.
+
+ // restore(); done in callee to save space!
+}
+
+
+void MacroAssembler::warn(const char* msg) {
+ save_frame(::round_to(sizeof(RegistersForDebugging) / BytesPerWord, 2));
+ RegistersForDebugging::save_registers(this);
+ mov(O0, L0);
+ // Size of set() should stay the same
+ patchable_set((intptr_t)msg, O0);
+ call( CAST_FROM_FN_PTR(address, warning) );
+ delayed()->nop();
+// ret();
+// delayed()->restore();
+ RegistersForDebugging::restore_registers(this, L0);
+ restore();
+}
+
+
+void MacroAssembler::untested(const char* what) {
+ // We must be able to turn interactive prompting off
+ // in order to run automated test scripts on the VM
+ // Use the flag ShowMessageBoxOnError
+
+ char* b = new char[1024];
+ sprintf(b, "untested: %s", what);
+
+ if (ShowMessageBoxOnError) { STOP(b); }
+ else { warn(b); }
+}
+
+
+void MacroAssembler::stop_subroutine() {
+ RegistersForDebugging::save_registers(this);
+
+ // for the sake of the debugger, stick a PC on the current frame
+ // (this assumes that the caller has performed an extra "save")
+ mov(I7, L7);
+ add(O7, -7 * BytesPerInt, I7);
+
+ save_frame(); // one more save to free up another O7 register
+ mov(I0, O1); // addr of reg save area
+
+ // We expect pointer to message in I1. Caller must set it up in O1
+ mov(I1, O0); // get msg
+ call (CAST_FROM_FN_PTR(address, MacroAssembler::debug), relocInfo::runtime_call_type);
+ delayed()->nop();
+
+ restore();
+
+ RegistersForDebugging::restore_registers(this, O0);
+
+ save_frame(0);
+ call(CAST_FROM_FN_PTR(address,breakpoint));
+ delayed()->nop();
+ restore();
+
+ mov(L7, I7);
+ retl();
+ delayed()->restore(); // see stop above
+}
+
+
+void MacroAssembler::debug(char* msg, RegistersForDebugging* regs) {
+ if ( ShowMessageBoxOnError ) {
+ JavaThread* thread = JavaThread::current();
+ JavaThreadState saved_state = thread->thread_state();
+ thread->set_thread_state(_thread_in_vm);
+ {
+ // In order to get locks work, we need to fake a in_VM state
+ ttyLocker ttyl;
+ ::tty->print_cr("EXECUTION STOPPED: %s\n", msg);
+ if (CountBytecodes || TraceBytecodes || StopInterpreterAt) {
+ BytecodeCounter::print();
+ }
+ if (os::message_box(msg, "Execution stopped, print registers?"))
+ regs->print(::tty);
+ }
+ BREAKPOINT;
+ ThreadStateTransition::transition(JavaThread::current(), _thread_in_vm, saved_state);
+ }
+ else {
+ ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg);
+ }
+ assert(false, err_msg("DEBUG MESSAGE: %s", msg));
+}
+
+
+void MacroAssembler::calc_mem_param_words(Register Rparam_words, Register Rresult) {
+ subcc( Rparam_words, Argument::n_register_parameters, Rresult); // how many mem words?
+ Label no_extras;
+ br( negative, true, pt, no_extras ); // if neg, clear reg
+ delayed()->set(0, Rresult); // annuled, so only if taken
+ bind( no_extras );
+}
+
+
+void MacroAssembler::calc_frame_size(Register Rextra_words, Register Rresult) {
+#ifdef _LP64
+ add(Rextra_words, frame::memory_parameter_word_sp_offset, Rresult);
+#else
+ add(Rextra_words, frame::memory_parameter_word_sp_offset + 1, Rresult);
+#endif
+ bclr(1, Rresult);
+ sll(Rresult, LogBytesPerWord, Rresult); // Rresult has total frame bytes
+}
+
+
+void MacroAssembler::calc_frame_size_and_save(Register Rextra_words, Register Rresult) {
+ calc_frame_size(Rextra_words, Rresult);
+ neg(Rresult);
+ save(SP, Rresult, SP);
+}
+
+
+// ---------------------------------------------------------
+Assembler::RCondition cond2rcond(Assembler::Condition c) {
+ switch (c) {
+ /*case zero: */
+ case Assembler::equal: return Assembler::rc_z;
+ case Assembler::lessEqual: return Assembler::rc_lez;
+ case Assembler::less: return Assembler::rc_lz;
+ /*case notZero:*/
+ case Assembler::notEqual: return Assembler::rc_nz;
+ case Assembler::greater: return Assembler::rc_gz;
+ case Assembler::greaterEqual: return Assembler::rc_gez;
+ }
+ ShouldNotReachHere();
+ return Assembler::rc_z;
+}
+
+// compares (32 bit) register with zero and branches. NOT FOR USE WITH 64-bit POINTERS
+void MacroAssembler::cmp_zero_and_br(Condition c, Register s1, Label& L, bool a, Predict p) {
+ tst(s1);
+ br (c, a, p, L);
+}
+
+// Compares a pointer register with zero and branches on null.
+// Does a test & branch on 32-bit systems and a register-branch on 64-bit.
+void MacroAssembler::br_null( Register s1, bool a, Predict p, Label& L ) {
+ assert_not_delayed();
+#ifdef _LP64
+ bpr( rc_z, a, p, s1, L );
+#else
+ tst(s1);
+ br ( zero, a, p, L );
+#endif
+}
+
+void MacroAssembler::br_notnull( Register s1, bool a, Predict p, Label& L ) {
+ assert_not_delayed();
+#ifdef _LP64
+ bpr( rc_nz, a, p, s1, L );
+#else
+ tst(s1);
+ br ( notZero, a, p, L );
+#endif
+}
+
+// Compare registers and branch with nop in delay slot or cbcond without delay slot.
+
+// Compare integer (32 bit) values (icc only).
+void MacroAssembler::cmp_and_br_short(Register s1, Register s2, Condition c,
+ Predict p, Label& L) {
+ assert_not_delayed();
+ if (use_cbcond(L)) {
+ Assembler::cbcond(c, icc, s1, s2, L);
+ } else {
+ cmp(s1, s2);
+ br(c, false, p, L);
+ delayed()->nop();
+ }
+}
+
+// Compare integer (32 bit) values (icc only).
+void MacroAssembler::cmp_and_br_short(Register s1, int simm13a, Condition c,
+ Predict p, Label& L) {
+ assert_not_delayed();
+ if (is_simm(simm13a,5) && use_cbcond(L)) {
+ Assembler::cbcond(c, icc, s1, simm13a, L);
+ } else {
+ cmp(s1, simm13a);
+ br(c, false, p, L);
+ delayed()->nop();
+ }
+}
+
+// Branch that tests xcc in LP64 and icc in !LP64
+void MacroAssembler::cmp_and_brx_short(Register s1, Register s2, Condition c,
+ Predict p, Label& L) {
+ assert_not_delayed();
+ if (use_cbcond(L)) {
+ Assembler::cbcond(c, ptr_cc, s1, s2, L);
+ } else {
+ cmp(s1, s2);
+ brx(c, false, p, L);
+ delayed()->nop();
+ }
+}
+
+// Branch that tests xcc in LP64 and icc in !LP64
+void MacroAssembler::cmp_and_brx_short(Register s1, int simm13a, Condition c,
+ Predict p, Label& L) {
+ assert_not_delayed();
+ if (is_simm(simm13a,5) && use_cbcond(L)) {
+ Assembler::cbcond(c, ptr_cc, s1, simm13a, L);
+ } else {
+ cmp(s1, simm13a);
+ brx(c, false, p, L);
+ delayed()->nop();
+ }
+}
+
+// Short branch version for compares a pointer with zero.
+
+void MacroAssembler::br_null_short(Register s1, Predict p, Label& L) {
+ assert_not_delayed();
+ if (use_cbcond(L)) {
+ Assembler::cbcond(zero, ptr_cc, s1, 0, L);
+ return;
+ }
+ br_null(s1, false, p, L);
+ delayed()->nop();
+}
+
+void MacroAssembler::br_notnull_short(Register s1, Predict p, Label& L) {
+ assert_not_delayed();
+ if (use_cbcond(L)) {
+ Assembler::cbcond(notZero, ptr_cc, s1, 0, L);
+ return;
+ }
+ br_notnull(s1, false, p, L);
+ delayed()->nop();
+}
+
+// Unconditional short branch
+void MacroAssembler::ba_short(Label& L) {
+ if (use_cbcond(L)) {
+ Assembler::cbcond(equal, icc, G0, G0, L);
+ return;
+ }
+ br(always, false, pt, L);
+ delayed()->nop();
+}
+
+// instruction sequences factored across compiler & interpreter
+
+
+void MacroAssembler::lcmp( Register Ra_hi, Register Ra_low,
+ Register Rb_hi, Register Rb_low,
+ Register Rresult) {
+
+ Label check_low_parts, done;
+
+ cmp(Ra_hi, Rb_hi ); // compare hi parts
+ br(equal, true, pt, check_low_parts);
+ delayed()->cmp(Ra_low, Rb_low); // test low parts
+
+ // And, with an unsigned comparison, it does not matter if the numbers
+ // are negative or not.
+ // E.g., -2 cmp -1: the low parts are 0xfffffffe and 0xffffffff.
+ // The second one is bigger (unsignedly).
+
+ // Other notes: The first move in each triplet can be unconditional
+ // (and therefore probably prefetchable).
+ // And the equals case for the high part does not need testing,
+ // since that triplet is reached only after finding the high halves differ.
+
+ if (VM_Version::v9_instructions_work()) {
+ mov(-1, Rresult);
+ ba(done); delayed()-> movcc(greater, false, icc, 1, Rresult);
+ } else {
+ br(less, true, pt, done); delayed()-> set(-1, Rresult);
+ br(greater, true, pt, done); delayed()-> set( 1, Rresult);
+ }
+
+ bind( check_low_parts );
+
+ if (VM_Version::v9_instructions_work()) {
+ mov( -1, Rresult);
+ movcc(equal, false, icc, 0, Rresult);
+ movcc(greaterUnsigned, false, icc, 1, Rresult);
+ } else {
+ set(-1, Rresult);
+ br(equal, true, pt, done); delayed()->set( 0, Rresult);
+ br(greaterUnsigned, true, pt, done); delayed()->set( 1, Rresult);
+ }
+ bind( done );
+}
+
+void MacroAssembler::lneg( Register Rhi, Register Rlow ) {
+ subcc( G0, Rlow, Rlow );
+ subc( G0, Rhi, Rhi );
+}
+
+void MacroAssembler::lshl( Register Rin_high, Register Rin_low,
+ Register Rcount,
+ Register Rout_high, Register Rout_low,
+ Register Rtemp ) {
+
+
+ Register Ralt_count = Rtemp;
+ Register Rxfer_bits = Rtemp;
+
+ assert( Ralt_count != Rin_high
+ && Ralt_count != Rin_low
+ && Ralt_count != Rcount
+ && Rxfer_bits != Rin_low
+ && Rxfer_bits != Rin_high
+ && Rxfer_bits != Rcount
+ && Rxfer_bits != Rout_low
+ && Rout_low != Rin_high,
+ "register alias checks");
+
+ Label big_shift, done;
+
+ // This code can be optimized to use the 64 bit shifts in V9.
+ // Here we use the 32 bit shifts.
+
+ and3( Rcount, 0x3f, Rcount); // take least significant 6 bits
+ subcc(Rcount, 31, Ralt_count);
+ br(greater, true, pn, big_shift);
+ delayed()->dec(Ralt_count);
+
+ // shift < 32 bits, Ralt_count = Rcount-31
+
+ // We get the transfer bits by shifting right by 32-count the low
+ // register. This is done by shifting right by 31-count and then by one
+ // more to take care of the special (rare) case where count is zero
+ // (shifting by 32 would not work).
+
+ neg(Ralt_count);
+
+ // The order of the next two instructions is critical in the case where
+ // Rin and Rout are the same and should not be reversed.
+
+ srl(Rin_low, Ralt_count, Rxfer_bits); // shift right by 31-count
+ if (Rcount != Rout_low) {
+ sll(Rin_low, Rcount, Rout_low); // low half
+ }
+ sll(Rin_high, Rcount, Rout_high);
+ if (Rcount == Rout_low) {
+ sll(Rin_low, Rcount, Rout_low); // low half
+ }
+ srl(Rxfer_bits, 1, Rxfer_bits ); // shift right by one more
+ ba(done);
+ delayed()->or3(Rout_high, Rxfer_bits, Rout_high); // new hi value: or in shifted old hi part and xfer from low
+
+ // shift >= 32 bits, Ralt_count = Rcount-32
+ bind(big_shift);
+ sll(Rin_low, Ralt_count, Rout_high );
+ clr(Rout_low);
+
+ bind(done);
+}
+
+
+void MacroAssembler::lshr( Register Rin_high, Register Rin_low,
+ Register Rcount,
+ Register Rout_high, Register Rout_low,
+ Register Rtemp ) {
+
+ Register Ralt_count = Rtemp;
+ Register Rxfer_bits = Rtemp;
+
+ assert( Ralt_count != Rin_high
+ && Ralt_count != Rin_low
+ && Ralt_count != Rcount
+ && Rxfer_bits != Rin_low
+ && Rxfer_bits != Rin_high
+ && Rxfer_bits != Rcount
+ && Rxfer_bits != Rout_high
+ && Rout_high != Rin_low,
+ "register alias checks");
+
+ Label big_shift, done;
+
+ // This code can be optimized to use the 64 bit shifts in V9.
+ // Here we use the 32 bit shifts.
+
+ and3( Rcount, 0x3f, Rcount); // take least significant 6 bits
+ subcc(Rcount, 31, Ralt_count);
+ br(greater, true, pn, big_shift);
+ delayed()->dec(Ralt_count);
+
+ // shift < 32 bits, Ralt_count = Rcount-31
+
+ // We get the transfer bits by shifting left by 32-count the high
+ // register. This is done by shifting left by 31-count and then by one
+ // more to take care of the special (rare) case where count is zero
+ // (shifting by 32 would not work).
+
+ neg(Ralt_count);
+ if (Rcount != Rout_low) {
+ srl(Rin_low, Rcount, Rout_low);
+ }
+
+ // The order of the next two instructions is critical in the case where
+ // Rin and Rout are the same and should not be reversed.
+
+ sll(Rin_high, Ralt_count, Rxfer_bits); // shift left by 31-count
+ sra(Rin_high, Rcount, Rout_high ); // high half
+ sll(Rxfer_bits, 1, Rxfer_bits); // shift left by one more
+ if (Rcount == Rout_low) {
+ srl(Rin_low, Rcount, Rout_low);
+ }
+ ba(done);
+ delayed()->or3(Rout_low, Rxfer_bits, Rout_low); // new low value: or shifted old low part and xfer from high
+
+ // shift >= 32 bits, Ralt_count = Rcount-32
+ bind(big_shift);
+
+ sra(Rin_high, Ralt_count, Rout_low);
+ sra(Rin_high, 31, Rout_high); // sign into hi
+
+ bind( done );
+}
+
+
+
+void MacroAssembler::lushr( Register Rin_high, Register Rin_low,
+ Register Rcount,
+ Register Rout_high, Register Rout_low,
+ Register Rtemp ) {
+
+ Register Ralt_count = Rtemp;
+ Register Rxfer_bits = Rtemp;
+
+ assert( Ralt_count != Rin_high
+ && Ralt_count != Rin_low
+ && Ralt_count != Rcount
+ && Rxfer_bits != Rin_low
+ && Rxfer_bits != Rin_high
+ && Rxfer_bits != Rcount
+ && Rxfer_bits != Rout_high
+ && Rout_high != Rin_low,
+ "register alias checks");
+
+ Label big_shift, done;
+
+ // This code can be optimized to use the 64 bit shifts in V9.
+ // Here we use the 32 bit shifts.
+
+ and3( Rcount, 0x3f, Rcount); // take least significant 6 bits
+ subcc(Rcount, 31, Ralt_count);
+ br(greater, true, pn, big_shift);
+ delayed()->dec(Ralt_count);
+
+ // shift < 32 bits, Ralt_count = Rcount-31
+
+ // We get the transfer bits by shifting left by 32-count the high
+ // register. This is done by shifting left by 31-count and then by one
+ // more to take care of the special (rare) case where count is zero
+ // (shifting by 32 would not work).
+
+ neg(Ralt_count);
+ if (Rcount != Rout_low) {
+ srl(Rin_low, Rcount, Rout_low);
+ }
+
+ // The order of the next two instructions is critical in the case where
+ // Rin and Rout are the same and should not be reversed.
+
+ sll(Rin_high, Ralt_count, Rxfer_bits); // shift left by 31-count
+ srl(Rin_high, Rcount, Rout_high ); // high half
+ sll(Rxfer_bits, 1, Rxfer_bits); // shift left by one more
+ if (Rcount == Rout_low) {
+ srl(Rin_low, Rcount, Rout_low);
+ }
+ ba(done);
+ delayed()->or3(Rout_low, Rxfer_bits, Rout_low); // new low value: or shifted old low part and xfer from high
+
+ // shift >= 32 bits, Ralt_count = Rcount-32
+ bind(big_shift);
+
+ srl(Rin_high, Ralt_count, Rout_low);
+ clr(Rout_high);
+
+ bind( done );
+}
+
+#ifdef _LP64
+void MacroAssembler::lcmp( Register Ra, Register Rb, Register Rresult) {
+ cmp(Ra, Rb);
+ mov(-1, Rresult);
+ movcc(equal, false, xcc, 0, Rresult);
+ movcc(greater, false, xcc, 1, Rresult);
+}
+#endif
+
+
+void MacroAssembler::load_sized_value(Address src, Register dst, size_t size_in_bytes, bool is_signed) {
+ switch (size_in_bytes) {
+ case 8: ld_long(src, dst); break;
+ case 4: ld( src, dst); break;
+ case 2: is_signed ? ldsh(src, dst) : lduh(src, dst); break;
+ case 1: is_signed ? ldsb(src, dst) : ldub(src, dst); break;
+ default: ShouldNotReachHere();
+ }
+}
+
+void MacroAssembler::store_sized_value(Register src, Address dst, size_t size_in_bytes) {
+ switch (size_in_bytes) {
+ case 8: st_long(src, dst); break;
+ case 4: st( src, dst); break;
+ case 2: sth( src, dst); break;
+ case 1: stb( src, dst); break;
+ default: ShouldNotReachHere();
+ }
+}
+
+
+void MacroAssembler::float_cmp( bool is_float, int unordered_result,
+ FloatRegister Fa, FloatRegister Fb,
+ Register Rresult) {
+
+ fcmp(is_float ? FloatRegisterImpl::S : FloatRegisterImpl::D, fcc0, Fa, Fb);
+
+ Condition lt = unordered_result == -1 ? f_unorderedOrLess : f_less;
+ Condition eq = f_equal;
+ Condition gt = unordered_result == 1 ? f_unorderedOrGreater : f_greater;
+
+ if (VM_Version::v9_instructions_work()) {
+
+ mov(-1, Rresult);
+ movcc(eq, true, fcc0, 0, Rresult);
+ movcc(gt, true, fcc0, 1, Rresult);
+
+ } else {
+ Label done;
+
+ set( -1, Rresult );
+ //fb(lt, true, pn, done); delayed()->set( -1, Rresult );
+ fb( eq, true, pn, done); delayed()->set( 0, Rresult );
+ fb( gt, true, pn, done); delayed()->set( 1, Rresult );
+
+ bind (done);
+ }
+}
+
+
+void MacroAssembler::fneg( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d)
+{
+ if (VM_Version::v9_instructions_work()) {
+ Assembler::fneg(w, s, d);
+ } else {
+ if (w == FloatRegisterImpl::S) {
+ Assembler::fneg(w, s, d);
+ } else if (w == FloatRegisterImpl::D) {
+ // number() does a sanity check on the alignment.
+ assert(((s->encoding(FloatRegisterImpl::D) & 1) == 0) &&
+ ((d->encoding(FloatRegisterImpl::D) & 1) == 0), "float register alignment check");
+
+ Assembler::fneg(FloatRegisterImpl::S, s, d);
+ Assembler::fmov(FloatRegisterImpl::S, s->successor(), d->successor());
+ } else {
+ assert(w == FloatRegisterImpl::Q, "Invalid float register width");
+
+ // number() does a sanity check on the alignment.
+ assert(((s->encoding(FloatRegisterImpl::D) & 3) == 0) &&
+ ((d->encoding(FloatRegisterImpl::D) & 3) == 0), "float register alignment check");
+
+ Assembler::fneg(FloatRegisterImpl::S, s, d);
+ Assembler::fmov(FloatRegisterImpl::S, s->successor(), d->successor());
+ Assembler::fmov(FloatRegisterImpl::S, s->successor()->successor(), d->successor()->successor());
+ Assembler::fmov(FloatRegisterImpl::S, s->successor()->successor()->successor(), d->successor()->successor()->successor());
+ }
+ }
+}
+
+void MacroAssembler::fmov( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d)
+{
+ if (VM_Version::v9_instructions_work()) {
+ Assembler::fmov(w, s, d);
+ } else {
+ if (w == FloatRegisterImpl::S) {
+ Assembler::fmov(w, s, d);
+ } else if (w == FloatRegisterImpl::D) {
+ // number() does a sanity check on the alignment.
+ assert(((s->encoding(FloatRegisterImpl::D) & 1) == 0) &&
+ ((d->encoding(FloatRegisterImpl::D) & 1) == 0), "float register alignment check");
+
+ Assembler::fmov(FloatRegisterImpl::S, s, d);
+ Assembler::fmov(FloatRegisterImpl::S, s->successor(), d->successor());
+ } else {
+ assert(w == FloatRegisterImpl::Q, "Invalid float register width");
+
+ // number() does a sanity check on the alignment.
+ assert(((s->encoding(FloatRegisterImpl::D) & 3) == 0) &&
+ ((d->encoding(FloatRegisterImpl::D) & 3) == 0), "float register alignment check");
+
+ Assembler::fmov(FloatRegisterImpl::S, s, d);
+ Assembler::fmov(FloatRegisterImpl::S, s->successor(), d->successor());
+ Assembler::fmov(FloatRegisterImpl::S, s->successor()->successor(), d->successor()->successor());
+ Assembler::fmov(FloatRegisterImpl::S, s->successor()->successor()->successor(), d->successor()->successor()->successor());
+ }
+ }
+}
+
+void MacroAssembler::fabs( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d)
+{
+ if (VM_Version::v9_instructions_work()) {
+ Assembler::fabs(w, s, d);
+ } else {
+ if (w == FloatRegisterImpl::S) {
+ Assembler::fabs(w, s, d);
+ } else if (w == FloatRegisterImpl::D) {
+ // number() does a sanity check on the alignment.
+ assert(((s->encoding(FloatRegisterImpl::D) & 1) == 0) &&
+ ((d->encoding(FloatRegisterImpl::D) & 1) == 0), "float register alignment check");
+
+ Assembler::fabs(FloatRegisterImpl::S, s, d);
+ Assembler::fmov(FloatRegisterImpl::S, s->successor(), d->successor());
+ } else {
+ assert(w == FloatRegisterImpl::Q, "Invalid float register width");
+
+ // number() does a sanity check on the alignment.
+ assert(((s->encoding(FloatRegisterImpl::D) & 3) == 0) &&
+ ((d->encoding(FloatRegisterImpl::D) & 3) == 0), "float register alignment check");
+
+ Assembler::fabs(FloatRegisterImpl::S, s, d);
+ Assembler::fmov(FloatRegisterImpl::S, s->successor(), d->successor());
+ Assembler::fmov(FloatRegisterImpl::S, s->successor()->successor(), d->successor()->successor());
+ Assembler::fmov(FloatRegisterImpl::S, s->successor()->successor()->successor(), d->successor()->successor()->successor());
+ }
+ }
+}
+
+void MacroAssembler::save_all_globals_into_locals() {
+ mov(G1,L1);
+ mov(G2,L2);
+ mov(G3,L3);
+ mov(G4,L4);
+ mov(G5,L5);
+ mov(G6,L6);
+ mov(G7,L7);
+}
+
+void MacroAssembler::restore_globals_from_locals() {
+ mov(L1,G1);
+ mov(L2,G2);
+ mov(L3,G3);
+ mov(L4,G4);
+ mov(L5,G5);
+ mov(L6,G6);
+ mov(L7,G7);
+}
+
+// Use for 64 bit operation.
+void MacroAssembler::casx_under_lock(Register top_ptr_reg, Register top_reg, Register ptr_reg, address lock_addr, bool use_call_vm)
+{
+ // store ptr_reg as the new top value
+#ifdef _LP64
+ casx(top_ptr_reg, top_reg, ptr_reg);
+#else
+ cas_under_lock(top_ptr_reg, top_reg, ptr_reg, lock_addr, use_call_vm);
+#endif // _LP64
+}
+
+// [RGV] This routine does not handle 64 bit operations.
+// use casx_under_lock() or casx directly!!!
+void MacroAssembler::cas_under_lock(Register top_ptr_reg, Register top_reg, Register ptr_reg, address lock_addr, bool use_call_vm)
+{
+ // store ptr_reg as the new top value
+ if (VM_Version::v9_instructions_work()) {
+ cas(top_ptr_reg, top_reg, ptr_reg);
+ } else {
+
+ // If the register is not an out nor global, it is not visible
+ // after the save. Allocate a register for it, save its
+ // value in the register save area (the save may not flush
+ // registers to the save area).
+
+ Register top_ptr_reg_after_save;
+ Register top_reg_after_save;
+ Register ptr_reg_after_save;
+
+ if (top_ptr_reg->is_out() || top_ptr_reg->is_global()) {
+ top_ptr_reg_after_save = top_ptr_reg->after_save();
+ } else {
+ Address reg_save_addr = top_ptr_reg->address_in_saved_window();
+ top_ptr_reg_after_save = L0;
+ st(top_ptr_reg, reg_save_addr);
+ }
+
+ if (top_reg->is_out() || top_reg->is_global()) {
+ top_reg_after_save = top_reg->after_save();
+ } else {
+ Address reg_save_addr = top_reg->address_in_saved_window();
+ top_reg_after_save = L1;
+ st(top_reg, reg_save_addr);
+ }
+
+ if (ptr_reg->is_out() || ptr_reg->is_global()) {
+ ptr_reg_after_save = ptr_reg->after_save();
+ } else {
+ Address reg_save_addr = ptr_reg->address_in_saved_window();
+ ptr_reg_after_save = L2;
+ st(ptr_reg, reg_save_addr);
+ }
+
+ const Register& lock_reg = L3;
+ const Register& lock_ptr_reg = L4;
+ const Register& value_reg = L5;
+ const Register& yield_reg = L6;
+ const Register& yieldall_reg = L7;
+
+ save_frame();
+
+ if (top_ptr_reg_after_save == L0) {
+ ld(top_ptr_reg->address_in_saved_window().after_save(), top_ptr_reg_after_save);
+ }
+
+ if (top_reg_after_save == L1) {
+ ld(top_reg->address_in_saved_window().after_save(), top_reg_after_save);
+ }
+
+ if (ptr_reg_after_save == L2) {
+ ld(ptr_reg->address_in_saved_window().after_save(), ptr_reg_after_save);
+ }
+
+ Label(retry_get_lock);
+ Label(not_same);
+ Label(dont_yield);
+
+ assert(lock_addr, "lock_address should be non null for v8");
+ set((intptr_t)lock_addr, lock_ptr_reg);
+ // Initialize yield counter
+ mov(G0,yield_reg);
+ mov(G0, yieldall_reg);
+ set(StubRoutines::Sparc::locked, lock_reg);
+
+ bind(retry_get_lock);
+ cmp_and_br_short(yield_reg, V8AtomicOperationUnderLockSpinCount, Assembler::less, Assembler::pt, dont_yield);
+
+ if(use_call_vm) {
+ Untested("Need to verify global reg consistancy");
+ call_VM(noreg, CAST_FROM_FN_PTR(address, SharedRuntime::yield_all), yieldall_reg);
+ } else {
+ // Save the regs and make space for a C call
+ save(SP, -96, SP);
+ save_all_globals_into_locals();
+ call(CAST_FROM_FN_PTR(address,os::yield_all));
+ delayed()->mov(yieldall_reg, O0);
+ restore_globals_from_locals();
+ restore();
+ }
+
+ // reset the counter
+ mov(G0,yield_reg);
+ add(yieldall_reg, 1, yieldall_reg);
+
+ bind(dont_yield);
+ // try to get lock
+ Assembler::swap(lock_ptr_reg, 0, lock_reg);
+
+ // did we get the lock?
+ cmp(lock_reg, StubRoutines::Sparc::unlocked);
+ br(Assembler::notEqual, true, Assembler::pn, retry_get_lock);
+ delayed()->add(yield_reg,1,yield_reg);
+
+ // yes, got lock. do we have the same top?
+ ld(top_ptr_reg_after_save, 0, value_reg);
+ cmp_and_br_short(value_reg, top_reg_after_save, Assembler::notEqual, Assembler::pn, not_same);
+
+ // yes, same top.
+ st(ptr_reg_after_save, top_ptr_reg_after_save, 0);
+ membar(Assembler::StoreStore);
+
+ bind(not_same);
+ mov(value_reg, ptr_reg_after_save);
+ st(lock_reg, lock_ptr_reg, 0); // unlock
+
+ restore();
+ }
+}
+
+RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr,
+ Register tmp,
+ int offset) {
+ intptr_t value = *delayed_value_addr;
+ if (value != 0)
+ return RegisterOrConstant(value + offset);
+
+ // load indirectly to solve generation ordering problem
+ AddressLiteral a(delayed_value_addr);
+ load_ptr_contents(a, tmp);
+
+#ifdef ASSERT
+ tst(tmp);
+ breakpoint_trap(zero, xcc);
+#endif
+
+ if (offset != 0)
+ add(tmp, offset, tmp);
+
+ return RegisterOrConstant(tmp);
+}
+
+
+RegisterOrConstant MacroAssembler::regcon_andn_ptr(RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp) {
+ assert(d.register_or_noreg() != G0, "lost side effect");
+ if ((s2.is_constant() && s2.as_constant() == 0) ||
+ (s2.is_register() && s2.as_register() == G0)) {
+ // Do nothing, just move value.
+ if (s1.is_register()) {
+ if (d.is_constant()) d = temp;
+ mov(s1.as_register(), d.as_register());
+ return d;
+ } else {
+ return s1;
+ }
+ }
+
+ if (s1.is_register()) {
+ assert_different_registers(s1.as_register(), temp);
+ if (d.is_constant()) d = temp;
+ andn(s1.as_register(), ensure_simm13_or_reg(s2, temp), d.as_register());
+ return d;
+ } else {
+ if (s2.is_register()) {
+ assert_different_registers(s2.as_register(), temp);
+ if (d.is_constant()) d = temp;
+ set(s1.as_constant(), temp);
+ andn(temp, s2.as_register(), d.as_register());
+ return d;
+ } else {
+ intptr_t res = s1.as_constant() & ~s2.as_constant();
+ return res;
+ }
+ }
+}
+
+RegisterOrConstant MacroAssembler::regcon_inc_ptr(RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp) {
+ assert(d.register_or_noreg() != G0, "lost side effect");
+ if ((s2.is_constant() && s2.as_constant() == 0) ||
+ (s2.is_register() && s2.as_register() == G0)) {
+ // Do nothing, just move value.
+ if (s1.is_register()) {
+ if (d.is_constant()) d = temp;
+ mov(s1.as_register(), d.as_register());
+ return d;
+ } else {
+ return s1;
+ }
+ }
+
+ if (s1.is_register()) {
+ assert_different_registers(s1.as_register(), temp);
+ if (d.is_constant()) d = temp;
+ add(s1.as_register(), ensure_simm13_or_reg(s2, temp), d.as_register());
+ return d;
+ } else {
+ if (s2.is_register()) {
+ assert_different_registers(s2.as_register(), temp);
+ if (d.is_constant()) d = temp;
+ add(s2.as_register(), ensure_simm13_or_reg(s1, temp), d.as_register());
+ return d;
+ } else {
+ intptr_t res = s1.as_constant() + s2.as_constant();
+ return res;
+ }
+ }
+}
+
+RegisterOrConstant MacroAssembler::regcon_sll_ptr(RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp) {
+ assert(d.register_or_noreg() != G0, "lost side effect");
+ if (!is_simm13(s2.constant_or_zero()))
+ s2 = (s2.as_constant() & 0xFF);
+ if ((s2.is_constant() && s2.as_constant() == 0) ||
+ (s2.is_register() && s2.as_register() == G0)) {
+ // Do nothing, just move value.
+ if (s1.is_register()) {
+ if (d.is_constant()) d = temp;
+ mov(s1.as_register(), d.as_register());
+ return d;
+ } else {
+ return s1;
+ }
+ }
+
+ if (s1.is_register()) {
+ assert_different_registers(s1.as_register(), temp);
+ if (d.is_constant()) d = temp;
+ sll_ptr(s1.as_register(), ensure_simm13_or_reg(s2, temp), d.as_register());
+ return d;
+ } else {
+ if (s2.is_register()) {
+ assert_different_registers(s2.as_register(), temp);
+ if (d.is_constant()) d = temp;
+ set(s1.as_constant(), temp);
+ sll_ptr(temp, s2.as_register(), d.as_register());
+ return d;
+ } else {
+ intptr_t res = s1.as_constant() << s2.as_constant();
+ return res;
+ }
+ }
+}
+
+
+// Look up the method for a megamorphic invokeinterface call.
+// The target method is determined by .
+// The receiver klass is in recv_klass.
+// On success, the result will be in method_result, and execution falls through.
+// On failure, execution transfers to the given label.
+void MacroAssembler::lookup_interface_method(Register recv_klass,
+ Register intf_klass,
+ RegisterOrConstant itable_index,
+ Register method_result,
+ Register scan_temp,
+ Register sethi_temp,
+ Label& L_no_such_interface) {
+ assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
+ assert(itable_index.is_constant() || itable_index.as_register() == method_result,
+ "caller must use same register for non-constant itable index as for method");
+
+ Label L_no_such_interface_restore;
+ bool did_save = false;
+ if (scan_temp == noreg || sethi_temp == noreg) {
+ Register recv_2 = recv_klass->is_global() ? recv_klass : L0;
+ Register intf_2 = intf_klass->is_global() ? intf_klass : L1;
+ assert(method_result->is_global(), "must be able to return value");
+ scan_temp = L2;
+ sethi_temp = L3;
+ save_frame_and_mov(0, recv_klass, recv_2, intf_klass, intf_2);
+ recv_klass = recv_2;
+ intf_klass = intf_2;
+ did_save = true;
+ }
+
+ // Compute start of first itableOffsetEntry (which is at the end of the vtable)
+ int vtable_base = InstanceKlass::vtable_start_offset() * wordSize;
+ int scan_step = itableOffsetEntry::size() * wordSize;
+ int vte_size = vtableEntry::size() * wordSize;
+
+ lduw(recv_klass, InstanceKlass::vtable_length_offset() * wordSize, scan_temp);
+ // %%% We should store the aligned, prescaled offset in the klassoop.
+ // Then the next several instructions would fold away.
+
+ int round_to_unit = ((HeapWordsPerLong > 1) ? BytesPerLong : 0);
+ int itb_offset = vtable_base;
+ if (round_to_unit != 0) {
+ // hoist first instruction of round_to(scan_temp, BytesPerLong):
+ itb_offset += round_to_unit - wordSize;
+ }
+ int itb_scale = exact_log2(vtableEntry::size() * wordSize);
+ sll(scan_temp, itb_scale, scan_temp);
+ add(scan_temp, itb_offset, scan_temp);
+ if (round_to_unit != 0) {
+ // Round up to align_object_offset boundary
+ // see code for InstanceKlass::start_of_itable!
+ // Was: round_to(scan_temp, BytesPerLong);
+ // Hoisted: add(scan_temp, BytesPerLong-1, scan_temp);
+ and3(scan_temp, -round_to_unit, scan_temp);
+ }
+ add(recv_klass, scan_temp, scan_temp);
+
+ // Adjust recv_klass by scaled itable_index, so we can free itable_index.
+ RegisterOrConstant itable_offset = itable_index;
+ itable_offset = regcon_sll_ptr(itable_index, exact_log2(itableMethodEntry::size() * wordSize), itable_offset);
+ itable_offset = regcon_inc_ptr(itable_offset, itableMethodEntry::method_offset_in_bytes(), itable_offset);
+ add(recv_klass, ensure_simm13_or_reg(itable_offset, sethi_temp), recv_klass);
+
+ // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
+ // if (scan->interface() == intf) {
+ // result = (klass + scan->offset() + itable_index);
+ // }
+ // }
+ Label L_search, L_found_method;
+
+ for (int peel = 1; peel >= 0; peel--) {
+ // %%%% Could load both offset and interface in one ldx, if they were
+ // in the opposite order. This would save a load.
+ ld_ptr(scan_temp, itableOffsetEntry::interface_offset_in_bytes(), method_result);
+
+ // Check that this entry is non-null. A null entry means that
+ // the receiver class doesn't implement the interface, and wasn't the
+ // same as when the caller was compiled.
+ bpr(Assembler::rc_z, false, Assembler::pn, method_result, did_save ? L_no_such_interface_restore : L_no_such_interface);
+ delayed()->cmp(method_result, intf_klass);
+
+ if (peel) {
+ brx(Assembler::equal, false, Assembler::pt, L_found_method);
+ } else {
+ brx(Assembler::notEqual, false, Assembler::pn, L_search);
+ // (invert the test to fall through to found_method...)
+ }
+ delayed()->add(scan_temp, scan_step, scan_temp);
+
+ if (!peel) break;
+
+ bind(L_search);
+ }
+
+ bind(L_found_method);
+
+ // Got a hit.
+ int ito_offset = itableOffsetEntry::offset_offset_in_bytes();
+ // scan_temp[-scan_step] points to the vtable offset we need
+ ito_offset -= scan_step;
+ lduw(scan_temp, ito_offset, scan_temp);
+ ld_ptr(recv_klass, scan_temp, method_result);
+
+ if (did_save) {
+ Label L_done;
+ ba(L_done);
+ delayed()->restore();
+
+ bind(L_no_such_interface_restore);
+ ba(L_no_such_interface);
+ delayed()->restore();
+
+ bind(L_done);
+ }
+}
+
+
+// virtual method calling
+void MacroAssembler::lookup_virtual_method(Register recv_klass,
+ RegisterOrConstant vtable_index,
+ Register method_result) {
+ assert_different_registers(recv_klass, method_result, vtable_index.register_or_noreg());
+ Register sethi_temp = method_result;
+ const int base = (InstanceKlass::vtable_start_offset() * wordSize +
+ // method pointer offset within the vtable entry:
+ vtableEntry::method_offset_in_bytes());
+ RegisterOrConstant vtable_offset = vtable_index;
+ // Each of the following three lines potentially generates an instruction.
+ // But the total number of address formation instructions will always be
+ // at most two, and will often be zero. In any case, it will be optimal.
+ // If vtable_index is a register, we will have (sll_ptr N,x; inc_ptr B,x; ld_ptr k,x).
+ // If vtable_index is a constant, we will have at most (set B+X<is_global()) sub_2 = L0;
+ if (!sup_2->is_global()) sup_2 = L1;
+ bool did_save = false;
+ if (temp_reg == noreg || temp2_reg == noreg) {
+ temp_reg = L2;
+ temp2_reg = L3;
+ save_frame_and_mov(0, sub_klass, sub_2, super_klass, sup_2);
+ sub_klass = sub_2;
+ super_klass = sup_2;
+ did_save = true;
+ }
+ Label L_failure, L_pop_to_failure, L_pop_to_success;
+ check_klass_subtype_fast_path(sub_klass, super_klass,
+ temp_reg, temp2_reg,
+ (did_save ? &L_pop_to_success : &L_success),
+ (did_save ? &L_pop_to_failure : &L_failure), NULL);
+
+ if (!did_save)
+ save_frame_and_mov(0, sub_klass, sub_2, super_klass, sup_2);
+ check_klass_subtype_slow_path(sub_2, sup_2,
+ L2, L3, L4, L5,
+ NULL, &L_pop_to_failure);
+
+ // on success:
+ bind(L_pop_to_success);
+ restore();
+ ba_short(L_success);
+
+ // on failure:
+ bind(L_pop_to_failure);
+ restore();
+ bind(L_failure);
+}
+
+
+void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass,
+ Register super_klass,
+ Register temp_reg,
+ Register temp2_reg,
+ Label* L_success,
+ Label* L_failure,
+ Label* L_slow_path,
+ RegisterOrConstant super_check_offset) {
+ int sc_offset = in_bytes(Klass::secondary_super_cache_offset());
+ int sco_offset = in_bytes(Klass::super_check_offset_offset());
+
+ bool must_load_sco = (super_check_offset.constant_or_zero() == -1);
+ bool need_slow_path = (must_load_sco ||
+ super_check_offset.constant_or_zero() == sco_offset);
+
+ assert_different_registers(sub_klass, super_klass, temp_reg);
+ if (super_check_offset.is_register()) {
+ assert_different_registers(sub_klass, super_klass, temp_reg,
+ super_check_offset.as_register());
+ } else if (must_load_sco) {
+ assert(temp2_reg != noreg, "supply either a temp or a register offset");
+ }
+
+ Label L_fallthrough;
+ int label_nulls = 0;
+ if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; }
+ if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; }
+ if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; }
+ assert(label_nulls <= 1 ||
+ (L_slow_path == &L_fallthrough && label_nulls <= 2 && !need_slow_path),
+ "at most one NULL in the batch, usually");
+
+ // If the pointers are equal, we are done (e.g., String[] elements).
+ // This self-check enables sharing of secondary supertype arrays among
+ // non-primary types such as array-of-interface. Otherwise, each such
+ // type would need its own customized SSA.
+ // We move this check to the front of the fast path because many
+ // type checks are in fact trivially successful in this manner,
+ // so we get a nicely predicted branch right at the start of the check.
+ cmp(super_klass, sub_klass);
+ brx(Assembler::equal, false, Assembler::pn, *L_success);
+ delayed()->nop();
+
+ // Check the supertype display:
+ if (must_load_sco) {
+ // The super check offset is always positive...
+ lduw(super_klass, sco_offset, temp2_reg);
+ super_check_offset = RegisterOrConstant(temp2_reg);
+ // super_check_offset is register.
+ assert_different_registers(sub_klass, super_klass, temp_reg, super_check_offset.as_register());
+ }
+ ld_ptr(sub_klass, super_check_offset, temp_reg);
+ cmp(super_klass, temp_reg);
+
+ // This check has worked decisively for primary supers.
+ // Secondary supers are sought in the super_cache ('super_cache_addr').
+ // (Secondary supers are interfaces and very deeply nested subtypes.)
+ // This works in the same check above because of a tricky aliasing
+ // between the super_cache and the primary super display elements.
+ // (The 'super_check_addr' can address either, as the case requires.)
+ // Note that the cache is updated below if it does not help us find
+ // what we need immediately.
+ // So if it was a primary super, we can just fail immediately.
+ // Otherwise, it's the slow path for us (no success at this point).
+
+ // Hacked ba(), which may only be used just before L_fallthrough.
+#define FINAL_JUMP(label) \
+ if (&(label) != &L_fallthrough) { \
+ ba(label); delayed()->nop(); \
+ }
+
+ if (super_check_offset.is_register()) {
+ brx(Assembler::equal, false, Assembler::pn, *L_success);
+ delayed()->cmp(super_check_offset.as_register(), sc_offset);
+
+ if (L_failure == &L_fallthrough) {
+ brx(Assembler::equal, false, Assembler::pt, *L_slow_path);
+ delayed()->nop();
+ } else {
+ brx(Assembler::notEqual, false, Assembler::pn, *L_failure);
+ delayed()->nop();
+ FINAL_JUMP(*L_slow_path);
+ }
+ } else if (super_check_offset.as_constant() == sc_offset) {
+ // Need a slow path; fast failure is impossible.
+ if (L_slow_path == &L_fallthrough) {
+ brx(Assembler::equal, false, Assembler::pt, *L_success);
+ delayed()->nop();
+ } else {
+ brx(Assembler::notEqual, false, Assembler::pn, *L_slow_path);
+ delayed()->nop();
+ FINAL_JUMP(*L_success);
+ }
+ } else {
+ // No slow path; it's a fast decision.
+ if (L_failure == &L_fallthrough) {
+ brx(Assembler::equal, false, Assembler::pt, *L_success);
+ delayed()->nop();
+ } else {
+ brx(Assembler::notEqual, false, Assembler::pn, *L_failure);
+ delayed()->nop();
+ FINAL_JUMP(*L_success);
+ }
+ }
+
+ bind(L_fallthrough);
+
+#undef FINAL_JUMP
+}
+
+
+void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass,
+ Register super_klass,
+ Register count_temp,
+ Register scan_temp,
+ Register scratch_reg,
+ Register coop_reg,
+ Label* L_success,
+ Label* L_failure) {
+ assert_different_registers(sub_klass, super_klass,
+ count_temp, scan_temp, scratch_reg, coop_reg);
+
+ Label L_fallthrough, L_loop;
+ int label_nulls = 0;
+ if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; }
+ if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; }
+ assert(label_nulls <= 1, "at most one NULL in the batch");
+
+ // a couple of useful fields in sub_klass:
+ int ss_offset = in_bytes(Klass::secondary_supers_offset());
+ int sc_offset = in_bytes(Klass::secondary_super_cache_offset());
+
+ // Do a linear scan of the secondary super-klass chain.
+ // This code is rarely used, so simplicity is a virtue here.
+
+#ifndef PRODUCT
+ int* pst_counter = &SharedRuntime::_partial_subtype_ctr;
+ inc_counter((address) pst_counter, count_temp, scan_temp);
+#endif
+
+ // We will consult the secondary-super array.
+ ld_ptr(sub_klass, ss_offset, scan_temp);
+
+ Register search_key = super_klass;
+
+ // Load the array length. (Positive movl does right thing on LP64.)
+ lduw(scan_temp, Array::length_offset_in_bytes(), count_temp);
+
+ // Check for empty secondary super list
+ tst(count_temp);
+
+ // In the array of super classes elements are pointer sized.
+ int element_size = wordSize;
+
+ // Top of search loop
+ bind(L_loop);
+ br(Assembler::equal, false, Assembler::pn, *L_failure);
+ delayed()->add(scan_temp, element_size, scan_temp);
+
+ // Skip the array header in all array accesses.
+ int elem_offset = Array::base_offset_in_bytes();
+ elem_offset -= element_size; // the scan pointer was pre-incremented also
+
+ // Load next super to check
+ ld_ptr( scan_temp, elem_offset, scratch_reg );
+
+ // Look for Rsuper_klass on Rsub_klass's secondary super-class-overflow list
+ cmp(scratch_reg, search_key);
+
+ // A miss means we are NOT a subtype and need to keep looping
+ brx(Assembler::notEqual, false, Assembler::pn, L_loop);
+ delayed()->deccc(count_temp); // decrement trip counter in delay slot
+
+ // Success. Cache the super we found and proceed in triumph.
+ st_ptr(super_klass, sub_klass, sc_offset);
+
+ if (L_success != &L_fallthrough) {
+ ba(*L_success);
+ delayed()->nop();
+ }
+
+ bind(L_fallthrough);
+}
+
+
+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;
+ int offset = extra_slot_offset * stackElementSize;
+ if (arg_slot.is_constant()) {
+ offset += arg_slot.as_constant() * stackElementSize;
+ return offset;
+ } else {
+ assert(temp_reg != noreg, "must specify");
+ sll_ptr(arg_slot.as_register(), exact_log2(stackElementSize), temp_reg);
+ if (offset != 0)
+ 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, temp_reg, extra_slot_offset));
+}
+
+
+void MacroAssembler::biased_locking_enter(Register obj_reg, Register mark_reg,
+ Register temp_reg,
+ Label& done, Label* slow_case,
+ BiasedLockingCounters* counters) {
+ assert(UseBiasedLocking, "why call this otherwise?");
+
+ if (PrintBiasedLockingStatistics) {
+ assert_different_registers(obj_reg, mark_reg, temp_reg, O7);
+ if (counters == NULL)
+ counters = BiasedLocking::counters();
+ }
+
+ Label cas_label;
+
+ // Biased locking
+ // See whether the lock is currently biased toward our thread and
+ // whether the epoch is still valid
+ // Note that the runtime guarantees sufficient alignment of JavaThread
+ // pointers to allow age to be placed into low bits
+ assert(markOopDesc::age_shift == markOopDesc::lock_bits + markOopDesc::biased_lock_bits, "biased locking makes assumptions about bit layout");
+ and3(mark_reg, markOopDesc::biased_lock_mask_in_place, temp_reg);
+ cmp_and_brx_short(temp_reg, markOopDesc::biased_lock_pattern, Assembler::notEqual, Assembler::pn, cas_label);
+
+ load_klass(obj_reg, temp_reg);
+ ld_ptr(Address(temp_reg, Klass::prototype_header_offset()), temp_reg);
+ or3(G2_thread, temp_reg, temp_reg);
+ xor3(mark_reg, temp_reg, temp_reg);
+ andcc(temp_reg, ~((int) markOopDesc::age_mask_in_place), temp_reg);
+ if (counters != NULL) {
+ cond_inc(Assembler::equal, (address) counters->biased_lock_entry_count_addr(), mark_reg, temp_reg);
+ // Reload mark_reg as we may need it later
+ ld_ptr(Address(obj_reg, oopDesc::mark_offset_in_bytes()), mark_reg);
+ }
+ brx(Assembler::equal, true, Assembler::pt, done);
+ delayed()->nop();
+
+ Label try_revoke_bias;
+ Label try_rebias;
+ Address mark_addr = Address(obj_reg, oopDesc::mark_offset_in_bytes());
+ assert(mark_addr.disp() == 0, "cas must take a zero displacement");
+
+ // At this point we know that the header has the bias pattern and
+ // that we are not the bias owner in the current epoch. We need to
+ // figure out more details about the state of the header in order to
+ // know what operations can be legally performed on the object's
+ // header.
+
+ // If the low three bits in the xor result aren't clear, that means
+ // the prototype header is no longer biased and we have to revoke
+ // the bias on this object.
+ btst(markOopDesc::biased_lock_mask_in_place, temp_reg);
+ brx(Assembler::notZero, false, Assembler::pn, try_revoke_bias);
+
+ // Biasing is still enabled for this data type. See whether the
+ // epoch of the current bias is still valid, meaning that the epoch
+ // bits of the mark word are equal to the epoch bits of the
+ // prototype header. (Note that the prototype header's epoch bits
+ // only change at a safepoint.) If not, attempt to rebias the object
+ // toward the current thread. Note that we must be absolutely sure
+ // that the current epoch is invalid in order to do this because
+ // otherwise the manipulations it performs on the mark word are
+ // illegal.
+ delayed()->btst(markOopDesc::epoch_mask_in_place, temp_reg);
+ brx(Assembler::notZero, false, Assembler::pn, try_rebias);
+
+ // The epoch of the current bias is still valid but we know nothing
+ // about the owner; it might be set or it might be clear. Try to
+ // acquire the bias of the object using an atomic operation. If this
+ // fails we will go in to the runtime to revoke the object's bias.
+ // Note that we first construct the presumed unbiased header so we
+ // don't accidentally blow away another thread's valid bias.
+ delayed()->and3(mark_reg,
+ markOopDesc::biased_lock_mask_in_place | markOopDesc::age_mask_in_place | markOopDesc::epoch_mask_in_place,
+ mark_reg);
+ or3(G2_thread, mark_reg, temp_reg);
+ casn(mark_addr.base(), mark_reg, temp_reg);
+ // If the biasing toward our thread failed, this means that
+ // another thread succeeded in biasing it toward itself and we
+ // need to revoke that bias. The revocation will occur in the
+ // interpreter runtime in the slow case.
+ cmp(mark_reg, temp_reg);
+ if (counters != NULL) {
+ cond_inc(Assembler::zero, (address) counters->anonymously_biased_lock_entry_count_addr(), mark_reg, temp_reg);
+ }
+ if (slow_case != NULL) {
+ brx(Assembler::notEqual, true, Assembler::pn, *slow_case);
+ delayed()->nop();
+ }
+ ba_short(done);
+
+ bind(try_rebias);
+ // At this point we know the epoch has expired, meaning that the
+ // current "bias owner", if any, is actually invalid. Under these
+ // circumstances _only_, we are allowed to use the current header's
+ // value as the comparison value when doing the cas to acquire the
+ // bias in the current epoch. In other words, we allow transfer of
+ // the bias from one thread to another directly in this situation.
+ //
+ // FIXME: due to a lack of registers we currently blow away the age
+ // bits in this situation. Should attempt to preserve them.
+ load_klass(obj_reg, temp_reg);
+ ld_ptr(Address(temp_reg, Klass::prototype_header_offset()), temp_reg);
+ or3(G2_thread, temp_reg, temp_reg);
+ casn(mark_addr.base(), mark_reg, temp_reg);
+ // If the biasing toward our thread failed, this means that
+ // another thread succeeded in biasing it toward itself and we
+ // need to revoke that bias. The revocation will occur in the
+ // interpreter runtime in the slow case.
+ cmp(mark_reg, temp_reg);
+ if (counters != NULL) {
+ cond_inc(Assembler::zero, (address) counters->rebiased_lock_entry_count_addr(), mark_reg, temp_reg);
+ }
+ if (slow_case != NULL) {
+ brx(Assembler::notEqual, true, Assembler::pn, *slow_case);
+ delayed()->nop();
+ }
+ ba_short(done);
+
+ bind(try_revoke_bias);
+ // The prototype mark in the klass doesn't have the bias bit set any
+ // more, indicating that objects of this data type are not supposed
+ // to be biased any more. We are going to try to reset the mark of
+ // this object to the prototype value and fall through to the
+ // CAS-based locking scheme. Note that if our CAS fails, it means
+ // that another thread raced us for the privilege of revoking the
+ // bias of this particular object, so it's okay to continue in the
+ // normal locking code.
+ //
+ // FIXME: due to a lack of registers we currently blow away the age
+ // bits in this situation. Should attempt to preserve them.
+ load_klass(obj_reg, temp_reg);
+ ld_ptr(Address(temp_reg, Klass::prototype_header_offset()), temp_reg);
+ casn(mark_addr.base(), mark_reg, temp_reg);
+ // Fall through to the normal CAS-based lock, because no matter what
+ // the result of the above CAS, some thread must have succeeded in
+ // removing the bias bit from the object's header.
+ if (counters != NULL) {
+ cmp(mark_reg, temp_reg);
+ cond_inc(Assembler::zero, (address) counters->revoked_lock_entry_count_addr(), mark_reg, temp_reg);
+ }
+
+ bind(cas_label);
+}
+
+void MacroAssembler::biased_locking_exit (Address mark_addr, Register temp_reg, Label& done,
+ bool allow_delay_slot_filling) {
+ // Check for biased locking unlock case, which is a no-op
+ // Note: we do not have to check the thread ID for two reasons.
+ // First, the interpreter checks for IllegalMonitorStateException at
+ // a higher level. Second, if the bias was revoked while we held the
+ // lock, the object could not be rebiased toward another thread, so
+ // the bias bit would be clear.
+ ld_ptr(mark_addr, temp_reg);
+ and3(temp_reg, markOopDesc::biased_lock_mask_in_place, temp_reg);
+ cmp(temp_reg, markOopDesc::biased_lock_pattern);
+ brx(Assembler::equal, allow_delay_slot_filling, Assembler::pt, done);
+ delayed();
+ if (!allow_delay_slot_filling) {
+ nop();
+ }
+}
+
+
+// CASN -- 32-64 bit switch hitter similar to the synthetic CASN provided by
+// Solaris/SPARC's "as". Another apt name would be cas_ptr()
+
+void MacroAssembler::casn (Register addr_reg, Register cmp_reg, Register set_reg ) {
+ casx_under_lock (addr_reg, cmp_reg, set_reg, (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr());
+}
+
+
+
+// compiler_lock_object() and compiler_unlock_object() are direct transliterations
+// of i486.ad fast_lock() and fast_unlock(). See those methods for detailed comments.
+// The code could be tightened up considerably.
+//
+// box->dhw disposition - post-conditions at DONE_LABEL.
+// - Successful inflated lock: box->dhw != 0.
+// Any non-zero value suffices.
+// Consider G2_thread, rsp, boxReg, or unused_mark()
+// - Successful Stack-lock: box->dhw == mark.
+// box->dhw must contain the displaced mark word value
+// - Failure -- icc.ZFlag == 0 and box->dhw is undefined.
+// The slow-path fast_enter() and slow_enter() operators
+// are responsible for setting box->dhw = NonZero (typically ::unused_mark).
+// - Biased: box->dhw is undefined
+//
+// SPARC refworkload performance - specifically jetstream and scimark - are
+// extremely sensitive to the size of the code emitted by compiler_lock_object
+// and compiler_unlock_object. Critically, the key factor is code size, not path
+// length. (Simply experiments to pad CLO with unexecuted NOPs demonstrte the
+// effect).
+
+
+void MacroAssembler::compiler_lock_object(Register Roop, Register Rmark,
+ Register Rbox, Register Rscratch,
+ BiasedLockingCounters* counters,
+ bool try_bias) {
+ Address mark_addr(Roop, oopDesc::mark_offset_in_bytes());
+
+ verify_oop(Roop);
+ Label done ;
+
+ if (counters != NULL) {
+ inc_counter((address) counters->total_entry_count_addr(), Rmark, Rscratch);
+ }
+
+ if (EmitSync & 1) {
+ mov(3, Rscratch);
+ st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
+ cmp(SP, G0);
+ return ;
+ }
+
+ if (EmitSync & 2) {
+
+ // Fetch object's markword
+ ld_ptr(mark_addr, Rmark);
+
+ if (try_bias) {
+ biased_locking_enter(Roop, Rmark, Rscratch, done, NULL, counters);
+ }
+
+ // Save Rbox in Rscratch to be used for the cas operation
+ mov(Rbox, Rscratch);
+
+ // set Rmark to markOop | markOopDesc::unlocked_value
+ or3(Rmark, markOopDesc::unlocked_value, Rmark);
+
+ // Initialize the box. (Must happen before we update the object mark!)
+ st_ptr(Rmark, Rbox, BasicLock::displaced_header_offset_in_bytes());
+
+ // compare object markOop with Rmark and if equal exchange Rscratch with object markOop
+ assert(mark_addr.disp() == 0, "cas must take a zero displacement");
+ casx_under_lock(mark_addr.base(), Rmark, Rscratch,
+ (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr());
+
+ // if compare/exchange succeeded we found an unlocked object and we now have locked it
+ // hence we are done
+ cmp(Rmark, Rscratch);
+#ifdef _LP64
+ sub(Rscratch, STACK_BIAS, Rscratch);
+#endif
+ brx(Assembler::equal, false, Assembler::pt, done);
+ delayed()->sub(Rscratch, SP, Rscratch); //pull next instruction into delay slot
+
+ // we did not find an unlocked object so see if this is a recursive case
+ // sub(Rscratch, SP, Rscratch);
+ assert(os::vm_page_size() > 0xfff, "page size too small - change the constant");
+ andcc(Rscratch, 0xfffff003, Rscratch);
+ st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
+ bind (done);
+ return ;
+ }
+
+ Label Egress ;
+
+ if (EmitSync & 256) {
+ Label IsInflated ;
+
+ ld_ptr(mark_addr, Rmark); // fetch obj->mark
+ // Triage: biased, stack-locked, neutral, inflated
+ if (try_bias) {
+ biased_locking_enter(Roop, Rmark, Rscratch, done, NULL, counters);
+ // Invariant: if control reaches this point in the emitted stream
+ // then Rmark has not been modified.
+ }
+
+ // Store mark into displaced mark field in the on-stack basic-lock "box"
+ // Critically, this must happen before the CAS
+ // Maximize the ST-CAS distance to minimize the ST-before-CAS penalty.
+ st_ptr(Rmark, Rbox, BasicLock::displaced_header_offset_in_bytes());
+ andcc(Rmark, 2, G0);
+ brx(Assembler::notZero, false, Assembler::pn, IsInflated);
+ delayed()->
+
+ // Try stack-lock acquisition.
+ // Beware: the 1st instruction is in a delay slot
+ mov(Rbox, Rscratch);
+ or3(Rmark, markOopDesc::unlocked_value, Rmark);
+ assert(mark_addr.disp() == 0, "cas must take a zero displacement");
+ casn(mark_addr.base(), Rmark, Rscratch);
+ cmp(Rmark, Rscratch);
+ brx(Assembler::equal, false, Assembler::pt, done);
+ delayed()->sub(Rscratch, SP, Rscratch);
+
+ // Stack-lock attempt failed - check for recursive stack-lock.
+ // See the comments below about how we might remove this case.
+#ifdef _LP64
+ sub(Rscratch, STACK_BIAS, Rscratch);
+#endif
+ assert(os::vm_page_size() > 0xfff, "page size too small - change the constant");
+ andcc(Rscratch, 0xfffff003, Rscratch);
+ br(Assembler::always, false, Assembler::pt, done);
+ delayed()-> st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
+
+ bind(IsInflated);
+ if (EmitSync & 64) {
+ // If m->owner != null goto IsLocked
+ // Pessimistic form: Test-and-CAS vs CAS
+ // The optimistic form avoids RTS->RTO cache line upgrades.
+ ld_ptr(Rmark, ObjectMonitor::owner_offset_in_bytes() - 2, Rscratch);
+ andcc(Rscratch, Rscratch, G0);
+ brx(Assembler::notZero, false, Assembler::pn, done);
+ delayed()->nop();
+ // m->owner == null : it's unlocked.
+ }
+
+ // Try to CAS m->owner from null to Self
+ // Invariant: if we acquire the lock then _recursions should be 0.
+ add(Rmark, ObjectMonitor::owner_offset_in_bytes()-2, Rmark);
+ mov(G2_thread, Rscratch);
+ casn(Rmark, G0, Rscratch);
+ cmp(Rscratch, G0);
+ // Intentional fall-through into done
+ } else {
+ // Aggressively avoid the Store-before-CAS penalty
+ // Defer the store into box->dhw until after the CAS
+ Label IsInflated, Recursive ;
+
+// Anticipate CAS -- Avoid RTS->RTO upgrade
+// prefetch (mark_addr, Assembler::severalWritesAndPossiblyReads);
+
+ ld_ptr(mark_addr, Rmark); // fetch obj->mark
+ // Triage: biased, stack-locked, neutral, inflated
+
+ if (try_bias) {
+ biased_locking_enter(Roop, Rmark, Rscratch, done, NULL, counters);
+ // Invariant: if control reaches this point in the emitted stream
+ // then Rmark has not been modified.
+ }
+ andcc(Rmark, 2, G0);
+ brx(Assembler::notZero, false, Assembler::pn, IsInflated);
+ delayed()-> // Beware - dangling delay-slot
+
+ // Try stack-lock acquisition.
+ // Transiently install BUSY (0) encoding in the mark word.
+ // if the CAS of 0 into the mark was successful then we execute:
+ // ST box->dhw = mark -- save fetched mark in on-stack basiclock box
+ // ST obj->mark = box -- overwrite transient 0 value
+ // This presumes TSO, of course.
+
+ mov(0, Rscratch);
+ or3(Rmark, markOopDesc::unlocked_value, Rmark);
+ assert(mark_addr.disp() == 0, "cas must take a zero displacement");
+ casn(mark_addr.base(), Rmark, Rscratch);
+// prefetch (mark_addr, Assembler::severalWritesAndPossiblyReads);
+ cmp(Rscratch, Rmark);
+ brx(Assembler::notZero, false, Assembler::pn, Recursive);
+ delayed()->st_ptr(Rmark, Rbox, BasicLock::displaced_header_offset_in_bytes());
+ if (counters != NULL) {
+ cond_inc(Assembler::equal, (address) counters->fast_path_entry_count_addr(), Rmark, Rscratch);
+ }
+ ba(done);
+ delayed()->st_ptr(Rbox, mark_addr);
+
+ bind(Recursive);
+ // Stack-lock attempt failed - check for recursive stack-lock.
+ // Tests show that we can remove the recursive case with no impact
+ // on refworkload 0.83. If we need to reduce the size of the code
+ // emitted by compiler_lock_object() the recursive case is perfect
+ // candidate.
+ //
+ // A more extreme idea is to always inflate on stack-lock recursion.
+ // This lets us eliminate the recursive checks in compiler_lock_object
+ // and compiler_unlock_object and the (box->dhw == 0) encoding.
+ // A brief experiment - requiring changes to synchronizer.cpp, interpreter,
+ // and showed a performance *increase*. In the same experiment I eliminated
+ // the fast-path stack-lock code from the interpreter and always passed
+ // control to the "slow" operators in synchronizer.cpp.
+
+ // RScratch contains the fetched obj->mark value from the failed CASN.
+#ifdef _LP64
+ sub(Rscratch, STACK_BIAS, Rscratch);
+#endif
+ sub(Rscratch, SP, Rscratch);
+ assert(os::vm_page_size() > 0xfff, "page size too small - change the constant");
+ andcc(Rscratch, 0xfffff003, Rscratch);
+ if (counters != NULL) {
+ // Accounting needs the Rscratch register
+ st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
+ cond_inc(Assembler::equal, (address) counters->fast_path_entry_count_addr(), Rmark, Rscratch);
+ ba_short(done);
+ } else {
+ ba(done);
+ delayed()->st_ptr(Rscratch, Rbox, BasicLock::displaced_header_offset_in_bytes());
+ }
+
+ bind (IsInflated);
+ if (EmitSync & 64) {
+ // If m->owner != null goto IsLocked
+ // Test-and-CAS vs CAS
+ // Pessimistic form avoids futile (doomed) CAS attempts
+ // The optimistic form avoids RTS->RTO cache line upgrades.
+ ld_ptr(Rmark, ObjectMonitor::owner_offset_in_bytes() - 2, Rscratch);
+ andcc(Rscratch, Rscratch, G0);
+ brx(Assembler::notZero, false, Assembler::pn, done);
+ delayed()->nop();
+ // m->owner == null : it's unlocked.
+ }
+
+ // Try to CAS m->owner from null to Self
+ // Invariant: if we acquire the lock then _recursions should be 0.
+ add(Rmark, ObjectMonitor::owner_offset_in_bytes()-2, Rmark);
+ mov(G2_thread, Rscratch);
+ casn(Rmark, G0, Rscratch);
+ cmp(Rscratch, G0);
+ // ST box->displaced_header = NonZero.
+ // Any non-zero value suffices:
+ // unused_mark(), G2_thread, RBox, RScratch, rsp, etc.
+ st_ptr(Rbox, Rbox, BasicLock::displaced_header_offset_in_bytes());
+ // Intentional fall-through into done
+ }
+
+ bind (done);
+}
+
+void MacroAssembler::compiler_unlock_object(Register Roop, Register Rmark,
+ Register Rbox, Register Rscratch,
+ bool try_bias) {
+ Address mark_addr(Roop, oopDesc::mark_offset_in_bytes());
+
+ Label done ;
+
+ if (EmitSync & 4) {
+ cmp(SP, G0);
+ return ;
+ }
+
+ if (EmitSync & 8) {
+ if (try_bias) {
+ biased_locking_exit(mark_addr, Rscratch, done);
+ }
+
+ // Test first if it is a fast recursive unlock
+ ld_ptr(Rbox, BasicLock::displaced_header_offset_in_bytes(), Rmark);
+ br_null_short(Rmark, Assembler::pt, done);
+
+ // Check if it is still a light weight lock, this is is true if we see
+ // the stack address of the basicLock in the markOop of the object
+ assert(mark_addr.disp() == 0, "cas must take a zero displacement");
+ casx_under_lock(mark_addr.base(), Rbox, Rmark,
+ (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr());
+ ba(done);
+ delayed()->cmp(Rbox, Rmark);
+ bind(done);
+ return ;
+ }
+
+ // Beware ... If the aggregate size of the code emitted by CLO and CUO is
+ // is too large performance rolls abruptly off a cliff.
+ // This could be related to inlining policies, code cache management, or
+ // I$ effects.
+ Label LStacked ;
+
+ if (try_bias) {
+ // TODO: eliminate redundant LDs of obj->mark
+ biased_locking_exit(mark_addr, Rscratch, done);
+ }
+
+ ld_ptr(Roop, oopDesc::mark_offset_in_bytes(), Rmark);
+ ld_ptr(Rbox, BasicLock::displaced_header_offset_in_bytes(), Rscratch);
+ andcc(Rscratch, Rscratch, G0);
+ brx(Assembler::zero, false, Assembler::pn, done);
+ delayed()->nop(); // consider: relocate fetch of mark, above, into this DS
+ andcc(Rmark, 2, G0);
+ brx(Assembler::zero, false, Assembler::pt, LStacked);
+ delayed()->nop();
+
+ // It's inflated
+ // Conceptually we need a #loadstore|#storestore "release" MEMBAR before
+ // the ST of 0 into _owner which releases the lock. This prevents loads
+ // and stores within the critical section from reordering (floating)
+ // past the store that releases the lock. But TSO is a strong memory model
+ // and that particular flavor of barrier is a noop, so we can safely elide it.
+ // Note that we use 1-0 locking by default for the inflated case. We
+ // close the resultant (and rare) race by having contented threads in
+ // monitorenter periodically poll _owner.
+ ld_ptr(Rmark, ObjectMonitor::owner_offset_in_bytes() - 2, Rscratch);
+ ld_ptr(Rmark, ObjectMonitor::recursions_offset_in_bytes() - 2, Rbox);
+ xor3(Rscratch, G2_thread, Rscratch);
+ orcc(Rbox, Rscratch, Rbox);
+ brx(Assembler::notZero, false, Assembler::pn, done);
+ delayed()->
+ ld_ptr(Rmark, ObjectMonitor::EntryList_offset_in_bytes() - 2, Rscratch);
+ ld_ptr(Rmark, ObjectMonitor::cxq_offset_in_bytes() - 2, Rbox);
+ orcc(Rbox, Rscratch, G0);
+ if (EmitSync & 65536) {
+ Label LSucc ;
+ brx(Assembler::notZero, false, Assembler::pn, LSucc);
+ delayed()->nop();
+ ba(done);
+ delayed()->st_ptr(G0, Rmark, ObjectMonitor::owner_offset_in_bytes() - 2);
+
+ bind(LSucc);
+ st_ptr(G0, Rmark, ObjectMonitor::owner_offset_in_bytes() - 2);
+ if (os::is_MP()) { membar (StoreLoad); }
+ ld_ptr(Rmark, ObjectMonitor::succ_offset_in_bytes() - 2, Rscratch);
+ andcc(Rscratch, Rscratch, G0);
+ brx(Assembler::notZero, false, Assembler::pt, done);
+ delayed()->andcc(G0, G0, G0);
+ add(Rmark, ObjectMonitor::owner_offset_in_bytes()-2, Rmark);
+ mov(G2_thread, Rscratch);
+ casn(Rmark, G0, Rscratch);
+ // invert icc.zf and goto done
+ br_notnull(Rscratch, false, Assembler::pt, done);
+ delayed()->cmp(G0, G0);
+ ba(done);
+ delayed()->cmp(G0, 1);
+ } else {
+ brx(Assembler::notZero, false, Assembler::pn, done);
+ delayed()->nop();
+ ba(done);
+ delayed()->st_ptr(G0, Rmark, ObjectMonitor::owner_offset_in_bytes() - 2);
+ }
+
+ bind (LStacked);
+ // Consider: we could replace the expensive CAS in the exit
+ // path with a simple ST of the displaced mark value fetched from
+ // the on-stack basiclock box. That admits a race where a thread T2
+ // in the slow lock path -- inflating with monitor M -- could race a
+ // thread T1 in the fast unlock path, resulting in a missed wakeup for T2.
+ // More precisely T1 in the stack-lock unlock path could "stomp" the
+ // inflated mark value M installed by T2, resulting in an orphan
+ // object monitor M and T2 becoming stranded. We can remedy that situation
+ // by having T2 periodically poll the object's mark word using timed wait
+ // operations. If T2 discovers that a stomp has occurred it vacates
+ // the monitor M and wakes any other threads stranded on the now-orphan M.
+ // In addition the monitor scavenger, which performs deflation,
+ // would also need to check for orpan monitors and stranded threads.
+ //
+ // Finally, inflation is also used when T2 needs to assign a hashCode
+ // to O and O is stack-locked by T1. The "stomp" race could cause
+ // an assigned hashCode value to be lost. We can avoid that condition
+ // and provide the necessary hashCode stability invariants by ensuring
+ // that hashCode generation is idempotent between copying GCs.
+ // For example we could compute the hashCode of an object O as
+ // O's heap address XOR some high quality RNG value that is refreshed
+ // at GC-time. The monitor scavenger would install the hashCode
+ // found in any orphan monitors. Again, the mechanism admits a
+ // lost-update "stomp" WAW race but detects and recovers as needed.
+ //
+ // A prototype implementation showed excellent results, although
+ // the scavenger and timeout code was rather involved.
+
+ casn(mark_addr.base(), Rbox, Rscratch);
+ cmp(Rbox, Rscratch);
+ // Intentional fall through into done ...
+
+ bind(done);
+}
+
+
+
+void MacroAssembler::print_CPU_state() {
+ // %%%%% need to implement this
+}
+
+void MacroAssembler::verify_FPU(int stack_depth, const char* s) {
+ // %%%%% need to implement this
+}
+
+void MacroAssembler::push_IU_state() {
+ // %%%%% need to implement this
+}
+
+
+void MacroAssembler::pop_IU_state() {
+ // %%%%% need to implement this
+}
+
+
+void MacroAssembler::push_FPU_state() {
+ // %%%%% need to implement this
+}
+
+
+void MacroAssembler::pop_FPU_state() {
+ // %%%%% need to implement this
+}
+
+
+void MacroAssembler::push_CPU_state() {
+ // %%%%% need to implement this
+}
+
+
+void MacroAssembler::pop_CPU_state() {
+ // %%%%% need to implement this
+}
+
+
+
+void MacroAssembler::verify_tlab() {
+#ifdef ASSERT
+ if (UseTLAB && VerifyOops) {
+ Label next, next2, ok;
+ Register t1 = L0;
+ Register t2 = L1;
+ Register t3 = L2;
+
+ save_frame(0);
+ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), t1);
+ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_start_offset()), t2);
+ or3(t1, t2, t3);
+ cmp_and_br_short(t1, t2, Assembler::greaterEqual, Assembler::pn, next);
+ STOP("assert(top >= start)");
+ should_not_reach_here();
+
+ bind(next);
+ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), t1);
+ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_end_offset()), t2);
+ or3(t3, t2, t3);
+ cmp_and_br_short(t1, t2, Assembler::lessEqual, Assembler::pn, next2);
+ STOP("assert(top <= end)");
+ should_not_reach_here();
+
+ bind(next2);
+ and3(t3, MinObjAlignmentInBytesMask, t3);
+ cmp_and_br_short(t3, 0, Assembler::lessEqual, Assembler::pn, ok);
+ STOP("assert(aligned)");
+ should_not_reach_here();
+
+ bind(ok);
+ restore();
+ }
+#endif
+}
+
+
+void MacroAssembler::eden_allocate(
+ Register obj, // result: pointer to object after successful allocation
+ Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
+ int con_size_in_bytes, // object size in bytes if known at compile time
+ Register t1, // temp register
+ Register t2, // temp register
+ Label& slow_case // continuation point if fast allocation fails
+){
+ // make sure arguments make sense
+ assert_different_registers(obj, var_size_in_bytes, t1, t2);
+ assert(0 <= con_size_in_bytes && Assembler::is_simm13(con_size_in_bytes), "illegal object size");
+ assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0, "object size is not multiple of alignment");
+
+ if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) {
+ // No allocation in the shared eden.
+ ba_short(slow_case);
+ } else {
+ // get eden boundaries
+ // note: we need both top & top_addr!
+ const Register top_addr = t1;
+ const Register end = t2;
+
+ CollectedHeap* ch = Universe::heap();
+ set((intx)ch->top_addr(), top_addr);
+ intx delta = (intx)ch->end_addr() - (intx)ch->top_addr();
+ ld_ptr(top_addr, delta, end);
+ ld_ptr(top_addr, 0, obj);
+
+ // try to allocate
+ Label retry;
+ bind(retry);
+#ifdef ASSERT
+ // make sure eden top is properly aligned
+ {
+ Label L;
+ btst(MinObjAlignmentInBytesMask, obj);
+ br(Assembler::zero, false, Assembler::pt, L);
+ delayed()->nop();
+ STOP("eden top is not properly aligned");
+ bind(L);
+ }
+#endif // ASSERT
+ const Register free = end;
+ sub(end, obj, free); // compute amount of free space
+ if (var_size_in_bytes->is_valid()) {
+ // size is unknown at compile time
+ cmp(free, var_size_in_bytes);
+ br(Assembler::lessUnsigned, false, Assembler::pn, slow_case); // if there is not enough space go the slow case
+ delayed()->add(obj, var_size_in_bytes, end);
+ } else {
+ // size is known at compile time
+ cmp(free, con_size_in_bytes);
+ br(Assembler::lessUnsigned, false, Assembler::pn, slow_case); // if there is not enough space go the slow case
+ delayed()->add(obj, con_size_in_bytes, end);
+ }
+ // Compare obj with the value at top_addr; if still equal, swap the value of
+ // end with the value at top_addr. If not equal, read the value at top_addr
+ // into end.
+ casx_under_lock(top_addr, obj, end, (address)StubRoutines::Sparc::atomic_memory_operation_lock_addr());
+ // if someone beat us on the allocation, try again, otherwise continue
+ cmp(obj, end);
+ brx(Assembler::notEqual, false, Assembler::pn, retry);
+ delayed()->mov(end, obj); // nop if successfull since obj == end
+
+#ifdef ASSERT
+ // make sure eden top is properly aligned
+ {
+ Label L;
+ const Register top_addr = t1;
+
+ set((intx)ch->top_addr(), top_addr);
+ ld_ptr(top_addr, 0, top_addr);
+ btst(MinObjAlignmentInBytesMask, top_addr);
+ br(Assembler::zero, false, Assembler::pt, L);
+ delayed()->nop();
+ STOP("eden top is not properly aligned");
+ bind(L);
+ }
+#endif // ASSERT
+ }
+}
+
+
+void MacroAssembler::tlab_allocate(
+ Register obj, // result: pointer to object after successful allocation
+ Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
+ int con_size_in_bytes, // object size in bytes if known at compile time
+ Register t1, // temp register
+ Label& slow_case // continuation point if fast allocation fails
+){
+ // make sure arguments make sense
+ assert_different_registers(obj, var_size_in_bytes, t1);
+ assert(0 <= con_size_in_bytes && is_simm13(con_size_in_bytes), "illegal object size");
+ assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0, "object size is not multiple of alignment");
+
+ const Register free = t1;
+
+ verify_tlab();
+
+ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), obj);
+
+ // calculate amount of free space
+ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_end_offset()), free);
+ sub(free, obj, free);
+
+ Label done;
+ if (var_size_in_bytes == noreg) {
+ cmp(free, con_size_in_bytes);
+ } else {
+ cmp(free, var_size_in_bytes);
+ }
+ br(Assembler::less, false, Assembler::pn, slow_case);
+ // calculate the new top pointer
+ if (var_size_in_bytes == noreg) {
+ delayed()->add(obj, con_size_in_bytes, free);
+ } else {
+ delayed()->add(obj, var_size_in_bytes, free);
+ }
+
+ bind(done);
+
+#ifdef ASSERT
+ // make sure new free pointer is properly aligned
+ {
+ Label L;
+ btst(MinObjAlignmentInBytesMask, free);
+ br(Assembler::zero, false, Assembler::pt, L);
+ delayed()->nop();
+ STOP("updated TLAB free is not properly aligned");
+ bind(L);
+ }
+#endif // ASSERT
+
+ // update the tlab top pointer
+ st_ptr(free, G2_thread, in_bytes(JavaThread::tlab_top_offset()));
+ verify_tlab();
+}
+
+
+void MacroAssembler::tlab_refill(Label& retry, Label& try_eden, Label& slow_case) {
+ Register top = O0;
+ Register t1 = G1;
+ Register t2 = G3;
+ Register t3 = O1;
+ assert_different_registers(top, t1, t2, t3, G4, G5 /* preserve G4 and G5 */);
+ Label do_refill, discard_tlab;
+
+ if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) {
+ // No allocation in the shared eden.
+ ba_short(slow_case);
+ }
+
+ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_top_offset()), top);
+ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_end_offset()), t1);
+ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_refill_waste_limit_offset()), t2);
+
+ // calculate amount of free space
+ sub(t1, top, t1);
+ srl_ptr(t1, LogHeapWordSize, t1);
+
+ // Retain tlab and allocate object in shared space if
+ // the amount free in the tlab is too large to discard.
+ cmp(t1, t2);
+ brx(Assembler::lessEqual, false, Assembler::pt, discard_tlab);
+
+ // increment waste limit to prevent getting stuck on this slow path
+ delayed()->add(t2, ThreadLocalAllocBuffer::refill_waste_limit_increment(), t2);
+ st_ptr(t2, G2_thread, in_bytes(JavaThread::tlab_refill_waste_limit_offset()));
+ if (TLABStats) {
+ // increment number of slow_allocations
+ ld(G2_thread, in_bytes(JavaThread::tlab_slow_allocations_offset()), t2);
+ add(t2, 1, t2);
+ stw(t2, G2_thread, in_bytes(JavaThread::tlab_slow_allocations_offset()));
+ }
+ ba_short(try_eden);
+
+ bind(discard_tlab);
+ if (TLABStats) {
+ // increment number of refills
+ ld(G2_thread, in_bytes(JavaThread::tlab_number_of_refills_offset()), t2);
+ add(t2, 1, t2);
+ stw(t2, G2_thread, in_bytes(JavaThread::tlab_number_of_refills_offset()));
+ // accumulate wastage
+ ld(G2_thread, in_bytes(JavaThread::tlab_fast_refill_waste_offset()), t2);
+ add(t2, t1, t2);
+ stw(t2, G2_thread, in_bytes(JavaThread::tlab_fast_refill_waste_offset()));
+ }
+
+ // if tlab is currently allocated (top or end != null) then
+ // fill [top, end + alignment_reserve) with array object
+ br_null_short(top, Assembler::pn, do_refill);
+
+ set((intptr_t)markOopDesc::prototype()->copy_set_hash(0x2), t2);
+ st_ptr(t2, top, oopDesc::mark_offset_in_bytes()); // set up the mark word
+ // set klass to intArrayKlass
+ sub(t1, typeArrayOopDesc::header_size(T_INT), t1);
+ add(t1, ThreadLocalAllocBuffer::alignment_reserve(), t1);
+ sll_ptr(t1, log2_intptr(HeapWordSize/sizeof(jint)), t1);
+ st(t1, top, arrayOopDesc::length_offset_in_bytes());
+ set((intptr_t)Universe::intArrayKlassObj_addr(), t2);
+ ld_ptr(t2, 0, t2);
+ // store klass last. concurrent gcs assumes klass length is valid if
+ // klass field is not null.
+ store_klass(t2, top);
+ verify_oop(top);
+
+ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_start_offset()), t1);
+ sub(top, t1, t1); // size of tlab's allocated portion
+ incr_allocated_bytes(t1, t2, t3);
+
+ // refill the tlab with an eden allocation
+ bind(do_refill);
+ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_size_offset()), t1);
+ sll_ptr(t1, LogHeapWordSize, t1);
+ // allocate new tlab, address returned in top
+ eden_allocate(top, t1, 0, t2, t3, slow_case);
+
+ st_ptr(top, G2_thread, in_bytes(JavaThread::tlab_start_offset()));
+ st_ptr(top, G2_thread, in_bytes(JavaThread::tlab_top_offset()));
+#ifdef ASSERT
+ // check that tlab_size (t1) is still valid
+ {
+ Label ok;
+ ld_ptr(G2_thread, in_bytes(JavaThread::tlab_size_offset()), t2);
+ sll_ptr(t2, LogHeapWordSize, t2);
+ cmp_and_br_short(t1, t2, Assembler::equal, Assembler::pt, ok);
+ STOP("assert(t1 == tlab_size)");
+ should_not_reach_here();
+
+ bind(ok);
+ }
+#endif // ASSERT
+ add(top, t1, top); // t1 is tlab_size
+ sub(top, ThreadLocalAllocBuffer::alignment_reserve_in_bytes(), top);
+ st_ptr(top, G2_thread, in_bytes(JavaThread::tlab_end_offset()));
+ verify_tlab();
+ ba_short(retry);
+}
+
+void MacroAssembler::incr_allocated_bytes(RegisterOrConstant size_in_bytes,
+ Register t1, Register t2) {
+ // Bump total bytes allocated by this thread
+ assert(t1->is_global(), "must be global reg"); // so all 64 bits are saved on a context switch
+ assert_different_registers(size_in_bytes.register_or_noreg(), t1, t2);
+ // v8 support has gone the way of the dodo
+ ldx(G2_thread, in_bytes(JavaThread::allocated_bytes_offset()), t1);
+ add(t1, ensure_simm13_or_reg(size_in_bytes, t2), t1);
+ stx(t1, G2_thread, in_bytes(JavaThread::allocated_bytes_offset()));
+}
+
+Assembler::Condition MacroAssembler::negate_condition(Assembler::Condition cond) {
+ switch (cond) {
+ // Note some conditions are synonyms for others
+ case Assembler::never: return Assembler::always;
+ case Assembler::zero: return Assembler::notZero;
+ case Assembler::lessEqual: return Assembler::greater;
+ case Assembler::less: return Assembler::greaterEqual;
+ case Assembler::lessEqualUnsigned: return Assembler::greaterUnsigned;
+ case Assembler::lessUnsigned: return Assembler::greaterEqualUnsigned;
+ case Assembler::negative: return Assembler::positive;
+ case Assembler::overflowSet: return Assembler::overflowClear;
+ case Assembler::always: return Assembler::never;
+ case Assembler::notZero: return Assembler::zero;
+ case Assembler::greater: return Assembler::lessEqual;
+ case Assembler::greaterEqual: return Assembler::less;
+ case Assembler::greaterUnsigned: return Assembler::lessEqualUnsigned;
+ case Assembler::greaterEqualUnsigned: return Assembler::lessUnsigned;
+ case Assembler::positive: return Assembler::negative;
+ case Assembler::overflowClear: return Assembler::overflowSet;
+ }
+
+ ShouldNotReachHere(); return Assembler::overflowClear;
+}
+
+void MacroAssembler::cond_inc(Assembler::Condition cond, address counter_ptr,
+ Register Rtmp1, Register Rtmp2 /*, Register Rtmp3, Register Rtmp4 */) {
+ Condition negated_cond = negate_condition(cond);
+ Label L;
+ brx(negated_cond, false, Assembler::pt, L);
+ delayed()->nop();
+ inc_counter(counter_ptr, Rtmp1, Rtmp2);
+ bind(L);
+}
+
+void MacroAssembler::inc_counter(address counter_addr, Register Rtmp1, Register Rtmp2) {
+ AddressLiteral addrlit(counter_addr);
+ sethi(addrlit, Rtmp1); // Move hi22 bits into temporary register.
+ Address addr(Rtmp1, addrlit.low10()); // Build an address with low10 bits.
+ ld(addr, Rtmp2);
+ inc(Rtmp2);
+ st(Rtmp2, addr);
+}
+
+void MacroAssembler::inc_counter(int* counter_addr, Register Rtmp1, Register Rtmp2) {
+ inc_counter((address) counter_addr, Rtmp1, Rtmp2);
+}
+
+SkipIfEqual::SkipIfEqual(
+ MacroAssembler* masm, Register temp, const bool* flag_addr,
+ Assembler::Condition condition) {
+ _masm = masm;
+ AddressLiteral flag(flag_addr);
+ _masm->sethi(flag, temp);
+ _masm->ldub(temp, flag.low10(), temp);
+ _masm->tst(temp);
+ _masm->br(condition, false, Assembler::pt, _label);
+ _masm->delayed()->nop();
+}
+
+SkipIfEqual::~SkipIfEqual() {
+ _masm->bind(_label);
+}
+
+
+// Writes to stack successive pages until offset reached to check for
+// stack overflow + shadow pages. This clobbers tsp and scratch.
+void MacroAssembler::bang_stack_size(Register Rsize, Register Rtsp,
+ Register Rscratch) {
+ // Use stack pointer in temp stack pointer
+ mov(SP, Rtsp);
+
+ // Bang stack for total size given plus stack shadow page size.
+ // Bang one page at a time because a large size can overflow yellow and
+ // red zones (the bang will fail but stack overflow handling can't tell that
+ // it was a stack overflow bang vs a regular segv).
+ int offset = os::vm_page_size();
+ Register Roffset = Rscratch;
+
+ Label loop;
+ bind(loop);
+ set((-offset)+STACK_BIAS, Rscratch);
+ st(G0, Rtsp, Rscratch);
+ set(offset, Roffset);
+ sub(Rsize, Roffset, Rsize);
+ cmp(Rsize, G0);
+ br(Assembler::greater, false, Assembler::pn, loop);
+ delayed()->sub(Rtsp, Roffset, Rtsp);
+
+ // Bang down shadow pages too.
+ // The -1 because we already subtracted 1 page.
+ for (int i = 0; i< StackShadowPages-1; i++) {
+ set((-i*offset)+STACK_BIAS, Rscratch);
+ st(G0, Rtsp, Rscratch);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////
+#ifndef SERIALGC
+
+static address satb_log_enqueue_with_frame = NULL;
+static u_char* satb_log_enqueue_with_frame_end = NULL;
+
+static address satb_log_enqueue_frameless = NULL;
+static u_char* satb_log_enqueue_frameless_end = NULL;
+
+static int EnqueueCodeSize = 128 DEBUG_ONLY( + 256); // Instructions?
+
+static void generate_satb_log_enqueue(bool with_frame) {
+ BufferBlob* bb = BufferBlob::create("enqueue_with_frame", EnqueueCodeSize);
+ CodeBuffer buf(bb);
+ MacroAssembler masm(&buf);
+
+#define __ masm.
+
+ address start = __ pc();
+ Register pre_val;
+
+ Label refill, restart;
+ if (with_frame) {
+ __ save_frame(0);
+ pre_val = I0; // Was O0 before the save.
+ } else {
+ pre_val = O0;
+ }
+
+ int satb_q_index_byte_offset =
+ in_bytes(JavaThread::satb_mark_queue_offset() +
+ PtrQueue::byte_offset_of_index());
+
+ int satb_q_buf_byte_offset =
+ in_bytes(JavaThread::satb_mark_queue_offset() +
+ PtrQueue::byte_offset_of_buf());
+
+ assert(in_bytes(PtrQueue::byte_width_of_index()) == sizeof(intptr_t) &&
+ in_bytes(PtrQueue::byte_width_of_buf()) == sizeof(intptr_t),
+ "check sizes in assembly below");
+
+ __ bind(restart);
+
+ // Load the index into the SATB buffer. PtrQueue::_index is a size_t
+ // so ld_ptr is appropriate.
+ __ ld_ptr(G2_thread, satb_q_index_byte_offset, L0);
+
+ // index == 0?
+ __ cmp_and_brx_short(L0, G0, Assembler::equal, Assembler::pn, refill);
+
+ __ ld_ptr(G2_thread, satb_q_buf_byte_offset, L1);
+ __ sub(L0, oopSize, L0);
+
+ __ st_ptr(pre_val, L1, L0); // [_buf + index] := I0
+ if (!with_frame) {
+ // Use return-from-leaf
+ __ retl();
+ __ delayed()->st_ptr(L0, G2_thread, satb_q_index_byte_offset);
+ } else {
+ // Not delayed.
+ __ st_ptr(L0, G2_thread, satb_q_index_byte_offset);
+ }
+ if (with_frame) {
+ __ ret();
+ __ delayed()->restore();
+ }
+ __ bind(refill);
+
+ address handle_zero =
+ CAST_FROM_FN_PTR(address,
+ &SATBMarkQueueSet::handle_zero_index_for_thread);
+ // This should be rare enough that we can afford to save all the
+ // scratch registers that the calling context might be using.
+ __ mov(G1_scratch, L0);
+ __ mov(G3_scratch, L1);
+ __ mov(G4, L2);
+ // We need the value of O0 above (for the write into the buffer), so we
+ // save and restore it.
+ __ mov(O0, L3);
+ // Since the call will overwrite O7, we save and restore that, as well.
+ __ mov(O7, L4);
+ __ call_VM_leaf(L5, handle_zero, G2_thread);
+ __ mov(L0, G1_scratch);
+ __ mov(L1, G3_scratch);
+ __ mov(L2, G4);
+ __ mov(L3, O0);
+ __ br(Assembler::always, /*annul*/false, Assembler::pt, restart);
+ __ delayed()->mov(L4, O7);
+
+ if (with_frame) {
+ satb_log_enqueue_with_frame = start;
+ satb_log_enqueue_with_frame_end = __ pc();
+ } else {
+ satb_log_enqueue_frameless = start;
+ satb_log_enqueue_frameless_end = __ pc();
+ }
+
+#undef __
+}
+
+static inline void generate_satb_log_enqueue_if_necessary(bool with_frame) {
+ if (with_frame) {
+ if (satb_log_enqueue_with_frame == 0) {
+ generate_satb_log_enqueue(with_frame);
+ assert(satb_log_enqueue_with_frame != 0, "postcondition.");
+ if (G1SATBPrintStubs) {
+ tty->print_cr("Generated with-frame satb enqueue:");
+ Disassembler::decode((u_char*)satb_log_enqueue_with_frame,
+ satb_log_enqueue_with_frame_end,
+ tty);
+ }
+ }
+ } else {
+ if (satb_log_enqueue_frameless == 0) {
+ generate_satb_log_enqueue(with_frame);
+ assert(satb_log_enqueue_frameless != 0, "postcondition.");
+ if (G1SATBPrintStubs) {
+ tty->print_cr("Generated frameless satb enqueue:");
+ Disassembler::decode((u_char*)satb_log_enqueue_frameless,
+ satb_log_enqueue_frameless_end,
+ tty);
+ }
+ }
+ }
+}
+
+void MacroAssembler::g1_write_barrier_pre(Register obj,
+ Register index,
+ int offset,
+ Register pre_val,
+ Register tmp,
+ bool preserve_o_regs) {
+ Label filtered;
+
+ if (obj == noreg) {
+ // We are not loading the previous value so make
+ // sure that we don't trash the value in pre_val
+ // with the code below.
+ assert_different_registers(pre_val, tmp);
+ } else {
+ // We will be loading the previous value
+ // in this code so...
+ assert(offset == 0 || index == noreg, "choose one");
+ assert(pre_val == noreg, "check this code");
+ }
+
+ // Is marking active?
+ if (in_bytes(PtrQueue::byte_width_of_active()) == 4) {
+ ld(G2,
+ in_bytes(JavaThread::satb_mark_queue_offset() +
+ PtrQueue::byte_offset_of_active()),
+ tmp);
+ } else {
+ guarantee(in_bytes(PtrQueue::byte_width_of_active()) == 1,
+ "Assumption");
+ ldsb(G2,
+ in_bytes(JavaThread::satb_mark_queue_offset() +
+ PtrQueue::byte_offset_of_active()),
+ tmp);
+ }
+
+ // Is marking active?
+ cmp_and_br_short(tmp, G0, Assembler::equal, Assembler::pt, filtered);
+
+ // Do we need to load the previous value?
+ if (obj != noreg) {
+ // Load the previous value...
+ if (index == noreg) {
+ if (Assembler::is_simm13(offset)) {
+ load_heap_oop(obj, offset, tmp);
+ } else {
+ set(offset, tmp);
+ load_heap_oop(obj, tmp, tmp);
+ }
+ } else {
+ load_heap_oop(obj, index, tmp);
+ }
+ // Previous value has been loaded into tmp
+ pre_val = tmp;
+ }
+
+ assert(pre_val != noreg, "must have a real register");
+
+ // Is the previous value null?
+ cmp_and_brx_short(pre_val, G0, Assembler::equal, Assembler::pt, filtered);
+
+ // OK, it's not filtered, so we'll need to call enqueue. In the normal
+ // case, pre_val will be a scratch G-reg, but there are some cases in
+ // which it's an O-reg. In the first case, do a normal call. In the
+ // latter, do a save here and call the frameless version.
+
+ guarantee(pre_val->is_global() || pre_val->is_out(),
+ "Or we need to think harder.");
+
+ if (pre_val->is_global() && !preserve_o_regs) {
+ generate_satb_log_enqueue_if_necessary(true); // with frame
+
+ call(satb_log_enqueue_with_frame);
+ delayed()->mov(pre_val, O0);
+ } else {
+ generate_satb_log_enqueue_if_necessary(false); // frameless
+
+ save_frame(0);
+ call(satb_log_enqueue_frameless);
+ delayed()->mov(pre_val->after_save(), O0);
+ restore();
+ }
+
+ bind(filtered);
+}
+
+static address dirty_card_log_enqueue = 0;
+static u_char* dirty_card_log_enqueue_end = 0;
+
+// This gets to assume that o0 contains the object address.
+static void generate_dirty_card_log_enqueue(jbyte* byte_map_base) {
+ BufferBlob* bb = BufferBlob::create("dirty_card_enqueue", EnqueueCodeSize*2);
+ CodeBuffer buf(bb);
+ MacroAssembler masm(&buf);
+#define __ masm.
+ address start = __ pc();
+
+ Label not_already_dirty, restart, refill;
+
+#ifdef _LP64
+ __ srlx(O0, CardTableModRefBS::card_shift, O0);
+#else
+ __ srl(O0, CardTableModRefBS::card_shift, O0);
+#endif
+ AddressLiteral addrlit(byte_map_base);
+ __ set(addrlit, O1); // O1 :=
+ __ ldub(O0, O1, O2); // O2 := [O0 + O1]
+
+ assert(CardTableModRefBS::dirty_card_val() == 0, "otherwise check this code");
+ __ cmp_and_br_short(O2, G0, Assembler::notEqual, Assembler::pt, not_already_dirty);
+
+ // We didn't take the branch, so we're already dirty: return.
+ // Use return-from-leaf
+ __ retl();
+ __ delayed()->nop();
+
+ // Not dirty.
+ __ bind(not_already_dirty);
+
+ // Get O0 + O1 into a reg by itself
+ __ add(O0, O1, O3);
+
+ // First, dirty it.
+ __ stb(G0, O3, G0); // [cardPtr] := 0 (i.e., dirty).
+
+ int dirty_card_q_index_byte_offset =
+ in_bytes(JavaThread::dirty_card_queue_offset() +
+ PtrQueue::byte_offset_of_index());
+ int dirty_card_q_buf_byte_offset =
+ in_bytes(JavaThread::dirty_card_queue_offset() +
+ PtrQueue::byte_offset_of_buf());
+ __ bind(restart);
+
+ // Load the index into the update buffer. PtrQueue::_index is
+ // a size_t so ld_ptr is appropriate here.
+ __ ld_ptr(G2_thread, dirty_card_q_index_byte_offset, L0);
+
+ // index == 0?
+ __ cmp_and_brx_short(L0, G0, Assembler::equal, Assembler::pn, refill);
+
+ __ ld_ptr(G2_thread, dirty_card_q_buf_byte_offset, L1);
+ __ sub(L0, oopSize, L0);
+
+ __ st_ptr(O3, L1, L0); // [_buf + index] := I0
+ // Use return-from-leaf
+ __ retl();
+ __ delayed()->st_ptr(L0, G2_thread, dirty_card_q_index_byte_offset);
+
+ __ bind(refill);
+ address handle_zero =
+ CAST_FROM_FN_PTR(address,
+ &DirtyCardQueueSet::handle_zero_index_for_thread);
+ // This should be rare enough that we can afford to save all the
+ // scratch registers that the calling context might be using.
+ __ mov(G1_scratch, L3);
+ __ mov(G3_scratch, L5);
+ // We need the value of O3 above (for the write into the buffer), so we
+ // save and restore it.
+ __ mov(O3, L6);
+ // Since the call will overwrite O7, we save and restore that, as well.
+ __ mov(O7, L4);
+
+ __ call_VM_leaf(L7_thread_cache, handle_zero, G2_thread);
+ __ mov(L3, G1_scratch);
+ __ mov(L5, G3_scratch);
+ __ mov(L6, O3);
+ __ br(Assembler::always, /*annul*/false, Assembler::pt, restart);
+ __ delayed()->mov(L4, O7);
+
+ dirty_card_log_enqueue = start;
+ dirty_card_log_enqueue_end = __ pc();
+ // XXX Should have a guarantee here about not going off the end!
+ // Does it already do so? Do an experiment...
+
+#undef __
+
+}
+
+static inline void
+generate_dirty_card_log_enqueue_if_necessary(jbyte* byte_map_base) {
+ if (dirty_card_log_enqueue == 0) {
+ generate_dirty_card_log_enqueue(byte_map_base);
+ assert(dirty_card_log_enqueue != 0, "postcondition.");
+ if (G1SATBPrintStubs) {
+ tty->print_cr("Generated dirty_card enqueue:");
+ Disassembler::decode((u_char*)dirty_card_log_enqueue,
+ dirty_card_log_enqueue_end,
+ tty);
+ }
+ }
+}
+
+
+void MacroAssembler::g1_write_barrier_post(Register store_addr, Register new_val, Register tmp) {
+
+ Label filtered;
+ MacroAssembler* post_filter_masm = this;
+
+ if (new_val == G0) return;
+
+ G1SATBCardTableModRefBS* bs = (G1SATBCardTableModRefBS*) Universe::heap()->barrier_set();
+ assert(bs->kind() == BarrierSet::G1SATBCT ||
+ bs->kind() == BarrierSet::G1SATBCTLogging, "wrong barrier");
+
+ if (G1RSBarrierRegionFilter) {
+ xor3(store_addr, new_val, tmp);
+#ifdef _LP64
+ srlx(tmp, HeapRegion::LogOfHRGrainBytes, tmp);
+#else
+ srl(tmp, HeapRegion::LogOfHRGrainBytes, tmp);
+#endif
+
+ // XXX Should I predict this taken or not? Does it matter?
+ cmp_and_brx_short(tmp, G0, Assembler::equal, Assembler::pt, filtered);
+ }
+
+ // If the "store_addr" register is an "in" or "local" register, move it to
+ // a scratch reg so we can pass it as an argument.
+ bool use_scr = !(store_addr->is_global() || store_addr->is_out());
+ // Pick a scratch register different from "tmp".
+ Register scr = (tmp == G1_scratch ? G3_scratch : G1_scratch);
+ // Make sure we use up the delay slot!
+ if (use_scr) {
+ post_filter_masm->mov(store_addr, scr);
+ } else {
+ post_filter_masm->nop();
+ }
+ generate_dirty_card_log_enqueue_if_necessary(bs->byte_map_base);
+ save_frame(0);
+ call(dirty_card_log_enqueue);
+ if (use_scr) {
+ delayed()->mov(scr, O0);
+ } else {
+ delayed()->mov(store_addr->after_save(), O0);
+ }
+ restore();
+
+ bind(filtered);
+}
+
+#endif // SERIALGC
+///////////////////////////////////////////////////////////////////////////////////
+
+void MacroAssembler::card_write_barrier_post(Register store_addr, Register new_val, Register tmp) {
+ // If we're writing constant NULL, we can skip the write barrier.
+ if (new_val == G0) return;
+ CardTableModRefBS* bs = (CardTableModRefBS*) Universe::heap()->barrier_set();
+ assert(bs->kind() == BarrierSet::CardTableModRef ||
+ bs->kind() == BarrierSet::CardTableExtension, "wrong barrier");
+ card_table_write(bs->byte_map_base, tmp, store_addr);
+}
+
+void MacroAssembler::load_klass(Register src_oop, Register klass) {
+ // The number of bytes in this code is used by
+ // MachCallDynamicJavaNode::ret_addr_offset()
+ // if this changes, change that.
+ if (UseCompressedKlassPointers) {
+ lduw(src_oop, oopDesc::klass_offset_in_bytes(), klass);
+ decode_klass_not_null(klass);
+ } else {
+ ld_ptr(src_oop, oopDesc::klass_offset_in_bytes(), klass);
+ }
+}
+
+void MacroAssembler::store_klass(Register klass, Register dst_oop) {
+ if (UseCompressedKlassPointers) {
+ assert(dst_oop != klass, "not enough registers");
+ encode_klass_not_null(klass);
+ st(klass, dst_oop, oopDesc::klass_offset_in_bytes());
+ } else {
+ st_ptr(klass, dst_oop, oopDesc::klass_offset_in_bytes());
+ }
+}
+
+void MacroAssembler::store_klass_gap(Register s, Register d) {
+ if (UseCompressedKlassPointers) {
+ assert(s != d, "not enough registers");
+ st(s, d, oopDesc::klass_gap_offset_in_bytes());
+ }
+}
+
+void MacroAssembler::load_heap_oop(const Address& s, Register d) {
+ if (UseCompressedOops) {
+ lduw(s, d);
+ decode_heap_oop(d);
+ } else {
+ ld_ptr(s, d);
+ }
+}
+
+void MacroAssembler::load_heap_oop(Register s1, Register s2, Register d) {
+ if (UseCompressedOops) {
+ lduw(s1, s2, d);
+ decode_heap_oop(d, d);
+ } else {
+ ld_ptr(s1, s2, d);
+ }
+}
+
+void MacroAssembler::load_heap_oop(Register s1, int simm13a, Register d) {
+ if (UseCompressedOops) {
+ lduw(s1, simm13a, d);
+ decode_heap_oop(d, d);
+ } else {
+ ld_ptr(s1, simm13a, d);
+ }
+}
+
+void MacroAssembler::load_heap_oop(Register s1, RegisterOrConstant s2, Register d) {
+ if (s2.is_constant()) load_heap_oop(s1, s2.as_constant(), d);
+ else load_heap_oop(s1, s2.as_register(), d);
+}
+
+void MacroAssembler::store_heap_oop(Register d, Register s1, Register s2) {
+ if (UseCompressedOops) {
+ assert(s1 != d && s2 != d, "not enough registers");
+ encode_heap_oop(d);
+ st(d, s1, s2);
+ } else {
+ st_ptr(d, s1, s2);
+ }
+}
+
+void MacroAssembler::store_heap_oop(Register d, Register s1, int simm13a) {
+ if (UseCompressedOops) {
+ assert(s1 != d, "not enough registers");
+ encode_heap_oop(d);
+ st(d, s1, simm13a);
+ } else {
+ st_ptr(d, s1, simm13a);
+ }
+}
+
+void MacroAssembler::store_heap_oop(Register d, const Address& a, int offset) {
+ if (UseCompressedOops) {
+ assert(a.base() != d, "not enough registers");
+ encode_heap_oop(d);
+ st(d, a, offset);
+ } else {
+ st_ptr(d, a, offset);
+ }
+}
+
+
+void MacroAssembler::encode_heap_oop(Register src, Register dst) {
+ assert (UseCompressedOops, "must be compressed");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+ verify_oop(src);
+ if (Universe::narrow_oop_base() == NULL) {
+ srlx(src, LogMinObjAlignmentInBytes, dst);
+ return;
+ }
+ Label done;
+ if (src == dst) {
+ // optimize for frequent case src == dst
+ bpr(rc_nz, true, Assembler::pt, src, done);
+ delayed() -> sub(src, G6_heapbase, dst); // annuled if not taken
+ bind(done);
+ srlx(src, LogMinObjAlignmentInBytes, dst);
+ } else {
+ bpr(rc_z, false, Assembler::pn, src, done);
+ delayed() -> mov(G0, dst);
+ // could be moved before branch, and annulate delay,
+ // but may add some unneeded work decoding null
+ sub(src, G6_heapbase, dst);
+ srlx(dst, LogMinObjAlignmentInBytes, dst);
+ bind(done);
+ }
+}
+
+
+void MacroAssembler::encode_heap_oop_not_null(Register r) {
+ assert (UseCompressedOops, "must be compressed");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+ verify_oop(r);
+ if (Universe::narrow_oop_base() != NULL)
+ sub(r, G6_heapbase, r);
+ srlx(r, LogMinObjAlignmentInBytes, r);
+}
+
+void MacroAssembler::encode_heap_oop_not_null(Register src, Register dst) {
+ assert (UseCompressedOops, "must be compressed");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+ verify_oop(src);
+ if (Universe::narrow_oop_base() == NULL) {
+ srlx(src, LogMinObjAlignmentInBytes, dst);
+ } else {
+ sub(src, G6_heapbase, dst);
+ srlx(dst, LogMinObjAlignmentInBytes, dst);
+ }
+}
+
+// Same algorithm as oops.inline.hpp decode_heap_oop.
+void MacroAssembler::decode_heap_oop(Register src, Register dst) {
+ assert (UseCompressedOops, "must be compressed");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+ sllx(src, LogMinObjAlignmentInBytes, dst);
+ if (Universe::narrow_oop_base() != NULL) {
+ Label done;
+ bpr(rc_nz, true, Assembler::pt, dst, done);
+ delayed() -> add(dst, G6_heapbase, dst); // annuled if not taken
+ bind(done);
+ }
+ verify_oop(dst);
+}
+
+void MacroAssembler::decode_heap_oop_not_null(Register r) {
+ // Do not add assert code to this unless you change vtableStubs_sparc.cpp
+ // pd_code_size_limit.
+ // Also do not verify_oop as this is called by verify_oop.
+ assert (UseCompressedOops, "must be compressed");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+ sllx(r, LogMinObjAlignmentInBytes, r);
+ if (Universe::narrow_oop_base() != NULL)
+ add(r, G6_heapbase, r);
+}
+
+void MacroAssembler::decode_heap_oop_not_null(Register src, Register dst) {
+ // Do not add assert code to this unless you change vtableStubs_sparc.cpp
+ // pd_code_size_limit.
+ // Also do not verify_oop as this is called by verify_oop.
+ assert (UseCompressedOops, "must be compressed");
+ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+ sllx(src, LogMinObjAlignmentInBytes, dst);
+ if (Universe::narrow_oop_base() != NULL)
+ add(dst, G6_heapbase, dst);
+}
+
+void MacroAssembler::encode_klass_not_null(Register r) {
+ assert(Metaspace::is_initialized(), "metaspace should be initialized");
+ assert (UseCompressedKlassPointers, "must be compressed");
+ assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
+ if (Universe::narrow_klass_base() != NULL)
+ sub(r, G6_heapbase, r);
+ srlx(r, LogKlassAlignmentInBytes, r);
+}
+
+void MacroAssembler::encode_klass_not_null(Register src, Register dst) {
+ assert(Metaspace::is_initialized(), "metaspace should be initialized");
+ assert (UseCompressedKlassPointers, "must be compressed");
+ assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
+ if (Universe::narrow_klass_base() == NULL) {
+ srlx(src, LogKlassAlignmentInBytes, dst);
+ } else {
+ sub(src, G6_heapbase, dst);
+ srlx(dst, LogKlassAlignmentInBytes, dst);
+ }
+}
+
+void MacroAssembler::decode_klass_not_null(Register r) {
+ assert(Metaspace::is_initialized(), "metaspace should be initialized");
+ // Do not add assert code to this unless you change vtableStubs_sparc.cpp
+ // pd_code_size_limit.
+ assert (UseCompressedKlassPointers, "must be compressed");
+ assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
+ sllx(r, LogKlassAlignmentInBytes, r);
+ if (Universe::narrow_klass_base() != NULL)
+ add(r, G6_heapbase, r);
+}
+
+void MacroAssembler::decode_klass_not_null(Register src, Register dst) {
+ assert(Metaspace::is_initialized(), "metaspace should be initialized");
+ // Do not add assert code to this unless you change vtableStubs_sparc.cpp
+ // pd_code_size_limit.
+ assert (UseCompressedKlassPointers, "must be compressed");
+ assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
+ sllx(src, LogKlassAlignmentInBytes, dst);
+ if (Universe::narrow_klass_base() != NULL)
+ add(dst, G6_heapbase, dst);
+}
+
+void MacroAssembler::reinit_heapbase() {
+ if (UseCompressedOops || UseCompressedKlassPointers) {
+ AddressLiteral base(Universe::narrow_ptrs_base_addr());
+ load_ptr_contents(base, G6_heapbase);
+ }
+}
+
+// Compare char[] arrays aligned to 4 bytes.
+void MacroAssembler::char_arrays_equals(Register ary1, Register ary2,
+ Register limit, Register result,
+ Register chr1, Register chr2, Label& Ldone) {
+ Label Lvector, Lloop;
+ assert(chr1 == result, "should be the same");
+
+ // Note: limit contains number of bytes (2*char_elements) != 0.
+ andcc(limit, 0x2, chr1); // trailing character ?
+ br(Assembler::zero, false, Assembler::pt, Lvector);
+ delayed()->nop();
+
+ // compare the trailing char
+ sub(limit, sizeof(jchar), limit);
+ lduh(ary1, limit, chr1);
+ lduh(ary2, limit, chr2);
+ cmp(chr1, chr2);
+ br(Assembler::notEqual, true, Assembler::pt, Ldone);
+ delayed()->mov(G0, result); // not equal
+
+ // only one char ?
+ cmp_zero_and_br(zero, limit, Ldone, true, Assembler::pn);
+ delayed()->add(G0, 1, result); // zero-length arrays are equal
+
+ // word by word compare, dont't need alignment check
+ bind(Lvector);
+ // Shift ary1 and ary2 to the end of the arrays, negate limit
+ add(ary1, limit, ary1);
+ add(ary2, limit, ary2);
+ neg(limit, limit);
+
+ lduw(ary1, limit, chr1);
+ bind(Lloop);
+ lduw(ary2, limit, chr2);
+ cmp(chr1, chr2);
+ br(Assembler::notEqual, true, Assembler::pt, Ldone);
+ delayed()->mov(G0, result); // not equal
+ inccc(limit, 2*sizeof(jchar));
+ // annul LDUW if branch is not taken to prevent access past end of array
+ br(Assembler::notZero, true, Assembler::pt, Lloop);
+ delayed()->lduw(ary1, limit, chr1); // hoisted
+
+ // Caller should set it:
+ // add(G0, 1, result); // equals
+}
+
+// Use BIS for zeroing (count is in bytes).
+void MacroAssembler::bis_zeroing(Register to, Register count, Register temp, Label& Ldone) {
+ assert(UseBlockZeroing && VM_Version::has_block_zeroing(), "only works with BIS zeroing");
+ Register end = count;
+ int cache_line_size = VM_Version::prefetch_data_size();
+ // Minimum count when BIS zeroing can be used since
+ // it needs membar which is expensive.
+ int block_zero_size = MAX2(cache_line_size*3, (int)BlockZeroingLowLimit);
+
+ Label small_loop;
+ // Check if count is negative (dead code) or zero.
+ // Note, count uses 64bit in 64 bit VM.
+ cmp_and_brx_short(count, 0, Assembler::lessEqual, Assembler::pn, Ldone);
+
+ // Use BIS zeroing only for big arrays since it requires membar.
+ if (Assembler::is_simm13(block_zero_size)) { // < 4096
+ cmp(count, block_zero_size);
+ } else {
+ set(block_zero_size, temp);
+ cmp(count, temp);
+ }
+ br(Assembler::lessUnsigned, false, Assembler::pt, small_loop);
+ delayed()->add(to, count, end);
+
+ // Note: size is >= three (32 bytes) cache lines.
+
+ // Clean the beginning of space up to next cache line.
+ for (int offs = 0; offs < cache_line_size; offs += 8) {
+ stx(G0, to, offs);
+ }
+
+ // align to next cache line
+ add(to, cache_line_size, to);
+ and3(to, -cache_line_size, to);
+
+ // Note: size left >= two (32 bytes) cache lines.
+
+ // BIS should not be used to zero tail (64 bytes)
+ // to avoid zeroing a header of the following object.
+ sub(end, (cache_line_size*2)-8, end);
+
+ Label bis_loop;
+ bind(bis_loop);
+ stxa(G0, to, G0, Assembler::ASI_ST_BLKINIT_PRIMARY);
+ add(to, cache_line_size, to);
+ cmp_and_brx_short(to, end, Assembler::lessUnsigned, Assembler::pt, bis_loop);
+
+ // BIS needs membar.
+ membar(Assembler::StoreLoad);
+
+ add(end, (cache_line_size*2)-8, end); // restore end
+ cmp_and_brx_short(to, end, Assembler::greaterEqualUnsigned, Assembler::pn, Ldone);
+
+ // Clean the tail.
+ bind(small_loop);
+ stx(G0, to, 0);
+ add(to, 8, to);
+ cmp_and_brx_short(to, end, Assembler::lessUnsigned, Assembler::pt, small_loop);
+ nop(); // Separate short branches
+}
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/macroAssembler_sparc.hpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cpu/sparc/vm/macroAssembler_sparc.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -0,0 +1,1500 @@
+/*
+ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_SPARC_VM_MACROASSEMBLER_SPARC_HPP
+#define CPU_SPARC_VM_MACROASSEMBLER_SPARC_HPP
+
+#include "asm/assembler.hpp"
+
+// promises that the system will not use traps 16-31
+#define ST_RESERVED_FOR_USER_0 0x10
+
+class BiasedLockingCounters;
+
+
+// Register aliases for parts of the system:
+
+// 64 bit values can be kept in g1-g5, o1-o5 and o7 and all 64 bits are safe
+// across context switches in V8+ ABI. Of course, there are no 64 bit regs
+// in V8 ABI. All 64 bits are preserved in V9 ABI for all registers.
+
+// g2-g4 are scratch registers called "application globals". Their
+// meaning is reserved to the "compilation system"--which means us!
+// They are are not supposed to be touched by ordinary C code, although
+// highly-optimized C code might steal them for temps. They are safe
+// across thread switches, and the ABI requires that they be safe
+// across function calls.
+//
+// g1 and g3 are touched by more modules. V8 allows g1 to be clobbered
+// across func calls, and V8+ also allows g5 to be clobbered across
+// func calls. Also, g1 and g5 can get touched while doing shared
+// library loading.
+//
+// We must not touch g7 (it is the thread-self register) and g6 is
+// reserved for certain tools. g0, of course, is always zero.
+//
+// (Sources: SunSoft Compilers Group, thread library engineers.)
+
+// %%%% The interpreter should be revisited to reduce global scratch regs.
+
+// This global always holds the current JavaThread pointer:
+
+REGISTER_DECLARATION(Register, G2_thread , G2);
+REGISTER_DECLARATION(Register, G6_heapbase , G6);
+
+// The following globals are part of the Java calling convention:
+
+REGISTER_DECLARATION(Register, G5_method , G5);
+REGISTER_DECLARATION(Register, G5_megamorphic_method , G5_method);
+REGISTER_DECLARATION(Register, G5_inline_cache_reg , G5_method);
+
+// The following globals are used for the new C1 & interpreter calling convention:
+REGISTER_DECLARATION(Register, Gargs , G4); // pointing to the last argument
+
+// This local is used to preserve G2_thread in the interpreter and in stubs:
+REGISTER_DECLARATION(Register, L7_thread_cache , L7);
+
+// These globals are used as scratch registers in the interpreter:
+
+REGISTER_DECLARATION(Register, Gframe_size , G1); // SAME REG as G1_scratch
+REGISTER_DECLARATION(Register, G1_scratch , G1); // also SAME
+REGISTER_DECLARATION(Register, G3_scratch , G3);
+REGISTER_DECLARATION(Register, G4_scratch , G4);
+
+// These globals are used as short-lived scratch registers in the compiler:
+
+REGISTER_DECLARATION(Register, Gtemp , G5);
+
+// JSR 292 fixed register usages:
+REGISTER_DECLARATION(Register, G5_method_type , G5);
+REGISTER_DECLARATION(Register, G3_method_handle , G3);
+REGISTER_DECLARATION(Register, L7_mh_SP_save , L7);
+
+// The compiler requires that G5_megamorphic_method is G5_inline_cache_klass,
+// because a single patchable "set" instruction (NativeMovConstReg,
+// or NativeMovConstPatching for compiler1) instruction
+// serves to set up either quantity, depending on whether the compiled
+// call site is an inline cache or is megamorphic. See the function
+// CompiledIC::set_to_megamorphic.
+//
+// If a inline cache targets an interpreted method, then the
+// G5 register will be used twice during the call. First,
+// the call site will be patched to load a compiledICHolder
+// into G5. (This is an ordered pair of ic_klass, method.)
+// The c2i adapter will first check the ic_klass, then load
+// G5_method with the method part of the pair just before
+// jumping into the interpreter.
+//
+// Note that G5_method is only the method-self for the interpreter,
+// and is logically unrelated to G5_megamorphic_method.
+//
+// Invariants on G2_thread (the JavaThread pointer):
+// - it should not be used for any other purpose anywhere
+// - it must be re-initialized by StubRoutines::call_stub()
+// - it must be preserved around every use of call_VM
+
+// We can consider using g2/g3/g4 to cache more values than the
+// JavaThread, such as the card-marking base or perhaps pointers into
+// Eden. It's something of a waste to use them as scratch temporaries,
+// since they are not supposed to be volatile. (Of course, if we find
+// that Java doesn't benefit from application globals, then we can just
+// use them as ordinary temporaries.)
+//
+// Since g1 and g5 (and/or g6) are the volatile (caller-save) registers,
+// it makes sense to use them routinely for procedure linkage,
+// whenever the On registers are not applicable. Examples: G5_method,
+// G5_inline_cache_klass, and a double handful of miscellaneous compiler
+// stubs. This means that compiler stubs, etc., should be kept to a
+// maximum of two or three G-register arguments.
+
+
+// stub frames
+
+REGISTER_DECLARATION(Register, Lentry_args , L0); // pointer to args passed to callee (interpreter) not stub itself
+
+// Interpreter frames
+
+#ifdef CC_INTERP
+REGISTER_DECLARATION(Register, Lstate , L0); // interpreter state object pointer
+REGISTER_DECLARATION(Register, L1_scratch , L1); // scratch
+REGISTER_DECLARATION(Register, Lmirror , L1); // mirror (for native methods only)
+REGISTER_DECLARATION(Register, L2_scratch , L2);
+REGISTER_DECLARATION(Register, L3_scratch , L3);
+REGISTER_DECLARATION(Register, L4_scratch , L4);
+REGISTER_DECLARATION(Register, Lscratch , L5); // C1 uses
+REGISTER_DECLARATION(Register, Lscratch2 , L6); // C1 uses
+REGISTER_DECLARATION(Register, L7_scratch , L7); // constant pool cache
+REGISTER_DECLARATION(Register, O5_savedSP , O5);
+REGISTER_DECLARATION(Register, I5_savedSP , I5); // Saved SP before bumping for locals. This is simply
+ // a copy SP, so in 64-bit it's a biased value. The bias
+ // is added and removed as needed in the frame code.
+// Interface to signature handler
+REGISTER_DECLARATION(Register, Llocals , L7); // pointer to locals for signature handler
+REGISTER_DECLARATION(Register, Lmethod , L6); // Method* when calling signature handler
+
+#else
+REGISTER_DECLARATION(Register, Lesp , L0); // expression stack pointer
+REGISTER_DECLARATION(Register, Lbcp , L1); // pointer to next bytecode
+REGISTER_DECLARATION(Register, Lmethod , L2);
+REGISTER_DECLARATION(Register, Llocals , L3);
+REGISTER_DECLARATION(Register, Largs , L3); // pointer to locals for signature handler
+ // must match Llocals in asm interpreter
+REGISTER_DECLARATION(Register, Lmonitors , L4);
+REGISTER_DECLARATION(Register, Lbyte_code , L5);
+// When calling out from the interpreter we record SP so that we can remove any extra stack
+// space allocated during adapter transitions. This register is only live from the point
+// of the call until we return.
+REGISTER_DECLARATION(Register, Llast_SP , L5);
+REGISTER_DECLARATION(Register, Lscratch , L5);
+REGISTER_DECLARATION(Register, Lscratch2 , L6);
+REGISTER_DECLARATION(Register, LcpoolCache , L6); // constant pool cache
+
+REGISTER_DECLARATION(Register, O5_savedSP , O5);
+REGISTER_DECLARATION(Register, I5_savedSP , I5); // Saved SP before bumping for locals. This is simply
+ // a copy SP, so in 64-bit it's a biased value. The bias
+ // is added and removed as needed in the frame code.
+REGISTER_DECLARATION(Register, IdispatchTables , I4); // Base address of the bytecode dispatch tables
+REGISTER_DECLARATION(Register, IdispatchAddress , I3); // Register which saves the dispatch address for each bytecode
+REGISTER_DECLARATION(Register, ImethodDataPtr , I2); // Pointer to the current method data
+#endif /* CC_INTERP */
+
+// NOTE: Lscratch2 and LcpoolCache point to the same registers in
+// the interpreter code. If Lscratch2 needs to be used for some
+// purpose than LcpoolCache should be restore after that for
+// the interpreter to work right
+// (These assignments must be compatible with L7_thread_cache; see above.)
+
+// Since Lbcp points into the middle of the method object,
+// it is temporarily converted into a "bcx" during GC.
+
+// Exception processing
+// These registers are passed into exception handlers.
+// All exception handlers require the exception object being thrown.
+// In addition, an nmethod's exception handler must be passed
+// the address of the call site within the nmethod, to allow
+// proper selection of the applicable catch block.
+// (Interpreter frames use their own bcp() for this purpose.)
+//
+// The Oissuing_pc value is not always needed. When jumping to a
+// handler that is known to be interpreted, the Oissuing_pc value can be
+// omitted. An actual catch block in compiled code receives (from its
+// nmethod's exception handler) the thrown exception in the Oexception,
+// but it doesn't need the Oissuing_pc.
+//
+// If an exception handler (either interpreted or compiled)
+// discovers there is no applicable catch block, it updates
+// the Oissuing_pc to the continuation PC of its own caller,
+// pops back to that caller's stack frame, and executes that
+// caller's exception handler. Obviously, this process will
+// iterate until the control stack is popped back to a method
+// containing an applicable catch block. A key invariant is
+// that the Oissuing_pc value is always a value local to
+// the method whose exception handler is currently executing.
+//
+// Note: The issuing PC value is __not__ a raw return address (I7 value).
+// It is a "return pc", the address __following__ the call.
+// Raw return addresses are converted to issuing PCs by frame::pc(),
+// or by stubs. Issuing PCs can be used directly with PC range tables.
+//
+REGISTER_DECLARATION(Register, Oexception , O0); // exception being thrown
+REGISTER_DECLARATION(Register, Oissuing_pc , O1); // where the exception is coming from
+
+
+// These must occur after the declarations above
+#ifndef DONT_USE_REGISTER_DEFINES
+
+#define Gthread AS_REGISTER(Register, Gthread)
+#define Gmethod AS_REGISTER(Register, Gmethod)
+#define Gmegamorphic_method AS_REGISTER(Register, Gmegamorphic_method)
+#define Ginline_cache_reg AS_REGISTER(Register, Ginline_cache_reg)
+#define Gargs AS_REGISTER(Register, Gargs)
+#define Lthread_cache AS_REGISTER(Register, Lthread_cache)
+#define Gframe_size AS_REGISTER(Register, Gframe_size)
+#define Gtemp AS_REGISTER(Register, Gtemp)
+
+#ifdef CC_INTERP
+#define Lstate AS_REGISTER(Register, Lstate)
+#define Lesp AS_REGISTER(Register, Lesp)
+#define L1_scratch AS_REGISTER(Register, L1_scratch)
+#define Lmirror AS_REGISTER(Register, Lmirror)
+#define L2_scratch AS_REGISTER(Register, L2_scratch)
+#define L3_scratch AS_REGISTER(Register, L3_scratch)
+#define L4_scratch AS_REGISTER(Register, L4_scratch)
+#define Lscratch AS_REGISTER(Register, Lscratch)
+#define Lscratch2 AS_REGISTER(Register, Lscratch2)
+#define L7_scratch AS_REGISTER(Register, L7_scratch)
+#define Ostate AS_REGISTER(Register, Ostate)
+#else
+#define Lesp AS_REGISTER(Register, Lesp)
+#define Lbcp AS_REGISTER(Register, Lbcp)
+#define Lmethod AS_REGISTER(Register, Lmethod)
+#define Llocals AS_REGISTER(Register, Llocals)
+#define Lmonitors AS_REGISTER(Register, Lmonitors)
+#define Lbyte_code AS_REGISTER(Register, Lbyte_code)
+#define Lscratch AS_REGISTER(Register, Lscratch)
+#define Lscratch2 AS_REGISTER(Register, Lscratch2)
+#define LcpoolCache AS_REGISTER(Register, LcpoolCache)
+#endif /* ! CC_INTERP */
+
+#define Lentry_args AS_REGISTER(Register, Lentry_args)
+#define I5_savedSP AS_REGISTER(Register, I5_savedSP)
+#define O5_savedSP AS_REGISTER(Register, O5_savedSP)
+#define IdispatchAddress AS_REGISTER(Register, IdispatchAddress)
+#define ImethodDataPtr AS_REGISTER(Register, ImethodDataPtr)
+#define IdispatchTables AS_REGISTER(Register, IdispatchTables)
+
+#define Oexception AS_REGISTER(Register, Oexception)
+#define Oissuing_pc AS_REGISTER(Register, Oissuing_pc)
+
+#endif
+
+
+// Address is an abstraction used to represent a memory location.
+//
+// Note: A register location is represented via a Register, not
+// via an address for efficiency & simplicity reasons.
+
+class Address VALUE_OBJ_CLASS_SPEC {
+ private:
+ Register _base; // Base register.
+ RegisterOrConstant _index_or_disp; // Index register or constant displacement.
+ RelocationHolder _rspec;
+
+ public:
+ Address() : _base(noreg), _index_or_disp(noreg) {}
+
+ Address(Register base, RegisterOrConstant index_or_disp)
+ : _base(base),
+ _index_or_disp(index_or_disp) {
+ }
+
+ Address(Register base, Register index)
+ : _base(base),
+ _index_or_disp(index) {
+ }
+
+ Address(Register base, int disp)
+ : _base(base),
+ _index_or_disp(disp) {
+ }
+
+#ifdef ASSERT
+ // ByteSize is only a class when ASSERT is defined, otherwise it's an int.
+ Address(Register base, ByteSize disp)
+ : _base(base),
+ _index_or_disp(in_bytes(disp)) {
+ }
+#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(); }
+
+ 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; }
+
+ RelocationHolder rspec(int offset) const {
+ return offset == 0 ? _rspec : _rspec.plus(offset);
+ }
+
+ inline bool is_simm13(int offset = 0); // check disp+offset for overflow
+
+ Address plus_disp(int plusdisp) const { // bump disp by a small amount
+ assert(_index_or_disp.is_constant(), "must have a displacement");
+ 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);
+ a._base = a._base->after_save();
+ return a;
+ }
+
+ Address after_restore() const {
+ Address a = (*this);
+ a._base = a._base->after_restore();
+ return a;
+ }
+
+ // Convert the raw encoding form into the form expected by the
+ // constructor for Address.
+ static Address make_raw(int base, int index, int scale, int disp, relocInfo::relocType disp_reloc);
+
+ friend class Assembler;
+};
+
+
+class AddressLiteral VALUE_OBJ_CLASS_SPEC {
+ private:
+ address _address;
+ RelocationHolder _rspec;
+
+ RelocationHolder rspec_from_rtype(relocInfo::relocType rtype, address addr) {
+ switch (rtype) {
+ case relocInfo::external_word_type:
+ return external_word_Relocation::spec(addr);
+ case relocInfo::internal_word_type:
+ return internal_word_Relocation::spec(addr);
+#ifdef _LP64
+ case relocInfo::opt_virtual_call_type:
+ return opt_virtual_call_Relocation::spec();
+ case relocInfo::static_call_type:
+ return static_call_Relocation::spec();
+ case relocInfo::runtime_call_type:
+ return runtime_call_Relocation::spec();
+#endif
+ case relocInfo::none:
+ return RelocationHolder();
+ default:
+ ShouldNotReachHere();
+ return RelocationHolder();
+ }
+ }
+
+ protected:
+ // creation
+ AddressLiteral() : _address(NULL), _rspec(NULL) {}
+
+ public:
+ AddressLiteral(address addr, RelocationHolder const& rspec)
+ : _address(addr),
+ _rspec(rspec) {}
+
+ // Some constructors to avoid casting at the call site.
+ AddressLiteral(jobject obj, RelocationHolder const& rspec)
+ : _address((address) obj),
+ _rspec(rspec) {}
+
+ AddressLiteral(intptr_t value, RelocationHolder const& rspec)
+ : _address((address) value),
+ _rspec(rspec) {}
+
+ AddressLiteral(address addr, relocInfo::relocType rtype = relocInfo::none)
+ : _address((address) addr),
+ _rspec(rspec_from_rtype(rtype, (address) addr)) {}
+
+ // Some constructors to avoid casting at the call site.
+ AddressLiteral(address* addr, relocInfo::relocType rtype = relocInfo::none)
+ : _address((address) addr),
+ _rspec(rspec_from_rtype(rtype, (address) addr)) {}
+
+ AddressLiteral(bool* addr, relocInfo::relocType rtype = relocInfo::none)
+ : _address((address) addr),
+ _rspec(rspec_from_rtype(rtype, (address) addr)) {}
+
+ AddressLiteral(const bool* addr, relocInfo::relocType rtype = relocInfo::none)
+ : _address((address) addr),
+ _rspec(rspec_from_rtype(rtype, (address) addr)) {}
+
+ AddressLiteral(signed char* addr, relocInfo::relocType rtype = relocInfo::none)
+ : _address((address) addr),
+ _rspec(rspec_from_rtype(rtype, (address) addr)) {}
+
+ AddressLiteral(int* addr, relocInfo::relocType rtype = relocInfo::none)
+ : _address((address) addr),
+ _rspec(rspec_from_rtype(rtype, (address) addr)) {}
+
+ AddressLiteral(intptr_t addr, relocInfo::relocType rtype = relocInfo::none)
+ : _address((address) addr),
+ _rspec(rspec_from_rtype(rtype, (address) addr)) {}
+
+#ifdef _LP64
+ // 32-bit complains about a multiple declaration for int*.
+ AddressLiteral(intptr_t* addr, relocInfo::relocType rtype = relocInfo::none)
+ : _address((address) addr),
+ _rspec(rspec_from_rtype(rtype, (address) addr)) {}
+#endif
+
+ AddressLiteral(Metadata* addr, relocInfo::relocType rtype = relocInfo::none)
+ : _address((address) addr),
+ _rspec(rspec_from_rtype(rtype, (address) addr)) {}
+
+ AddressLiteral(Metadata** 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)) {}
+
+ AddressLiteral(double* addr, relocInfo::relocType rtype = relocInfo::none)
+ : _address((address) addr),
+ _rspec(rspec_from_rtype(rtype, (address) addr)) {}
+
+ intptr_t value() const { return (intptr_t) _address; }
+ int low10() const;
+
+ const relocInfo::relocType rtype() const { return _rspec.type(); }
+ const RelocationHolder& rspec() const { return _rspec; }
+
+ RelocationHolder rspec(int offset) const {
+ return offset == 0 ? _rspec : _rspec.plus(offset);
+ }
+};
+
+// 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(Metadata** 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));
+}
+
+
+
+// Argument is an abstraction used to represent an outgoing
+// actual argument or an incoming formal parameter, whether
+// it resides in memory or in a register, in a manner consistent
+// with the SPARC Application Binary Interface, or ABI. This is
+// often referred to as the native or C calling convention.
+
+class Argument VALUE_OBJ_CLASS_SPEC {
+ private:
+ int _number;
+ bool _is_in;
+
+ public:
+#ifdef _LP64
+ enum {
+ n_register_parameters = 6, // only 6 registers may contain integer parameters
+ n_float_register_parameters = 16 // Can have up to 16 floating registers
+ };
+#else
+ enum {
+ n_register_parameters = 6 // only 6 registers may contain integer parameters
+ };
+#endif
+
+ // creation
+ Argument(int number, bool is_in) : _number(number), _is_in(is_in) {}
+
+ int number() const { return _number; }
+ bool is_in() const { return _is_in; }
+ bool is_out() const { return !is_in(); }
+
+ Argument successor() const { return Argument(number() + 1, is_in()); }
+ Argument as_in() const { return Argument(number(), true ); }
+ Argument as_out() const { return Argument(number(), false); }
+
+ // locating register-based arguments:
+ bool is_register() const { return _number < n_register_parameters; }
+
+#ifdef _LP64
+ // locating Floating Point register-based arguments:
+ bool is_float_register() const { return _number < n_float_register_parameters; }
+
+ FloatRegister as_float_register() const {
+ assert(is_float_register(), "must be a register argument");
+ return as_FloatRegister(( number() *2 ) + 1);
+ }
+ FloatRegister as_double_register() const {
+ assert(is_float_register(), "must be a register argument");
+ return as_FloatRegister(( number() *2 ));
+ }
+#endif
+
+ Register as_register() const {
+ assert(is_register(), "must be a register argument");
+ return is_in() ? as_iRegister(number()) : as_oRegister(number());
+ }
+
+ // locating memory-based arguments
+ Address as_address() const {
+ assert(!is_register(), "must be a memory argument");
+ return address_in_frame();
+ }
+
+ // When applied to a register-based argument, give the corresponding address
+ // into the 6-word area "into which callee may store register arguments"
+ // (This is a different place than the corresponding register-save area location.)
+ Address address_in_frame() const;
+
+ // debugging
+ const char* name() const;
+
+ friend class Assembler;
+};
+
+
+class RegistersForDebugging : public StackObj {
+ public:
+ intptr_t i[8], l[8], o[8], g[8];
+ float f[32];
+ double d[32];
+
+ void print(outputStream* s);
+
+ static int i_offset(int j) { return offset_of(RegistersForDebugging, i[j]); }
+ static int l_offset(int j) { return offset_of(RegistersForDebugging, l[j]); }
+ static int o_offset(int j) { return offset_of(RegistersForDebugging, o[j]); }
+ static int g_offset(int j) { return offset_of(RegistersForDebugging, g[j]); }
+ static int f_offset(int j) { return offset_of(RegistersForDebugging, f[j]); }
+ static int d_offset(int j) { return offset_of(RegistersForDebugging, d[j / 2]); }
+
+ // gen asm code to save regs
+ static void save_registers(MacroAssembler* a);
+
+ // restore global registers in case C code disturbed them
+ static void restore_registers(MacroAssembler* a, Register r);
+};
+
+
+// MacroAssembler extends Assembler by a few frequently used macros.
+//
+// Most of the standard SPARC synthetic ops are defined here.
+// Instructions for which a 'better' code sequence exists depending
+// on arguments should also go in here.
+
+#define JMP2(r1, r2) jmp(r1, r2, __FILE__, __LINE__)
+#define JMP(r1, off) jmp(r1, off, __FILE__, __LINE__)
+#define JUMP(a, temp, off) jump(a, temp, off, __FILE__, __LINE__)
+#define JUMPL(a, temp, d, off) jumpl(a, temp, d, off, __FILE__, __LINE__)
+
+
+class MacroAssembler : public Assembler {
+ // code patchers need various routines like inv_wdisp()
+ friend class NativeInstruction;
+ friend class NativeGeneralJump;
+ friend class Relocation;
+ friend class Label;
+
+ protected:
+ static int patched_branch(int dest_pos, int inst, int inst_pos);
+ static int branch_destination(int inst, int pos);
+
+ // Support for VM calls
+ // This is the base routine called by the different versions of call_VM_leaf. The interpreter
+ // may customize this version by overriding it for its purposes (e.g., to save/restore
+ // additional registers when doing a VM call).
+#ifdef CC_INTERP
+ #define VIRTUAL
+#else
+ #define VIRTUAL virtual
+#endif
+
+ VIRTUAL void call_VM_leaf_base(Register thread_cache, address entry_point, int number_of_arguments);
+
+ //
+ // It is imperative that all calls into the VM are handled via the call_VM macros.
+ // They make sure that the stack linkage is setup correctly. call_VM's correspond
+ // to ENTRY/ENTRY_X entry points while call_VM_leaf's correspond to LEAF entry points.
+ //
+ // This is the base routine called by the different versions of call_VM. The interpreter
+ // may customize this version by overriding it for its purposes (e.g., to save/restore
+ // additional registers when doing a VM call).
+ //
+ // A non-volatile java_thread_cache register should be specified so
+ // that the G2_thread value can be preserved across the call.
+ // (If java_thread_cache is noreg, then a slow get_thread call
+ // will re-initialize the G2_thread.) call_VM_base returns the register that contains the
+ // thread.
+ //
+ // If no last_java_sp is specified (noreg) than SP will be used instead.
+
+ virtual void call_VM_base(
+ Register oop_result, // where an oop-result ends up if any; use noreg otherwise
+ Register java_thread_cache, // the thread if computed before ; use noreg otherwise
+ Register last_java_sp, // to set up last_Java_frame in stubs; use noreg otherwise
+ address entry_point, // the entry point
+ int number_of_arguments, // the number of arguments (w/o thread) to pop after call
+ bool check_exception=true // flag which indicates if exception should be checked
+ );
+
+ // This routine should emit JVMTI PopFrame and ForceEarlyReturn handling code.
+ // The implementation is only non-empty for the InterpreterMacroAssembler,
+ // as only the interpreter handles and ForceEarlyReturn PopFrame requests.
+ virtual void check_and_handle_popframe(Register scratch_reg);
+ virtual void check_and_handle_earlyret(Register scratch_reg);
+
+ public:
+ MacroAssembler(CodeBuffer* code) : Assembler(code) {}
+
+ // Support for NULL-checks
+ //
+ // Generates code that causes a NULL OS exception if the content of reg is NULL.
+ // If the accessed location is M[reg + offset] and the offset is known, provide the
+ // offset. No explicit code generation is needed if the offset is within a certain
+ // range (0 <= offset <= page_size).
+ //
+ // %%%%%% Currently not done for SPARC
+
+ void null_check(Register reg, int offset = -1);
+ static bool needs_explicit_null_check(intptr_t offset);
+
+ // support for delayed instructions
+ MacroAssembler* delayed() { Assembler::delayed(); return this; }
+
+ // branches that use right instruction for v8 vs. v9
+ inline void br( Condition c, bool a, Predict p, address d, relocInfo::relocType rt = relocInfo::none );
+ inline void br( Condition c, bool a, Predict p, Label& L );
+
+ inline void fb( Condition c, bool a, Predict p, address d, relocInfo::relocType rt = relocInfo::none );
+ inline void fb( Condition c, bool a, Predict p, Label& L );
+
+ // compares register with zero (32 bit) and branches (V9 and V8 instructions)
+ void cmp_zero_and_br( Condition c, Register s1, Label& L, bool a = false, Predict p = pn );
+ // Compares a pointer register with zero and branches on (not)null.
+ // Does a test & branch on 32-bit systems and a register-branch on 64-bit.
+ void br_null ( Register s1, bool a, Predict p, Label& L );
+ void br_notnull( Register s1, bool a, Predict p, Label& L );
+
+ //
+ // Compare registers and branch with nop in delay slot or cbcond without delay slot.
+ //
+ // ATTENTION: use these instructions with caution because cbcond instruction
+ // has very short distance: 512 instructions (2Kbyte).
+
+ // Compare integer (32 bit) values (icc only).
+ void cmp_and_br_short(Register s1, Register s2, Condition c, Predict p, Label& L);
+ void cmp_and_br_short(Register s1, int simm13a, Condition c, Predict p, Label& L);
+ // Platform depending version for pointer compare (icc on !LP64 and xcc on LP64).
+ void cmp_and_brx_short(Register s1, Register s2, Condition c, Predict p, Label& L);
+ void cmp_and_brx_short(Register s1, int simm13a, Condition c, Predict p, Label& L);
+
+ // Short branch version for compares a pointer pwith zero.
+ void br_null_short ( Register s1, Predict p, Label& L );
+ void br_notnull_short( Register s1, Predict p, Label& L );
+
+ // unconditional short branch
+ void ba_short(Label& L);
+
+ inline void bp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt = relocInfo::none );
+ inline void bp( Condition c, bool a, CC cc, Predict p, Label& L );
+
+ // Branch that tests xcc in LP64 and icc in !LP64
+ inline void brx( Condition c, bool a, Predict p, address d, relocInfo::relocType rt = relocInfo::none );
+ inline void brx( Condition c, bool a, Predict p, Label& L );
+
+ // unconditional branch
+ inline void ba( Label& L );
+
+ // Branch that tests fp condition codes
+ inline void fbp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt = relocInfo::none );
+ inline void fbp( Condition c, bool a, CC cc, Predict p, Label& L );
+
+ // get PC the best way
+ inline int get_pc( Register d );
+
+ // Sparc shorthands(pp 85, V8 manual, pp 289 V9 manual)
+ inline void cmp( Register s1, Register s2 ) { subcc( s1, s2, G0 ); }
+ inline void cmp( Register s1, int simm13a ) { subcc( s1, simm13a, G0 ); }
+
+ inline void jmp( Register s1, Register s2 );
+ inline void jmp( Register s1, int simm13a, RelocationHolder const& rspec = RelocationHolder() );
+
+ // Check if the call target is out of wdisp30 range (relative to the code cache)
+ static inline bool is_far_target(address d);
+ inline void call( address d, relocInfo::relocType rt = relocInfo::runtime_call_type );
+ inline void call( Label& L, relocInfo::relocType rt = relocInfo::runtime_call_type );
+ inline void callr( Register s1, Register s2 );
+ inline void callr( Register s1, int simm13a, RelocationHolder const& rspec = RelocationHolder() );
+
+ // Emits nothing on V8
+ inline void iprefetch( address d, relocInfo::relocType rt = relocInfo::none );
+ inline void iprefetch( Label& L);
+
+ inline void tst( Register s ) { orcc( G0, s, G0 ); }
+
+#ifdef PRODUCT
+ inline void ret( bool trace = TraceJumps ) { if (trace) {
+ mov(I7, O7); // traceable register
+ JMP(O7, 2 * BytesPerInstWord);
+ } else {
+ jmpl( I7, 2 * BytesPerInstWord, G0 );
+ }
+ }
+
+ inline void retl( bool trace = TraceJumps ) { if (trace) JMP(O7, 2 * BytesPerInstWord);
+ else jmpl( O7, 2 * BytesPerInstWord, G0 ); }
+#else
+ void ret( bool trace = TraceJumps );
+ void retl( bool trace = TraceJumps );
+#endif /* PRODUCT */
+
+ // Required platform-specific helpers for Label::patch_instructions.
+ // They _shadow_ the declarations in AbstractAssembler, which are undefined.
+ void pd_patch_instruction(address branch, address target);
+
+ // sethi Macro handles optimizations and relocations
+private:
+ void internal_sethi(const AddressLiteral& addrlit, Register d, bool ForceRelocatable);
+public:
+ void sethi(const AddressLiteral& addrlit, Register d);
+ void patchable_sethi(const AddressLiteral& addrlit, Register d);
+
+ // compute the number of instructions for a sethi/set
+ static int insts_for_sethi( address a, bool worst_case = false );
+ static int worst_case_insts_for_set();
+
+ // set may be either setsw or setuw (high 32 bits may be zero or sign)
+private:
+ void internal_set(const AddressLiteral& al, Register d, bool ForceRelocatable);
+ static int insts_for_internal_set(intptr_t value);
+public:
+ void set(const AddressLiteral& addrlit, Register d);
+ void set(intptr_t value, Register d);
+ void set(address addr, Register d, RelocationHolder const& rspec);
+ static int insts_for_set(intptr_t value) { return insts_for_internal_set(value); }
+
+ void patchable_set(const AddressLiteral& addrlit, Register d);
+ void patchable_set(intptr_t value, Register d);
+ void set64(jlong value, Register d, Register tmp);
+ static int insts_for_set64(jlong value);
+
+ // sign-extend 32 to 64
+ inline void signx( Register s, Register d ) { sra( s, G0, d); }
+ inline void signx( Register d ) { sra( d, G0, d); }
+
+ inline void not1( Register s, Register d ) { xnor( s, G0, d ); }
+ inline void not1( Register d ) { xnor( d, G0, d ); }
+
+ inline void neg( Register s, Register d ) { sub( G0, s, d ); }
+ inline void neg( Register d ) { sub( G0, d, d ); }
+
+ inline void cas( Register s1, Register s2, Register d) { casa( s1, s2, d, ASI_PRIMARY); }
+ inline void casx( Register s1, Register s2, Register d) { casxa(s1, s2, d, ASI_PRIMARY); }
+ // Functions for isolating 64 bit atomic swaps for LP64
+ // cas_ptr will perform cas for 32 bit VM's and casx for 64 bit VM's
+ inline void cas_ptr( Register s1, Register s2, Register d) {
+#ifdef _LP64
+ casx( s1, s2, d );
+#else
+ cas( s1, s2, d );
+#endif
+ }
+
+ // Functions for isolating 64 bit shifts for LP64
+ inline void sll_ptr( Register s1, Register s2, Register d );
+ inline void sll_ptr( Register s1, int imm6a, Register d );
+ inline void sll_ptr( Register s1, RegisterOrConstant s2, Register d );
+ inline void srl_ptr( Register s1, Register s2, Register d );
+ inline void srl_ptr( Register s1, int imm6a, Register d );
+
+ // little-endian
+ inline void casl( Register s1, Register s2, Register d) { casa( s1, s2, d, ASI_PRIMARY_LITTLE); }
+ inline void casxl( Register s1, Register s2, Register d) { casxa(s1, s2, d, ASI_PRIMARY_LITTLE); }
+
+ inline void inc( Register d, int const13 = 1 ) { add( d, const13, d); }
+ inline void inccc( Register d, int const13 = 1 ) { addcc( d, const13, d); }
+
+ inline void dec( Register d, int const13 = 1 ) { sub( d, const13, d); }
+ inline void deccc( Register d, int const13 = 1 ) { subcc( d, const13, d); }
+
+ using Assembler::add;
+ inline void add(Register s1, int simm13a, Register d, relocInfo::relocType rtype);
+ inline void add(Register s1, int simm13a, Register d, RelocationHolder const& rspec);
+ inline void add(Register s1, RegisterOrConstant s2, Register d, int offset = 0);
+ inline void add(const Address& a, Register d, int offset = 0);
+
+ using Assembler::andn;
+ inline void andn( Register s1, RegisterOrConstant s2, Register d);
+
+ inline void btst( Register s1, Register s2 ) { andcc( s1, s2, G0 ); }
+ inline void btst( int simm13a, Register s ) { andcc( s, simm13a, G0 ); }
+
+ inline void bset( Register s1, Register s2 ) { or3( s1, s2, s2 ); }
+ inline void bset( int simm13a, Register s ) { or3( s, simm13a, s ); }
+
+ inline void bclr( Register s1, Register s2 ) { andn( s1, s2, s2 ); }
+ inline void bclr( int simm13a, Register s ) { andn( s, simm13a, s ); }
+
+ inline void btog( Register s1, Register s2 ) { xor3( s1, s2, s2 ); }
+ inline void btog( int simm13a, Register s ) { xor3( s, simm13a, s ); }
+
+ inline void clr( Register d ) { or3( G0, G0, d ); }
+
+ inline void clrb( Register s1, Register s2);
+ inline void clrh( Register s1, Register s2);
+ inline void clr( Register s1, Register s2);
+ inline void clrx( Register s1, Register s2);
+
+ inline void clrb( Register s1, int simm13a);
+ inline void clrh( Register s1, int simm13a);
+ inline void clr( Register s1, int simm13a);
+ inline void clrx( Register s1, int simm13a);
+
+ // copy & clear upper word
+ inline void clruw( Register s, Register d ) { srl( s, G0, d); }
+ // clear upper word
+ inline void clruwu( Register d ) { srl( d, G0, d); }
+
+ using Assembler::ldsb;
+ using Assembler::ldsh;
+ using Assembler::ldsw;
+ using Assembler::ldub;
+ using Assembler::lduh;
+ using Assembler::lduw;
+ using Assembler::ldx;
+ using Assembler::ldd;
+
+#ifdef ASSERT
+ // ByteSize is only a class when ASSERT is defined, otherwise it's an int.
+ inline void ld(Register s1, ByteSize simm13a, Register d);
+#endif
+
+ inline void ld(Register s1, Register s2, Register d);
+ inline void ld(Register s1, int simm13a, Register d);
+
+ inline void ldsb(const Address& a, Register d, int offset = 0);
+ inline void ldsh(const Address& a, Register d, int offset = 0);
+ inline void ldsw(const Address& a, Register d, int offset = 0);
+ inline void ldub(const Address& a, Register d, int offset = 0);
+ inline void lduh(const Address& a, Register d, int offset = 0);
+ inline void lduw(const Address& a, Register d, int offset = 0);
+ inline void ldx( const Address& a, Register d, int offset = 0);
+ inline void ld( const Address& a, Register d, int offset = 0);
+ inline void ldd( const Address& a, Register d, int offset = 0);
+
+ inline void ldub(Register s1, RegisterOrConstant s2, Register d );
+ inline void ldsb(Register s1, RegisterOrConstant s2, Register d );
+ inline void lduh(Register s1, RegisterOrConstant s2, Register d );
+ inline void ldsh(Register s1, RegisterOrConstant s2, Register d );
+ inline void lduw(Register s1, RegisterOrConstant s2, Register d );
+ inline void ldsw(Register s1, RegisterOrConstant s2, Register d );
+ inline void ldx( Register s1, RegisterOrConstant s2, Register d );
+ inline void ld( Register s1, RegisterOrConstant s2, Register d );
+ inline void ldd( Register s1, RegisterOrConstant s2, Register d );
+
+ using Assembler::ldf;
+ inline void ldf(FloatRegisterImpl::Width w, Register s1, RegisterOrConstant s2, FloatRegister d);
+ inline void ldf(FloatRegisterImpl::Width w, const Address& a, FloatRegister d, int offset = 0);
+
+ // membar psuedo instruction. takes into account target memory model.
+ inline void membar( Assembler::Membar_mask_bits const7a );
+
+ // returns if membar generates anything.
+ inline bool membar_has_effect( Assembler::Membar_mask_bits const7a );
+
+ // mov pseudo instructions
+ inline void mov( Register s, Register d) {
+ if ( s != d ) or3( G0, s, d);
+ else assert_not_delayed(); // Put something useful in the delay slot!
+ }
+
+ inline void mov_or_nop( Register s, Register d) {
+ if ( s != d ) or3( G0, s, d);
+ else nop();
+ }
+
+ inline void mov( int simm13a, Register d) { or3( G0, simm13a, d); }
+
+ using Assembler::prefetch;
+ inline void prefetch(const Address& a, PrefetchFcn F, int offset = 0);
+
+ using Assembler::stb;
+ using Assembler::sth;
+ using Assembler::stw;
+ using Assembler::stx;
+ using Assembler::std;
+
+#ifdef ASSERT
+ // ByteSize is only a class when ASSERT is defined, otherwise it's an int.
+ inline void st(Register d, Register s1, ByteSize simm13a);
+#endif
+
+ inline void st(Register d, Register s1, Register s2);
+ inline void st(Register d, Register s1, int simm13a);
+
+ inline void stb(Register d, const Address& a, int offset = 0 );
+ inline void sth(Register d, const Address& a, int offset = 0 );
+ inline void stw(Register d, const Address& a, int offset = 0 );
+ inline void stx(Register d, const Address& a, int offset = 0 );
+ inline void st( Register d, const Address& a, int offset = 0 );
+ inline void std(Register d, const Address& a, int offset = 0 );
+
+ inline void stb(Register d, Register s1, RegisterOrConstant s2 );
+ inline void sth(Register d, Register s1, RegisterOrConstant s2 );
+ inline void stw(Register d, Register s1, RegisterOrConstant s2 );
+ inline void stx(Register d, Register s1, RegisterOrConstant s2 );
+ inline void std(Register d, Register s1, RegisterOrConstant s2 );
+ inline void st( Register d, Register s1, RegisterOrConstant s2 );
+
+ using Assembler::stf;
+ inline void stf(FloatRegisterImpl::Width w, FloatRegister d, Register s1, RegisterOrConstant s2);
+ inline void stf(FloatRegisterImpl::Width w, FloatRegister d, const Address& a, int offset = 0);
+
+ // Note: offset is added to s2.
+ using Assembler::sub;
+ inline void sub(Register s1, RegisterOrConstant s2, Register d, int offset = 0);
+
+ using Assembler::swap;
+ inline void swap(Address& a, Register d, int offset = 0);
+
+ // address pseudos: make these names unlike instruction names to avoid confusion
+ inline intptr_t load_pc_address( Register reg, int bytes_to_skip );
+ inline void load_contents(const AddressLiteral& addrlit, Register d, int offset = 0);
+ inline void load_bool_contents(const AddressLiteral& addrlit, Register d, int offset = 0);
+ inline void load_ptr_contents(const AddressLiteral& addrlit, Register d, int offset = 0);
+ inline void store_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset = 0);
+ inline void store_ptr_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset = 0);
+ inline void jumpl_to(const AddressLiteral& addrlit, Register temp, Register d, int offset = 0);
+ inline void jump_to(const AddressLiteral& addrlit, Register temp, int offset = 0);
+ inline void jump_indirect_to(Address& a, Register temp, int ld_offset = 0, int jmp_offset = 0);
+
+ // ring buffer traceable jumps
+
+ void jmp2( Register r1, Register r2, const char* file, int line );
+ void jmp ( Register r1, int offset, const char* file, int line );
+
+ void jumpl(const AddressLiteral& addrlit, Register temp, Register d, int offset, const char* file, int line);
+ void jump (const AddressLiteral& addrlit, Register temp, int offset, const char* file, int line);
+
+
+ // argument pseudos:
+
+ inline void load_argument( Argument& a, Register d );
+ inline void store_argument( Register s, Argument& a );
+ inline void store_ptr_argument( Register s, Argument& a );
+ inline void store_float_argument( FloatRegister s, Argument& a );
+ inline void store_double_argument( FloatRegister s, Argument& a );
+ inline void store_long_argument( Register s, Argument& a );
+
+ // handy macros:
+
+ inline void round_to( Register r, int modulus ) {
+ assert_not_delayed();
+ inc( r, modulus - 1 );
+ and3( r, -modulus, r );
+ }
+
+ // --------------------------------------------------
+
+ // Functions for isolating 64 bit loads for LP64
+ // ld_ptr will perform ld for 32 bit VM's and ldx for 64 bit VM's
+ // st_ptr will perform st for 32 bit VM's and stx for 64 bit VM's
+ inline void ld_ptr(Register s1, Register s2, Register d);
+ inline void ld_ptr(Register s1, int simm13a, Register d);
+ inline void ld_ptr(Register s1, RegisterOrConstant s2, Register d);
+ inline void ld_ptr(const Address& a, Register d, int offset = 0);
+ inline void st_ptr(Register d, Register s1, Register s2);
+ inline void st_ptr(Register d, Register s1, int simm13a);
+ inline void st_ptr(Register d, Register s1, RegisterOrConstant s2);
+ inline void st_ptr(Register d, const Address& a, int offset = 0);
+
+#ifdef ASSERT
+ // ByteSize is only a class when ASSERT is defined, otherwise it's an int.
+ inline void ld_ptr(Register s1, ByteSize simm13a, Register d);
+ inline void st_ptr(Register d, Register s1, ByteSize simm13a);
+#endif
+
+ // ld_long will perform ldd for 32 bit VM's and ldx for 64 bit VM's
+ // st_long will perform std for 32 bit VM's and stx for 64 bit VM's
+ inline void ld_long(Register s1, Register s2, Register d);
+ inline void ld_long(Register s1, int simm13a, Register d);
+ inline void ld_long(Register s1, RegisterOrConstant s2, Register d);
+ inline void ld_long(const Address& a, Register d, int offset = 0);
+ inline void st_long(Register d, Register s1, Register s2);
+ inline void st_long(Register d, Register s1, int simm13a);
+ inline void st_long(Register d, Register s1, RegisterOrConstant s2);
+ inline void st_long(Register d, const Address& a, int offset = 0);
+
+ // Helpers for address formation.
+ // - They emit only a move if s2 is a constant zero.
+ // - If dest is a constant and either s1 or s2 is a register, the temp argument is required and becomes the result.
+ // - If dest is a register and either s1 or s2 is a non-simm13 constant, the temp argument is required and used to materialize the constant.
+ RegisterOrConstant regcon_andn_ptr(RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp = noreg);
+ RegisterOrConstant regcon_inc_ptr( RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp = noreg);
+ RegisterOrConstant regcon_sll_ptr( RegisterOrConstant s1, RegisterOrConstant s2, RegisterOrConstant d, Register temp = noreg);
+
+ RegisterOrConstant ensure_simm13_or_reg(RegisterOrConstant src, Register temp) {
+ if (is_simm13(src.constant_or_zero()))
+ return src; // register or short constant
+ guarantee(temp != noreg, "constant offset overflow");
+ set(src.as_constant(), temp);
+ return temp;
+ }
+
+ // --------------------------------------------------
+
+ public:
+ // traps as per trap.h (SPARC ABI?)
+
+ void breakpoint_trap();
+ void breakpoint_trap(Condition c, CC cc);
+ void flush_windows_trap();
+ void clean_windows_trap();
+ void get_psr_trap();
+ void set_psr_trap();
+
+ // V8/V9 flush_windows
+ void flush_windows();
+
+ // Support for serializing memory accesses between threads
+ void serialize_memory(Register thread, Register tmp1, Register tmp2);
+
+ // Stack frame creation/removal
+ void enter();
+ void leave();
+
+ // V8/V9 integer multiply
+ void mult(Register s1, Register s2, Register d);
+ void mult(Register s1, int simm13a, Register d);
+
+ // V8/V9 read and write of condition codes.
+ void read_ccr(Register d);
+ void write_ccr(Register s);
+
+ // Manipulation of C++ bools
+ // These are idioms to flag the need for care with accessing bools but on
+ // this platform we assume byte size
+
+ inline void stbool(Register d, const Address& a) { stb(d, a); }
+ inline void ldbool(const Address& a, Register d) { ldub(a, d); }
+ inline void movbool( bool boolconst, Register d) { mov( (int) boolconst, d); }
+
+ // klass oop manipulations if compressed
+ void load_klass(Register src_oop, Register klass);
+ void store_klass(Register klass, Register dst_oop);
+ void store_klass_gap(Register s, Register dst_oop);
+
+ // oop manipulations
+ void load_heap_oop(const Address& s, Register d);
+ void load_heap_oop(Register s1, Register s2, Register d);
+ void load_heap_oop(Register s1, int simm13a, Register d);
+ void load_heap_oop(Register s1, RegisterOrConstant s2, Register d);
+ void store_heap_oop(Register d, Register s1, Register s2);
+ void store_heap_oop(Register d, Register s1, int simm13a);
+ void store_heap_oop(Register d, const Address& a, int offset = 0);
+
+ void encode_heap_oop(Register src, Register dst);
+ void encode_heap_oop(Register r) {
+ encode_heap_oop(r, r);
+ }
+ void decode_heap_oop(Register src, Register dst);
+ void decode_heap_oop(Register r) {
+ decode_heap_oop(r, r);
+ }
+ void encode_heap_oop_not_null(Register r);
+ void decode_heap_oop_not_null(Register r);
+ void encode_heap_oop_not_null(Register src, Register dst);
+ void decode_heap_oop_not_null(Register src, Register dst);
+
+ void encode_klass_not_null(Register r);
+ void decode_klass_not_null(Register r);
+ void encode_klass_not_null(Register src, Register dst);
+ void decode_klass_not_null(Register src, Register dst);
+
+ // Support for managing the JavaThread pointer (i.e.; the reference to
+ // thread-local information).
+ void get_thread(); // load G2_thread
+ void verify_thread(); // verify G2_thread contents
+ void save_thread (const Register threache); // save to cache
+ void restore_thread(const Register thread_cache); // restore from cache
+
+ // Support for last Java frame (but use call_VM instead where possible)
+ void set_last_Java_frame(Register last_java_sp, Register last_Java_pc);
+ void reset_last_Java_frame(void);
+
+ // Call into the VM.
+ // Passes the thread pointer (in O0) as a prepended argument.
+ // Makes sure oop return values are visible to the GC.
+ void call_VM(Register oop_result, address entry_point, int number_of_arguments = 0, bool check_exceptions = true);
+ void call_VM(Register oop_result, address entry_point, Register arg_1, bool check_exceptions = true);
+ void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true);
+ void call_VM(Register oop_result, address entry_point, Register arg_1, Register arg_2, Register arg_3, bool check_exceptions = true);
+
+ // these overloadings are not presently used on SPARC:
+ void call_VM(Register oop_result, Register last_java_sp, address entry_point, int number_of_arguments = 0, bool check_exceptions = true);
+ void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, bool check_exceptions = true);
+ void call_VM(Register oop_result, Register last_java_sp, address entry_point, Register arg_1, Register arg_2, bool check_exceptions = true);
+ void 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 call_VM_leaf(Register thread_cache, address entry_point, int number_of_arguments = 0);
+ void call_VM_leaf(Register thread_cache, address entry_point, Register arg_1);
+ void call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2);
+ void call_VM_leaf(Register thread_cache, address entry_point, Register arg_1, Register arg_2, Register arg_3);
+
+ void get_vm_result (Register oop_result);
+ void get_vm_result_2(Register metadata_result);
+
+ // vm result is currently getting hijacked to for oop preservation
+ void set_vm_result(Register oop_result);
+
+ // Emit the CompiledIC call idiom
+ void ic_call(address entry, bool emit_delay = true);
+
+ // if call_VM_base was called with check_exceptions=false, then call
+ // check_and_forward_exception to handle exceptions when it is safe
+ void check_and_forward_exception(Register scratch_reg);
+
+ private:
+ // For V8
+ void read_ccr_trap(Register ccr_save);
+ void write_ccr_trap(Register ccr_save1, Register scratch1, Register scratch2);
+
+#ifdef ASSERT
+ // For V8 debugging. Uses V8 instruction sequence and checks
+ // result with V9 insturctions rdccr and wrccr.
+ // Uses Gscatch and Gscatch2
+ void read_ccr_v8_assert(Register ccr_save);
+ void write_ccr_v8_assert(Register ccr_save);
+#endif // ASSERT
+
+ public:
+
+ // Write to card table for - register is destroyed afterwards.
+ void card_table_write(jbyte* byte_map_base, Register tmp, Register obj);
+
+ void card_write_barrier_post(Register store_addr, Register new_val, Register tmp);
+
+#ifndef SERIALGC
+ // General G1 pre-barrier generator.
+ void g1_write_barrier_pre(Register obj, Register index, int offset, Register pre_val, Register tmp, bool preserve_o_regs);
+
+ // General G1 post-barrier generator
+ void g1_write_barrier_post(Register store_addr, Register new_val, Register tmp);
+#endif // SERIALGC
+
+ // pushes double TOS element of FPU stack on CPU stack; pops from FPU stack
+ void push_fTOS();
+
+ // pops double TOS element from CPU stack and pushes on FPU stack
+ void pop_fTOS();
+
+ void empty_FPU_stack();
+
+ void push_IU_state();
+ void pop_IU_state();
+
+ void push_FPU_state();
+ void pop_FPU_state();
+
+ void push_CPU_state();
+ void pop_CPU_state();
+
+ // if heap base register is used - reinit it with the correct value
+ void reinit_heapbase();
+
+ // Debugging
+ void _verify_oop(Register reg, const char * msg, const char * file, int line);
+ void _verify_oop_addr(Address addr, const char * msg, const char * file, int line);
+
+ // TODO: verify_method and klass metadata (compare against vptr?)
+ void _verify_method_ptr(Register reg, const char * msg, const char * file, int line) {}
+ void _verify_klass_ptr(Register reg, const char * msg, const char * file, int line){}
+
+#define verify_oop(reg) _verify_oop(reg, "broken oop " #reg, __FILE__, __LINE__)
+#define verify_oop_addr(addr) _verify_oop_addr(addr, "broken oop addr ", __FILE__, __LINE__)
+#define verify_method_ptr(reg) _verify_method_ptr(reg, "broken method " #reg, __FILE__, __LINE__)
+#define verify_klass_ptr(reg) _verify_klass_ptr(reg, "broken klass " #reg, __FILE__, __LINE__)
+
+ // only if +VerifyOops
+ void verify_FPU(int stack_depth, const char* s = "illegal FPU state");
+ // only if +VerifyFPU
+ void stop(const char* msg); // prints msg, dumps registers and stops execution
+ void warn(const char* msg); // prints msg, but don't stop
+ void untested(const char* what = "");
+ void unimplemented(const char* what = "") { char* b = new char[1024]; jio_snprintf(b, 1024, "unimplemented: %s", what); stop(b); }
+ void should_not_reach_here() { stop("should not reach here"); }
+ void print_CPU_state();
+
+ // oops in code
+ AddressLiteral allocate_oop_address(jobject obj); // allocate_index
+ AddressLiteral constant_oop_address(jobject obj); // find_index
+ inline void set_oop (jobject obj, Register d); // uses allocate_oop_address
+ inline void set_oop_constant (jobject obj, Register d); // uses constant_oop_address
+ inline void set_oop (const AddressLiteral& obj_addr, Register d); // same as load_address
+
+ // metadata in code that we have to keep track of
+ AddressLiteral allocate_metadata_address(Metadata* obj); // allocate_index
+ AddressLiteral constant_metadata_address(Metadata* obj); // find_index
+ inline void set_metadata (Metadata* obj, Register d); // uses allocate_metadata_address
+ inline void set_metadata_constant (Metadata* obj, Register d); // uses constant_metadata_address
+ inline void set_metadata (const AddressLiteral& obj_addr, Register d); // same as load_address
+
+ void set_narrow_oop( jobject obj, Register d );
+ void set_narrow_klass( Klass* k, Register d );
+
+ // nop padding
+ void align(int modulus);
+
+ // declare a safepoint
+ void safepoint();
+
+ // factor out part of stop into subroutine to save space
+ void stop_subroutine();
+ // factor out part of verify_oop into subroutine to save space
+ void verify_oop_subroutine();
+
+ // side-door communication with signalHandler in os_solaris.cpp
+ static address _verify_oop_implicit_branch[3];
+
+ int total_frame_size_in_bytes(int extraWords);
+
+ // used when extraWords known statically
+ 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
+ void save_frame_and_mov(int extraWords, Register s1, Register d1, Register s2 = Register(), Register d2 = Register());
+
+ // give no. (outgoing) params, calc # of words will need on frame
+ void calc_mem_param_words(Register Rparam_words, Register Rresult);
+
+ // used to calculate frame size dynamically
+ // result is in bytes and must be negated for save inst
+ void calc_frame_size(Register extraWords, Register resultReg);
+
+ // calc and also save
+ void calc_frame_size_and_save(Register extraWords, Register resultReg);
+
+ static void debug(char* msg, RegistersForDebugging* outWindow);
+
+ // implementations of bytecodes used by both interpreter and compiler
+
+ void lcmp( Register Ra_hi, Register Ra_low,
+ Register Rb_hi, Register Rb_low,
+ Register Rresult);
+
+ void lneg( Register Rhi, Register Rlow );
+
+ void lshl( Register Rin_high, Register Rin_low, Register Rcount,
+ Register Rout_high, Register Rout_low, Register Rtemp );
+
+ void lshr( Register Rin_high, Register Rin_low, Register Rcount,
+ Register Rout_high, Register Rout_low, Register Rtemp );
+
+ void lushr( Register Rin_high, Register Rin_low, Register Rcount,
+ Register Rout_high, Register Rout_low, Register Rtemp );
+
+#ifdef _LP64
+ void lcmp( Register Ra, Register Rb, Register Rresult);
+#endif
+
+ // Load and store values by size and signed-ness
+ void load_sized_value( Address src, Register dst, size_t size_in_bytes, bool is_signed);
+ void store_sized_value(Register src, Address dst, size_t size_in_bytes);
+
+ void float_cmp( bool is_float, int unordered_result,
+ FloatRegister Fa, FloatRegister Fb,
+ Register Rresult);
+
+ void fneg( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d);
+ void fneg( FloatRegisterImpl::Width w, FloatRegister sd ) { Assembler::fneg(w, sd); }
+ void fmov( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d);
+ void fabs( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d);
+
+ void save_all_globals_into_locals();
+ void restore_globals_from_locals();
+
+ void casx_under_lock(Register top_ptr_reg, Register top_reg, Register ptr_reg,
+ address lock_addr=0, bool use_call_vm=false);
+ void cas_under_lock(Register top_ptr_reg, Register top_reg, Register ptr_reg,
+ address lock_addr=0, bool use_call_vm=false);
+ void casn (Register addr_reg, Register cmp_reg, Register set_reg) ;
+
+ // These set the icc condition code to equal if the lock succeeded
+ // and notEqual if it failed and requires a slow case
+ void compiler_lock_object(Register Roop, Register Rmark, Register Rbox,
+ Register Rscratch,
+ BiasedLockingCounters* counters = NULL,
+ bool try_bias = UseBiasedLocking);
+ void compiler_unlock_object(Register Roop, Register Rmark, Register Rbox,
+ Register Rscratch,
+ bool try_bias = UseBiasedLocking);
+
+ // Biased locking support
+ // Upon entry, lock_reg must point to the lock record on the stack,
+ // obj_reg must contain the target object, and mark_reg must contain
+ // the target object's header.
+ // Destroys mark_reg if an attempt is made to bias an anonymously
+ // biased lock. In this case a failure will go either to the slow
+ // case or fall through with the notEqual condition code set with
+ // the expectation that the slow case in the runtime will be called.
+ // In the fall-through case where the CAS-based lock is done,
+ // mark_reg is not destroyed.
+ void biased_locking_enter(Register obj_reg, Register mark_reg, Register temp_reg,
+ Label& done, Label* slow_case = NULL,
+ BiasedLockingCounters* counters = NULL);
+ // Upon entry, the base register of mark_addr must contain the oop.
+ // Destroys temp_reg.
+
+ // If allow_delay_slot_filling is set to true, the next instruction
+ // emitted after this one will go in an annulled delay slot if the
+ // biased locking exit case failed.
+ void biased_locking_exit(Address mark_addr, Register temp_reg, Label& done, bool allow_delay_slot_filling = false);
+
+ // allocation
+ void eden_allocate(
+ Register obj, // result: pointer to object after successful allocation
+ Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
+ int con_size_in_bytes, // object size in bytes if known at compile time
+ Register t1, // temp register
+ Register t2, // temp register
+ Label& slow_case // continuation point if fast allocation fails
+ );
+ void tlab_allocate(
+ Register obj, // result: pointer to object after successful allocation
+ Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
+ int con_size_in_bytes, // object size in bytes if known at compile time
+ Register t1, // temp register
+ Label& slow_case // continuation point if fast allocation fails
+ );
+ void tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case);
+ void incr_allocated_bytes(RegisterOrConstant size_in_bytes,
+ Register t1, Register t2);
+
+ // interface method calling
+ void lookup_interface_method(Register recv_klass,
+ Register intf_klass,
+ RegisterOrConstant itable_index,
+ Register method_result,
+ Register temp_reg, Register temp2_reg,
+ Label& no_such_interface);
+
+ // virtual method calling
+ void lookup_virtual_method(Register recv_klass,
+ RegisterOrConstant vtable_index,
+ Register method_result);
+
+ // Test sub_klass against super_klass, with fast and slow paths.
+
+ // The fast path produces a tri-state answer: yes / no / maybe-slow.
+ // One of the three labels can be NULL, meaning take the fall-through.
+ // If super_check_offset is -1, the value is loaded up from super_klass.
+ // No registers are killed, except temp_reg and temp2_reg.
+ // If super_check_offset is not -1, temp2_reg is not used and can be noreg.
+ void check_klass_subtype_fast_path(Register sub_klass,
+ Register super_klass,
+ Register temp_reg,
+ Register temp2_reg,
+ Label* L_success,
+ Label* L_failure,
+ Label* L_slow_path,
+ RegisterOrConstant super_check_offset = RegisterOrConstant(-1));
+
+ // The rest of the type check; must be wired to a corresponding fast path.
+ // It does not repeat the fast path logic, so don't use it standalone.
+ // The temp_reg can be noreg, if no temps are available.
+ // It can also be sub_klass or super_klass, meaning it's OK to kill that one.
+ // Updates the sub's secondary super cache as necessary.
+ void check_klass_subtype_slow_path(Register sub_klass,
+ Register super_klass,
+ Register temp_reg,
+ Register temp2_reg,
+ Register temp3_reg,
+ Register temp4_reg,
+ Label* L_success,
+ Label* L_failure);
+
+ // Simplified, combined version, good for typical uses.
+ // Falls through on failure.
+ void check_klass_subtype(Register sub_klass,
+ Register super_klass,
+ Register temp_reg,
+ Register temp2_reg,
+ Label& L_success);
+
+ // method handles (JSR 292)
+ // 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 = noreg,
+ int extra_slot_offset = 0);
+
+ // Stack overflow checking
+
+ // Note: this clobbers G3_scratch
+ void bang_stack_with_offset(int offset) {
+ // stack grows down, caller passes positive offset
+ assert(offset > 0, "must bang with negative offset");
+ set((-offset)+STACK_BIAS, G3_scratch);
+ st(G0, SP, G3_scratch);
+ }
+
+ // Writes to stack successive pages until offset reached to check for
+ // stack overflow + shadow pages. Clobbers tsp and scratch registers.
+ void bang_stack_size(Register Rsize, Register Rtsp, Register Rscratch);
+
+ virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr, Register tmp, int offset);
+
+ void verify_tlab();
+
+ Condition negate_condition(Condition cond);
+
+ // Helper functions for statistics gathering.
+ // Conditionally (non-atomically) increments passed counter address, preserving condition codes.
+ void cond_inc(Condition cond, address counter_addr, Register Rtemp1, Register Rtemp2);
+ // Unconditional increment.
+ void inc_counter(address counter_addr, Register Rtmp1, Register Rtmp2);
+ void inc_counter(int* counter_addr, Register Rtmp1, Register Rtmp2);
+
+ // Compare char[] arrays aligned to 4 bytes.
+ void char_arrays_equals(Register ary1, Register ary2,
+ Register limit, Register result,
+ Register chr1, Register chr2, Label& Ldone);
+ // Use BIS for zeroing
+ void bis_zeroing(Register to, Register count, Register temp, Label& Ldone);
+
+#undef VIRTUAL
+};
+
+/**
+ * class SkipIfEqual:
+ *
+ * Instantiating this class will result in assembly code being output that will
+ * jump around any code emitted between the creation of the instance and it's
+ * automatic destruction at the end of a scope block, depending on the value of
+ * the flag passed to the constructor, which will be checked at run-time.
+ */
+class SkipIfEqual : public StackObj {
+ private:
+ MacroAssembler* _masm;
+ Label _label;
+
+ public:
+ // 'temp' is a temp register that this object can use (and trash)
+ SkipIfEqual(MacroAssembler*, Register temp,
+ const bool* flag_addr, Assembler::Condition condition);
+ ~SkipIfEqual();
+};
+
+#endif // CPU_SPARC_VM_MACROASSEMBLER_SPARC_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cpu/sparc/vm/macroAssembler_sparc.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -0,0 +1,757 @@
+/*
+ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_SPARC_VM_MACROASSEMBLER_SPARC_INLINE_HPP
+#define CPU_SPARC_VM_MACROASSEMBLER_SPARC_INLINE_HPP
+
+#include "asm/assembler.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/codeBuffer.hpp"
+#include "code/codeCache.hpp"
+
+inline bool Address::is_simm13(int offset) { return Assembler::is_simm13(disp() + offset); }
+
+
+inline int AddressLiteral::low10() const {
+ return Assembler::low10(value());
+}
+
+
+inline void MacroAssembler::pd_patch_instruction(address branch, address target) {
+ jint& stub_inst = *(jint*) branch;
+ stub_inst = patched_branch(target - branch, stub_inst, 0);
+}
+
+// Use the right loads/stores for the platform
+inline void MacroAssembler::ld_ptr( Register s1, Register s2, Register d ) {
+#ifdef _LP64
+ Assembler::ldx(s1, s2, d);
+#else
+ ld( s1, s2, d);
+#endif
+}
+
+inline void MacroAssembler::ld_ptr( Register s1, int simm13a, Register d ) {
+#ifdef _LP64
+ Assembler::ldx(s1, simm13a, d);
+#else
+ ld( s1, simm13a, d);
+#endif
+}
+
+#ifdef ASSERT
+// ByteSize is only a class when ASSERT is defined, otherwise it's an int.
+inline void MacroAssembler::ld_ptr( Register s1, ByteSize simm13a, Register d ) {
+ ld_ptr(s1, in_bytes(simm13a), d);
+}
+#endif
+
+inline void MacroAssembler::ld_ptr( Register s1, RegisterOrConstant s2, Register d ) {
+#ifdef _LP64
+ ldx(s1, s2, d);
+#else
+ ld( s1, s2, d);
+#endif
+}
+
+inline void MacroAssembler::ld_ptr(const Address& a, Register d, int offset) {
+#ifdef _LP64
+ ldx(a, d, offset);
+#else
+ ld( a, d, offset);
+#endif
+}
+
+inline void MacroAssembler::st_ptr( Register d, Register s1, Register s2 ) {
+#ifdef _LP64
+ Assembler::stx(d, s1, s2);
+#else
+ st( d, s1, s2);
+#endif
+}
+
+inline void MacroAssembler::st_ptr( Register d, Register s1, int simm13a ) {
+#ifdef _LP64
+ Assembler::stx(d, s1, simm13a);
+#else
+ st( d, s1, simm13a);
+#endif
+}
+
+#ifdef ASSERT
+// ByteSize is only a class when ASSERT is defined, otherwise it's an int.
+inline void MacroAssembler::st_ptr( Register d, Register s1, ByteSize simm13a ) {
+ st_ptr(d, s1, in_bytes(simm13a));
+}
+#endif
+
+inline void MacroAssembler::st_ptr( Register d, Register s1, RegisterOrConstant s2 ) {
+#ifdef _LP64
+ stx(d, s1, s2);
+#else
+ st( d, s1, s2);
+#endif
+}
+
+inline void MacroAssembler::st_ptr(Register d, const Address& a, int offset) {
+#ifdef _LP64
+ stx(d, a, offset);
+#else
+ st( d, a, offset);
+#endif
+}
+
+// Use the right loads/stores for the platform
+inline void MacroAssembler::ld_long( Register s1, Register s2, Register d ) {
+#ifdef _LP64
+ Assembler::ldx(s1, s2, d);
+#else
+ Assembler::ldd(s1, s2, d);
+#endif
+}
+
+inline void MacroAssembler::ld_long( Register s1, int simm13a, Register d ) {
+#ifdef _LP64
+ Assembler::ldx(s1, simm13a, d);
+#else
+ Assembler::ldd(s1, simm13a, d);
+#endif
+}
+
+inline void MacroAssembler::ld_long( Register s1, RegisterOrConstant s2, Register d ) {
+#ifdef _LP64
+ ldx(s1, s2, d);
+#else
+ ldd(s1, s2, d);
+#endif
+}
+
+inline void MacroAssembler::ld_long(const Address& a, Register d, int offset) {
+#ifdef _LP64
+ ldx(a, d, offset);
+#else
+ ldd(a, d, offset);
+#endif
+}
+
+inline void MacroAssembler::st_long( Register d, Register s1, Register s2 ) {
+#ifdef _LP64
+ Assembler::stx(d, s1, s2);
+#else
+ Assembler::std(d, s1, s2);
+#endif
+}
+
+inline void MacroAssembler::st_long( Register d, Register s1, int simm13a ) {
+#ifdef _LP64
+ Assembler::stx(d, s1, simm13a);
+#else
+ Assembler::std(d, s1, simm13a);
+#endif
+}
+
+inline void MacroAssembler::st_long( Register d, Register s1, RegisterOrConstant s2 ) {
+#ifdef _LP64
+ stx(d, s1, s2);
+#else
+ std(d, s1, s2);
+#endif
+}
+
+inline void MacroAssembler::st_long( Register d, const Address& a, int offset ) {
+#ifdef _LP64
+ stx(d, a, offset);
+#else
+ std(d, a, offset);
+#endif
+}
+
+// Functions for isolating 64 bit shifts for LP64
+
+inline void MacroAssembler::sll_ptr( Register s1, Register s2, Register d ) {
+#ifdef _LP64
+ Assembler::sllx(s1, s2, d);
+#else
+ Assembler::sll( s1, s2, d);
+#endif
+}
+
+inline void MacroAssembler::sll_ptr( Register s1, int imm6a, Register d ) {
+#ifdef _LP64
+ Assembler::sllx(s1, imm6a, d);
+#else
+ Assembler::sll( s1, imm6a, d);
+#endif
+}
+
+inline void MacroAssembler::srl_ptr( Register s1, Register s2, Register d ) {
+#ifdef _LP64
+ Assembler::srlx(s1, s2, d);
+#else
+ Assembler::srl( s1, s2, d);
+#endif
+}
+
+inline void MacroAssembler::srl_ptr( Register s1, int imm6a, Register d ) {
+#ifdef _LP64
+ Assembler::srlx(s1, imm6a, d);
+#else
+ Assembler::srl( s1, imm6a, d);
+#endif
+}
+
+inline void MacroAssembler::sll_ptr( Register s1, RegisterOrConstant s2, Register d ) {
+ if (s2.is_register()) sll_ptr(s1, s2.as_register(), d);
+ else sll_ptr(s1, s2.as_constant(), d);
+}
+
+// Use the right branch for the platform
+
+inline void MacroAssembler::br( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) {
+ if (VM_Version::v9_instructions_work())
+ Assembler::bp(c, a, icc, p, d, rt);
+ else
+ Assembler::br(c, a, d, rt);
+}
+
+inline void MacroAssembler::br( Condition c, bool a, Predict p, Label& L ) {
+ br(c, a, p, target(L));
+}
+
+
+// Branch that tests either xcc or icc depending on the
+// architecture compiled (LP64 or not)
+inline void MacroAssembler::brx( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) {
+#ifdef _LP64
+ Assembler::bp(c, a, xcc, p, d, rt);
+#else
+ MacroAssembler::br(c, a, p, d, rt);
+#endif
+}
+
+inline void MacroAssembler::brx( Condition c, bool a, Predict p, Label& L ) {
+ brx(c, a, p, target(L));
+}
+
+inline void MacroAssembler::ba( Label& L ) {
+ br(always, false, pt, L);
+}
+
+// Warning: V9 only functions
+inline void MacroAssembler::bp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt ) {
+ Assembler::bp(c, a, cc, p, d, rt);
+}
+
+inline void MacroAssembler::bp( Condition c, bool a, CC cc, Predict p, Label& L ) {
+ Assembler::bp(c, a, cc, p, L);
+}
+
+inline void MacroAssembler::fb( Condition c, bool a, Predict p, address d, relocInfo::relocType rt ) {
+ if (VM_Version::v9_instructions_work())
+ fbp(c, a, fcc0, p, d, rt);
+ else
+ Assembler::fb(c, a, d, rt);
+}
+
+inline void MacroAssembler::fb( Condition c, bool a, Predict p, Label& L ) {
+ fb(c, a, p, target(L));
+}
+
+inline void MacroAssembler::fbp( Condition c, bool a, CC cc, Predict p, address d, relocInfo::relocType rt ) {
+ Assembler::fbp(c, a, cc, p, d, rt);
+}
+
+inline void MacroAssembler::fbp( Condition c, bool a, CC cc, Predict p, Label& L ) {
+ Assembler::fbp(c, a, cc, p, L);
+}
+
+inline void MacroAssembler::jmp( Register s1, Register s2 ) { jmpl( s1, s2, G0 ); }
+inline void MacroAssembler::jmp( Register s1, int simm13a, RelocationHolder const& rspec ) { jmpl( s1, simm13a, G0, rspec); }
+
+inline bool MacroAssembler::is_far_target(address d) {
+ if (ForceUnreachable) {
+ // References outside the code cache should be treated as far
+ return d < CodeCache::low_bound() || d > CodeCache::high_bound();
+ }
+ return !is_in_wdisp30_range(d, CodeCache::low_bound()) || !is_in_wdisp30_range(d, CodeCache::high_bound());
+}
+
+// Call with a check to see if we need to deal with the added
+// expense of relocation and if we overflow the displacement
+// of the quick call instruction.
+inline void MacroAssembler::call( address d, relocInfo::relocType rt ) {
+#ifdef _LP64
+ intptr_t disp;
+ // NULL is ok because it will be relocated later.
+ // Must change NULL to a reachable address in order to
+ // pass asserts here and in wdisp.
+ if ( d == NULL )
+ d = pc();
+
+ // Is this address within range of the call instruction?
+ // If not, use the expensive instruction sequence
+ if (is_far_target(d)) {
+ relocate(rt);
+ AddressLiteral dest(d);
+ jumpl_to(dest, O7, O7);
+ } else {
+ Assembler::call(d, rt);
+ }
+#else
+ Assembler::call( d, rt );
+#endif
+}
+
+inline void MacroAssembler::call( Label& L, relocInfo::relocType rt ) {
+ MacroAssembler::call( target(L), rt);
+}
+
+
+
+inline void MacroAssembler::callr( Register s1, Register s2 ) { jmpl( s1, s2, O7 ); }
+inline void MacroAssembler::callr( Register s1, int simm13a, RelocationHolder const& rspec ) { jmpl( s1, simm13a, O7, rspec); }
+
+// prefetch instruction
+inline void MacroAssembler::iprefetch( address d, relocInfo::relocType rt ) {
+ if (VM_Version::v9_instructions_work())
+ Assembler::bp( never, true, xcc, pt, d, rt );
+}
+inline void MacroAssembler::iprefetch( Label& L) { iprefetch( target(L) ); }
+
+
+// clobbers o7 on V8!!
+// returns delta from gotten pc to addr after
+inline int MacroAssembler::get_pc( Register d ) {
+ int x = offset();
+ if (VM_Version::v9_instructions_work())
+ rdpc(d);
+ else {
+ Label lbl;
+ Assembler::call(lbl, relocInfo::none); // No relocation as this is call to pc+0x8
+ if (d == O7) delayed()->nop();
+ else delayed()->mov(O7, d);
+ bind(lbl);
+ }
+ return offset() - x;
+}
+
+
+// Note: All MacroAssembler::set_foo functions are defined out-of-line.
+
+
+// Loads the current PC of the following instruction as an immediate value in
+// 2 instructions. All PCs in the CodeCache are within 2 Gig of each other.
+inline intptr_t MacroAssembler::load_pc_address( Register reg, int bytes_to_skip ) {
+ intptr_t thepc = (intptr_t)pc() + 2*BytesPerInstWord + bytes_to_skip;
+#ifdef _LP64
+ Unimplemented();
+#else
+ Assembler::sethi( thepc & ~0x3ff, reg, internal_word_Relocation::spec((address)thepc));
+ add(reg, thepc & 0x3ff, reg, internal_word_Relocation::spec((address)thepc));
+#endif
+ return thepc;
+}
+
+
+inline void MacroAssembler::load_contents(const AddressLiteral& addrlit, Register d, int offset) {
+ assert_not_delayed();
+ if (ForceUnreachable) {
+ patchable_sethi(addrlit, d);
+ } else {
+ sethi(addrlit, d);
+ }
+ ld(d, addrlit.low10() + offset, d);
+}
+
+
+inline void MacroAssembler::load_bool_contents(const AddressLiteral& addrlit, Register d, int offset) {
+ assert_not_delayed();
+ if (ForceUnreachable) {
+ patchable_sethi(addrlit, d);
+ } else {
+ sethi(addrlit, d);
+ }
+ ldub(d, addrlit.low10() + offset, d);
+}
+
+
+inline void MacroAssembler::load_ptr_contents(const AddressLiteral& addrlit, Register d, int offset) {
+ assert_not_delayed();
+ if (ForceUnreachable) {
+ patchable_sethi(addrlit, d);
+ } else {
+ sethi(addrlit, d);
+ }
+ ld_ptr(d, addrlit.low10() + offset, d);
+}
+
+
+inline void MacroAssembler::store_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset) {
+ assert_not_delayed();
+ if (ForceUnreachable) {
+ patchable_sethi(addrlit, temp);
+ } else {
+ sethi(addrlit, temp);
+ }
+ st(s, temp, addrlit.low10() + offset);
+}
+
+
+inline void MacroAssembler::store_ptr_contents(Register s, const AddressLiteral& addrlit, Register temp, int offset) {
+ assert_not_delayed();
+ if (ForceUnreachable) {
+ patchable_sethi(addrlit, temp);
+ } else {
+ sethi(addrlit, temp);
+ }
+ st_ptr(s, temp, addrlit.low10() + offset);
+}
+
+
+// This code sequence is relocatable to any address, even on LP64.
+inline void MacroAssembler::jumpl_to(const AddressLiteral& addrlit, Register temp, Register d, int offset) {
+ assert_not_delayed();
+ // Force fixed length sethi because NativeJump and NativeFarCall don't handle
+ // variable length instruction streams.
+ patchable_sethi(addrlit, temp);
+ jmpl(temp, addrlit.low10() + offset, d);
+}
+
+
+inline void MacroAssembler::jump_to(const AddressLiteral& addrlit, Register temp, int offset) {
+ jumpl_to(addrlit, temp, G0, offset);
+}
+
+
+inline void MacroAssembler::jump_indirect_to(Address& a, Register temp,
+ int ld_offset, int jmp_offset) {
+ assert_not_delayed();
+ //sethi(al); // sethi is caller responsibility for this one
+ ld_ptr(a, temp, ld_offset);
+ jmp(temp, jmp_offset);
+}
+
+
+inline void MacroAssembler::set_metadata(Metadata* obj, Register d) {
+ set_metadata(allocate_metadata_address(obj), d);
+}
+
+inline void MacroAssembler::set_metadata_constant(Metadata* obj, Register d) {
+ set_metadata(constant_metadata_address(obj), d);
+}
+
+inline void MacroAssembler::set_metadata(const AddressLiteral& obj_addr, Register d) {
+ assert(obj_addr.rspec().type() == relocInfo::metadata_type, "must be a metadata reloc");
+ set(obj_addr, d);
+}
+
+inline void MacroAssembler::set_oop(jobject obj, Register d) {
+ set_oop(allocate_oop_address(obj), d);
+}
+
+
+inline void MacroAssembler::set_oop_constant(jobject obj, Register d) {
+ set_oop(constant_oop_address(obj), d);
+}
+
+
+inline void MacroAssembler::set_oop(const AddressLiteral& obj_addr, Register d) {
+ assert(obj_addr.rspec().type() == relocInfo::oop_type, "must be an oop reloc");
+ set(obj_addr, d);
+}
+
+
+inline void MacroAssembler::load_argument( Argument& a, Register d ) {
+ if (a.is_register())
+ mov(a.as_register(), d);
+ else
+ ld (a.as_address(), d);
+}
+
+inline void MacroAssembler::store_argument( Register s, Argument& a ) {
+ if (a.is_register())
+ mov(s, a.as_register());
+ else
+ st_ptr (s, a.as_address()); // ABI says everything is right justified.
+}
+
+inline void MacroAssembler::store_ptr_argument( Register s, Argument& a ) {
+ if (a.is_register())
+ mov(s, a.as_register());
+ else
+ st_ptr (s, a.as_address());
+}
+
+
+#ifdef _LP64
+inline void MacroAssembler::store_float_argument( FloatRegister s, Argument& a ) {
+ if (a.is_float_register())
+// V9 ABI has F1, F3, F5 are used to pass instead of O0, O1, O2
+ fmov(FloatRegisterImpl::S, s, a.as_float_register() );
+ else
+ // Floats are stored in the high half of the stack entry
+ // The low half is undefined per the ABI.
+ stf(FloatRegisterImpl::S, s, a.as_address(), sizeof(jfloat));
+}
+
+inline void MacroAssembler::store_double_argument( FloatRegister s, Argument& a ) {
+ if (a.is_float_register())
+// V9 ABI has D0, D2, D4 are used to pass instead of O0, O1, O2
+ fmov(FloatRegisterImpl::D, s, a.as_double_register() );
+ else
+ stf(FloatRegisterImpl::D, s, a.as_address());
+}
+
+inline void MacroAssembler::store_long_argument( Register s, Argument& a ) {
+ if (a.is_register())
+ mov(s, a.as_register());
+ else
+ stx(s, a.as_address());
+}
+#endif
+
+inline void MacroAssembler::add(Register s1, int simm13a, Register d, relocInfo::relocType rtype) {
+ relocate(rtype);
+ add(s1, simm13a, d);
+}
+inline void MacroAssembler::add(Register s1, int simm13a, Register d, RelocationHolder const& rspec) {
+ relocate(rspec);
+ add(s1, simm13a, d);
+}
+
+// form effective addresses this way:
+inline void MacroAssembler::add(const Address& a, Register d, int offset) {
+ if (a.has_index()) add(a.base(), a.index(), d);
+ else { add(a.base(), a.disp() + offset, d, a.rspec(offset)); offset = 0; }
+ if (offset != 0) add(d, offset, d);
+}
+inline void MacroAssembler::add(Register s1, RegisterOrConstant s2, Register d, int offset) {
+ if (s2.is_register()) add(s1, s2.as_register(), d);
+ else { add(s1, s2.as_constant() + offset, d); offset = 0; }
+ if (offset != 0) add(d, offset, d);
+}
+
+inline void MacroAssembler::andn(Register s1, RegisterOrConstant s2, Register d) {
+ if (s2.is_register()) andn(s1, s2.as_register(), d);
+ else andn(s1, s2.as_constant(), d);
+}
+
+inline void MacroAssembler::clrb( Register s1, Register s2) { stb( G0, s1, s2 ); }
+inline void MacroAssembler::clrh( Register s1, Register s2) { sth( G0, s1, s2 ); }
+inline void MacroAssembler::clr( Register s1, Register s2) { stw( G0, s1, s2 ); }
+inline void MacroAssembler::clrx( Register s1, Register s2) { stx( G0, s1, s2 ); }
+
+inline void MacroAssembler::clrb( Register s1, int simm13a) { stb( G0, s1, simm13a); }
+inline void MacroAssembler::clrh( Register s1, int simm13a) { sth( G0, s1, simm13a); }
+inline void MacroAssembler::clr( Register s1, int simm13a) { stw( G0, s1, simm13a); }
+inline void MacroAssembler::clrx( Register s1, int simm13a) { stx( G0, s1, simm13a); }
+
+#ifdef _LP64
+// Make all 32 bit loads signed so 64 bit registers maintain proper sign
+inline void MacroAssembler::ld( Register s1, Register s2, Register d) { ldsw( s1, s2, d); }
+inline void MacroAssembler::ld( Register s1, int simm13a, Register d) { ldsw( s1, simm13a, d); }
+#else
+inline void MacroAssembler::ld( Register s1, Register s2, Register d) { lduw( s1, s2, d); }
+inline void MacroAssembler::ld( Register s1, int simm13a, Register d) { lduw( s1, simm13a, d); }
+#endif
+
+#ifdef ASSERT
+ // ByteSize is only a class when ASSERT is defined, otherwise it's an int.
+# ifdef _LP64
+inline void MacroAssembler::ld(Register s1, ByteSize simm13a, Register d) { ldsw( s1, in_bytes(simm13a), d); }
+# else
+inline void MacroAssembler::ld(Register s1, ByteSize simm13a, Register d) { lduw( s1, in_bytes(simm13a), d); }
+# endif
+#endif
+
+inline void MacroAssembler::ld( const Address& a, Register d, int offset) {
+ if (a.has_index()) { assert(offset == 0, ""); ld( a.base(), a.index(), d); }
+ else { ld( a.base(), a.disp() + offset, d); }
+}
+
+inline void MacroAssembler::ldsb(const Address& a, Register d, int offset) {
+ if (a.has_index()) { assert(offset == 0, ""); ldsb(a.base(), a.index(), d); }
+ else { ldsb(a.base(), a.disp() + offset, d); }
+}
+inline void MacroAssembler::ldsh(const Address& a, Register d, int offset) {
+ if (a.has_index()) { assert(offset == 0, ""); ldsh(a.base(), a.index(), d); }
+ else { ldsh(a.base(), a.disp() + offset, d); }
+}
+inline void MacroAssembler::ldsw(const Address& a, Register d, int offset) {
+ if (a.has_index()) { assert(offset == 0, ""); ldsw(a.base(), a.index(), d); }
+ else { ldsw(a.base(), a.disp() + offset, d); }
+}
+inline void MacroAssembler::ldub(const Address& a, Register d, int offset) {
+ if (a.has_index()) { assert(offset == 0, ""); ldub(a.base(), a.index(), d); }
+ else { ldub(a.base(), a.disp() + offset, d); }
+}
+inline void MacroAssembler::lduh(const Address& a, Register d, int offset) {
+ if (a.has_index()) { assert(offset == 0, ""); lduh(a.base(), a.index(), d); }
+ else { lduh(a.base(), a.disp() + offset, d); }
+}
+inline void MacroAssembler::lduw(const Address& a, Register d, int offset) {
+ if (a.has_index()) { assert(offset == 0, ""); lduw(a.base(), a.index(), d); }
+ else { lduw(a.base(), a.disp() + offset, d); }
+}
+inline void MacroAssembler::ldd( const Address& a, Register d, int offset) {
+ if (a.has_index()) { assert(offset == 0, ""); ldd( a.base(), a.index(), d); }
+ else { ldd( a.base(), a.disp() + offset, d); }
+}
+inline void MacroAssembler::ldx( const Address& a, Register d, int offset) {
+ if (a.has_index()) { assert(offset == 0, ""); ldx( a.base(), a.index(), d); }
+ else { ldx( a.base(), a.disp() + offset, d); }
+}
+
+inline void MacroAssembler::ldub(Register s1, RegisterOrConstant s2, Register d) { ldub(Address(s1, s2), d); }
+inline void MacroAssembler::ldsb(Register s1, RegisterOrConstant s2, Register d) { ldsb(Address(s1, s2), d); }
+inline void MacroAssembler::lduh(Register s1, RegisterOrConstant s2, Register d) { lduh(Address(s1, s2), d); }
+inline void MacroAssembler::ldsh(Register s1, RegisterOrConstant s2, Register d) { ldsh(Address(s1, s2), d); }
+inline void MacroAssembler::lduw(Register s1, RegisterOrConstant s2, Register d) { lduw(Address(s1, s2), d); }
+inline void MacroAssembler::ldsw(Register s1, RegisterOrConstant s2, Register d) { ldsw(Address(s1, s2), d); }
+inline void MacroAssembler::ldx( Register s1, RegisterOrConstant s2, Register d) { ldx( Address(s1, s2), d); }
+inline void MacroAssembler::ld( Register s1, RegisterOrConstant s2, Register d) { ld( Address(s1, s2), d); }
+inline void MacroAssembler::ldd( Register s1, RegisterOrConstant s2, Register d) { ldd( Address(s1, s2), d); }
+
+inline void MacroAssembler::ldf(FloatRegisterImpl::Width w, Register s1, RegisterOrConstant s2, FloatRegister d) {
+ if (s2.is_register()) ldf(w, s1, s2.as_register(), d);
+ else ldf(w, s1, s2.as_constant(), d);
+}
+
+inline void MacroAssembler::ldf(FloatRegisterImpl::Width w, const Address& a, FloatRegister d, int offset) {
+ relocate(a.rspec(offset));
+ ldf(w, a.base(), a.disp() + offset, d);
+}
+
+// returns if membar generates anything, obviously this code should mirror
+// membar below.
+inline bool MacroAssembler::membar_has_effect( Membar_mask_bits const7a ) {
+ if( !os::is_MP() ) return false; // Not needed on single CPU
+ if( VM_Version::v9_instructions_work() ) {
+ const Membar_mask_bits effective_mask =
+ Membar_mask_bits(const7a & ~(LoadLoad | LoadStore | StoreStore));
+ return (effective_mask != 0);
+ } else {
+ return true;
+ }
+}
+
+inline void MacroAssembler::membar( Membar_mask_bits const7a ) {
+ // Uniprocessors do not need memory barriers
+ if (!os::is_MP()) return;
+ // Weakened for current Sparcs and TSO. See the v9 manual, sections 8.4.3,
+ // 8.4.4.3, a.31 and a.50.
+ if( VM_Version::v9_instructions_work() ) {
+ // Under TSO, setting bit 3, 2, or 0 is redundant, so the only value
+ // of the mmask subfield of const7a that does anything that isn't done
+ // implicitly is StoreLoad.
+ const Membar_mask_bits effective_mask =
+ Membar_mask_bits(const7a & ~(LoadLoad | LoadStore | StoreStore));
+ if ( effective_mask != 0 ) {
+ Assembler::membar( effective_mask );
+ }
+ } else {
+ // stbar is the closest there is on v8. Equivalent to membar(StoreStore). We
+ // do not issue the stbar because to my knowledge all v8 machines implement TSO,
+ // which guarantees that all stores behave as if an stbar were issued just after
+ // each one of them. On these machines, stbar ought to be a nop. There doesn't
+ // appear to be an equivalent of membar(StoreLoad) on v8: TSO doesn't require it,
+ // it can't be specified by stbar, nor have I come up with a way to simulate it.
+ //
+ // Addendum. Dave says that ldstub guarantees a write buffer flush to coherent
+ // space. Put one here to be on the safe side.
+ Assembler::ldstub(SP, 0, G0);
+ }
+}
+
+inline void MacroAssembler::prefetch(const Address& a, PrefetchFcn f, int offset) {
+ relocate(a.rspec(offset));
+ assert(!a.has_index(), "");
+ prefetch(a.base(), a.disp() + offset, f);
+}
+
+inline void MacroAssembler::st(Register d, Register s1, Register s2) { stw(d, s1, s2); }
+inline void MacroAssembler::st(Register d, Register s1, int simm13a) { stw(d, s1, simm13a); }
+
+#ifdef ASSERT
+// ByteSize is only a class when ASSERT is defined, otherwise it's an int.
+inline void MacroAssembler::st(Register d, Register s1, ByteSize simm13a) { stw(d, s1, in_bytes(simm13a)); }
+#endif
+
+inline void MacroAssembler::st(Register d, const Address& a, int offset) {
+ if (a.has_index()) { assert(offset == 0, ""); st( d, a.base(), a.index() ); }
+ else { st( d, a.base(), a.disp() + offset); }
+}
+
+inline void MacroAssembler::stb(Register d, const Address& a, int offset) {
+ if (a.has_index()) { assert(offset == 0, ""); stb(d, a.base(), a.index() ); }
+ else { stb(d, a.base(), a.disp() + offset); }
+}
+inline void MacroAssembler::sth(Register d, const Address& a, int offset) {
+ if (a.has_index()) { assert(offset == 0, ""); sth(d, a.base(), a.index() ); }
+ else { sth(d, a.base(), a.disp() + offset); }
+}
+inline void MacroAssembler::stw(Register d, const Address& a, int offset) {
+ if (a.has_index()) { assert(offset == 0, ""); stw(d, a.base(), a.index() ); }
+ else { stw(d, a.base(), a.disp() + offset); }
+}
+inline void MacroAssembler::std(Register d, const Address& a, int offset) {
+ if (a.has_index()) { assert(offset == 0, ""); std(d, a.base(), a.index() ); }
+ else { std(d, a.base(), a.disp() + offset); }
+}
+inline void MacroAssembler::stx(Register d, const Address& a, int offset) {
+ if (a.has_index()) { assert(offset == 0, ""); stx(d, a.base(), a.index() ); }
+ else { stx(d, a.base(), a.disp() + offset); }
+}
+
+inline void MacroAssembler::stb(Register d, Register s1, RegisterOrConstant s2) { stb(d, Address(s1, s2)); }
+inline void MacroAssembler::sth(Register d, Register s1, RegisterOrConstant s2) { sth(d, Address(s1, s2)); }
+inline void MacroAssembler::stw(Register d, Register s1, RegisterOrConstant s2) { stw(d, Address(s1, s2)); }
+inline void MacroAssembler::stx(Register d, Register s1, RegisterOrConstant s2) { stx(d, Address(s1, s2)); }
+inline void MacroAssembler::std(Register d, Register s1, RegisterOrConstant s2) { std(d, Address(s1, s2)); }
+inline void MacroAssembler::st( Register d, Register s1, RegisterOrConstant s2) { st( d, Address(s1, s2)); }
+
+inline void MacroAssembler::stf(FloatRegisterImpl::Width w, FloatRegister d, Register s1, RegisterOrConstant s2) {
+ if (s2.is_register()) stf(w, d, s1, s2.as_register());
+ else stf(w, d, s1, s2.as_constant());
+}
+
+inline void MacroAssembler::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 MacroAssembler::sub(Register s1, RegisterOrConstant s2, Register d, int offset) {
+ if (s2.is_register()) sub(s1, s2.as_register(), d);
+ else { sub(s1, s2.as_constant() + offset, d); offset = 0; }
+ if (offset != 0) sub(d, offset, d);
+}
+
+inline void MacroAssembler::swap(Address& a, Register d, int offset) {
+ relocate(a.rspec(offset));
+ if (a.has_index()) { assert(offset == 0, ""); swap(a.base(), a.index(), d ); }
+ else { swap(a.base(), a.disp() + offset, d); }
+}
+
+#endif // CPU_SPARC_VM_MACROASSEMBLER_SPARC_INLINE_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/metaspaceShared_sparc.cpp
--- a/src/cpu/sparc/vm/metaspaceShared_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/metaspaceShared_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,8 @@
*/
#include "precompiled.hpp"
-#include "assembler_sparc.inline.hpp"
+#include "asm/macroAssembler.inline.hpp"
+#include "asm/codeBuffer.hpp"
#include "memory/metaspaceShared.hpp"
// Generate the self-patching vtable method:
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/methodHandles_sparc.cpp
--- a/src/cpu/sparc/vm/methodHandles_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "asm/macroAssembler.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/allocation.inline.hpp"
#include "prims/methodHandles.hpp"
@@ -170,7 +171,8 @@
if (VerifyMethodHandles && !for_compiler_entry) {
// make sure recv is already on stack
- __ load_sized_value(Address(method_temp, Method::size_of_parameters_offset()),
+ __ ld_ptr(method_temp, in_bytes(Method::const_offset()), temp2);
+ __ load_sized_value(Address(temp2, ConstMethod::size_of_parameters_offset()),
temp2,
sizeof(u2), /*is_signed*/ false);
// assert(sizeof(u2) == sizeof(Method::_size_of_parameters), "");
@@ -232,7 +234,8 @@
int ref_kind = signature_polymorphic_intrinsic_ref_kind(iid);
assert(ref_kind != 0 || iid == vmIntrinsics::_invokeBasic, "must be _invokeBasic or a linkTo intrinsic");
if (ref_kind == 0 || MethodHandles::ref_kind_has_receiver(ref_kind)) {
- __ load_sized_value(Address(G5_method, Method::size_of_parameters_offset()),
+ __ ld_ptr(G5_method, in_bytes(Method::const_offset()), O4_param_size);
+ __ load_sized_value(Address(O4_param_size, ConstMethod::size_of_parameters_offset()),
O4_param_size,
sizeof(u2), /*is_signed*/ false);
// assert(sizeof(u2) == sizeof(Method::_size_of_parameters), "");
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/nativeInst_sparc.cpp
--- a/src/cpu/sparc/vm/nativeInst_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/nativeInst_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "assembler_sparc.inline.hpp"
+#include "asm/macroAssembler.hpp"
#include "memory/resourceArea.hpp"
#include "nativeInst_sparc.hpp"
#include "oops/oop.inline.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/nativeInst_sparc.hpp
--- a/src/cpu/sparc/vm/nativeInst_sparc.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/nativeInst_sparc.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,7 +25,7 @@
#ifndef CPU_SPARC_VM_NATIVEINST_SPARC_HPP
#define CPU_SPARC_VM_NATIVEINST_SPARC_HPP
-#include "asm/assembler.hpp"
+#include "asm/macroAssembler.hpp"
#include "memory/allocation.hpp"
#include "runtime/icache.hpp"
#include "runtime/os.hpp"
@@ -194,11 +194,10 @@
static int inv_simm( int x, int nbits ) { return Assembler::inv_simm(x, nbits); }
static intptr_t inv_wdisp( int x, int nbits ) { return Assembler::inv_wdisp( x, 0, nbits); }
static intptr_t inv_wdisp16( int x ) { return Assembler::inv_wdisp16(x, 0); }
- static int branch_destination_offset(int x) { return Assembler::branch_destination(x, 0); }
+ static int branch_destination_offset(int x) { return MacroAssembler::branch_destination(x, 0); }
static int patch_branch_destination_offset(int dest_offset, int x) {
- return Assembler::patched_branch(dest_offset, x, 0);
+ return MacroAssembler::patched_branch(dest_offset, x, 0);
}
- void set_annul_bit() { set_long_at(0, long_at(0) | Assembler::annul(true)); }
// utility for checking if x is either of 2 small constants
static bool is_either(int x, int k1, int k2) {
@@ -889,7 +888,6 @@
int patched_instr = patch_branch_destination_offset(dest - addr_at(0), long_at(0));
set_long_at(0, patched_instr);
}
- void set_annul() { set_annul_bit(); }
NativeInstruction *delay_slot_instr() { return nativeInstruction_at(addr_at(4));}
void fill_delay_slot(int instr) { set_long_at(4, instr);}
Assembler::Condition condition() {
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/relocInfo_sparc.cpp
--- a/src/cpu/sparc/vm/relocInfo_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/relocInfo_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.inline.hpp"
-#include "assembler_sparc.inline.hpp"
+#include "asm/assembler.hpp"
#include "code/relocInfo.hpp"
#include "nativeInst_sparc.hpp"
#include "oops/oop.inline.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/runtime_sparc.cpp
--- a/src/cpu/sparc/vm/runtime_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/runtime_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -24,8 +24,7 @@
#include "precompiled.hpp"
#ifdef COMPILER2
-#include "asm/assembler.hpp"
-#include "assembler_sparc.inline.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/vmreg.hpp"
#include "interpreter/interpreter.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/sharedRuntime_sparc.cpp
--- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_sparc.inline.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "code/debugInfoRec.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
@@ -2322,7 +2321,7 @@
// Pre-load a static method's oop into O1. Used both by locking code and
// the normal JNI call code.
if (method->is_static() && !is_critical_native) {
- __ set_oop_constant(JNIHandles::make_local(Klass::cast(method->method_holder())->java_mirror()), O1);
+ __ set_oop_constant(JNIHandles::make_local(method->method_holder()->java_mirror()), O1);
// Now handlize the static class mirror in O1. It's known not-null.
__ st_ptr(O1, SP, klass_offset + STACK_BIAS);
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/sparc.ad
--- a/src/cpu/sparc/vm/sparc.ad Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/sparc.ad Sun Feb 03 22:43:57 2013 +0100
@@ -10224,7 +10224,7 @@
//---------- Zeros Count Instructions ------------------------------------------
-instruct countLeadingZerosI(iRegI dst, iRegI src, iRegI tmp, flagsReg cr) %{
+instruct countLeadingZerosI(iRegIsafe dst, iRegI src, iRegI tmp, flagsReg cr) %{
predicate(UsePopCountInstruction); // See Matcher::match_rule_supported
match(Set dst (CountLeadingZerosI src));
effect(TEMP dst, TEMP tmp, KILL cr);
@@ -10321,7 +10321,7 @@
ins_pipe(ialu_reg);
%}
-instruct countTrailingZerosI(iRegI dst, iRegI src, flagsReg cr) %{
+instruct countTrailingZerosI(iRegIsafe dst, iRegI src, flagsReg cr) %{
predicate(UsePopCountInstruction); // See Matcher::match_rule_supported
match(Set dst (CountTrailingZerosI src));
effect(TEMP dst, KILL cr);
@@ -10364,19 +10364,21 @@
//---------- Population Count Instructions -------------------------------------
-instruct popCountI(iRegI dst, iRegI src) %{
+instruct popCountI(iRegIsafe dst, iRegI src) %{
predicate(UsePopCountInstruction);
match(Set dst (PopCountI src));
- format %{ "POPC $src, $dst" %}
- ins_encode %{
- __ popc($src$$Register, $dst$$Register);
+ format %{ "SRL $src, G0, $dst\t! clear upper word for 64 bit POPC\n\t"
+ "POPC $dst, $dst" %}
+ ins_encode %{
+ __ srl($src$$Register, G0, $dst$$Register);
+ __ popc($dst$$Register, $dst$$Register);
%}
ins_pipe(ialu_reg);
%}
// Note: Long.bitCount(long) returns an int.
-instruct popCountL(iRegI dst, iRegL src) %{
+instruct popCountL(iRegIsafe dst, iRegL src) %{
predicate(UsePopCountInstruction);
match(Set dst (PopCountL src));
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/stubGenerator_sparc.cpp
--- a/src/cpu/sparc/vm/stubGenerator_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/stubGenerator_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_sparc.inline.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "nativeInst_sparc.hpp"
#include "oops/instanceOop.hpp"
@@ -37,13 +36,8 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubCodeGenerator.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
#include "utilities/top.hpp"
-#ifdef TARGET_OS_FAMILY_linux
-# include "thread_linux.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_solaris
-# include "thread_solaris.inline.hpp"
-#endif
#ifdef COMPILER2
#include "opto/runtime.hpp"
#endif
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/stubRoutines_sparc.cpp
--- a/src/cpu/sparc/vm/stubRoutines_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/stubRoutines_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -26,12 +26,7 @@
#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/stubRoutines.hpp"
-#ifdef TARGET_OS_FAMILY_linux
-# include "thread_linux.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_solaris
-# include "thread_solaris.inline.hpp"
-#endif
+#include "runtime/thread.inline.hpp"
// Implementation of the platform-specific part of StubRoutines - for
// a description of how to extend it, see the stubRoutines.hpp file.
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/templateInterpreter_sparc.cpp
--- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
+#include "asm/macroAssembler.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterGenerator.hpp"
@@ -259,7 +259,7 @@
}
__ ret(); // return from interpreter activation
__ delayed()->restore(I5_savedSP, G0, SP); // remove interpreter frame
- NOT_PRODUCT(__ emit_long(0);) // marker for disassembly
+ NOT_PRODUCT(__ emit_int32(0);) // marker for disassembly
return entry;
}
@@ -434,7 +434,7 @@
// the frame is greater than one page in size, so check against
// the bottom of the stack
- __ cmp_and_brx_short(SP, Rscratch, Assembler::greater, Assembler::pt, after_frame_check);
+ __ cmp_and_brx_short(SP, Rscratch, Assembler::greaterUnsigned, Assembler::pt, after_frame_check);
// the stack will overflow, throw an exception
@@ -494,9 +494,6 @@
// (gri - 2/25/2000)
- const Address size_of_parameters(G5_method, Method::size_of_parameters_offset());
- const Address size_of_locals (G5_method, Method::size_of_locals_offset());
- const Address max_stack (G5_method, Method::max_stack_offset());
int rounded_vm_local_words = round_to( frame::interpreter_frame_vm_local_words, WordsPerLong );
const int extra_space =
@@ -506,11 +503,15 @@
(native_call ? frame::interpreter_frame_extra_outgoing_argument_words : 0);
const Register Glocals_size = G3;
+ const Register RconstMethod = Glocals_size;
const Register Otmp1 = O3;
const Register Otmp2 = O4;
// Lscratch can't be used as a temporary because the call_stub uses
// it to assert that the stack frame was setup correctly.
+ const Address constMethod (G5_method, Method::const_offset());
+ const Address size_of_parameters(RconstMethod, ConstMethod::size_of_parameters_offset());
+ __ ld_ptr( constMethod, RconstMethod );
__ lduh( size_of_parameters, Glocals_size);
// Gargs points to first local + BytesPerWord
@@ -530,6 +531,8 @@
//
// Compute number of locals in method apart from incoming parameters
//
+ const Address size_of_locals (Otmp1, ConstMethod::size_of_locals_offset());
+ __ ld_ptr( constMethod, Otmp1 );
__ lduh( size_of_locals, Otmp1 );
__ sub( Otmp1, Glocals_size, Glocals_size );
__ round_to( Glocals_size, WordsPerLong );
@@ -538,7 +541,8 @@
// see if the frame is greater than one page in size. If so,
// then we need to verify there is enough stack space remaining
// Frame_size = (max_stack + extra_space) * BytesPerWord;
- __ lduh( max_stack, Gframe_size );
+ __ ld_ptr( constMethod, Gframe_size );
+ __ lduh( Gframe_size, in_bytes(ConstMethod::max_stack_offset()), Gframe_size );
__ add( Gframe_size, extra_space, Gframe_size );
__ round_to( Gframe_size, WordsPerLong );
__ sll( Gframe_size, Interpreter::logStackElementSize, Gframe_size);
@@ -1255,8 +1259,7 @@
// make sure registers are different!
assert_different_registers(G2_thread, G5_method, Gargs, Gtmp1, Gtmp2);
- const Address size_of_parameters(G5_method, Method::size_of_parameters_offset());
- const Address size_of_locals (G5_method, Method::size_of_locals_offset());
+ const Address constMethod (G5_method, Method::const_offset());
// Seems like G5_method is live at the point this is used. So we could make this look consistent
// and use in the asserts.
const Address access_flags (Lmethod, Method::access_flags_offset());
@@ -1306,8 +1309,13 @@
init_value = G0;
Label clear_loop;
+ const Register RconstMethod = O1;
+ const Address size_of_parameters(RconstMethod, ConstMethod::size_of_parameters_offset());
+ const Address size_of_locals (RconstMethod, ConstMethod::size_of_locals_offset());
+
// NOTE: If you change the frame layout, this code will need to
// be updated!
+ __ ld_ptr( constMethod, RconstMethod );
__ lduh( size_of_locals, O2 );
__ lduh( size_of_parameters, O1 );
__ sll( O2, Interpreter::logStackElementSize, O2);
@@ -1822,9 +1830,13 @@
const Register Gtmp1 = G3_scratch;
const Register Gtmp2 = G1_scratch;
+ const Register RconstMethod = Gtmp1;
+ const Address constMethod(Lmethod, Method::const_offset());
+ const Address size_of_parameters(RconstMethod, ConstMethod::size_of_parameters_offset());
// Compute size of arguments for saving when returning to deoptimized caller
- __ lduh(Lmethod, in_bytes(Method::size_of_parameters_offset()), Gtmp1);
+ __ ld_ptr(constMethod, RconstMethod);
+ __ lduh(size_of_parameters, Gtmp1);
__ sll(Gtmp1, Interpreter::logStackElementSize, Gtmp1);
__ sub(Llocals, Gtmp1, Gtmp2);
__ add(Gtmp2, wordSize, Gtmp2);
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/templateTable_sparc.cpp
--- a/src/cpu/sparc/vm/templateTable_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/templateTable_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -3040,7 +3040,8 @@
Register Rtemp = G4_scratch;
// Load receiver from stack slot
- __ lduh(G5_method, in_bytes(Method::size_of_parameters_offset()), G4_scratch);
+ __ ld_ptr(G5_method, in_bytes(Method::const_offset()), G4_scratch);
+ __ lduh(G4_scratch, in_bytes(ConstMethod::size_of_parameters_offset()), G4_scratch);
__ load_receiver(G4_scratch, O0);
// receiver NULL check
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/vmStructs_sparc.hpp
--- a/src/cpu/sparc/vm/vmStructs_sparc.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/vmStructs_sparc.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -29,7 +29,7 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \
+#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
\
/******************************/ \
/* JavaCallWrapper */ \
@@ -37,22 +37,12 @@
/******************************/ \
/* JavaFrameAnchor */ \
/******************************/ \
- volatile_nonstatic_field(JavaFrameAnchor, _flags, int) \
- \
+ volatile_nonstatic_field(JavaFrameAnchor, _flags, int)
- /* NOTE that we do not use the last_entry() macro here; it is used */
- /* in vmStructs__.hpp's VM_STRUCTS_OS_CPU macro (and must */
- /* be present there) */
+#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
-#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \
-
- /* NOTE that we do not use the last_entry() macro here; it is used */
- /* in vmStructs__.hpp's VM_TYPES_OS_CPU macro (and must */
- /* be present there) */
-
-
-#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
+#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \
/******************************/ \
/* Register numbers (C2 only) */ \
/******************************/ \
@@ -90,15 +80,6 @@
declare_c2_constant(R_G6_num) \
declare_c2_constant(R_G7_num)
-
- /* NOTE that we do not use the last_entry() macro here; it is used */
- /* in vmStructs__.hpp's VM_INT_CONSTANTS_OS_CPU macro (and must */
- /* be present there) */
-
-#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
-
- /* NOTE that we do not use the last_entry() macro here; it is used */
- /* in vmStructs__.hpp's VM_LONG_CONSTANTS_OS_CPU macro (and must */
- /* be present there) */
+#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
#endif // CPU_SPARC_VM_VMSTRUCTS_SPARC_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/vm_version_sparc.cpp
--- a/src/cpu/sparc/vm/vm_version_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/vm_version_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "assembler_sparc.inline.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/java.hpp"
#include "runtime/stubCodeGenerator.hpp"
@@ -259,6 +259,10 @@
if (!has_vis1()) // Drop to 0 if no VIS1 support
UseVIS = 0;
+ if (FLAG_IS_DEFAULT(ContendedPaddingWidth) &&
+ (cache_line_size > ContendedPaddingWidth))
+ ContendedPaddingWidth = cache_line_size;
+
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose) {
tty->print("Allocation");
@@ -286,6 +290,9 @@
if (PrefetchFieldsAhead > 0) {
tty->print_cr("PrefetchFieldsAhead %d", PrefetchFieldsAhead);
}
+ if (ContendedPaddingWidth > 0) {
+ tty->print_cr("ContendedPaddingWidth %d", ContendedPaddingWidth);
+ }
}
#endif // PRODUCT
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/vmreg_sparc.cpp
--- a/src/cpu/sparc/vm/vmreg_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/vmreg_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,6 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
#include "code/vmreg.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/sparc/vm/vtableStubs_sparc.cpp
--- a/src/cpu/sparc/vm/vtableStubs_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/sparc/vm/vtableStubs_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_sparc.inline.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "code/vtableStubs.hpp"
#include "interp_masm_sparc.hpp"
#include "memory/resourceArea.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/assembler_x86.cpp
--- a/src/cpu/x86/vm/assembler_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/assembler_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,8 @@
*/
#include "precompiled.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/assembler.hpp"
+#include "asm/assembler.inline.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/cardTableModRefBS.hpp"
@@ -181,7 +182,7 @@
// make this go away someday
void Assembler::emit_data(jint data, relocInfo::relocType rtype, int format) {
if (rtype == relocInfo::none)
- emit_long(data);
+ emit_int32(data);
else emit_data(data, Relocation::spec_simple(rtype), format);
}
@@ -201,7 +202,7 @@
else
code_section()->relocate(inst_mark(), rspec, format);
}
- emit_long(data);
+ emit_int32(data);
}
static int encode(Register r) {
@@ -225,9 +226,9 @@
assert(isByte(op1) && isByte(op2), "wrong opcode");
assert(isByte(imm8), "not a byte");
assert((op1 & 0x01) == 0, "should be 8bit operation");
- emit_byte(op1);
- emit_byte(op2 | encode(dst));
- emit_byte(imm8);
+ emit_int8(op1);
+ emit_int8(op2 | encode(dst));
+ emit_int8(imm8);
}
@@ -236,13 +237,13 @@
assert((op1 & 0x01) == 1, "should be 32bit operation");
assert((op1 & 0x02) == 0, "sign-extension bit should not be set");
if (is8bit(imm32)) {
- emit_byte(op1 | 0x02); // set sign bit
- emit_byte(op2 | encode(dst));
- emit_byte(imm32 & 0xFF);
+ emit_int8(op1 | 0x02); // set sign bit
+ emit_int8(op2 | encode(dst));
+ emit_int8(imm32 & 0xFF);
} else {
- emit_byte(op1);
- emit_byte(op2 | encode(dst));
- emit_long(imm32);
+ emit_int8(op1);
+ emit_int8(op2 | encode(dst));
+ emit_int32(imm32);
}
}
@@ -251,9 +252,9 @@
assert(isByte(op1) && isByte(op2), "wrong opcode");
assert((op1 & 0x01) == 1, "should be 32bit operation");
assert((op1 & 0x02) == 0, "sign-extension bit should not be set");
- emit_byte(op1);
- emit_byte(op2 | encode(dst));
- emit_long(imm32);
+ emit_int8(op1);
+ emit_int8(op2 | encode(dst));
+ emit_int32(imm32);
}
// immediate-to-memory forms
@@ -261,21 +262,21 @@
assert((op1 & 0x01) == 1, "should be 32bit operation");
assert((op1 & 0x02) == 0, "sign-extension bit should not be set");
if (is8bit(imm32)) {
- emit_byte(op1 | 0x02); // set sign bit
+ emit_int8(op1 | 0x02); // set sign bit
emit_operand(rm, adr, 1);
- emit_byte(imm32 & 0xFF);
+ emit_int8(imm32 & 0xFF);
} else {
- emit_byte(op1);
+ emit_int8(op1);
emit_operand(rm, adr, 4);
- emit_long(imm32);
+ emit_int32(imm32);
}
}
void Assembler::emit_arith(int op1, int op2, Register dst, Register src) {
assert(isByte(op1) && isByte(op2), "wrong opcode");
- emit_byte(op1);
- emit_byte(op2 | encode(dst) << 3 | encode(src));
+ emit_int8(op1);
+ emit_int8(op2 | encode(dst) << 3 | encode(src));
}
@@ -300,21 +301,21 @@
// [base + index*scale]
// [00 reg 100][ss index base]
assert(index != rsp, "illegal addressing mode");
- emit_byte(0x04 | regenc);
- emit_byte(scale << 6 | indexenc | baseenc);
+ emit_int8(0x04 | regenc);
+ emit_int8(scale << 6 | indexenc | baseenc);
} else if (is8bit(disp) && rtype == relocInfo::none) {
// [base + index*scale + imm8]
// [01 reg 100][ss index base] imm8
assert(index != rsp, "illegal addressing mode");
- emit_byte(0x44 | regenc);
- emit_byte(scale << 6 | indexenc | baseenc);
- emit_byte(disp & 0xFF);
+ emit_int8(0x44 | regenc);
+ emit_int8(scale << 6 | indexenc | baseenc);
+ emit_int8(disp & 0xFF);
} else {
// [base + index*scale + disp32]
// [10 reg 100][ss index base] disp32
assert(index != rsp, "illegal addressing mode");
- emit_byte(0x84 | regenc);
- emit_byte(scale << 6 | indexenc | baseenc);
+ emit_int8(0x84 | regenc);
+ emit_int8(scale << 6 | indexenc | baseenc);
emit_data(disp, rspec, disp32_operand);
}
} else if (base == rsp LP64_ONLY(|| base == r12)) {
@@ -322,19 +323,19 @@
if (disp == 0 && rtype == relocInfo::none) {
// [rsp]
// [00 reg 100][00 100 100]
- emit_byte(0x04 | regenc);
- emit_byte(0x24);
+ emit_int8(0x04 | regenc);
+ emit_int8(0x24);
} else if (is8bit(disp) && rtype == relocInfo::none) {
// [rsp + imm8]
// [01 reg 100][00 100 100] disp8
- emit_byte(0x44 | regenc);
- emit_byte(0x24);
- emit_byte(disp & 0xFF);
+ emit_int8(0x44 | regenc);
+ emit_int8(0x24);
+ emit_int8(disp & 0xFF);
} else {
// [rsp + imm32]
// [10 reg 100][00 100 100] disp32
- emit_byte(0x84 | regenc);
- emit_byte(0x24);
+ emit_int8(0x84 | regenc);
+ emit_int8(0x24);
emit_data(disp, rspec, disp32_operand);
}
} else {
@@ -344,16 +345,16 @@
base != rbp LP64_ONLY(&& base != r13)) {
// [base]
// [00 reg base]
- emit_byte(0x00 | regenc | baseenc);
+ emit_int8(0x00 | regenc | baseenc);
} else if (is8bit(disp) && rtype == relocInfo::none) {
// [base + disp8]
// [01 reg base] disp8
- emit_byte(0x40 | regenc | baseenc);
- emit_byte(disp & 0xFF);
+ emit_int8(0x40 | regenc | baseenc);
+ emit_int8(disp & 0xFF);
} else {
// [base + disp32]
// [10 reg base] disp32
- emit_byte(0x80 | regenc | baseenc);
+ emit_int8(0x80 | regenc | baseenc);
emit_data(disp, rspec, disp32_operand);
}
}
@@ -363,14 +364,14 @@
// [index*scale + disp]
// [00 reg 100][ss index 101] disp32
assert(index != rsp, "illegal addressing mode");
- emit_byte(0x04 | regenc);
- emit_byte(scale << 6 | indexenc | 0x05);
+ emit_int8(0x04 | regenc);
+ emit_int8(scale << 6 | indexenc | 0x05);
emit_data(disp, rspec, disp32_operand);
} else if (rtype != relocInfo::none ) {
// [disp] (64bit) RIP-RELATIVE (32bit) abs
// [00 000 101] disp32
- emit_byte(0x05 | regenc);
+ emit_int8(0x05 | regenc);
// Note that the RIP-rel. correction applies to the generated
// disp field, but _not_ to the target address in the rspec.
@@ -390,8 +391,8 @@
// 32bit never did this, did everything as the rip-rel/disp code above
// [disp] ABSOLUTE
// [00 reg 100][00 100 101] disp32
- emit_byte(0x04 | regenc);
- emit_byte(0x25);
+ emit_int8(0x04 | regenc);
+ emit_int8(0x25);
emit_data(disp, rspec, disp32_operand);
}
}
@@ -882,8 +883,8 @@
void Assembler::emit_farith(int b1, int b2, int i) {
assert(isByte(b1) && isByte(b2), "wrong opcode");
assert(0 <= i && i < 8, "illegal stack offset");
- emit_byte(b1);
- emit_byte(b2 + i);
+ emit_int8(b1);
+ emit_int8(b2 + i);
}
@@ -898,7 +899,7 @@
void Assembler::adcl(Address dst, Register src) {
InstructionMark im(this);
prefix(dst, src);
- emit_byte(0x11);
+ emit_int8(0x11);
emit_operand(src, dst);
}
@@ -910,7 +911,7 @@
void Assembler::adcl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
- emit_byte(0x13);
+ emit_int8(0x13);
emit_operand(dst, src);
}
@@ -928,7 +929,7 @@
void Assembler::addl(Address dst, Register src) {
InstructionMark im(this);
prefix(dst, src);
- emit_byte(0x01);
+ emit_int8(0x01);
emit_operand(src, dst);
}
@@ -940,7 +941,7 @@
void Assembler::addl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
- emit_byte(0x03);
+ emit_int8(0x03);
emit_operand(dst, src);
}
@@ -952,39 +953,41 @@
void Assembler::addr_nop_4() {
assert(UseAddressNop, "no CPU support");
// 4 bytes: NOP DWORD PTR [EAX+0]
- emit_byte(0x0F);
- emit_byte(0x1F);
- emit_byte(0x40); // emit_rm(cbuf, 0x1, EAX_enc, EAX_enc);
- emit_byte(0); // 8-bits offset (1 byte)
+ emit_int8(0x0F);
+ emit_int8(0x1F);
+ emit_int8(0x40); // emit_rm(cbuf, 0x1, EAX_enc, EAX_enc);
+ emit_int8(0); // 8-bits offset (1 byte)
}
void Assembler::addr_nop_5() {
assert(UseAddressNop, "no CPU support");
// 5 bytes: NOP DWORD PTR [EAX+EAX*0+0] 8-bits offset
- emit_byte(0x0F);
- emit_byte(0x1F);
- emit_byte(0x44); // emit_rm(cbuf, 0x1, EAX_enc, 0x4);
- emit_byte(0x00); // emit_rm(cbuf, 0x0, EAX_enc, EAX_enc);
- emit_byte(0); // 8-bits offset (1 byte)
+ emit_int8(0x0F);
+ emit_int8(0x1F);
+ emit_int8(0x44); // emit_rm(cbuf, 0x1, EAX_enc, 0x4);
+ emit_int8(0x00); // emit_rm(cbuf, 0x0, EAX_enc, EAX_enc);
+ emit_int8(0); // 8-bits offset (1 byte)
}
void Assembler::addr_nop_7() {
assert(UseAddressNop, "no CPU support");
// 7 bytes: NOP DWORD PTR [EAX+0] 32-bits offset
- emit_byte(0x0F);
- emit_byte(0x1F);
- emit_byte(0x80); // emit_rm(cbuf, 0x2, EAX_enc, EAX_enc);
- emit_long(0); // 32-bits offset (4 bytes)
+ emit_int8(0x0F);
+ emit_int8(0x1F);
+ emit_int8((unsigned char)0x80);
+ // emit_rm(cbuf, 0x2, EAX_enc, EAX_enc);
+ emit_int32(0); // 32-bits offset (4 bytes)
}
void Assembler::addr_nop_8() {
assert(UseAddressNop, "no CPU support");
// 8 bytes: NOP DWORD PTR [EAX+EAX*0+0] 32-bits offset
- emit_byte(0x0F);
- emit_byte(0x1F);
- emit_byte(0x84); // emit_rm(cbuf, 0x2, EAX_enc, 0x4);
- emit_byte(0x00); // emit_rm(cbuf, 0x0, EAX_enc, EAX_enc);
- emit_long(0); // 32-bits offset (4 bytes)
+ emit_int8(0x0F);
+ emit_int8(0x1F);
+ emit_int8((unsigned char)0x84);
+ // emit_rm(cbuf, 0x2, EAX_enc, 0x4);
+ emit_int8(0x00); // emit_rm(cbuf, 0x0, EAX_enc, EAX_enc);
+ emit_int32(0); // 32-bits offset (4 bytes)
}
void Assembler::addsd(XMMRegister dst, XMMRegister src) {
@@ -1007,12 +1010,73 @@
emit_simd_arith(0x58, dst, src, VEX_SIMD_F3);
}
+void Assembler::aesdec(XMMRegister dst, Address src) {
+ assert(VM_Version::supports_aes(), "");
+ InstructionMark im(this);
+ simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38);
+ emit_int8((unsigned char)0xDE);
+ emit_operand(dst, src);
+}
+
+void Assembler::aesdec(XMMRegister dst, XMMRegister src) {
+ assert(VM_Version::supports_aes(), "");
+ int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38);
+ emit_int8((unsigned char)0xDE);
+ emit_int8(0xC0 | encode);
+}
+
+void Assembler::aesdeclast(XMMRegister dst, Address src) {
+ assert(VM_Version::supports_aes(), "");
+ InstructionMark im(this);
+ simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38);
+ emit_int8((unsigned char)0xDF);
+ emit_operand(dst, src);
+}
+
+void Assembler::aesdeclast(XMMRegister dst, XMMRegister src) {
+ assert(VM_Version::supports_aes(), "");
+ int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38);
+ emit_int8((unsigned char)0xDF);
+ emit_int8((unsigned char)(0xC0 | encode));
+}
+
+void Assembler::aesenc(XMMRegister dst, Address src) {
+ assert(VM_Version::supports_aes(), "");
+ InstructionMark im(this);
+ simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38);
+ emit_int8((unsigned char)0xDC);
+ emit_operand(dst, src);
+}
+
+void Assembler::aesenc(XMMRegister dst, XMMRegister src) {
+ assert(VM_Version::supports_aes(), "");
+ int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38);
+ emit_int8((unsigned char)0xDC);
+ emit_int8(0xC0 | encode);
+}
+
+void Assembler::aesenclast(XMMRegister dst, Address src) {
+ assert(VM_Version::supports_aes(), "");
+ InstructionMark im(this);
+ simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38);
+ emit_int8((unsigned char)0xDD);
+ emit_operand(dst, src);
+}
+
+void Assembler::aesenclast(XMMRegister dst, XMMRegister src) {
+ assert(VM_Version::supports_aes(), "");
+ int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38);
+ emit_int8((unsigned char)0xDD);
+ emit_int8((unsigned char)(0xC0 | encode));
+}
+
+
void Assembler::andl(Address dst, int32_t imm32) {
InstructionMark im(this);
prefix(dst);
- emit_byte(0x81);
+ emit_int8((unsigned char)0x81);
emit_operand(rsp, dst, 4);
- emit_long(imm32);
+ emit_int32(imm32);
}
void Assembler::andl(Register dst, int32_t imm32) {
@@ -1023,7 +1087,7 @@
void Assembler::andl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
- emit_byte(0x23);
+ emit_int8(0x23);
emit_operand(dst, src);
}
@@ -1034,23 +1098,23 @@
void Assembler::bsfl(Register dst, Register src) {
int encode = prefix_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0xBC);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xBC);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::bsrl(Register dst, Register src) {
assert(!VM_Version::supports_lzcnt(), "encoding is treated as LZCNT");
int encode = prefix_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0xBD);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xBD);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::bswapl(Register reg) { // bswap
int encode = prefix_and_encode(reg->encoding());
- emit_byte(0x0F);
- emit_byte(0xC8 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)(0xC8 | encode));
}
void Assembler::call(Label& L, relocInfo::relocType rtype) {
@@ -1063,37 +1127,37 @@
assert(offs <= 0, "assembler error");
InstructionMark im(this);
// 1110 1000 #32-bit disp
- emit_byte(0xE8);
+ emit_int8((unsigned char)0xE8);
emit_data(offs - long_size, rtype, operand);
} else {
InstructionMark im(this);
// 1110 1000 #32-bit disp
L.add_patch_at(code(), locator());
- emit_byte(0xE8);
+ emit_int8((unsigned char)0xE8);
emit_data(int(0), rtype, operand);
}
}
void Assembler::call(Register dst) {
int encode = prefix_and_encode(dst->encoding());
- emit_byte(0xFF);
- emit_byte(0xD0 | encode);
+ emit_int8((unsigned char)0xFF);
+ emit_int8((unsigned char)(0xD0 | encode));
}
void Assembler::call(Address adr) {
InstructionMark im(this);
prefix(adr);
- emit_byte(0xFF);
+ emit_int8((unsigned char)0xFF);
emit_operand(rdx, adr);
}
void Assembler::call_literal(address entry, RelocationHolder const& rspec) {
assert(entry != NULL, "call most probably wrong");
InstructionMark im(this);
- emit_byte(0xE8);
- intptr_t disp = entry - (_code_pos + sizeof(int32_t));
+ emit_int8((unsigned char)0xE8);
+ intptr_t disp = entry - (pc() + sizeof(int32_t));
assert(is_simm32(disp), "must be 32bit offset (call2)");
// Technically, should use call32_operand, but this format is
// implied by the fact that we're emitting a call instruction.
@@ -1103,40 +1167,44 @@
}
void Assembler::cdql() {
- emit_byte(0x99);
+ emit_int8((unsigned char)0x99);
+}
+
+void Assembler::cld() {
+ emit_int8((unsigned char)0xFC);
}
void Assembler::cmovl(Condition cc, Register dst, Register src) {
NOT_LP64(guarantee(VM_Version::supports_cmov(), "illegal instruction"));
int encode = prefix_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0x40 | cc);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8(0x40 | cc);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::cmovl(Condition cc, Register dst, Address src) {
NOT_LP64(guarantee(VM_Version::supports_cmov(), "illegal instruction"));
prefix(src, dst);
- emit_byte(0x0F);
- emit_byte(0x40 | cc);
+ emit_int8(0x0F);
+ emit_int8(0x40 | cc);
emit_operand(dst, src);
}
void Assembler::cmpb(Address dst, int imm8) {
InstructionMark im(this);
prefix(dst);
- emit_byte(0x80);
+ emit_int8((unsigned char)0x80);
emit_operand(rdi, dst, 1);
- emit_byte(imm8);
+ emit_int8(imm8);
}
void Assembler::cmpl(Address dst, int32_t imm32) {
InstructionMark im(this);
prefix(dst);
- emit_byte(0x81);
+ emit_int8((unsigned char)0x81);
emit_operand(rdi, dst, 4);
- emit_long(imm32);
+ emit_int32(imm32);
}
void Assembler::cmpl(Register dst, int32_t imm32) {
@@ -1153,17 +1221,17 @@
void Assembler::cmpl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
- emit_byte(0x3B);
+ emit_int8((unsigned char)0x3B);
emit_operand(dst, src);
}
void Assembler::cmpw(Address dst, int imm16) {
InstructionMark im(this);
assert(!dst.base_needs_rex() && !dst.index_needs_rex(), "no extended registers");
- emit_byte(0x66);
- emit_byte(0x81);
+ emit_int8(0x66);
+ emit_int8((unsigned char)0x81);
emit_operand(rdi, dst, 2);
- emit_word(imm16);
+ emit_int16(imm16);
}
// The 32-bit cmpxchg compares the value at adr with the contents of rax,
@@ -1172,8 +1240,8 @@
void Assembler::cmpxchgl(Register reg, Address adr) { // cmpxchg
InstructionMark im(this);
prefix(adr, reg);
- emit_byte(0x0F);
- emit_byte(0xB1);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xB1);
emit_operand(reg, adr);
}
@@ -1199,6 +1267,11 @@
emit_simd_arith_nonds(0x2F, dst, src, VEX_SIMD_NONE);
}
+void Assembler::cpuid() {
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xA2);
+}
+
void Assembler::cvtdq2pd(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
emit_simd_arith_nonds(0xE6, dst, src, VEX_SIMD_F3);
@@ -1222,8 +1295,8 @@
void Assembler::cvtsi2sdl(XMMRegister dst, Register src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F2);
- emit_byte(0x2A);
- emit_byte(0xC0 | encode);
+ emit_int8(0x2A);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::cvtsi2sdl(XMMRegister dst, Address src) {
@@ -1234,8 +1307,8 @@
void Assembler::cvtsi2ssl(XMMRegister dst, Register src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3);
- emit_byte(0x2A);
- emit_byte(0xC0 | encode);
+ emit_int8(0x2A);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::cvtsi2ssl(XMMRegister dst, Address src) {
@@ -1257,22 +1330,22 @@
void Assembler::cvttsd2sil(Register dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
int encode = simd_prefix_and_encode(dst, src, VEX_SIMD_F2);
- emit_byte(0x2C);
- emit_byte(0xC0 | encode);
+ emit_int8(0x2C);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::cvttss2sil(Register dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
int encode = simd_prefix_and_encode(dst, src, VEX_SIMD_F3);
- emit_byte(0x2C);
- emit_byte(0xC0 | encode);
+ emit_int8(0x2C);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::decl(Address dst) {
// Don't use it directly. Use MacroAssembler::decrement() instead.
InstructionMark im(this);
prefix(dst);
- emit_byte(0xFF);
+ emit_int8((unsigned char)0xFF);
emit_operand(rcx, dst);
}
@@ -1298,44 +1371,44 @@
void Assembler::emms() {
NOT_LP64(assert(VM_Version::supports_mmx(), ""));
- emit_byte(0x0F);
- emit_byte(0x77);
+ emit_int8(0x0F);
+ emit_int8(0x77);
}
void Assembler::hlt() {
- emit_byte(0xF4);
+ emit_int8((unsigned char)0xF4);
}
void Assembler::idivl(Register src) {
int encode = prefix_and_encode(src->encoding());
- emit_byte(0xF7);
- emit_byte(0xF8 | encode);
+ emit_int8((unsigned char)0xF7);
+ emit_int8((unsigned char)(0xF8 | encode));
}
void Assembler::divl(Register src) { // Unsigned
int encode = prefix_and_encode(src->encoding());
- emit_byte(0xF7);
- emit_byte(0xF0 | encode);
+ emit_int8((unsigned char)0xF7);
+ emit_int8((unsigned char)(0xF0 | encode));
}
void Assembler::imull(Register dst, Register src) {
int encode = prefix_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0xAF);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xAF);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::imull(Register dst, Register src, int value) {
int encode = prefix_and_encode(dst->encoding(), src->encoding());
if (is8bit(value)) {
- emit_byte(0x6B);
- emit_byte(0xC0 | encode);
- emit_byte(value & 0xFF);
+ emit_int8(0x6B);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int8(value & 0xFF);
} else {
- emit_byte(0x69);
- emit_byte(0xC0 | encode);
- emit_long(value);
+ emit_int8(0x69);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int32(value);
}
}
@@ -1343,7 +1416,7 @@
// Don't use it directly. Use MacroAssembler::increment() instead.
InstructionMark im(this);
prefix(dst);
- emit_byte(0xFF);
+ emit_int8((unsigned char)0xFF);
emit_operand(rax, dst);
}
@@ -1356,18 +1429,18 @@
const int short_size = 2;
const int long_size = 6;
- intptr_t offs = (intptr_t)dst - (intptr_t)_code_pos;
+ intptr_t offs = (intptr_t)dst - (intptr_t)pc();
if (maybe_short && is8bit(offs - short_size)) {
// 0111 tttn #8-bit disp
- emit_byte(0x70 | cc);
- emit_byte((offs - short_size) & 0xFF);
+ emit_int8(0x70 | cc);
+ emit_int8((offs - short_size) & 0xFF);
} else {
// 0000 1111 1000 tttn #32-bit disp
assert(is_simm32(offs - long_size),
"must be 32bit offset (call4)");
- emit_byte(0x0F);
- emit_byte(0x80 | cc);
- emit_long(offs - long_size);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)(0x80 | cc));
+ emit_int32(offs - long_size);
}
} else {
// Note: could eliminate cond. jumps to this jump if condition
@@ -1375,9 +1448,9 @@
// Note: use jccb() if label to be bound is very close to get
// an 8-bit displacement
L.add_patch_at(code(), locator());
- emit_byte(0x0F);
- emit_byte(0x80 | cc);
- emit_long(0);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)(0x80 | cc));
+ emit_int32(0);
}
}
@@ -1386,29 +1459,29 @@
const int short_size = 2;
address entry = target(L);
#ifdef ASSERT
- intptr_t dist = (intptr_t)entry - ((intptr_t)_code_pos + short_size);
+ intptr_t dist = (intptr_t)entry - ((intptr_t)pc() + short_size);
intptr_t delta = short_branch_delta();
if (delta != 0) {
dist += (dist < 0 ? (-delta) :delta);
}
assert(is8bit(dist), "Dispacement too large for a short jmp");
#endif
- intptr_t offs = (intptr_t)entry - (intptr_t)_code_pos;
+ intptr_t offs = (intptr_t)entry - (intptr_t)pc();
// 0111 tttn #8-bit disp
- emit_byte(0x70 | cc);
- emit_byte((offs - short_size) & 0xFF);
+ emit_int8(0x70 | cc);
+ emit_int8((offs - short_size) & 0xFF);
} else {
InstructionMark im(this);
L.add_patch_at(code(), locator());
- emit_byte(0x70 | cc);
- emit_byte(0);
+ emit_int8(0x70 | cc);
+ emit_int8(0);
}
}
void Assembler::jmp(Address adr) {
InstructionMark im(this);
prefix(adr);
- emit_byte(0xFF);
+ emit_int8((unsigned char)0xFF);
emit_operand(rsp, adr);
}
@@ -1419,13 +1492,13 @@
InstructionMark im(this);
const int short_size = 2;
const int long_size = 5;
- intptr_t offs = entry - _code_pos;
+ intptr_t offs = entry - pc();
if (maybe_short && is8bit(offs - short_size)) {
- emit_byte(0xEB);
- emit_byte((offs - short_size) & 0xFF);
+ emit_int8((unsigned char)0xEB);
+ emit_int8((offs - short_size) & 0xFF);
} else {
- emit_byte(0xE9);
- emit_long(offs - long_size);
+ emit_int8((unsigned char)0xE9);
+ emit_int32(offs - long_size);
}
} else {
// By default, forward jumps are always 32-bit displacements, since
@@ -1434,22 +1507,22 @@
// force an 8-bit displacement.
InstructionMark im(this);
L.add_patch_at(code(), locator());
- emit_byte(0xE9);
- emit_long(0);
+ emit_int8((unsigned char)0xE9);
+ emit_int32(0);
}
}
void Assembler::jmp(Register entry) {
int encode = prefix_and_encode(entry->encoding());
- emit_byte(0xFF);
- emit_byte(0xE0 | encode);
+ emit_int8((unsigned char)0xFF);
+ emit_int8((unsigned char)(0xE0 | encode));
}
void Assembler::jmp_literal(address dest, RelocationHolder const& rspec) {
InstructionMark im(this);
- emit_byte(0xE9);
+ emit_int8((unsigned char)0xE9);
assert(dest != NULL, "must have a target");
- intptr_t disp = dest - (_code_pos + sizeof(int32_t));
+ intptr_t disp = dest - (pc() + sizeof(int32_t));
assert(is_simm32(disp), "must be 32bit offset (jmp)");
emit_data(disp, rspec.reloc(), call32_operand);
}
@@ -1460,21 +1533,21 @@
address entry = target(L);
assert(entry != NULL, "jmp most probably wrong");
#ifdef ASSERT
- intptr_t dist = (intptr_t)entry - ((intptr_t)_code_pos + short_size);
+ intptr_t dist = (intptr_t)entry - ((intptr_t)pc() + short_size);
intptr_t delta = short_branch_delta();
if (delta != 0) {
dist += (dist < 0 ? (-delta) :delta);
}
assert(is8bit(dist), "Dispacement too large for a short jmp");
#endif
- intptr_t offs = entry - _code_pos;
- emit_byte(0xEB);
- emit_byte((offs - short_size) & 0xFF);
+ intptr_t offs = entry - pc();
+ emit_int8((unsigned char)0xEB);
+ emit_int8((offs - short_size) & 0xFF);
} else {
InstructionMark im(this);
L.add_patch_at(code(), locator());
- emit_byte(0xEB);
- emit_byte(0);
+ emit_int8((unsigned char)0xEB);
+ emit_int8(0);
}
}
@@ -1482,40 +1555,46 @@
NOT_LP64(assert(VM_Version::supports_sse(), ""));
InstructionMark im(this);
prefix(src);
- emit_byte(0x0F);
- emit_byte(0xAE);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xAE);
emit_operand(as_Register(2), src);
}
void Assembler::leal(Register dst, Address src) {
InstructionMark im(this);
#ifdef _LP64
- emit_byte(0x67); // addr32
+ emit_int8(0x67); // addr32
prefix(src, dst);
#endif // LP64
- emit_byte(0x8D);
+ emit_int8((unsigned char)0x8D);
emit_operand(dst, src);
}
+void Assembler::lfence() {
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xAE);
+ emit_int8((unsigned char)0xE8);
+}
+
void Assembler::lock() {
- emit_byte(0xF0);
+ emit_int8((unsigned char)0xF0);
}
void Assembler::lzcntl(Register dst, Register src) {
assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR");
- emit_byte(0xF3);
+ emit_int8((unsigned char)0xF3);
int encode = prefix_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0xBD);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xBD);
+ emit_int8((unsigned char)(0xC0 | encode));
}
// Emit mfence instruction
void Assembler::mfence() {
NOT_LP64(assert(VM_Version::supports_sse2(), "unsupported");)
- emit_byte( 0x0F );
- emit_byte( 0xAE );
- emit_byte( 0xF0 );
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xAE);
+ emit_int8((unsigned char)0xF0);
}
void Assembler::mov(Register dst, Register src) {
@@ -1535,15 +1614,15 @@
void Assembler::movlhps(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
int encode = simd_prefix_and_encode(dst, src, src, VEX_SIMD_NONE);
- emit_byte(0x16);
- emit_byte(0xC0 | encode);
+ emit_int8(0x16);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::movb(Register dst, Address src) {
NOT_LP64(assert(dst->has_byte_register(), "must have byte register"));
InstructionMark im(this);
prefix(src, dst, true);
- emit_byte(0x8A);
+ emit_int8((unsigned char)0x8A);
emit_operand(dst, src);
}
@@ -1551,9 +1630,9 @@
void Assembler::movb(Address dst, int imm8) {
InstructionMark im(this);
prefix(dst);
- emit_byte(0xC6);
+ emit_int8((unsigned char)0xC6);
emit_operand(rax, dst, 1);
- emit_byte(imm8);
+ emit_int8(imm8);
}
@@ -1561,30 +1640,30 @@
assert(src->has_byte_register(), "must have byte register");
InstructionMark im(this);
prefix(dst, src, true);
- emit_byte(0x88);
+ emit_int8((unsigned char)0x88);
emit_operand(src, dst);
}
void Assembler::movdl(XMMRegister dst, Register src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
int encode = simd_prefix_and_encode(dst, src, VEX_SIMD_66);
- emit_byte(0x6E);
- emit_byte(0xC0 | encode);
+ emit_int8(0x6E);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::movdl(Register dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
// swap src/dst to get correct prefix
int encode = simd_prefix_and_encode(src, dst, VEX_SIMD_66);
- emit_byte(0x7E);
- emit_byte(0xC0 | encode);
+ emit_int8(0x7E);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::movdl(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
simd_prefix(dst, src, VEX_SIMD_66);
- emit_byte(0x6E);
+ emit_int8(0x6E);
emit_operand(dst, src);
}
@@ -1592,7 +1671,7 @@
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
simd_prefix(dst, src, VEX_SIMD_66);
- emit_byte(0x7E);
+ emit_int8(0x7E);
emit_operand(src, dst);
}
@@ -1615,7 +1694,7 @@
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
simd_prefix(dst, src, VEX_SIMD_F3);
- emit_byte(0x7F);
+ emit_int8(0x7F);
emit_operand(src, dst);
}
@@ -1624,8 +1703,8 @@
assert(UseAVX, "");
bool vector256 = true;
int encode = vex_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_F3, vector256);
- emit_byte(0x6F);
- emit_byte(0xC0 | encode);
+ emit_int8(0x6F);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::vmovdqu(XMMRegister dst, Address src) {
@@ -1633,7 +1712,7 @@
InstructionMark im(this);
bool vector256 = true;
vex_prefix(dst, xnoreg, src, VEX_SIMD_F3, vector256);
- emit_byte(0x6F);
+ emit_int8(0x6F);
emit_operand(dst, src);
}
@@ -1644,7 +1723,7 @@
// swap src<->dst for encoding
assert(src != xnoreg, "sanity");
vex_prefix(src, xnoreg, dst, VEX_SIMD_F3, vector256);
- emit_byte(0x7F);
+ emit_int8(0x7F);
emit_operand(src, dst);
}
@@ -1652,35 +1731,35 @@
void Assembler::movl(Register dst, int32_t imm32) {
int encode = prefix_and_encode(dst->encoding());
- emit_byte(0xB8 | encode);
- emit_long(imm32);
+ emit_int8((unsigned char)(0xB8 | encode));
+ emit_int32(imm32);
}
void Assembler::movl(Register dst, Register src) {
int encode = prefix_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x8B);
- emit_byte(0xC0 | encode);
+ emit_int8((unsigned char)0x8B);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::movl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
- emit_byte(0x8B);
+ emit_int8((unsigned char)0x8B);
emit_operand(dst, src);
}
void Assembler::movl(Address dst, int32_t imm32) {
InstructionMark im(this);
prefix(dst);
- emit_byte(0xC7);
+ emit_int8((unsigned char)0xC7);
emit_operand(rax, dst, 4);
- emit_long(imm32);
+ emit_int32(imm32);
}
void Assembler::movl(Address dst, Register src) {
InstructionMark im(this);
prefix(dst, src);
- emit_byte(0x89);
+ emit_int8((unsigned char)0x89);
emit_operand(src, dst);
}
@@ -1694,15 +1773,15 @@
void Assembler::movq( MMXRegister dst, Address src ) {
assert( VM_Version::supports_mmx(), "" );
- emit_byte(0x0F);
- emit_byte(0x6F);
+ emit_int8(0x0F);
+ emit_int8(0x6F);
emit_operand(dst, src);
}
void Assembler::movq( Address dst, MMXRegister src ) {
assert( VM_Version::supports_mmx(), "" );
- emit_byte(0x0F);
- emit_byte(0x7F);
+ emit_int8(0x0F);
+ emit_int8(0x7F);
// workaround gcc (3.2.1-7a) bug
// In that version of gcc with only an emit_operand(MMX, Address)
// gcc will tail jump and try and reverse the parameters completely
@@ -1716,7 +1795,7 @@
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
simd_prefix(dst, src, VEX_SIMD_F3);
- emit_byte(0x7E);
+ emit_int8(0x7E);
emit_operand(dst, src);
}
@@ -1724,24 +1803,24 @@
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
simd_prefix(dst, src, VEX_SIMD_66);
- emit_byte(0xD6);
+ emit_int8((unsigned char)0xD6);
emit_operand(src, dst);
}
void Assembler::movsbl(Register dst, Address src) { // movsxb
InstructionMark im(this);
prefix(src, dst);
- emit_byte(0x0F);
- emit_byte(0xBE);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xBE);
emit_operand(dst, src);
}
void Assembler::movsbl(Register dst, Register src) { // movsxb
NOT_LP64(assert(src->has_byte_register(), "must have byte register"));
int encode = prefix_and_encode(dst->encoding(), src->encoding(), true);
- emit_byte(0x0F);
- emit_byte(0xBE);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xBE);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::movsd(XMMRegister dst, XMMRegister src) {
@@ -1758,7 +1837,7 @@
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
simd_prefix(dst, src, VEX_SIMD_F2);
- emit_byte(0x11);
+ emit_int8(0x11);
emit_operand(src, dst);
}
@@ -1776,93 +1855,93 @@
NOT_LP64(assert(VM_Version::supports_sse(), ""));
InstructionMark im(this);
simd_prefix(dst, src, VEX_SIMD_F3);
- emit_byte(0x11);
+ emit_int8(0x11);
emit_operand(src, dst);
}
void Assembler::movswl(Register dst, Address src) { // movsxw
InstructionMark im(this);
prefix(src, dst);
- emit_byte(0x0F);
- emit_byte(0xBF);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xBF);
emit_operand(dst, src);
}
void Assembler::movswl(Register dst, Register src) { // movsxw
int encode = prefix_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0xBF);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xBF);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::movw(Address dst, int imm16) {
InstructionMark im(this);
- emit_byte(0x66); // switch to 16-bit mode
+ emit_int8(0x66); // switch to 16-bit mode
prefix(dst);
- emit_byte(0xC7);
+ emit_int8((unsigned char)0xC7);
emit_operand(rax, dst, 2);
- emit_word(imm16);
+ emit_int16(imm16);
}
void Assembler::movw(Register dst, Address src) {
InstructionMark im(this);
- emit_byte(0x66);
+ emit_int8(0x66);
prefix(src, dst);
- emit_byte(0x8B);
+ emit_int8((unsigned char)0x8B);
emit_operand(dst, src);
}
void Assembler::movw(Address dst, Register src) {
InstructionMark im(this);
- emit_byte(0x66);
+ emit_int8(0x66);
prefix(dst, src);
- emit_byte(0x89);
+ emit_int8((unsigned char)0x89);
emit_operand(src, dst);
}
void Assembler::movzbl(Register dst, Address src) { // movzxb
InstructionMark im(this);
prefix(src, dst);
- emit_byte(0x0F);
- emit_byte(0xB6);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xB6);
emit_operand(dst, src);
}
void Assembler::movzbl(Register dst, Register src) { // movzxb
NOT_LP64(assert(src->has_byte_register(), "must have byte register"));
int encode = prefix_and_encode(dst->encoding(), src->encoding(), true);
- emit_byte(0x0F);
- emit_byte(0xB6);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xB6);
+ emit_int8(0xC0 | encode);
}
void Assembler::movzwl(Register dst, Address src) { // movzxw
InstructionMark im(this);
prefix(src, dst);
- emit_byte(0x0F);
- emit_byte(0xB7);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xB7);
emit_operand(dst, src);
}
void Assembler::movzwl(Register dst, Register src) { // movzxw
int encode = prefix_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0xB7);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xB7);
+ emit_int8(0xC0 | encode);
}
void Assembler::mull(Address src) {
InstructionMark im(this);
prefix(src);
- emit_byte(0xF7);
+ emit_int8((unsigned char)0xF7);
emit_operand(rsp, src);
}
void Assembler::mull(Register src) {
int encode = prefix_and_encode(src->encoding());
- emit_byte(0xF7);
- emit_byte(0xE0 | encode);
+ emit_int8((unsigned char)0xF7);
+ emit_int8((unsigned char)(0xE0 | encode));
}
void Assembler::mulsd(XMMRegister dst, Address src) {
@@ -1887,8 +1966,8 @@
void Assembler::negl(Register dst) {
int encode = prefix_and_encode(dst->encoding());
- emit_byte(0xF7);
- emit_byte(0xD8 | encode);
+ emit_int8((unsigned char)0xF7);
+ emit_int8((unsigned char)(0xD8 | encode));
}
void Assembler::nop(int i) {
@@ -1899,7 +1978,7 @@
// speed is not an issue so simply use the single byte traditional nop
// to do alignment.
- for (; i > 0 ; i--) emit_byte(0x90);
+ for (; i > 0 ; i--) emit_int8((unsigned char)0x90);
return;
#endif // ASSERT
@@ -1929,33 +2008,35 @@
while(i >= 15) {
// For Intel don't generate consecutive addess nops (mix with regular nops)
i -= 15;
- emit_byte(0x66); // size prefix
- emit_byte(0x66); // size prefix
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
+ emit_int8(0x66); // size prefix
+ emit_int8(0x66); // size prefix
addr_nop_8();
- emit_byte(0x66); // size prefix
- emit_byte(0x66); // size prefix
- emit_byte(0x66); // size prefix
- emit_byte(0x90); // nop
+ emit_int8(0x66); // size prefix
+ emit_int8(0x66); // size prefix
+ emit_int8(0x66); // size prefix
+ emit_int8((unsigned char)0x90);
+ // nop
}
switch (i) {
case 14:
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 13:
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 12:
addr_nop_8();
- emit_byte(0x66); // size prefix
- emit_byte(0x66); // size prefix
- emit_byte(0x66); // size prefix
- emit_byte(0x90); // nop
+ emit_int8(0x66); // size prefix
+ emit_int8(0x66); // size prefix
+ emit_int8(0x66); // size prefix
+ emit_int8((unsigned char)0x90);
+ // nop
break;
case 11:
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 10:
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 9:
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 8:
addr_nop_8();
break;
@@ -1963,7 +2044,7 @@
addr_nop_7();
break;
case 6:
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 5:
addr_nop_5();
break;
@@ -1972,11 +2053,12 @@
break;
case 3:
// Don't use "0x0F 0x1F 0x00" - need patching safe padding
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 2:
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 1:
- emit_byte(0x90); // nop
+ emit_int8((unsigned char)0x90);
+ // nop
break;
default:
assert(i == 0, " ");
@@ -2009,24 +2091,24 @@
while(i >= 22) {
i -= 11;
- emit_byte(0x66); // size prefix
- emit_byte(0x66); // size prefix
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
+ emit_int8(0x66); // size prefix
+ emit_int8(0x66); // size prefix
addr_nop_8();
}
// Generate first nop for size between 21-12
switch (i) {
case 21:
i -= 1;
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 20:
case 19:
i -= 1;
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 18:
case 17:
i -= 1;
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 16:
case 15:
i -= 8;
@@ -2039,7 +2121,7 @@
break;
case 12:
i -= 6;
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
addr_nop_5();
break;
default:
@@ -2049,11 +2131,11 @@
// Generate second nop for size between 11-1
switch (i) {
case 11:
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 10:
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 9:
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 8:
addr_nop_8();
break;
@@ -2061,7 +2143,7 @@
addr_nop_7();
break;
case 6:
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 5:
addr_nop_5();
break;
@@ -2070,11 +2152,12 @@
break;
case 3:
// Don't use "0x0F 0x1F 0x00" - need patching safe padding
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 2:
- emit_byte(0x66); // size prefix
+ emit_int8(0x66); // size prefix
case 1:
- emit_byte(0x90); // nop
+ emit_int8((unsigned char)0x90);
+ // nop
break;
default:
assert(i == 0, " ");
@@ -2097,42 +2180,43 @@
//
while(i > 12) {
i -= 4;
- emit_byte(0x66); // size prefix
- emit_byte(0x66);
- emit_byte(0x66);
- emit_byte(0x90); // nop
+ emit_int8(0x66); // size prefix
+ emit_int8(0x66);
+ emit_int8(0x66);
+ emit_int8((unsigned char)0x90);
+ // nop
}
// 1 - 12 nops
if(i > 8) {
if(i > 9) {
i -= 1;
- emit_byte(0x66);
+ emit_int8(0x66);
}
i -= 3;
- emit_byte(0x66);
- emit_byte(0x66);
- emit_byte(0x90);
+ emit_int8(0x66);
+ emit_int8(0x66);
+ emit_int8((unsigned char)0x90);
}
// 1 - 8 nops
if(i > 4) {
if(i > 6) {
i -= 1;
- emit_byte(0x66);
+ emit_int8(0x66);
}
i -= 3;
- emit_byte(0x66);
- emit_byte(0x66);
- emit_byte(0x90);
+ emit_int8(0x66);
+ emit_int8(0x66);
+ emit_int8((unsigned char)0x90);
}
switch (i) {
case 4:
- emit_byte(0x66);
+ emit_int8(0x66);
case 3:
- emit_byte(0x66);
+ emit_int8(0x66);
case 2:
- emit_byte(0x66);
+ emit_int8(0x66);
case 1:
- emit_byte(0x90);
+ emit_int8((unsigned char)0x90);
break;
default:
assert(i == 0, " ");
@@ -2141,8 +2225,8 @@
void Assembler::notl(Register dst) {
int encode = prefix_and_encode(dst->encoding());
- emit_byte(0xF7);
- emit_byte(0xD0 | encode );
+ emit_int8((unsigned char)0xF7);
+ emit_int8((unsigned char)(0xD0 | encode));
}
void Assembler::orl(Address dst, int32_t imm32) {
@@ -2159,7 +2243,7 @@
void Assembler::orl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
- emit_byte(0x0B);
+ emit_int8(0x0B);
emit_operand(dst, src);
}
@@ -2179,65 +2263,77 @@
emit_simd_arith(0x67, dst, src, VEX_SIMD_66);
}
+void Assembler::vpackuswb(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) {
+ assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2");
+ emit_vex_arith(0x67, dst, nds, src, VEX_SIMD_66, vector256);
+}
+
+void Assembler::vpermq(XMMRegister dst, XMMRegister src, int imm8, bool vector256) {
+ int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A, true, vector256);
+ emit_int8(0x00);
+ emit_int8(0xC0 | encode);
+ emit_int8(imm8);
+}
+
void Assembler::pcmpestri(XMMRegister dst, Address src, int imm8) {
assert(VM_Version::supports_sse4_2(), "");
InstructionMark im(this);
simd_prefix(dst, src, VEX_SIMD_66, VEX_OPCODE_0F_3A);
- emit_byte(0x61);
+ emit_int8(0x61);
emit_operand(dst, src);
- emit_byte(imm8);
+ emit_int8(imm8);
}
void Assembler::pcmpestri(XMMRegister dst, XMMRegister src, int imm8) {
assert(VM_Version::supports_sse4_2(), "");
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_3A);
- emit_byte(0x61);
- emit_byte(0xC0 | encode);
- emit_byte(imm8);
+ emit_int8(0x61);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int8(imm8);
}
void Assembler::pmovzxbw(XMMRegister dst, Address src) {
assert(VM_Version::supports_sse4_1(), "");
InstructionMark im(this);
simd_prefix(dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38);
- emit_byte(0x30);
+ emit_int8(0x30);
emit_operand(dst, src);
}
void Assembler::pmovzxbw(XMMRegister dst, XMMRegister src) {
assert(VM_Version::supports_sse4_1(), "");
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_38);
- emit_byte(0x30);
- emit_byte(0xC0 | encode);
+ emit_int8(0x30);
+ emit_int8((unsigned char)(0xC0 | encode));
}
// generic
void Assembler::pop(Register dst) {
int encode = prefix_and_encode(dst->encoding());
- emit_byte(0x58 | encode);
+ emit_int8(0x58 | encode);
}
void Assembler::popcntl(Register dst, Address src) {
assert(VM_Version::supports_popcnt(), "must support");
InstructionMark im(this);
- emit_byte(0xF3);
+ emit_int8((unsigned char)0xF3);
prefix(src, dst);
- emit_byte(0x0F);
- emit_byte(0xB8);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xB8);
emit_operand(dst, src);
}
void Assembler::popcntl(Register dst, Register src) {
assert(VM_Version::supports_popcnt(), "must support");
- emit_byte(0xF3);
+ emit_int8((unsigned char)0xF3);
int encode = prefix_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0xB8);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xB8);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::popf() {
- emit_byte(0x9D);
+ emit_int8((unsigned char)0x9D);
}
#ifndef _LP64 // no 32bit push/pop on amd64
@@ -2245,21 +2341,21 @@
// NOTE: this will adjust stack by 8byte on 64bits
InstructionMark im(this);
prefix(dst);
- emit_byte(0x8F);
+ emit_int8((unsigned char)0x8F);
emit_operand(rax, dst);
}
#endif
void Assembler::prefetch_prefix(Address src) {
prefix(src);
- emit_byte(0x0F);
+ emit_int8(0x0F);
}
void Assembler::prefetchnta(Address src) {
NOT_LP64(assert(VM_Version::supports_sse(), "must support"));
InstructionMark im(this);
prefetch_prefix(src);
- emit_byte(0x18);
+ emit_int8(0x18);
emit_operand(rax, src); // 0, src
}
@@ -2267,7 +2363,7 @@
assert(VM_Version::supports_3dnow_prefetch(), "must support");
InstructionMark im(this);
prefetch_prefix(src);
- emit_byte(0x0D);
+ emit_int8(0x0D);
emit_operand(rax, src); // 0, src
}
@@ -2275,7 +2371,7 @@
NOT_LP64(assert(VM_Version::supports_sse(), "must support"));
InstructionMark im(this);
prefetch_prefix(src);
- emit_byte(0x18);
+ emit_int8(0x18);
emit_operand(rcx, src); // 1, src
}
@@ -2283,7 +2379,7 @@
NOT_LP64(assert(VM_Version::supports_sse(), "must support"));
InstructionMark im(this);
prefetch_prefix(src);
- emit_byte(0x18);
+ emit_int8(0x18);
emit_operand(rdx, src); // 2, src
}
@@ -2291,7 +2387,7 @@
NOT_LP64(assert(VM_Version::supports_sse(), "must support"));
InstructionMark im(this);
prefetch_prefix(src);
- emit_byte(0x18);
+ emit_int8(0x18);
emit_operand(rbx, src); // 3, src
}
@@ -2299,19 +2395,34 @@
assert(VM_Version::supports_3dnow_prefetch(), "must support");
InstructionMark im(this);
prefetch_prefix(src);
- emit_byte(0x0D);
+ emit_int8(0x0D);
emit_operand(rcx, src); // 1, src
}
void Assembler::prefix(Prefix p) {
- a_byte(p);
+ emit_int8(p);
+}
+
+void Assembler::pshufb(XMMRegister dst, XMMRegister src) {
+ assert(VM_Version::supports_ssse3(), "");
+ int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38);
+ emit_int8(0x00);
+ emit_int8((unsigned char)(0xC0 | encode));
+}
+
+void Assembler::pshufb(XMMRegister dst, Address src) {
+ assert(VM_Version::supports_ssse3(), "");
+ InstructionMark im(this);
+ simd_prefix(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38);
+ emit_int8(0x00);
+ emit_operand(dst, src);
}
void Assembler::pshufd(XMMRegister dst, XMMRegister src, int mode) {
assert(isByte(mode), "invalid value");
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
emit_simd_arith_nonds(0x70, dst, src, VEX_SIMD_66);
- emit_byte(mode & 0xFF);
+ emit_int8(mode & 0xFF);
}
@@ -2321,16 +2432,16 @@
assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes");
InstructionMark im(this);
simd_prefix(dst, src, VEX_SIMD_66);
- emit_byte(0x70);
+ emit_int8(0x70);
emit_operand(dst, src);
- emit_byte(mode & 0xFF);
+ emit_int8(mode & 0xFF);
}
void Assembler::pshuflw(XMMRegister dst, XMMRegister src, int mode) {
assert(isByte(mode), "invalid value");
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
emit_simd_arith_nonds(0x70, dst, src, VEX_SIMD_F2);
- emit_byte(mode & 0xFF);
+ emit_int8(mode & 0xFF);
}
void Assembler::pshuflw(XMMRegister dst, Address src, int mode) {
@@ -2339,18 +2450,18 @@
assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes");
InstructionMark im(this);
simd_prefix(dst, src, VEX_SIMD_F2);
- emit_byte(0x70);
+ emit_int8(0x70);
emit_operand(dst, src);
- emit_byte(mode & 0xFF);
+ emit_int8(mode & 0xFF);
}
void Assembler::psrldq(XMMRegister dst, int shift) {
// Shift 128 bit value in xmm register by number of bytes.
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
int encode = simd_prefix_and_encode(xmm3, dst, dst, VEX_SIMD_66);
- emit_byte(0x73);
- emit_byte(0xC0 | encode);
- emit_byte(shift);
+ emit_int8(0x73);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int8(shift);
}
void Assembler::ptest(XMMRegister dst, Address src) {
@@ -2358,15 +2469,35 @@
assert((UseAVX > 0), "SSE mode requires address alignment 16 bytes");
InstructionMark im(this);
simd_prefix(dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38);
- emit_byte(0x17);
+ emit_int8(0x17);
emit_operand(dst, src);
}
void Assembler::ptest(XMMRegister dst, XMMRegister src) {
assert(VM_Version::supports_sse4_1(), "");
int encode = simd_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, VEX_OPCODE_0F_38);
- emit_byte(0x17);
- emit_byte(0xC0 | encode);
+ emit_int8(0x17);
+ emit_int8((unsigned char)(0xC0 | encode));
+}
+
+void Assembler::vptest(XMMRegister dst, Address src) {
+ assert(VM_Version::supports_avx(), "");
+ InstructionMark im(this);
+ bool vector256 = true;
+ assert(dst != xnoreg, "sanity");
+ int dst_enc = dst->encoding();
+ // swap src<->dst for encoding
+ vex_prefix(src, 0, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, false, vector256);
+ emit_int8(0x17);
+ emit_operand(dst, src);
+}
+
+void Assembler::vptest(XMMRegister dst, XMMRegister src) {
+ assert(VM_Version::supports_avx(), "");
+ bool vector256 = true;
+ int encode = vex_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, vector256, VEX_OPCODE_0F_38);
+ emit_int8(0x17);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::punpcklbw(XMMRegister dst, Address src) {
@@ -2399,18 +2530,18 @@
void Assembler::push(int32_t imm32) {
// in 64bits we push 64bits onto the stack but only
// take a 32bit immediate
- emit_byte(0x68);
- emit_long(imm32);
+ emit_int8(0x68);
+ emit_int32(imm32);
}
void Assembler::push(Register src) {
int encode = prefix_and_encode(src->encoding());
- emit_byte(0x50 | encode);
+ emit_int8(0x50 | encode);
}
void Assembler::pushf() {
- emit_byte(0x9C);
+ emit_int8((unsigned char)0x9C);
}
#ifndef _LP64 // no 32bit push/pop on amd64
@@ -2418,7 +2549,7 @@
// Note this will push 64bit on 64bit
InstructionMark im(this);
prefix(src);
- emit_byte(0xFF);
+ emit_int8((unsigned char)0xFF);
emit_operand(rsi, src);
}
#endif
@@ -2427,58 +2558,64 @@
assert(isShiftCount(imm8), "illegal shift count");
int encode = prefix_and_encode(dst->encoding());
if (imm8 == 1) {
- emit_byte(0xD1);
- emit_byte(0xD0 | encode);
+ emit_int8((unsigned char)0xD1);
+ emit_int8((unsigned char)(0xD0 | encode));
} else {
- emit_byte(0xC1);
- emit_byte(0xD0 | encode);
- emit_byte(imm8);
+ emit_int8((unsigned char)0xC1);
+ emit_int8((unsigned char)0xD0 | encode);
+ emit_int8(imm8);
}
}
// copies data from [esi] to [edi] using rcx pointer sized words
// generic
void Assembler::rep_mov() {
- emit_byte(0xF3);
+ emit_int8((unsigned char)0xF3);
// MOVSQ
LP64_ONLY(prefix(REX_W));
- emit_byte(0xA5);
+ emit_int8((unsigned char)0xA5);
+}
+
+// sets rcx bytes with rax, value at [edi]
+void Assembler::rep_stosb() {
+ emit_int8((unsigned char)0xF3); // REP
+ LP64_ONLY(prefix(REX_W));
+ emit_int8((unsigned char)0xAA); // STOSB
}
// sets rcx pointer sized words with rax, value at [edi]
// generic
-void Assembler::rep_set() { // rep_set
- emit_byte(0xF3);
- // STOSQ
- LP64_ONLY(prefix(REX_W));
- emit_byte(0xAB);
+void Assembler::rep_stos() {
+ emit_int8((unsigned char)0xF3); // REP
+ LP64_ONLY(prefix(REX_W)); // LP64:STOSQ, LP32:STOSD
+ emit_int8((unsigned char)0xAB);
}
// scans rcx pointer sized words at [edi] for occurance of rax,
// generic
void Assembler::repne_scan() { // repne_scan
- emit_byte(0xF2);
+ emit_int8((unsigned char)0xF2);
// SCASQ
LP64_ONLY(prefix(REX_W));
- emit_byte(0xAF);
+ emit_int8((unsigned char)0xAF);
}
#ifdef _LP64
// scans rcx 4 byte words at [edi] for occurance of rax,
// generic
void Assembler::repne_scanl() { // repne_scan
- emit_byte(0xF2);
+ emit_int8((unsigned char)0xF2);
// SCASL
- emit_byte(0xAF);
+ emit_int8((unsigned char)0xAF);
}
#endif
void Assembler::ret(int imm16) {
if (imm16 == 0) {
- emit_byte(0xC3);
+ emit_int8((unsigned char)0xC3);
} else {
- emit_byte(0xC2);
- emit_word(imm16);
+ emit_int8((unsigned char)0xC2);
+ emit_int16(imm16);
}
}
@@ -2487,26 +2624,26 @@
// Not supported in 64bit mode
ShouldNotReachHere();
#endif
- emit_byte(0x9E);
+ emit_int8((unsigned char)0x9E);
}
void Assembler::sarl(Register dst, int imm8) {
int encode = prefix_and_encode(dst->encoding());
assert(isShiftCount(imm8), "illegal shift count");
if (imm8 == 1) {
- emit_byte(0xD1);
- emit_byte(0xF8 | encode);
+ emit_int8((unsigned char)0xD1);
+ emit_int8((unsigned char)(0xF8 | encode));
} else {
- emit_byte(0xC1);
- emit_byte(0xF8 | encode);
- emit_byte(imm8);
+ emit_int8((unsigned char)0xC1);
+ emit_int8((unsigned char)(0xF8 | encode));
+ emit_int8(imm8);
}
}
void Assembler::sarl(Register dst) {
int encode = prefix_and_encode(dst->encoding());
- emit_byte(0xD3);
- emit_byte(0xF8 | encode);
+ emit_int8((unsigned char)0xD3);
+ emit_int8((unsigned char)(0xF8 | encode));
}
void Assembler::sbbl(Address dst, int32_t imm32) {
@@ -2524,7 +2661,7 @@
void Assembler::sbbl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
- emit_byte(0x1B);
+ emit_int8(0x1B);
emit_operand(dst, src);
}
@@ -2536,47 +2673,47 @@
void Assembler::setb(Condition cc, Register dst) {
assert(0 <= cc && cc < 16, "illegal cc");
int encode = prefix_and_encode(dst->encoding(), true);
- emit_byte(0x0F);
- emit_byte(0x90 | cc);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0x90 | cc);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::shll(Register dst, int imm8) {
assert(isShiftCount(imm8), "illegal shift count");
int encode = prefix_and_encode(dst->encoding());
if (imm8 == 1 ) {
- emit_byte(0xD1);
- emit_byte(0xE0 | encode);
+ emit_int8((unsigned char)0xD1);
+ emit_int8((unsigned char)(0xE0 | encode));
} else {
- emit_byte(0xC1);
- emit_byte(0xE0 | encode);
- emit_byte(imm8);
+ emit_int8((unsigned char)0xC1);
+ emit_int8((unsigned char)(0xE0 | encode));
+ emit_int8(imm8);
}
}
void Assembler::shll(Register dst) {
int encode = prefix_and_encode(dst->encoding());
- emit_byte(0xD3);
- emit_byte(0xE0 | encode);
+ emit_int8((unsigned char)0xD3);
+ emit_int8((unsigned char)(0xE0 | encode));
}
void Assembler::shrl(Register dst, int imm8) {
assert(isShiftCount(imm8), "illegal shift count");
int encode = prefix_and_encode(dst->encoding());
- emit_byte(0xC1);
- emit_byte(0xE8 | encode);
- emit_byte(imm8);
+ emit_int8((unsigned char)0xC1);
+ emit_int8((unsigned char)(0xE8 | encode));
+ emit_int8(imm8);
}
void Assembler::shrl(Register dst) {
int encode = prefix_and_encode(dst->encoding());
- emit_byte(0xD3);
- emit_byte(0xE8 | encode);
+ emit_int8((unsigned char)0xD3);
+ emit_int8((unsigned char)(0xE8 | encode));
}
// copies a single word from [esi] to [edi]
void Assembler::smovl() {
- emit_byte(0xA5);
+ emit_int8((unsigned char)0xA5);
}
void Assembler::sqrtsd(XMMRegister dst, XMMRegister src) {
@@ -2594,6 +2731,10 @@
emit_simd_arith(0x51, dst, src, VEX_SIMD_F3);
}
+void Assembler::std() {
+ emit_int8((unsigned char)0xFD);
+}
+
void Assembler::sqrtss(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
emit_simd_arith(0x51, dst, src, VEX_SIMD_F3);
@@ -2603,8 +2744,8 @@
NOT_LP64(assert(VM_Version::supports_sse(), ""));
InstructionMark im(this);
prefix(dst);
- emit_byte(0x0F);
- emit_byte(0xAE);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xAE);
emit_operand(as_Register(3), dst);
}
@@ -2617,7 +2758,7 @@
void Assembler::subl(Address dst, Register src) {
InstructionMark im(this);
prefix(dst, src);
- emit_byte(0x29);
+ emit_int8(0x29);
emit_operand(src, dst);
}
@@ -2635,7 +2776,7 @@
void Assembler::subl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
- emit_byte(0x2B);
+ emit_int8(0x2B);
emit_operand(dst, src);
}
@@ -2676,13 +2817,13 @@
// 8bit operands
int encode = dst->encoding();
if (encode == 0) {
- emit_byte(0xA9);
+ emit_int8((unsigned char)0xA9);
} else {
encode = prefix_and_encode(encode);
- emit_byte(0xF7);
- emit_byte(0xC0 | encode);
+ emit_int8((unsigned char)0xF7);
+ emit_int8((unsigned char)(0xC0 | encode));
}
- emit_long(imm32);
+ emit_int32(imm32);
}
void Assembler::testl(Register dst, Register src) {
@@ -2693,7 +2834,7 @@
void Assembler::testl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
- emit_byte(0x85);
+ emit_int8((unsigned char)0x85);
emit_operand(dst, src);
}
@@ -2721,22 +2862,28 @@
void Assembler::xaddl(Address dst, Register src) {
InstructionMark im(this);
prefix(dst, src);
- emit_byte(0x0F);
- emit_byte(0xC1);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xC1);
emit_operand(src, dst);
}
void Assembler::xchgl(Register dst, Address src) { // xchg
InstructionMark im(this);
prefix(src, dst);
- emit_byte(0x87);
+ emit_int8((unsigned char)0x87);
emit_operand(dst, src);
}
void Assembler::xchgl(Register dst, Register src) {
int encode = prefix_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x87);
- emit_byte(0xc0 | encode);
+ emit_int8((unsigned char)0x87);
+ emit_int8((unsigned char)(0xC0 | encode));
+}
+
+void Assembler::xgetbv() {
+ emit_int8(0x0F);
+ emit_int8(0x01);
+ emit_int8((unsigned char)0xD0);
}
void Assembler::xorl(Register dst, int32_t imm32) {
@@ -2747,7 +2894,7 @@
void Assembler::xorl(Register dst, Address src) {
InstructionMark im(this);
prefix(src, dst);
- emit_byte(0x33);
+ emit_int8(0x33);
emit_operand(dst, src);
}
@@ -3173,8 +3320,8 @@
void Assembler::pmulld(XMMRegister dst, XMMRegister src) {
assert(VM_Version::supports_sse4_1(), "");
int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F_38);
- emit_byte(0x40);
- emit_byte(0xC0 | encode);
+ emit_int8(0x40);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::vpmullw(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) {
@@ -3185,8 +3332,8 @@
void Assembler::vpmulld(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) {
assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2");
int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector256, VEX_OPCODE_0F_38);
- emit_byte(0x40);
- emit_byte(0xC0 | encode);
+ emit_int8(0x40);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::vpmullw(XMMRegister dst, XMMRegister nds, Address src, bool vector256) {
@@ -3200,7 +3347,7 @@
int dst_enc = dst->encoding();
int nds_enc = nds->is_valid() ? nds->encoding() : 0;
vex_prefix(src, nds_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_38, false, vector256);
- emit_byte(0x40);
+ emit_int8(0x40);
emit_operand(dst, src);
}
@@ -3209,27 +3356,27 @@
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
// XMM6 is for /6 encoding: 66 0F 71 /6 ib
int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66);
- emit_byte(0x71);
- emit_byte(0xC0 | encode);
- emit_byte(shift & 0xFF);
+ emit_int8(0x71);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int8(shift & 0xFF);
}
void Assembler::pslld(XMMRegister dst, int shift) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
// XMM6 is for /6 encoding: 66 0F 72 /6 ib
int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66);
- emit_byte(0x72);
- emit_byte(0xC0 | encode);
- emit_byte(shift & 0xFF);
+ emit_int8(0x72);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int8(shift & 0xFF);
}
void Assembler::psllq(XMMRegister dst, int shift) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
// XMM6 is for /6 encoding: 66 0F 73 /6 ib
int encode = simd_prefix_and_encode(xmm6, dst, dst, VEX_SIMD_66);
- emit_byte(0x73);
- emit_byte(0xC0 | encode);
- emit_byte(shift & 0xFF);
+ emit_int8(0x73);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int8(shift & 0xFF);
}
void Assembler::psllw(XMMRegister dst, XMMRegister shift) {
@@ -3251,21 +3398,21 @@
assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2");
// XMM6 is for /6 encoding: 66 0F 71 /6 ib
emit_vex_arith(0x71, xmm6, dst, src, VEX_SIMD_66, vector256);
- emit_byte(shift & 0xFF);
+ emit_int8(shift & 0xFF);
}
void Assembler::vpslld(XMMRegister dst, XMMRegister src, int shift, bool vector256) {
assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2");
// XMM6 is for /6 encoding: 66 0F 72 /6 ib
emit_vex_arith(0x72, xmm6, dst, src, VEX_SIMD_66, vector256);
- emit_byte(shift & 0xFF);
+ emit_int8(shift & 0xFF);
}
void Assembler::vpsllq(XMMRegister dst, XMMRegister src, int shift, bool vector256) {
assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2");
// XMM6 is for /6 encoding: 66 0F 73 /6 ib
emit_vex_arith(0x73, xmm6, dst, src, VEX_SIMD_66, vector256);
- emit_byte(shift & 0xFF);
+ emit_int8(shift & 0xFF);
}
void Assembler::vpsllw(XMMRegister dst, XMMRegister src, XMMRegister shift, bool vector256) {
@@ -3288,18 +3435,18 @@
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
// XMM2 is for /2 encoding: 66 0F 71 /2 ib
int encode = simd_prefix_and_encode(xmm2, dst, dst, VEX_SIMD_66);
- emit_byte(0x71);
- emit_byte(0xC0 | encode);
- emit_byte(shift & 0xFF);
+ emit_int8(0x71);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int8(shift & 0xFF);
}
void Assembler::psrld(XMMRegister dst, int shift) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
// XMM2 is for /2 encoding: 66 0F 72 /2 ib
int encode = simd_prefix_and_encode(xmm2, dst, dst, VEX_SIMD_66);
- emit_byte(0x72);
- emit_byte(0xC0 | encode);
- emit_byte(shift & 0xFF);
+ emit_int8(0x72);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int8(shift & 0xFF);
}
void Assembler::psrlq(XMMRegister dst, int shift) {
@@ -3308,9 +3455,9 @@
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
// XMM2 is for /2 encoding: 66 0F 73 /2 ib
int encode = simd_prefix_and_encode(xmm2, dst, dst, VEX_SIMD_66);
- emit_byte(0x73);
- emit_byte(0xC0 | encode);
- emit_byte(shift & 0xFF);
+ emit_int8(0x73);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int8(shift & 0xFF);
}
void Assembler::psrlw(XMMRegister dst, XMMRegister shift) {
@@ -3332,21 +3479,21 @@
assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2");
// XMM2 is for /2 encoding: 66 0F 73 /2 ib
emit_vex_arith(0x71, xmm2, dst, src, VEX_SIMD_66, vector256);
- emit_byte(shift & 0xFF);
+ emit_int8(shift & 0xFF);
}
void Assembler::vpsrld(XMMRegister dst, XMMRegister src, int shift, bool vector256) {
assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2");
// XMM2 is for /2 encoding: 66 0F 73 /2 ib
emit_vex_arith(0x72, xmm2, dst, src, VEX_SIMD_66, vector256);
- emit_byte(shift & 0xFF);
+ emit_int8(shift & 0xFF);
}
void Assembler::vpsrlq(XMMRegister dst, XMMRegister src, int shift, bool vector256) {
assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2");
// XMM2 is for /2 encoding: 66 0F 73 /2 ib
emit_vex_arith(0x73, xmm2, dst, src, VEX_SIMD_66, vector256);
- emit_byte(shift & 0xFF);
+ emit_int8(shift & 0xFF);
}
void Assembler::vpsrlw(XMMRegister dst, XMMRegister src, XMMRegister shift, bool vector256) {
@@ -3369,18 +3516,18 @@
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
// XMM4 is for /4 encoding: 66 0F 71 /4 ib
int encode = simd_prefix_and_encode(xmm4, dst, dst, VEX_SIMD_66);
- emit_byte(0x71);
- emit_byte(0xC0 | encode);
- emit_byte(shift & 0xFF);
+ emit_int8(0x71);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int8(shift & 0xFF);
}
void Assembler::psrad(XMMRegister dst, int shift) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
// XMM4 is for /4 encoding: 66 0F 72 /4 ib
int encode = simd_prefix_and_encode(xmm4, dst, dst, VEX_SIMD_66);
- emit_byte(0x72);
- emit_byte(0xC0 | encode);
- emit_byte(shift & 0xFF);
+ emit_int8(0x72);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int8(shift & 0xFF);
}
void Assembler::psraw(XMMRegister dst, XMMRegister shift) {
@@ -3397,14 +3544,14 @@
assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2");
// XMM4 is for /4 encoding: 66 0F 71 /4 ib
emit_vex_arith(0x71, xmm4, dst, src, VEX_SIMD_66, vector256);
- emit_byte(shift & 0xFF);
+ emit_int8(shift & 0xFF);
}
void Assembler::vpsrad(XMMRegister dst, XMMRegister src, int shift, bool vector256) {
assert(VM_Version::supports_avx() && !vector256 || VM_Version::supports_avx2(), "256 bit integer vectors requires AVX2");
// XMM4 is for /4 encoding: 66 0F 71 /4 ib
emit_vex_arith(0x72, xmm4, dst, src, VEX_SIMD_66, vector256);
- emit_byte(shift & 0xFF);
+ emit_int8(shift & 0xFF);
}
void Assembler::vpsraw(XMMRegister dst, XMMRegister src, XMMRegister shift, bool vector256) {
@@ -3469,11 +3616,11 @@
assert(VM_Version::supports_avx(), "");
bool vector256 = true;
int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector256, VEX_OPCODE_0F_3A);
- emit_byte(0x18);
- emit_byte(0xC0 | encode);
+ emit_int8(0x18);
+ emit_int8((unsigned char)(0xC0 | encode));
// 0x00 - insert into lower 128 bits
// 0x01 - insert into upper 128 bits
- emit_byte(0x01);
+ emit_int8(0x01);
}
void Assembler::vinsertf128h(XMMRegister dst, Address src) {
@@ -3484,10 +3631,10 @@
int dst_enc = dst->encoding();
// swap src<->dst for encoding
vex_prefix(src, dst_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, false, vector256);
- emit_byte(0x18);
+ emit_int8(0x18);
emit_operand(dst, src);
// 0x01 - insert into upper 128 bits
- emit_byte(0x01);
+ emit_int8(0x01);
}
void Assembler::vextractf128h(Address dst, XMMRegister src) {
@@ -3497,21 +3644,21 @@
assert(src != xnoreg, "sanity");
int src_enc = src->encoding();
vex_prefix(dst, 0, src_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, false, vector256);
- emit_byte(0x19);
+ emit_int8(0x19);
emit_operand(src, dst);
// 0x01 - extract from upper 128 bits
- emit_byte(0x01);
+ emit_int8(0x01);
}
void Assembler::vinserti128h(XMMRegister dst, XMMRegister nds, XMMRegister src) {
assert(VM_Version::supports_avx2(), "");
bool vector256 = true;
int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector256, VEX_OPCODE_0F_3A);
- emit_byte(0x38);
- emit_byte(0xC0 | encode);
+ emit_int8(0x38);
+ emit_int8((unsigned char)(0xC0 | encode));
// 0x00 - insert into lower 128 bits
// 0x01 - insert into upper 128 bits
- emit_byte(0x01);
+ emit_int8(0x01);
}
void Assembler::vinserti128h(XMMRegister dst, Address src) {
@@ -3522,10 +3669,10 @@
int dst_enc = dst->encoding();
// swap src<->dst for encoding
vex_prefix(src, dst_enc, dst_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, false, vector256);
- emit_byte(0x38);
+ emit_int8(0x38);
emit_operand(dst, src);
// 0x01 - insert into upper 128 bits
- emit_byte(0x01);
+ emit_int8(0x01);
}
void Assembler::vextracti128h(Address dst, XMMRegister src) {
@@ -3535,16 +3682,25 @@
assert(src != xnoreg, "sanity");
int src_enc = src->encoding();
vex_prefix(dst, 0, src_enc, VEX_SIMD_66, VEX_OPCODE_0F_3A, false, vector256);
- emit_byte(0x39);
+ emit_int8(0x39);
emit_operand(src, dst);
// 0x01 - extract from upper 128 bits
- emit_byte(0x01);
+ emit_int8(0x01);
+}
+
+// duplicate 4-bytes integer data from src into 8 locations in dest
+void Assembler::vpbroadcastd(XMMRegister dst, XMMRegister src) {
+ assert(VM_Version::supports_avx2(), "");
+ bool vector256 = true;
+ int encode = vex_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_66, vector256, VEX_OPCODE_0F_38);
+ emit_int8(0x58);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::vzeroupper() {
assert(VM_Version::supports_avx(), "");
(void)vex_prefix_and_encode(xmm0, xmm0, xmm0, VEX_SIMD_NONE);
- emit_byte(0x77);
+ emit_int8(0x77);
}
@@ -3554,15 +3710,15 @@
void Assembler::cmp_literal32(Register src1, int32_t imm32, RelocationHolder const& rspec) {
// NO PREFIX AS NEVER 64BIT
InstructionMark im(this);
- emit_byte(0x81);
- emit_byte(0xF8 | src1->encoding());
+ emit_int8((unsigned char)0x81);
+ emit_int8((unsigned char)(0xF8 | src1->encoding()));
emit_data(imm32, rspec, 0);
}
void Assembler::cmp_literal32(Address src1, int32_t imm32, RelocationHolder const& rspec) {
// NO PREFIX AS NEVER 64BIT (not even 32bit versions of 64bit regs
InstructionMark im(this);
- emit_byte(0x81);
+ emit_int8((unsigned char)0x81);
emit_operand(rdi, src1);
emit_data(imm32, rspec, 0);
}
@@ -3572,14 +3728,14 @@
// into rdx:rax. The ZF is set if the compared values were equal, and cleared otherwise.
void Assembler::cmpxchg8(Address adr) {
InstructionMark im(this);
- emit_byte(0x0F);
- emit_byte(0xc7);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xC7);
emit_operand(rcx, adr);
}
void Assembler::decl(Register dst) {
// Don't use it directly. Use MacroAssembler::decrementl() instead.
- emit_byte(0x48 | dst->encoding());
+ emit_int8(0x48 | dst->encoding());
}
#endif // _LP64
@@ -3587,8 +3743,8 @@
// 64bit typically doesn't use the x87 but needs to for the trig funcs
void Assembler::fabs() {
- emit_byte(0xD9);
- emit_byte(0xE1);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xE1);
}
void Assembler::fadd(int i) {
@@ -3597,13 +3753,13 @@
void Assembler::fadd_d(Address src) {
InstructionMark im(this);
- emit_byte(0xDC);
+ emit_int8((unsigned char)0xDC);
emit_operand32(rax, src);
}
void Assembler::fadd_s(Address src) {
InstructionMark im(this);
- emit_byte(0xD8);
+ emit_int8((unsigned char)0xD8);
emit_operand32(rax, src);
}
@@ -3616,8 +3772,8 @@
}
void Assembler::fchs() {
- emit_byte(0xD9);
- emit_byte(0xE0);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xE0);
}
void Assembler::fcom(int i) {
@@ -3630,29 +3786,29 @@
void Assembler::fcomp_d(Address src) {
InstructionMark im(this);
- emit_byte(0xDC);
+ emit_int8((unsigned char)0xDC);
emit_operand32(rbx, src);
}
void Assembler::fcomp_s(Address src) {
InstructionMark im(this);
- emit_byte(0xD8);
+ emit_int8((unsigned char)0xD8);
emit_operand32(rbx, src);
}
void Assembler::fcompp() {
- emit_byte(0xDE);
- emit_byte(0xD9);
+ emit_int8((unsigned char)0xDE);
+ emit_int8((unsigned char)0xD9);
}
void Assembler::fcos() {
- emit_byte(0xD9);
- emit_byte(0xFF);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xFF);
}
void Assembler::fdecstp() {
- emit_byte(0xD9);
- emit_byte(0xF6);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xF6);
}
void Assembler::fdiv(int i) {
@@ -3661,13 +3817,13 @@
void Assembler::fdiv_d(Address src) {
InstructionMark im(this);
- emit_byte(0xDC);
+ emit_int8((unsigned char)0xDC);
emit_operand32(rsi, src);
}
void Assembler::fdiv_s(Address src) {
InstructionMark im(this);
- emit_byte(0xD8);
+ emit_int8((unsigned char)0xD8);
emit_operand32(rsi, src);
}
@@ -3688,13 +3844,13 @@
void Assembler::fdivr_d(Address src) {
InstructionMark im(this);
- emit_byte(0xDC);
+ emit_int8((unsigned char)0xDC);
emit_operand32(rdi, src);
}
void Assembler::fdivr_s(Address src) {
InstructionMark im(this);
- emit_byte(0xD8);
+ emit_int8((unsigned char)0xD8);
emit_operand32(rdi, src);
}
@@ -3712,59 +3868,59 @@
void Assembler::fild_d(Address adr) {
InstructionMark im(this);
- emit_byte(0xDF);
+ emit_int8((unsigned char)0xDF);
emit_operand32(rbp, adr);
}
void Assembler::fild_s(Address adr) {
InstructionMark im(this);
- emit_byte(0xDB);
+ emit_int8((unsigned char)0xDB);
emit_operand32(rax, adr);
}
void Assembler::fincstp() {
- emit_byte(0xD9);
- emit_byte(0xF7);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xF7);
}
void Assembler::finit() {
- emit_byte(0x9B);
- emit_byte(0xDB);
- emit_byte(0xE3);
+ emit_int8((unsigned char)0x9B);
+ emit_int8((unsigned char)0xDB);
+ emit_int8((unsigned char)0xE3);
}
void Assembler::fist_s(Address adr) {
InstructionMark im(this);
- emit_byte(0xDB);
+ emit_int8((unsigned char)0xDB);
emit_operand32(rdx, adr);
}
void Assembler::fistp_d(Address adr) {
InstructionMark im(this);
- emit_byte(0xDF);
+ emit_int8((unsigned char)0xDF);
emit_operand32(rdi, adr);
}
void Assembler::fistp_s(Address adr) {
InstructionMark im(this);
- emit_byte(0xDB);
+ emit_int8((unsigned char)0xDB);
emit_operand32(rbx, adr);
}
void Assembler::fld1() {
- emit_byte(0xD9);
- emit_byte(0xE8);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xE8);
}
void Assembler::fld_d(Address adr) {
InstructionMark im(this);
- emit_byte(0xDD);
+ emit_int8((unsigned char)0xDD);
emit_operand32(rax, adr);
}
void Assembler::fld_s(Address adr) {
InstructionMark im(this);
- emit_byte(0xD9);
+ emit_int8((unsigned char)0xD9);
emit_operand32(rax, adr);
}
@@ -3775,35 +3931,35 @@
void Assembler::fld_x(Address adr) {
InstructionMark im(this);
- emit_byte(0xDB);
+ emit_int8((unsigned char)0xDB);
emit_operand32(rbp, adr);
}
void Assembler::fldcw(Address src) {
InstructionMark im(this);
- emit_byte(0xd9);
+ emit_int8((unsigned char)0xD9);
emit_operand32(rbp, src);
}
void Assembler::fldenv(Address src) {
InstructionMark im(this);
- emit_byte(0xD9);
+ emit_int8((unsigned char)0xD9);
emit_operand32(rsp, src);
}
void Assembler::fldlg2() {
- emit_byte(0xD9);
- emit_byte(0xEC);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xEC);
}
void Assembler::fldln2() {
- emit_byte(0xD9);
- emit_byte(0xED);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xED);
}
void Assembler::fldz() {
- emit_byte(0xD9);
- emit_byte(0xEE);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xEE);
}
void Assembler::flog() {
@@ -3824,13 +3980,13 @@
void Assembler::fmul_d(Address src) {
InstructionMark im(this);
- emit_byte(0xDC);
+ emit_int8((unsigned char)0xDC);
emit_operand32(rcx, src);
}
void Assembler::fmul_s(Address src) {
InstructionMark im(this);
- emit_byte(0xD8);
+ emit_int8((unsigned char)0xD8);
emit_operand32(rcx, src);
}
@@ -3844,63 +4000,63 @@
void Assembler::fnsave(Address dst) {
InstructionMark im(this);
- emit_byte(0xDD);
+ emit_int8((unsigned char)0xDD);
emit_operand32(rsi, dst);
}
void Assembler::fnstcw(Address src) {
InstructionMark im(this);
- emit_byte(0x9B);
- emit_byte(0xD9);
+ emit_int8((unsigned char)0x9B);
+ emit_int8((unsigned char)0xD9);
emit_operand32(rdi, src);
}
void Assembler::fnstsw_ax() {
- emit_byte(0xdF);
- emit_byte(0xE0);
+ emit_int8((unsigned char)0xDF);
+ emit_int8((unsigned char)0xE0);
}
void Assembler::fprem() {
- emit_byte(0xD9);
- emit_byte(0xF8);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xF8);
}
void Assembler::fprem1() {
- emit_byte(0xD9);
- emit_byte(0xF5);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xF5);
}
void Assembler::frstor(Address src) {
InstructionMark im(this);
- emit_byte(0xDD);
+ emit_int8((unsigned char)0xDD);
emit_operand32(rsp, src);
}
void Assembler::fsin() {
- emit_byte(0xD9);
- emit_byte(0xFE);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xFE);
}
void Assembler::fsqrt() {
- emit_byte(0xD9);
- emit_byte(0xFA);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xFA);
}
void Assembler::fst_d(Address adr) {
InstructionMark im(this);
- emit_byte(0xDD);
+ emit_int8((unsigned char)0xDD);
emit_operand32(rdx, adr);
}
void Assembler::fst_s(Address adr) {
InstructionMark im(this);
- emit_byte(0xD9);
+ emit_int8((unsigned char)0xD9);
emit_operand32(rdx, adr);
}
void Assembler::fstp_d(Address adr) {
InstructionMark im(this);
- emit_byte(0xDD);
+ emit_int8((unsigned char)0xDD);
emit_operand32(rbx, adr);
}
@@ -3910,13 +4066,13 @@
void Assembler::fstp_s(Address adr) {
InstructionMark im(this);
- emit_byte(0xD9);
+ emit_int8((unsigned char)0xD9);
emit_operand32(rbx, adr);
}
void Assembler::fstp_x(Address adr) {
InstructionMark im(this);
- emit_byte(0xDB);
+ emit_int8((unsigned char)0xDB);
emit_operand32(rdi, adr);
}
@@ -3926,13 +4082,13 @@
void Assembler::fsub_d(Address src) {
InstructionMark im(this);
- emit_byte(0xDC);
+ emit_int8((unsigned char)0xDC);
emit_operand32(rsp, src);
}
void Assembler::fsub_s(Address src) {
InstructionMark im(this);
- emit_byte(0xD8);
+ emit_int8((unsigned char)0xD8);
emit_operand32(rsp, src);
}
@@ -3950,13 +4106,13 @@
void Assembler::fsubr_d(Address src) {
InstructionMark im(this);
- emit_byte(0xDC);
+ emit_int8((unsigned char)0xDC);
emit_operand32(rbp, src);
}
void Assembler::fsubr_s(Address src) {
InstructionMark im(this);
- emit_byte(0xD8);
+ emit_int8((unsigned char)0xD8);
emit_operand32(rbp, src);
}
@@ -3969,15 +4125,15 @@
}
void Assembler::ftan() {
- emit_byte(0xD9);
- emit_byte(0xF2);
- emit_byte(0xDD);
- emit_byte(0xD8);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xF2);
+ emit_int8((unsigned char)0xDD);
+ emit_int8((unsigned char)0xD8);
}
void Assembler::ftst() {
- emit_byte(0xD9);
- emit_byte(0xE4);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xE4);
}
void Assembler::fucomi(int i) {
@@ -3993,7 +4149,7 @@
}
void Assembler::fwait() {
- emit_byte(0x9B);
+ emit_int8((unsigned char)0x9B);
}
void Assembler::fxch(int i) {
@@ -4001,23 +4157,23 @@
}
void Assembler::fyl2x() {
- emit_byte(0xD9);
- emit_byte(0xF1);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xF1);
}
void Assembler::frndint() {
- emit_byte(0xD9);
- emit_byte(0xFC);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xFC);
}
void Assembler::f2xm1() {
- emit_byte(0xD9);
- emit_byte(0xF0);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xF0);
}
void Assembler::fldl2e() {
- emit_byte(0xD9);
- emit_byte(0xEA);
+ emit_int8((unsigned char)0xD9);
+ emit_int8((unsigned char)0xEA);
}
// SSE SIMD prefix byte values corresponding to VexSimdPrefix encoding.
@@ -4028,7 +4184,7 @@
// Generate SSE legacy REX prefix and SIMD opcode based on VEX encoding.
void Assembler::rex_prefix(Address adr, XMMRegister xreg, VexSimdPrefix pre, VexOpcode opc, bool rex_w) {
if (pre > 0) {
- emit_byte(simd_pre[pre]);
+ emit_int8(simd_pre[pre]);
}
if (rex_w) {
prefixq(adr, xreg);
@@ -4036,25 +4192,25 @@
prefix(adr, xreg);
}
if (opc > 0) {
- emit_byte(0x0F);
+ emit_int8(0x0F);
int opc2 = simd_opc[opc];
if (opc2 > 0) {
- emit_byte(opc2);
+ emit_int8(opc2);
}
}
}
int Assembler::rex_prefix_and_encode(int dst_enc, int src_enc, VexSimdPrefix pre, VexOpcode opc, bool rex_w) {
if (pre > 0) {
- emit_byte(simd_pre[pre]);
+ emit_int8(simd_pre[pre]);
}
int encode = (rex_w) ? prefixq_and_encode(dst_enc, src_enc) :
prefix_and_encode(dst_enc, src_enc);
if (opc > 0) {
- emit_byte(0x0F);
+ emit_int8(0x0F);
int opc2 = simd_opc[opc];
if (opc2 > 0) {
- emit_byte(opc2);
+ emit_int8(opc2);
}
}
return encode;
@@ -4068,11 +4224,11 @@
int byte1 = (vex_r ? VEX_R : 0) | (vex_x ? VEX_X : 0) | (vex_b ? VEX_B : 0);
byte1 = (~byte1) & 0xE0;
byte1 |= opc;
- a_byte(byte1);
+ emit_int8(byte1);
int byte2 = ((~nds_enc) & 0xf) << 3;
byte2 |= (vex_w ? VEX_W : 0) | (vector256 ? 4 : 0) | pre;
- emit_byte(byte2);
+ emit_int8(byte2);
} else {
prefix(VEX_2bytes);
@@ -4080,7 +4236,7 @@
byte1 = (~byte1) & 0x80;
byte1 |= ((~nds_enc) & 0xf) << 3;
byte1 |= (vector256 ? 4 : 0) | pre;
- emit_byte(byte1);
+ emit_int8(byte1);
}
}
@@ -4126,28 +4282,28 @@
void Assembler::emit_simd_arith(int opcode, XMMRegister dst, Address src, VexSimdPrefix pre) {
InstructionMark im(this);
simd_prefix(dst, dst, src, pre);
- emit_byte(opcode);
+ emit_int8(opcode);
emit_operand(dst, src);
}
void Assembler::emit_simd_arith(int opcode, XMMRegister dst, XMMRegister src, VexSimdPrefix pre) {
int encode = simd_prefix_and_encode(dst, dst, src, pre);
- emit_byte(opcode);
- emit_byte(0xC0 | encode);
+ emit_int8(opcode);
+ emit_int8((unsigned char)(0xC0 | encode));
}
// Versions with no second source register (non-destructive source).
void Assembler::emit_simd_arith_nonds(int opcode, XMMRegister dst, Address src, VexSimdPrefix pre) {
InstructionMark im(this);
simd_prefix(dst, xnoreg, src, pre);
- emit_byte(opcode);
+ emit_int8(opcode);
emit_operand(dst, src);
}
void Assembler::emit_simd_arith_nonds(int opcode, XMMRegister dst, XMMRegister src, VexSimdPrefix pre) {
int encode = simd_prefix_and_encode(dst, xnoreg, src, pre);
- emit_byte(opcode);
- emit_byte(0xC0 | encode);
+ emit_int8(opcode);
+ emit_int8((unsigned char)(0xC0 | encode));
}
// 3-operands AVX instructions
@@ -4155,22 +4311,22 @@
Address src, VexSimdPrefix pre, bool vector256) {
InstructionMark im(this);
vex_prefix(dst, nds, src, pre, vector256);
- emit_byte(opcode);
+ emit_int8(opcode);
emit_operand(dst, src);
}
void Assembler::emit_vex_arith(int opcode, XMMRegister dst, XMMRegister nds,
XMMRegister src, VexSimdPrefix pre, bool vector256) {
int encode = vex_prefix_and_encode(dst, nds, src, pre, vector256);
- emit_byte(opcode);
- emit_byte(0xC0 | encode);
+ emit_int8(opcode);
+ emit_int8((unsigned char)(0xC0 | encode));
}
#ifndef _LP64
void Assembler::incl(Register dst) {
// Don't use it directly. Use MacroAssembler::incrementl() instead.
- emit_byte(0x40 | dst->encoding());
+ emit_int8(0x40 | dst->encoding());
}
void Assembler::lea(Register dst, Address src) {
@@ -4179,7 +4335,7 @@
void Assembler::mov_literal32(Address dst, int32_t imm32, RelocationHolder const& rspec) {
InstructionMark im(this);
- emit_byte(0xC7);
+ emit_int8((unsigned char)0xC7);
emit_operand(rax, dst);
emit_data((int)imm32, rspec, 0);
}
@@ -4187,49 +4343,49 @@
void Assembler::mov_literal32(Register dst, int32_t imm32, RelocationHolder const& rspec) {
InstructionMark im(this);
int encode = prefix_and_encode(dst->encoding());
- emit_byte(0xB8 | encode);
+ emit_int8((unsigned char)(0xB8 | encode));
emit_data((int)imm32, rspec, 0);
}
void Assembler::popa() { // 32bit
- emit_byte(0x61);
+ emit_int8(0x61);
}
void Assembler::push_literal32(int32_t imm32, RelocationHolder const& rspec) {
InstructionMark im(this);
- emit_byte(0x68);
+ emit_int8(0x68);
emit_data(imm32, rspec, 0);
}
void Assembler::pusha() { // 32bit
- emit_byte(0x60);
+ emit_int8(0x60);
}
void Assembler::set_byte_if_not_zero(Register dst) {
- emit_byte(0x0F);
- emit_byte(0x95);
- emit_byte(0xE0 | dst->encoding());
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0x95);
+ emit_int8((unsigned char)(0xE0 | dst->encoding()));
}
void Assembler::shldl(Register dst, Register src) {
- emit_byte(0x0F);
- emit_byte(0xA5);
- emit_byte(0xC0 | src->encoding() << 3 | dst->encoding());
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xA5);
+ emit_int8((unsigned char)(0xC0 | src->encoding() << 3 | dst->encoding()));
}
void Assembler::shrdl(Register dst, Register src) {
- emit_byte(0x0F);
- emit_byte(0xAD);
- emit_byte(0xC0 | src->encoding() << 3 | dst->encoding());
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xAD);
+ emit_int8((unsigned char)(0xC0 | src->encoding() << 3 | dst->encoding()));
}
#else // LP64
void Assembler::set_byte_if_not_zero(Register dst) {
int enc = prefix_and_encode(dst->encoding(), true);
- emit_byte(0x0F);
- emit_byte(0x95);
- emit_byte(0xE0 | enc);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0x95);
+ emit_int8((unsigned char)(0xE0 | enc));
}
// 64bit only pieces of the assembler
@@ -4284,7 +4440,7 @@
disp = (int64_t)adr._target - ((int64_t)CodeCache::high_bound() + sizeof(int));
if (!is_simm32(disp)) return false;
- disp = (int64_t)adr._target - ((int64_t)_code_pos + sizeof(int));
+ disp = (int64_t)adr._target - ((int64_t)pc() + sizeof(int));
// Because rip relative is a disp + address_of_next_instruction and we
// don't know the value of address_of_next_instruction we apply a fudge factor
@@ -4315,7 +4471,7 @@
relocInfo::relocType rtype,
int format) {
if (rtype == relocInfo::none) {
- emit_long64(data);
+ emit_int64(data);
} else {
emit_data64(data, Relocation::spec_simple(rtype), format);
}
@@ -4333,7 +4489,7 @@
#ifdef ASSERT
check_relocation(rspec, format);
#endif
- emit_long64(data);
+ emit_int64(data);
}
int Assembler::prefix_and_encode(int reg_enc, bool byteinst) {
@@ -4567,7 +4723,7 @@
void Assembler::adcq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x13);
+ emit_int8(0x13);
emit_operand(dst, src);
}
@@ -4585,7 +4741,7 @@
void Assembler::addq(Address dst, Register src) {
InstructionMark im(this);
prefixq(dst, src);
- emit_byte(0x01);
+ emit_int8(0x01);
emit_operand(src, dst);
}
@@ -4597,7 +4753,7 @@
void Assembler::addq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x03);
+ emit_int8(0x03);
emit_operand(dst, src);
}
@@ -4609,9 +4765,9 @@
void Assembler::andq(Address dst, int32_t imm32) {
InstructionMark im(this);
prefixq(dst);
- emit_byte(0x81);
+ emit_int8((unsigned char)0x81);
emit_operand(rsp, dst, 4);
- emit_long(imm32);
+ emit_int32(imm32);
}
void Assembler::andq(Register dst, int32_t imm32) {
@@ -4622,7 +4778,7 @@
void Assembler::andq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x23);
+ emit_int8(0x23);
emit_operand(dst, src);
}
@@ -4633,58 +4789,58 @@
void Assembler::bsfq(Register dst, Register src) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0xBC);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xBC);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::bsrq(Register dst, Register src) {
assert(!VM_Version::supports_lzcnt(), "encoding is treated as LZCNT");
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0xBD);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xBD);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::bswapq(Register reg) {
int encode = prefixq_and_encode(reg->encoding());
- emit_byte(0x0F);
- emit_byte(0xC8 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)(0xC8 | encode));
}
void Assembler::cdqq() {
prefix(REX_W);
- emit_byte(0x99);
+ emit_int8((unsigned char)0x99);
}
void Assembler::clflush(Address adr) {
prefix(adr);
- emit_byte(0x0F);
- emit_byte(0xAE);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xAE);
emit_operand(rdi, adr);
}
void Assembler::cmovq(Condition cc, Register dst, Register src) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0x40 | cc);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8(0x40 | cc);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::cmovq(Condition cc, Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x0F);
- emit_byte(0x40 | cc);
+ emit_int8(0x0F);
+ emit_int8(0x40 | cc);
emit_operand(dst, src);
}
void Assembler::cmpq(Address dst, int32_t imm32) {
InstructionMark im(this);
prefixq(dst);
- emit_byte(0x81);
+ emit_int8((unsigned char)0x81);
emit_operand(rdi, dst, 4);
- emit_long(imm32);
+ emit_int32(imm32);
}
void Assembler::cmpq(Register dst, int32_t imm32) {
@@ -4695,7 +4851,7 @@
void Assembler::cmpq(Address dst, Register src) {
InstructionMark im(this);
prefixq(dst, src);
- emit_byte(0x3B);
+ emit_int8(0x3B);
emit_operand(src, dst);
}
@@ -4707,123 +4863,123 @@
void Assembler::cmpq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x3B);
+ emit_int8(0x3B);
emit_operand(dst, src);
}
void Assembler::cmpxchgq(Register reg, Address adr) {
InstructionMark im(this);
prefixq(adr, reg);
- emit_byte(0x0F);
- emit_byte(0xB1);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xB1);
emit_operand(reg, adr);
}
void Assembler::cvtsi2sdq(XMMRegister dst, Register src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
int encode = simd_prefix_and_encode_q(dst, dst, src, VEX_SIMD_F2);
- emit_byte(0x2A);
- emit_byte(0xC0 | encode);
+ emit_int8(0x2A);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::cvtsi2sdq(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
simd_prefix_q(dst, dst, src, VEX_SIMD_F2);
- emit_byte(0x2A);
+ emit_int8(0x2A);
emit_operand(dst, src);
}
void Assembler::cvtsi2ssq(XMMRegister dst, Register src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
int encode = simd_prefix_and_encode_q(dst, dst, src, VEX_SIMD_F3);
- emit_byte(0x2A);
- emit_byte(0xC0 | encode);
+ emit_int8(0x2A);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::cvtsi2ssq(XMMRegister dst, Address src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
InstructionMark im(this);
simd_prefix_q(dst, dst, src, VEX_SIMD_F3);
- emit_byte(0x2A);
+ emit_int8(0x2A);
emit_operand(dst, src);
}
void Assembler::cvttsd2siq(Register dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
int encode = simd_prefix_and_encode_q(dst, src, VEX_SIMD_F2);
- emit_byte(0x2C);
- emit_byte(0xC0 | encode);
+ emit_int8(0x2C);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::cvttss2siq(Register dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
int encode = simd_prefix_and_encode_q(dst, src, VEX_SIMD_F3);
- emit_byte(0x2C);
- emit_byte(0xC0 | encode);
+ emit_int8(0x2C);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::decl(Register dst) {
// Don't use it directly. Use MacroAssembler::decrementl() instead.
// Use two-byte form (one-byte form is a REX prefix in 64-bit mode)
int encode = prefix_and_encode(dst->encoding());
- emit_byte(0xFF);
- emit_byte(0xC8 | encode);
+ emit_int8((unsigned char)0xFF);
+ emit_int8((unsigned char)(0xC8 | encode));
}
void Assembler::decq(Register dst) {
// Don't use it directly. Use MacroAssembler::decrementq() instead.
// Use two-byte form (one-byte from is a REX prefix in 64-bit mode)
int encode = prefixq_and_encode(dst->encoding());
- emit_byte(0xFF);
- emit_byte(0xC8 | encode);
+ emit_int8((unsigned char)0xFF);
+ emit_int8(0xC8 | encode);
}
void Assembler::decq(Address dst) {
// Don't use it directly. Use MacroAssembler::decrementq() instead.
InstructionMark im(this);
prefixq(dst);
- emit_byte(0xFF);
+ emit_int8((unsigned char)0xFF);
emit_operand(rcx, dst);
}
void Assembler::fxrstor(Address src) {
prefixq(src);
- emit_byte(0x0F);
- emit_byte(0xAE);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xAE);
emit_operand(as_Register(1), src);
}
void Assembler::fxsave(Address dst) {
prefixq(dst);
- emit_byte(0x0F);
- emit_byte(0xAE);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xAE);
emit_operand(as_Register(0), dst);
}
void Assembler::idivq(Register src) {
int encode = prefixq_and_encode(src->encoding());
- emit_byte(0xF7);
- emit_byte(0xF8 | encode);
+ emit_int8((unsigned char)0xF7);
+ emit_int8((unsigned char)(0xF8 | encode));
}
void Assembler::imulq(Register dst, Register src) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0xAF);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xAF);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::imulq(Register dst, Register src, int value) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
if (is8bit(value)) {
- emit_byte(0x6B);
- emit_byte(0xC0 | encode);
- emit_byte(value & 0xFF);
+ emit_int8(0x6B);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int8(value & 0xFF);
} else {
- emit_byte(0x69);
- emit_byte(0xC0 | encode);
- emit_long(value);
+ emit_int8(0x69);
+ emit_int8((unsigned char)(0xC0 | encode));
+ emit_int32(value);
}
}
@@ -4831,23 +4987,23 @@
// Don't use it directly. Use MacroAssembler::incrementl() instead.
// Use two-byte form (one-byte from is a REX prefix in 64-bit mode)
int encode = prefix_and_encode(dst->encoding());
- emit_byte(0xFF);
- emit_byte(0xC0 | encode);
+ emit_int8((unsigned char)0xFF);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::incq(Register dst) {
// Don't use it directly. Use MacroAssembler::incrementq() instead.
// Use two-byte form (one-byte from is a REX prefix in 64-bit mode)
int encode = prefixq_and_encode(dst->encoding());
- emit_byte(0xFF);
- emit_byte(0xC0 | encode);
+ emit_int8((unsigned char)0xFF);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::incq(Address dst) {
// Don't use it directly. Use MacroAssembler::incrementq() instead.
InstructionMark im(this);
prefixq(dst);
- emit_byte(0xFF);
+ emit_int8((unsigned char)0xFF);
emit_operand(rax, dst);
}
@@ -4858,35 +5014,35 @@
void Assembler::leaq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x8D);
+ emit_int8((unsigned char)0x8D);
emit_operand(dst, src);
}
void Assembler::mov64(Register dst, int64_t imm64) {
InstructionMark im(this);
int encode = prefixq_and_encode(dst->encoding());
- emit_byte(0xB8 | encode);
- emit_long64(imm64);
+ emit_int8((unsigned char)(0xB8 | encode));
+ emit_int64(imm64);
}
void Assembler::mov_literal64(Register dst, intptr_t imm64, RelocationHolder const& rspec) {
InstructionMark im(this);
int encode = prefixq_and_encode(dst->encoding());
- emit_byte(0xB8 | encode);
+ emit_int8(0xB8 | encode);
emit_data64(imm64, rspec);
}
void Assembler::mov_narrow_oop(Register dst, int32_t imm32, RelocationHolder const& rspec) {
InstructionMark im(this);
int encode = prefix_and_encode(dst->encoding());
- emit_byte(0xB8 | encode);
+ emit_int8((unsigned char)(0xB8 | encode));
emit_data((int)imm32, rspec, narrow_oop_operand);
}
void Assembler::mov_narrow_oop(Address dst, int32_t imm32, RelocationHolder const& rspec) {
InstructionMark im(this);
prefix(dst);
- emit_byte(0xC7);
+ emit_int8((unsigned char)0xC7);
emit_operand(rax, dst, 4);
emit_data((int)imm32, rspec, narrow_oop_operand);
}
@@ -4894,34 +5050,34 @@
void Assembler::cmp_narrow_oop(Register src1, int32_t imm32, RelocationHolder const& rspec) {
InstructionMark im(this);
int encode = prefix_and_encode(src1->encoding());
- emit_byte(0x81);
- emit_byte(0xF8 | encode);
+ emit_int8((unsigned char)0x81);
+ emit_int8((unsigned char)(0xF8 | encode));
emit_data((int)imm32, rspec, narrow_oop_operand);
}
void Assembler::cmp_narrow_oop(Address src1, int32_t imm32, RelocationHolder const& rspec) {
InstructionMark im(this);
prefix(src1);
- emit_byte(0x81);
+ emit_int8((unsigned char)0x81);
emit_operand(rax, src1, 4);
emit_data((int)imm32, rspec, narrow_oop_operand);
}
void Assembler::lzcntq(Register dst, Register src) {
assert(VM_Version::supports_lzcnt(), "encoding is treated as BSR");
- emit_byte(0xF3);
+ emit_int8((unsigned char)0xF3);
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0xBD);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xBD);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::movdq(XMMRegister dst, Register src) {
// table D-1 says MMX/SSE2
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
int encode = simd_prefix_and_encode_q(dst, src, VEX_SIMD_66);
- emit_byte(0x6E);
- emit_byte(0xC0 | encode);
+ emit_int8(0x6E);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::movdq(Register dst, XMMRegister src) {
@@ -4929,43 +5085,43 @@
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
// swap src/dst to get correct prefix
int encode = simd_prefix_and_encode_q(src, dst, VEX_SIMD_66);
- emit_byte(0x7E);
- emit_byte(0xC0 | encode);
+ emit_int8(0x7E);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::movq(Register dst, Register src) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x8B);
- emit_byte(0xC0 | encode);
+ emit_int8((unsigned char)0x8B);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::movq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x8B);
+ emit_int8((unsigned char)0x8B);
emit_operand(dst, src);
}
void Assembler::movq(Address dst, Register src) {
InstructionMark im(this);
prefixq(dst, src);
- emit_byte(0x89);
+ emit_int8((unsigned char)0x89);
emit_operand(src, dst);
}
void Assembler::movsbq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x0F);
- emit_byte(0xBE);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xBE);
emit_operand(dst, src);
}
void Assembler::movsbq(Register dst, Register src) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0xBE);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xBE);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::movslq(Register dst, int32_t imm32) {
@@ -4975,95 +5131,95 @@
ShouldNotReachHere();
InstructionMark im(this);
int encode = prefixq_and_encode(dst->encoding());
- emit_byte(0xC7 | encode);
- emit_long(imm32);
+ emit_int8((unsigned char)(0xC7 | encode));
+ emit_int32(imm32);
}
void Assembler::movslq(Address dst, int32_t imm32) {
assert(is_simm32(imm32), "lost bits");
InstructionMark im(this);
prefixq(dst);
- emit_byte(0xC7);
+ emit_int8((unsigned char)0xC7);
emit_operand(rax, dst, 4);
- emit_long(imm32);
+ emit_int32(imm32);
}
void Assembler::movslq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x63);
+ emit_int8(0x63);
emit_operand(dst, src);
}
void Assembler::movslq(Register dst, Register src) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x63);
- emit_byte(0xC0 | encode);
+ emit_int8(0x63);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::movswq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x0F);
- emit_byte(0xBF);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xBF);
emit_operand(dst, src);
}
void Assembler::movswq(Register dst, Register src) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0xBF);
- emit_byte(0xC0 | encode);
+ emit_int8((unsigned char)0x0F);
+ emit_int8((unsigned char)0xBF);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::movzbq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x0F);
- emit_byte(0xB6);
+ emit_int8((unsigned char)0x0F);
+ emit_int8((unsigned char)0xB6);
emit_operand(dst, src);
}
void Assembler::movzbq(Register dst, Register src) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0xB6);
- emit_byte(0xC0 | encode);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xB6);
+ emit_int8(0xC0 | encode);
}
void Assembler::movzwq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x0F);
- emit_byte(0xB7);
+ emit_int8((unsigned char)0x0F);
+ emit_int8((unsigned char)0xB7);
emit_operand(dst, src);
}
void Assembler::movzwq(Register dst, Register src) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0xB7);
- emit_byte(0xC0 | encode);
+ emit_int8((unsigned char)0x0F);
+ emit_int8((unsigned char)0xB7);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::negq(Register dst) {
int encode = prefixq_and_encode(dst->encoding());
- emit_byte(0xF7);
- emit_byte(0xD8 | encode);
+ emit_int8((unsigned char)0xF7);
+ emit_int8((unsigned char)(0xD8 | encode));
}
void Assembler::notq(Register dst) {
int encode = prefixq_and_encode(dst->encoding());
- emit_byte(0xF7);
- emit_byte(0xD0 | encode);
+ emit_int8((unsigned char)0xF7);
+ emit_int8((unsigned char)(0xD0 | encode));
}
void Assembler::orq(Address dst, int32_t imm32) {
InstructionMark im(this);
prefixq(dst);
- emit_byte(0x81);
+ emit_int8((unsigned char)0x81);
emit_operand(rcx, dst, 4);
- emit_long(imm32);
+ emit_int32(imm32);
}
void Assembler::orq(Register dst, int32_t imm32) {
@@ -5074,7 +5230,7 @@
void Assembler::orq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x0B);
+ emit_int8(0x0B);
emit_operand(dst, src);
}
@@ -5107,26 +5263,26 @@
void Assembler::popcntq(Register dst, Address src) {
assert(VM_Version::supports_popcnt(), "must support");
InstructionMark im(this);
- emit_byte(0xF3);
+ emit_int8((unsigned char)0xF3);
prefixq(src, dst);
- emit_byte(0x0F);
- emit_byte(0xB8);
+ emit_int8((unsigned char)0x0F);
+ emit_int8((unsigned char)0xB8);
emit_operand(dst, src);
}
void Assembler::popcntq(Register dst, Register src) {
assert(VM_Version::supports_popcnt(), "must support");
- emit_byte(0xF3);
+ emit_int8((unsigned char)0xF3);
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x0F);
- emit_byte(0xB8);
- emit_byte(0xC0 | encode);
+ emit_int8((unsigned char)0x0F);
+ emit_int8((unsigned char)0xB8);
+ emit_int8((unsigned char)(0xC0 | encode));
}
void Assembler::popq(Address dst) {
InstructionMark im(this);
prefixq(dst);
- emit_byte(0x8F);
+ emit_int8((unsigned char)0x8F);
emit_operand(rax, dst);
}
@@ -5158,7 +5314,7 @@
void Assembler::pushq(Address src) {
InstructionMark im(this);
prefixq(src);
- emit_byte(0xFF);
+ emit_int8((unsigned char)0xFF);
emit_operand(rsi, src);
}
@@ -5166,31 +5322,31 @@
assert(isShiftCount(imm8 >> 1), "illegal shift count");
int encode = prefixq_and_encode(dst->encoding());
if (imm8 == 1) {
- emit_byte(0xD1);
- emit_byte(0xD0 | encode);
+ emit_int8((unsigned char)0xD1);
+ emit_int8((unsigned char)(0xD0 | encode));
} else {
- emit_byte(0xC1);
- emit_byte(0xD0 | encode);
- emit_byte(imm8);
+ emit_int8((unsigned char)0xC1);
+ emit_int8((unsigned char)(0xD0 | encode));
+ emit_int8(imm8);
}
}
void Assembler::sarq(Register dst, int imm8) {
assert(isShiftCount(imm8 >> 1), "illegal shift count");
int encode = prefixq_and_encode(dst->encoding());
if (imm8 == 1) {
- emit_byte(0xD1);
- emit_byte(0xF8 | encode);
+ emit_int8((unsigned char)0xD1);
+ emit_int8((unsigned char)(0xF8 | encode));
} else {
- emit_byte(0xC1);
- emit_byte(0xF8 | encode);
- emit_byte(imm8);
+ emit_int8((unsigned char)0xC1);
+ emit_int8((unsigned char)(0xF8 | encode));
+ emit_int8(imm8);
}
}
void Assembler::sarq(Register dst) {
int encode = prefixq_and_encode(dst->encoding());
- emit_byte(0xD3);
- emit_byte(0xF8 | encode);
+ emit_int8((unsigned char)0xD3);
+ emit_int8((unsigned char)(0xF8 | encode));
}
void Assembler::sbbq(Address dst, int32_t imm32) {
@@ -5207,7 +5363,7 @@
void Assembler::sbbq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x1B);
+ emit_int8(0x1B);
emit_operand(dst, src);
}
@@ -5220,33 +5376,33 @@
assert(isShiftCount(imm8 >> 1), "illegal shift count");
int encode = prefixq_and_encode(dst->encoding());
if (imm8 == 1) {
- emit_byte(0xD1);
- emit_byte(0xE0 | encode);
+ emit_int8((unsigned char)0xD1);
+ emit_int8((unsigned char)(0xE0 | encode));
} else {
- emit_byte(0xC1);
- emit_byte(0xE0 | encode);
- emit_byte(imm8);
+ emit_int8((unsigned char)0xC1);
+ emit_int8((unsigned char)(0xE0 | encode));
+ emit_int8(imm8);
}
}
void Assembler::shlq(Register dst) {
int encode = prefixq_and_encode(dst->encoding());
- emit_byte(0xD3);
- emit_byte(0xE0 | encode);
+ emit_int8((unsigned char)0xD3);
+ emit_int8((unsigned char)(0xE0 | encode));
}
void Assembler::shrq(Register dst, int imm8) {
assert(isShiftCount(imm8 >> 1), "illegal shift count");
int encode = prefixq_and_encode(dst->encoding());
- emit_byte(0xC1);
- emit_byte(0xE8 | encode);
- emit_byte(imm8);
+ emit_int8((unsigned char)0xC1);
+ emit_int8((unsigned char)(0xE8 | encode));
+ emit_int8(imm8);
}
void Assembler::shrq(Register dst) {
int encode = prefixq_and_encode(dst->encoding());
- emit_byte(0xD3);
- emit_byte(0xE8 | encode);
+ emit_int8((unsigned char)0xD3);
+ emit_int8(0xE8 | encode);
}
void Assembler::subq(Address dst, int32_t imm32) {
@@ -5258,7 +5414,7 @@
void Assembler::subq(Address dst, Register src) {
InstructionMark im(this);
prefixq(dst, src);
- emit_byte(0x29);
+ emit_int8(0x29);
emit_operand(src, dst);
}
@@ -5276,7 +5432,7 @@
void Assembler::subq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x2B);
+ emit_int8(0x2B);
emit_operand(dst, src);
}
@@ -5292,13 +5448,13 @@
int encode = dst->encoding();
if (encode == 0) {
prefix(REX_W);
- emit_byte(0xA9);
+ emit_int8((unsigned char)0xA9);
} else {
encode = prefixq_and_encode(encode);
- emit_byte(0xF7);
- emit_byte(0xC0 | encode);
+ emit_int8((unsigned char)0xF7);
+ emit_int8((unsigned char)(0xC0 | encode));
}
- emit_long(imm32);
+ emit_int32(imm32);
}
void Assembler::testq(Register dst, Register src) {
@@ -5309,22 +5465,22 @@
void Assembler::xaddq(Address dst, Register src) {
InstructionMark im(this);
prefixq(dst, src);
- emit_byte(0x0F);
- emit_byte(0xC1);
+ emit_int8(0x0F);
+ emit_int8((unsigned char)0xC1);
emit_operand(src, dst);
}
void Assembler::xchgq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x87);
+ emit_int8((unsigned char)0x87);
emit_operand(dst, src);
}
void Assembler::xchgq(Register dst, Register src) {
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
- emit_byte(0x87);
- emit_byte(0xc0 | encode);
+ emit_int8((unsigned char)0x87);
+ emit_int8((unsigned char)(0xc0 | encode));
}
void Assembler::xorq(Register dst, Register src) {
@@ -5335,6028 +5491,8 @@
void Assembler::xorq(Register dst, Address src) {
InstructionMark im(this);
prefixq(src, dst);
- emit_byte(0x33);
+ emit_int8(0x33);
emit_operand(dst, src);
}
#endif // !LP64
-
-static Assembler::Condition reverse[] = {
- Assembler::noOverflow /* overflow = 0x0 */ ,
- Assembler::overflow /* noOverflow = 0x1 */ ,
- Assembler::aboveEqual /* carrySet = 0x2, below = 0x2 */ ,
- Assembler::below /* aboveEqual = 0x3, carryClear = 0x3 */ ,
- Assembler::notZero /* zero = 0x4, equal = 0x4 */ ,
- Assembler::zero /* notZero = 0x5, notEqual = 0x5 */ ,
- Assembler::above /* belowEqual = 0x6 */ ,
- Assembler::belowEqual /* above = 0x7 */ ,
- Assembler::positive /* negative = 0x8 */ ,
- Assembler::negative /* positive = 0x9 */ ,
- Assembler::noParity /* parity = 0xa */ ,
- Assembler::parity /* noParity = 0xb */ ,
- Assembler::greaterEqual /* less = 0xc */ ,
- Assembler::less /* greaterEqual = 0xd */ ,
- Assembler::greater /* lessEqual = 0xe */ ,
- Assembler::lessEqual /* greater = 0xf, */
-
-};
-
-
-// Implementation of MacroAssembler
-
-// First all the versions that have distinct versions depending on 32/64 bit
-// Unless the difference is trivial (1 line or so).
-
-#ifndef _LP64
-
-// 32bit versions
-
-Address MacroAssembler::as_Address(AddressLiteral adr) {
- return Address(adr.target(), adr.rspec());
-}
-
-Address MacroAssembler::as_Address(ArrayAddress adr) {
- return Address::make_array(adr);
-}
-
-int MacroAssembler::biased_locking_enter(Register lock_reg,
- Register obj_reg,
- Register swap_reg,
- Register tmp_reg,
- bool swap_reg_contains_mark,
- Label& done,
- Label* slow_case,
- BiasedLockingCounters* counters) {
- assert(UseBiasedLocking, "why call this otherwise?");
- assert(swap_reg == rax, "swap_reg must be rax, for cmpxchg");
- assert_different_registers(lock_reg, obj_reg, swap_reg);
-
- if (PrintBiasedLockingStatistics && counters == NULL)
- counters = BiasedLocking::counters();
-
- bool need_tmp_reg = false;
- if (tmp_reg == noreg) {
- need_tmp_reg = true;
- tmp_reg = lock_reg;
- } else {
- assert_different_registers(lock_reg, obj_reg, swap_reg, tmp_reg);
- }
- assert(markOopDesc::age_shift == markOopDesc::lock_bits + markOopDesc::biased_lock_bits, "biased locking makes assumptions about bit layout");
- Address mark_addr (obj_reg, oopDesc::mark_offset_in_bytes());
- Address klass_addr (obj_reg, oopDesc::klass_offset_in_bytes());
- Address saved_mark_addr(lock_reg, 0);
-
- // Biased locking
- // See whether the lock is currently biased toward our thread and
- // whether the epoch is still valid
- // Note that the runtime guarantees sufficient alignment of JavaThread
- // pointers to allow age to be placed into low bits
- // First check to see whether biasing is even enabled for this object
- Label cas_label;
- int null_check_offset = -1;
- if (!swap_reg_contains_mark) {
- null_check_offset = offset();
- movl(swap_reg, mark_addr);
- }
- if (need_tmp_reg) {
- push(tmp_reg);
- }
- movl(tmp_reg, swap_reg);
- andl(tmp_reg, markOopDesc::biased_lock_mask_in_place);
- cmpl(tmp_reg, markOopDesc::biased_lock_pattern);
- if (need_tmp_reg) {
- pop(tmp_reg);
- }
- jcc(Assembler::notEqual, cas_label);
- // The bias pattern is present in the object's header. Need to check
- // whether the bias owner and the epoch are both still current.
- // Note that because there is no current thread register on x86 we
- // need to store off the mark word we read out of the object to
- // avoid reloading it and needing to recheck invariants below. This
- // store is unfortunate but it makes the overall code shorter and
- // simpler.
- movl(saved_mark_addr, swap_reg);
- if (need_tmp_reg) {
- push(tmp_reg);
- }
- get_thread(tmp_reg);
- xorl(swap_reg, tmp_reg);
- if (swap_reg_contains_mark) {
- null_check_offset = offset();
- }
- movl(tmp_reg, klass_addr);
- xorl(swap_reg, Address(tmp_reg, Klass::prototype_header_offset()));
- andl(swap_reg, ~((int) markOopDesc::age_mask_in_place));
- if (need_tmp_reg) {
- pop(tmp_reg);
- }
- if (counters != NULL) {
- cond_inc32(Assembler::zero,
- ExternalAddress((address)counters->biased_lock_entry_count_addr()));
- }
- jcc(Assembler::equal, done);
-
- Label try_revoke_bias;
- Label try_rebias;
-
- // At this point we know that the header has the bias pattern and
- // that we are not the bias owner in the current epoch. We need to
- // figure out more details about the state of the header in order to
- // know what operations can be legally performed on the object's
- // header.
-
- // If the low three bits in the xor result aren't clear, that means
- // the prototype header is no longer biased and we have to revoke
- // the bias on this object.
- testl(swap_reg, markOopDesc::biased_lock_mask_in_place);
- jcc(Assembler::notZero, try_revoke_bias);
-
- // Biasing is still enabled for this data type. See whether the
- // epoch of the current bias is still valid, meaning that the epoch
- // bits of the mark word are equal to the epoch bits of the
- // prototype header. (Note that the prototype header's epoch bits
- // only change at a safepoint.) If not, attempt to rebias the object
- // toward the current thread. Note that we must be absolutely sure
- // that the current epoch is invalid in order to do this because
- // otherwise the manipulations it performs on the mark word are
- // illegal.
- testl(swap_reg, markOopDesc::epoch_mask_in_place);
- jcc(Assembler::notZero, try_rebias);
-
- // The epoch of the current bias is still valid but we know nothing
- // about the owner; it might be set or it might be clear. Try to
- // acquire the bias of the object using an atomic operation. If this
- // fails we will go in to the runtime to revoke the object's bias.
- // Note that we first construct the presumed unbiased header so we
- // don't accidentally blow away another thread's valid bias.
- movl(swap_reg, saved_mark_addr);
- andl(swap_reg,
- markOopDesc::biased_lock_mask_in_place | markOopDesc::age_mask_in_place | markOopDesc::epoch_mask_in_place);
- if (need_tmp_reg) {
- push(tmp_reg);
- }
- get_thread(tmp_reg);
- orl(tmp_reg, swap_reg);
- if (os::is_MP()) {
- lock();
- }
- cmpxchgptr(tmp_reg, Address(obj_reg, 0));
- if (need_tmp_reg) {
- pop(tmp_reg);
- }
- // If the biasing toward our thread failed, this means that
- // another thread succeeded in biasing it toward itself and we
- // need to revoke that bias. The revocation will occur in the
- // interpreter runtime in the slow case.
- if (counters != NULL) {
- cond_inc32(Assembler::zero,
- ExternalAddress((address)counters->anonymously_biased_lock_entry_count_addr()));
- }
- if (slow_case != NULL) {
- jcc(Assembler::notZero, *slow_case);
- }
- jmp(done);
-
- bind(try_rebias);
- // At this point we know the epoch has expired, meaning that the
- // current "bias owner", if any, is actually invalid. Under these
- // circumstances _only_, we are allowed to use the current header's
- // value as the comparison value when doing the cas to acquire the
- // bias in the current epoch. In other words, we allow transfer of
- // the bias from one thread to another directly in this situation.
- //
- // FIXME: due to a lack of registers we currently blow away the age
- // bits in this situation. Should attempt to preserve them.
- if (need_tmp_reg) {
- push(tmp_reg);
- }
- get_thread(tmp_reg);
- movl(swap_reg, klass_addr);
- orl(tmp_reg, Address(swap_reg, Klass::prototype_header_offset()));
- movl(swap_reg, saved_mark_addr);
- if (os::is_MP()) {
- lock();
- }
- cmpxchgptr(tmp_reg, Address(obj_reg, 0));
- if (need_tmp_reg) {
- pop(tmp_reg);
- }
- // If the biasing toward our thread failed, then another thread
- // succeeded in biasing it toward itself and we need to revoke that
- // bias. The revocation will occur in the runtime in the slow case.
- if (counters != NULL) {
- cond_inc32(Assembler::zero,
- ExternalAddress((address)counters->rebiased_lock_entry_count_addr()));
- }
- if (slow_case != NULL) {
- jcc(Assembler::notZero, *slow_case);
- }
- jmp(done);
-
- bind(try_revoke_bias);
- // The prototype mark in the klass doesn't have the bias bit set any
- // more, indicating that objects of this data type are not supposed
- // to be biased any more. We are going to try to reset the mark of
- // this object to the prototype value and fall through to the
- // CAS-based locking scheme. Note that if our CAS fails, it means
- // that another thread raced us for the privilege of revoking the
- // bias of this particular object, so it's okay to continue in the
- // normal locking code.
- //
- // FIXME: due to a lack of registers we currently blow away the age
- // bits in this situation. Should attempt to preserve them.
- movl(swap_reg, saved_mark_addr);
- if (need_tmp_reg) {
- push(tmp_reg);
- }
- movl(tmp_reg, klass_addr);
- movl(tmp_reg, Address(tmp_reg, Klass::prototype_header_offset()));
- if (os::is_MP()) {
- lock();
- }
- cmpxchgptr(tmp_reg, Address(obj_reg, 0));
- if (need_tmp_reg) {
- pop(tmp_reg);
- }
- // Fall through to the normal CAS-based lock, because no matter what
- // the result of the above CAS, some thread must have succeeded in
- // removing the bias bit from the object's header.
- if (counters != NULL) {
- cond_inc32(Assembler::zero,
- ExternalAddress((address)counters->revoked_lock_entry_count_addr()));
- }
-
- bind(cas_label);
-
- return null_check_offset;
-}
-void MacroAssembler::call_VM_leaf_base(address entry_point,
- int number_of_arguments) {
- call(RuntimeAddress(entry_point));
- increment(rsp, number_of_arguments * wordSize);
-}
-
-void MacroAssembler::cmpklass(Address src1, Metadata* obj) {
- cmp_literal32(src1, (int32_t)obj, metadata_Relocation::spec_for_immediate());
-}
-
-void MacroAssembler::cmpklass(Register src1, Metadata* obj) {
- cmp_literal32(src1, (int32_t)obj, metadata_Relocation::spec_for_immediate());
-}
-
-void MacroAssembler::cmpoop(Address src1, jobject obj) {
- cmp_literal32(src1, (int32_t)obj, oop_Relocation::spec_for_immediate());
-}
-
-void MacroAssembler::cmpoop(Register src1, jobject obj) {
- cmp_literal32(src1, (int32_t)obj, oop_Relocation::spec_for_immediate());
-}
-
-void MacroAssembler::extend_sign(Register hi, Register lo) {
- // According to Intel Doc. AP-526, "Integer Divide", p.18.
- if (VM_Version::is_P6() && hi == rdx && lo == rax) {
- cdql();
- } else {
- movl(hi, lo);
- sarl(hi, 31);
- }
-}
-
-void MacroAssembler::jC2(Register tmp, Label& L) {
- // set parity bit if FPU flag C2 is set (via rax)
- save_rax(tmp);
- fwait(); fnstsw_ax();
- sahf();
- restore_rax(tmp);
- // branch
- jcc(Assembler::parity, L);
-}
-
-void MacroAssembler::jnC2(Register tmp, Label& L) {
- // set parity bit if FPU flag C2 is set (via rax)
- save_rax(tmp);
- fwait(); fnstsw_ax();
- sahf();
- restore_rax(tmp);
- // branch
- jcc(Assembler::noParity, L);
-}
-
-// 32bit can do a case table jump in one instruction but we no longer allow the base
-// to be installed in the Address class
-void MacroAssembler::jump(ArrayAddress entry) {
- jmp(as_Address(entry));
-}
-
-// Note: y_lo will be destroyed
-void MacroAssembler::lcmp2int(Register x_hi, Register x_lo, Register y_hi, Register y_lo) {
- // Long compare for Java (semantics as described in JVM spec.)
- Label high, low, done;
-
- cmpl(x_hi, y_hi);
- jcc(Assembler::less, low);
- jcc(Assembler::greater, high);
- // x_hi is the return register
- xorl(x_hi, x_hi);
- cmpl(x_lo, y_lo);
- jcc(Assembler::below, low);
- jcc(Assembler::equal, done);
-
- bind(high);
- xorl(x_hi, x_hi);
- increment(x_hi);
- jmp(done);
-
- bind(low);
- xorl(x_hi, x_hi);
- decrementl(x_hi);
-
- bind(done);
-}
-
-void MacroAssembler::lea(Register dst, AddressLiteral src) {
- mov_literal32(dst, (int32_t)src.target(), src.rspec());
-}
-
-void MacroAssembler::lea(Address dst, AddressLiteral adr) {
- // leal(dst, as_Address(adr));
- // see note in movl as to why we must use a move
- mov_literal32(dst, (int32_t) adr.target(), adr.rspec());
-}
-
-void MacroAssembler::leave() {
- mov(rsp, rbp);
- pop(rbp);
-}
-
-void MacroAssembler::lmul(int x_rsp_offset, int y_rsp_offset) {
- // Multiplication of two Java long values stored on the stack
- // as illustrated below. Result is in rdx:rax.
- //
- // rsp ---> [ ?? ] \ \
- // .... | y_rsp_offset |
- // [ y_lo ] / (in bytes) | x_rsp_offset
- // [ y_hi ] | (in bytes)
- // .... |
- // [ x_lo ] /
- // [ x_hi ]
- // ....
- //
- // Basic idea: lo(result) = lo(x_lo * y_lo)
- // hi(result) = hi(x_lo * y_lo) + lo(x_hi * y_lo) + lo(x_lo * y_hi)
- Address x_hi(rsp, x_rsp_offset + wordSize); Address x_lo(rsp, x_rsp_offset);
- Address y_hi(rsp, y_rsp_offset + wordSize); Address y_lo(rsp, y_rsp_offset);
- Label quick;
- // load x_hi, y_hi and check if quick
- // multiplication is possible
- movl(rbx, x_hi);
- movl(rcx, y_hi);
- movl(rax, rbx);
- orl(rbx, rcx); // rbx, = 0 <=> x_hi = 0 and y_hi = 0
- jcc(Assembler::zero, quick); // if rbx, = 0 do quick multiply
- // do full multiplication
- // 1st step
- mull(y_lo); // x_hi * y_lo
- movl(rbx, rax); // save lo(x_hi * y_lo) in rbx,
- // 2nd step
- movl(rax, x_lo);
- mull(rcx); // x_lo * y_hi
- addl(rbx, rax); // add lo(x_lo * y_hi) to rbx,
- // 3rd step
- bind(quick); // note: rbx, = 0 if quick multiply!
- movl(rax, x_lo);
- mull(y_lo); // x_lo * y_lo
- addl(rdx, rbx); // correct hi(x_lo * y_lo)
-}
-
-void MacroAssembler::lneg(Register hi, Register lo) {
- negl(lo);
- adcl(hi, 0);
- negl(hi);
-}
-
-void MacroAssembler::lshl(Register hi, Register lo) {
- // Java shift left long support (semantics as described in JVM spec., p.305)
- // (basic idea for shift counts s >= n: x << s == (x << n) << (s - n))
- // shift value is in rcx !
- assert(hi != rcx, "must not use rcx");
- assert(lo != rcx, "must not use rcx");
- const Register s = rcx; // shift count
- const int n = BitsPerWord;
- Label L;
- andl(s, 0x3f); // s := s & 0x3f (s < 0x40)
- cmpl(s, n); // if (s < n)
- jcc(Assembler::less, L); // else (s >= n)
- movl(hi, lo); // x := x << n
- xorl(lo, lo);
- // Note: subl(s, n) is not needed since the Intel shift instructions work rcx mod n!
- bind(L); // s (mod n) < n
- shldl(hi, lo); // x := x << s
- shll(lo);
-}
-
-
-void MacroAssembler::lshr(Register hi, Register lo, bool sign_extension) {
- // Java shift right long support (semantics as described in JVM spec., p.306 & p.310)
- // (basic idea for shift counts s >= n: x >> s == (x >> n) >> (s - n))
- assert(hi != rcx, "must not use rcx");
- assert(lo != rcx, "must not use rcx");
- const Register s = rcx; // shift count
- const int n = BitsPerWord;
- Label L;
- andl(s, 0x3f); // s := s & 0x3f (s < 0x40)
- cmpl(s, n); // if (s < n)
- jcc(Assembler::less, L); // else (s >= n)
- movl(lo, hi); // x := x >> n
- if (sign_extension) sarl(hi, 31);
- else xorl(hi, hi);
- // Note: subl(s, n) is not needed since the Intel shift instructions work rcx mod n!
- bind(L); // s (mod n) < n
- shrdl(lo, hi); // x := x >> s
- if (sign_extension) sarl(hi);
- else shrl(hi);
-}
-
-void MacroAssembler::movoop(Register dst, jobject obj) {
- mov_literal32(dst, (int32_t)obj, oop_Relocation::spec_for_immediate());
-}
-
-void MacroAssembler::movoop(Address dst, jobject obj) {
- mov_literal32(dst, (int32_t)obj, oop_Relocation::spec_for_immediate());
-}
-
-void MacroAssembler::mov_metadata(Register dst, Metadata* obj) {
- mov_literal32(dst, (int32_t)obj, metadata_Relocation::spec_for_immediate());
-}
-
-void MacroAssembler::mov_metadata(Address dst, Metadata* obj) {
- mov_literal32(dst, (int32_t)obj, metadata_Relocation::spec_for_immediate());
-}
-
-void MacroAssembler::movptr(Register dst, AddressLiteral src) {
- if (src.is_lval()) {
- mov_literal32(dst, (intptr_t)src.target(), src.rspec());
- } else {
- movl(dst, as_Address(src));
- }
-}
-
-void MacroAssembler::movptr(ArrayAddress dst, Register src) {
- movl(as_Address(dst), src);
-}
-
-void MacroAssembler::movptr(Register dst, ArrayAddress src) {
- movl(dst, as_Address(src));
-}
-
-// src should NEVER be a real pointer. Use AddressLiteral for true pointers
-void MacroAssembler::movptr(Address dst, intptr_t src) {
- movl(dst, src);
-}
-
-
-void MacroAssembler::pop_callee_saved_registers() {
- pop(rcx);
- pop(rdx);
- pop(rdi);
- pop(rsi);
-}
-
-void MacroAssembler::pop_fTOS() {
- fld_d(Address(rsp, 0));
- addl(rsp, 2 * wordSize);
-}
-
-void MacroAssembler::push_callee_saved_registers() {
- push(rsi);
- push(rdi);
- push(rdx);
- push(rcx);
-}
-
-void MacroAssembler::push_fTOS() {
- subl(rsp, 2 * wordSize);
- fstp_d(Address(rsp, 0));
-}
-
-
-void MacroAssembler::pushoop(jobject obj) {
- push_literal32((int32_t)obj, oop_Relocation::spec_for_immediate());
-}
-
-void MacroAssembler::pushklass(Metadata* obj) {
- push_literal32((int32_t)obj, metadata_Relocation::spec_for_immediate());
-}
-
-void MacroAssembler::pushptr(AddressLiteral src) {
- if (src.is_lval()) {
- push_literal32((int32_t)src.target(), src.rspec());
- } else {
- pushl(as_Address(src));
- }
-}
-
-void MacroAssembler::set_word_if_not_zero(Register dst) {
- xorl(dst, dst);
- set_byte_if_not_zero(dst);
-}
-
-static void pass_arg0(MacroAssembler* masm, Register arg) {
- masm->push(arg);
-}
-
-static void pass_arg1(MacroAssembler* masm, Register arg) {
- masm->push(arg);
-}
-
-static void pass_arg2(MacroAssembler* masm, Register arg) {
- masm->push(arg);
-}
-
-static void pass_arg3(MacroAssembler* masm, Register arg) {
- masm->push(arg);
-}
-
-#ifndef PRODUCT
-extern "C" void findpc(intptr_t x);
-#endif
-
-void MacroAssembler::debug32(int rdi, int rsi, int rbp, int rsp, int rbx, int rdx, int rcx, int rax, int eip, char* msg) {
- // In order to get locks to work, we need to fake a in_VM state
- JavaThread* thread = JavaThread::current();
- JavaThreadState saved_state = thread->thread_state();
- thread->set_thread_state(_thread_in_vm);
- if (ShowMessageBoxOnError) {
- JavaThread* thread = JavaThread::current();
- JavaThreadState saved_state = thread->thread_state();
- thread->set_thread_state(_thread_in_vm);
- if (CountBytecodes || TraceBytecodes || StopInterpreterAt) {
- ttyLocker ttyl;
- BytecodeCounter::print();
- }
- // To see where a verify_oop failed, get $ebx+40/X for this frame.
- // This is the value of eip which points to where verify_oop will return.
- if (os::message_box(msg, "Execution stopped, print registers?")) {
- print_state32(rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax, eip);
- BREAKPOINT;
- }
- } else {
- ttyLocker ttyl;
- ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg);
- }
- // Don't assert holding the ttyLock
- assert(false, err_msg("DEBUG MESSAGE: %s", msg));
- ThreadStateTransition::transition(thread, _thread_in_vm, saved_state);
-}
-
-void MacroAssembler::print_state32(int rdi, int rsi, int rbp, int rsp, int rbx, int rdx, int rcx, int rax, int eip) {
- ttyLocker ttyl;
- FlagSetting fs(Debugging, true);
- tty->print_cr("eip = 0x%08x", eip);
-#ifndef PRODUCT
- if ((WizardMode || Verbose) && PrintMiscellaneous) {
- tty->cr();
- findpc(eip);
- tty->cr();
- }
-#endif
-#define PRINT_REG(rax) \
- { tty->print("%s = ", #rax); os::print_location(tty, rax); }
- PRINT_REG(rax);
- PRINT_REG(rbx);
- PRINT_REG(rcx);
- PRINT_REG(rdx);
- PRINT_REG(rdi);
- PRINT_REG(rsi);
- PRINT_REG(rbp);
- PRINT_REG(rsp);
-#undef PRINT_REG
- // Print some words near top of staack.
- int* dump_sp = (int*) rsp;
- for (int col1 = 0; col1 < 8; col1++) {
- tty->print("(rsp+0x%03x) 0x%08x: ", (int)((intptr_t)dump_sp - (intptr_t)rsp), (intptr_t)dump_sp);
- os::print_location(tty, *dump_sp++);
- }
- for (int row = 0; row < 16; row++) {
- tty->print("(rsp+0x%03x) 0x%08x: ", (int)((intptr_t)dump_sp - (intptr_t)rsp), (intptr_t)dump_sp);
- for (int col = 0; col < 8; col++) {
- tty->print(" 0x%08x", *dump_sp++);
- }
- tty->cr();
- }
- // Print some instructions around pc:
- Disassembler::decode((address)eip-64, (address)eip);
- tty->print_cr("--------");
- Disassembler::decode((address)eip, (address)eip+32);
-}
-
-void MacroAssembler::stop(const char* msg) {
- ExternalAddress message((address)msg);
- // push address of message
- pushptr(message.addr());
- { Label L; call(L, relocInfo::none); bind(L); } // push eip
- pusha(); // push registers
- call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug32)));
- hlt();
-}
-
-void MacroAssembler::warn(const char* msg) {
- push_CPU_state();
-
- ExternalAddress message((address) msg);
- // push address of message
- pushptr(message.addr());
-
- call(RuntimeAddress(CAST_FROM_FN_PTR(address, warning)));
- addl(rsp, wordSize); // discard argument
- pop_CPU_state();
-}
-
-void MacroAssembler::print_state() {
- { Label L; call(L, relocInfo::none); bind(L); } // push eip
- pusha(); // push registers
-
- push_CPU_state();
- call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::print_state32)));
- pop_CPU_state();
-
- popa();
- addl(rsp, wordSize);
-}
-
-#else // _LP64
-
-// 64 bit versions
-
-Address MacroAssembler::as_Address(AddressLiteral adr) {
- // amd64 always does this as a pc-rel
- // we can be absolute or disp based on the instruction type
- // jmp/call are displacements others are absolute
- assert(!adr.is_lval(), "must be rval");
- assert(reachable(adr), "must be");
- return Address((int32_t)(intptr_t)(adr.target() - pc()), adr.target(), adr.reloc());
-
-}
-
-Address MacroAssembler::as_Address(ArrayAddress adr) {
- AddressLiteral base = adr.base();
- lea(rscratch1, base);
- Address index = adr.index();
- assert(index._disp == 0, "must not have disp"); // maybe it can?
- Address array(rscratch1, index._index, index._scale, index._disp);
- return array;
-}
-
-int MacroAssembler::biased_locking_enter(Register lock_reg,
- Register obj_reg,
- Register swap_reg,
- Register tmp_reg,
- bool swap_reg_contains_mark,
- Label& done,
- Label* slow_case,
- BiasedLockingCounters* counters) {
- assert(UseBiasedLocking, "why call this otherwise?");
- assert(swap_reg == rax, "swap_reg must be rax for cmpxchgq");
- assert(tmp_reg != noreg, "tmp_reg must be supplied");
- assert_different_registers(lock_reg, obj_reg, swap_reg, tmp_reg);
- assert(markOopDesc::age_shift == markOopDesc::lock_bits + markOopDesc::biased_lock_bits, "biased locking makes assumptions about bit layout");
- Address mark_addr (obj_reg, oopDesc::mark_offset_in_bytes());
- Address saved_mark_addr(lock_reg, 0);
-
- if (PrintBiasedLockingStatistics && counters == NULL)
- counters = BiasedLocking::counters();
-
- // Biased locking
- // See whether the lock is currently biased toward our thread and
- // whether the epoch is still valid
- // Note that the runtime guarantees sufficient alignment of JavaThread
- // pointers to allow age to be placed into low bits
- // First check to see whether biasing is even enabled for this object
- Label cas_label;
- int null_check_offset = -1;
- if (!swap_reg_contains_mark) {
- null_check_offset = offset();
- movq(swap_reg, mark_addr);
- }
- movq(tmp_reg, swap_reg);
- andq(tmp_reg, markOopDesc::biased_lock_mask_in_place);
- cmpq(tmp_reg, markOopDesc::biased_lock_pattern);
- jcc(Assembler::notEqual, cas_label);
- // The bias pattern is present in the object's header. Need to check
- // whether the bias owner and the epoch are both still current.
- load_prototype_header(tmp_reg, obj_reg);
- orq(tmp_reg, r15_thread);
- xorq(tmp_reg, swap_reg);
- andq(tmp_reg, ~((int) markOopDesc::age_mask_in_place));
- if (counters != NULL) {
- cond_inc32(Assembler::zero,
- ExternalAddress((address) counters->anonymously_biased_lock_entry_count_addr()));
- }
- jcc(Assembler::equal, done);
-
- Label try_revoke_bias;
- Label try_rebias;
-
- // At this point we know that the header has the bias pattern and
- // that we are not the bias owner in the current epoch. We need to
- // figure out more details about the state of the header in order to
- // know what operations can be legally performed on the object's
- // header.
-
- // If the low three bits in the xor result aren't clear, that means
- // the prototype header is no longer biased and we have to revoke
- // the bias on this object.
- testq(tmp_reg, markOopDesc::biased_lock_mask_in_place);
- jcc(Assembler::notZero, try_revoke_bias);
-
- // Biasing is still enabled for this data type. See whether the
- // epoch of the current bias is still valid, meaning that the epoch
- // bits of the mark word are equal to the epoch bits of the
- // prototype header. (Note that the prototype header's epoch bits
- // only change at a safepoint.) If not, attempt to rebias the object
- // toward the current thread. Note that we must be absolutely sure
- // that the current epoch is invalid in order to do this because
- // otherwise the manipulations it performs on the mark word are
- // illegal.
- testq(tmp_reg, markOopDesc::epoch_mask_in_place);
- jcc(Assembler::notZero, try_rebias);
-
- // The epoch of the current bias is still valid but we know nothing
- // about the owner; it might be set or it might be clear. Try to
- // acquire the bias of the object using an atomic operation. If this
- // fails we will go in to the runtime to revoke the object's bias.
- // Note that we first construct the presumed unbiased header so we
- // don't accidentally blow away another thread's valid bias.
- andq(swap_reg,
- markOopDesc::biased_lock_mask_in_place | markOopDesc::age_mask_in_place | markOopDesc::epoch_mask_in_place);
- movq(tmp_reg, swap_reg);
- orq(tmp_reg, r15_thread);
- if (os::is_MP()) {
- lock();
- }
- cmpxchgq(tmp_reg, Address(obj_reg, 0));
- // If the biasing toward our thread failed, this means that
- // another thread succeeded in biasing it toward itself and we
- // need to revoke that bias. The revocation will occur in the
- // interpreter runtime in the slow case.
- if (counters != NULL) {
- cond_inc32(Assembler::zero,
- ExternalAddress((address) counters->anonymously_biased_lock_entry_count_addr()));
- }
- if (slow_case != NULL) {
- jcc(Assembler::notZero, *slow_case);
- }
- jmp(done);
-
- bind(try_rebias);
- // At this point we know the epoch has expired, meaning that the
- // current "bias owner", if any, is actually invalid. Under these
- // circumstances _only_, we are allowed to use the current header's
- // value as the comparison value when doing the cas to acquire the
- // bias in the current epoch. In other words, we allow transfer of
- // the bias from one thread to another directly in this situation.
- //
- // FIXME: due to a lack of registers we currently blow away the age
- // bits in this situation. Should attempt to preserve them.
- load_prototype_header(tmp_reg, obj_reg);
- orq(tmp_reg, r15_thread);
- if (os::is_MP()) {
- lock();
- }
- cmpxchgq(tmp_reg, Address(obj_reg, 0));
- // If the biasing toward our thread failed, then another thread
- // succeeded in biasing it toward itself and we need to revoke that
- // bias. The revocation will occur in the runtime in the slow case.
- if (counters != NULL) {
- cond_inc32(Assembler::zero,
- ExternalAddress((address) counters->rebiased_lock_entry_count_addr()));
- }
- if (slow_case != NULL) {
- jcc(Assembler::notZero, *slow_case);
- }
- jmp(done);
-
- bind(try_revoke_bias);
- // The prototype mark in the klass doesn't have the bias bit set any
- // more, indicating that objects of this data type are not supposed
- // to be biased any more. We are going to try to reset the mark of
- // this object to the prototype value and fall through to the
- // CAS-based locking scheme. Note that if our CAS fails, it means
- // that another thread raced us for the privilege of revoking the
- // bias of this particular object, so it's okay to continue in the
- // normal locking code.
- //
- // FIXME: due to a lack of registers we currently blow away the age
- // bits in this situation. Should attempt to preserve them.
- load_prototype_header(tmp_reg, obj_reg);
- if (os::is_MP()) {
- lock();
- }
- cmpxchgq(tmp_reg, Address(obj_reg, 0));
- // Fall through to the normal CAS-based lock, because no matter what
- // the result of the above CAS, some thread must have succeeded in
- // removing the bias bit from the object's header.
- if (counters != NULL) {
- cond_inc32(Assembler::zero,
- ExternalAddress((address) counters->revoked_lock_entry_count_addr()));
- }
-
- bind(cas_label);
-
- return null_check_offset;
-}
-
-void MacroAssembler::call_VM_leaf_base(address entry_point, int num_args) {
- Label L, E;
-
-#ifdef _WIN64
- // Windows always allocates space for it's register args
- assert(num_args <= 4, "only register arguments supported");
- subq(rsp, frame::arg_reg_save_area_bytes);
-#endif
-
- // Align stack if necessary
- testl(rsp, 15);
- jcc(Assembler::zero, L);
-
- subq(rsp, 8);
- {
- call(RuntimeAddress(entry_point));
- }
- addq(rsp, 8);
- jmp(E);
-
- bind(L);
- {
- call(RuntimeAddress(entry_point));
- }
-
- bind(E);
-
-#ifdef _WIN64
- // restore stack pointer
- addq(rsp, frame::arg_reg_save_area_bytes);
-#endif
-
-}
-
-void MacroAssembler::cmp64(Register src1, AddressLiteral src2) {
- assert(!src2.is_lval(), "should use cmpptr");
-
- if (reachable(src2)) {
- cmpq(src1, as_Address(src2));
- } else {
- lea(rscratch1, src2);
- Assembler::cmpq(src1, Address(rscratch1, 0));
- }
-}
-
-int MacroAssembler::corrected_idivq(Register reg) {
- // Full implementation of Java ldiv and lrem; checks for special
- // case as described in JVM spec., p.243 & p.271. The function
- // returns the (pc) offset of the idivl instruction - may be needed
- // for implicit exceptions.
- //
- // normal case special case
- //
- // input : rax: dividend min_long
- // reg: divisor (may not be eax/edx) -1
- //
- // output: rax: quotient (= rax idiv reg) min_long
- // rdx: remainder (= rax irem reg) 0
- assert(reg != rax && reg != rdx, "reg cannot be rax or rdx register");
- static const int64_t min_long = 0x8000000000000000;
- Label normal_case, special_case;
-
- // check for special case
- cmp64(rax, ExternalAddress((address) &min_long));
- jcc(Assembler::notEqual, normal_case);
- xorl(rdx, rdx); // prepare rdx for possible special case (where
- // remainder = 0)
- cmpq(reg, -1);
- jcc(Assembler::equal, special_case);
-
- // handle normal case
- bind(normal_case);
- cdqq();
- int idivq_offset = offset();
- idivq(reg);
-
- // normal and special case exit
- bind(special_case);
-
- return idivq_offset;
-}
-
-void MacroAssembler::decrementq(Register reg, int value) {
- if (value == min_jint) { subq(reg, value); return; }
- if (value < 0) { incrementq(reg, -value); return; }
- if (value == 0) { ; return; }
- if (value == 1 && UseIncDec) { decq(reg) ; return; }
- /* else */ { subq(reg, value) ; return; }
-}
-
-void MacroAssembler::decrementq(Address dst, int value) {
- if (value == min_jint) { subq(dst, value); return; }
- if (value < 0) { incrementq(dst, -value); return; }
- if (value == 0) { ; return; }
- if (value == 1 && UseIncDec) { decq(dst) ; return; }
- /* else */ { subq(dst, value) ; return; }
-}
-
-void MacroAssembler::incrementq(Register reg, int value) {
- if (value == min_jint) { addq(reg, value); return; }
- if (value < 0) { decrementq(reg, -value); return; }
- if (value == 0) { ; return; }
- if (value == 1 && UseIncDec) { incq(reg) ; return; }
- /* else */ { addq(reg, value) ; return; }
-}
-
-void MacroAssembler::incrementq(Address dst, int value) {
- if (value == min_jint) { addq(dst, value); return; }
- if (value < 0) { decrementq(dst, -value); return; }
- if (value == 0) { ; return; }
- if (value == 1 && UseIncDec) { incq(dst) ; return; }
- /* else */ { addq(dst, value) ; return; }
-}
-
-// 32bit can do a case table jump in one instruction but we no longer allow the base
-// to be installed in the Address class
-void MacroAssembler::jump(ArrayAddress entry) {
- lea(rscratch1, entry.base());
- Address dispatch = entry.index();
- assert(dispatch._base == noreg, "must be");
- dispatch._base = rscratch1;
- jmp(dispatch);
-}
-
-void MacroAssembler::lcmp2int(Register x_hi, Register x_lo, Register y_hi, Register y_lo) {
- ShouldNotReachHere(); // 64bit doesn't use two regs
- cmpq(x_lo, y_lo);
-}
-
-void MacroAssembler::lea(Register dst, AddressLiteral src) {
- mov_literal64(dst, (intptr_t)src.target(), src.rspec());
-}
-
-void MacroAssembler::lea(Address dst, AddressLiteral adr) {
- mov_literal64(rscratch1, (intptr_t)adr.target(), adr.rspec());
- movptr(dst, rscratch1);
-}
-
-void MacroAssembler::leave() {
- // %%% is this really better? Why not on 32bit too?
- emit_byte(0xC9); // LEAVE
-}
-
-void MacroAssembler::lneg(Register hi, Register lo) {
- ShouldNotReachHere(); // 64bit doesn't use two regs
- negq(lo);
-}
-
-void MacroAssembler::movoop(Register dst, jobject obj) {
- mov_literal64(dst, (intptr_t)obj, oop_Relocation::spec_for_immediate());
-}
-
-void MacroAssembler::movoop(Address dst, jobject obj) {
- mov_literal64(rscratch1, (intptr_t)obj, oop_Relocation::spec_for_immediate());
- movq(dst, rscratch1);
-}
-
-void MacroAssembler::mov_metadata(Register dst, Metadata* obj) {
- mov_literal64(dst, (intptr_t)obj, metadata_Relocation::spec_for_immediate());
-}
-
-void MacroAssembler::mov_metadata(Address dst, Metadata* obj) {
- mov_literal64(rscratch1, (intptr_t)obj, metadata_Relocation::spec_for_immediate());
- movq(dst, rscratch1);
-}
-
-void MacroAssembler::movptr(Register dst, AddressLiteral src) {
- if (src.is_lval()) {
- mov_literal64(dst, (intptr_t)src.target(), src.rspec());
- } else {
- if (reachable(src)) {
- movq(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- movq(dst, Address(rscratch1,0));
- }
- }
-}
-
-void MacroAssembler::movptr(ArrayAddress dst, Register src) {
- movq(as_Address(dst), src);
-}
-
-void MacroAssembler::movptr(Register dst, ArrayAddress src) {
- movq(dst, as_Address(src));
-}
-
-// src should NEVER be a real pointer. Use AddressLiteral for true pointers
-void MacroAssembler::movptr(Address dst, intptr_t src) {
- mov64(rscratch1, src);
- movq(dst, rscratch1);
-}
-
-// These are mostly for initializing NULL
-void MacroAssembler::movptr(Address dst, int32_t src) {
- movslq(dst, src);
-}
-
-void MacroAssembler::movptr(Register dst, int32_t src) {
- mov64(dst, (intptr_t)src);
-}
-
-void MacroAssembler::pushoop(jobject obj) {
- movoop(rscratch1, obj);
- push(rscratch1);
-}
-
-void MacroAssembler::pushklass(Metadata* obj) {
- mov_metadata(rscratch1, obj);
- push(rscratch1);
-}
-
-void MacroAssembler::pushptr(AddressLiteral src) {
- lea(rscratch1, src);
- if (src.is_lval()) {
- push(rscratch1);
- } else {
- pushq(Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::reset_last_Java_frame(bool clear_fp,
- bool clear_pc) {
- // we must set sp to zero to clear frame
- movptr(Address(r15_thread, JavaThread::last_Java_sp_offset()), NULL_WORD);
- // must clear fp, so that compiled frames are not confused; it is
- // possible that we need it only for debugging
- if (clear_fp) {
- movptr(Address(r15_thread, JavaThread::last_Java_fp_offset()), NULL_WORD);
- }
-
- if (clear_pc) {
- movptr(Address(r15_thread, JavaThread::last_Java_pc_offset()), NULL_WORD);
- }
-}
-
-void MacroAssembler::set_last_Java_frame(Register last_java_sp,
- Register last_java_fp,
- address last_java_pc) {
- // determine last_java_sp register
- if (!last_java_sp->is_valid()) {
- last_java_sp = rsp;
- }
-
- // last_java_fp is optional
- if (last_java_fp->is_valid()) {
- movptr(Address(r15_thread, JavaThread::last_Java_fp_offset()),
- last_java_fp);
- }
-
- // last_java_pc is optional
- if (last_java_pc != NULL) {
- Address java_pc(r15_thread,
- JavaThread::frame_anchor_offset() + JavaFrameAnchor::last_Java_pc_offset());
- lea(rscratch1, InternalAddress(last_java_pc));
- movptr(java_pc, rscratch1);
- }
-
- movptr(Address(r15_thread, JavaThread::last_Java_sp_offset()), last_java_sp);
-}
-
-static void pass_arg0(MacroAssembler* masm, Register arg) {
- if (c_rarg0 != arg ) {
- masm->mov(c_rarg0, arg);
- }
-}
-
-static void pass_arg1(MacroAssembler* masm, Register arg) {
- if (c_rarg1 != arg ) {
- masm->mov(c_rarg1, arg);
- }
-}
-
-static void pass_arg2(MacroAssembler* masm, Register arg) {
- if (c_rarg2 != arg ) {
- masm->mov(c_rarg2, arg);
- }
-}
-
-static void pass_arg3(MacroAssembler* masm, Register arg) {
- if (c_rarg3 != arg ) {
- masm->mov(c_rarg3, arg);
- }
-}
-
-void MacroAssembler::stop(const char* msg) {
- address rip = pc();
- pusha(); // get regs on stack
- lea(c_rarg0, ExternalAddress((address) msg));
- lea(c_rarg1, InternalAddress(rip));
- movq(c_rarg2, rsp); // pass pointer to regs array
- andq(rsp, -16); // align stack as required by ABI
- call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug64)));
- hlt();
-}
-
-void MacroAssembler::warn(const char* msg) {
- push(rbp);
- movq(rbp, rsp);
- andq(rsp, -16); // align stack as required by push_CPU_state and call
- push_CPU_state(); // keeps alignment at 16 bytes
- lea(c_rarg0, ExternalAddress((address) msg));
- call_VM_leaf(CAST_FROM_FN_PTR(address, warning), c_rarg0);
- pop_CPU_state();
- mov(rsp, rbp);
- pop(rbp);
-}
-
-void MacroAssembler::print_state() {
- address rip = pc();
- pusha(); // get regs on stack
- push(rbp);
- movq(rbp, rsp);
- andq(rsp, -16); // align stack as required by push_CPU_state and call
- push_CPU_state(); // keeps alignment at 16 bytes
-
- lea(c_rarg0, InternalAddress(rip));
- lea(c_rarg1, Address(rbp, wordSize)); // pass pointer to regs array
- call_VM_leaf(CAST_FROM_FN_PTR(address, MacroAssembler::print_state64), c_rarg0, c_rarg1);
-
- pop_CPU_state();
- mov(rsp, rbp);
- pop(rbp);
- popa();
-}
-
-#ifndef PRODUCT
-extern "C" void findpc(intptr_t x);
-#endif
-
-void MacroAssembler::debug64(char* msg, int64_t pc, int64_t regs[]) {
- // In order to get locks to work, we need to fake a in_VM state
- if (ShowMessageBoxOnError) {
- JavaThread* thread = JavaThread::current();
- JavaThreadState saved_state = thread->thread_state();
- thread->set_thread_state(_thread_in_vm);
-#ifndef PRODUCT
- if (CountBytecodes || TraceBytecodes || StopInterpreterAt) {
- ttyLocker ttyl;
- BytecodeCounter::print();
- }
-#endif
- // To see where a verify_oop failed, get $ebx+40/X for this frame.
- // XXX correct this offset for amd64
- // This is the value of eip which points to where verify_oop will return.
- if (os::message_box(msg, "Execution stopped, print registers?")) {
- print_state64(pc, regs);
- BREAKPOINT;
- assert(false, "start up GDB");
- }
- ThreadStateTransition::transition(thread, _thread_in_vm, saved_state);
- } else {
- ttyLocker ttyl;
- ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n",
- msg);
- assert(false, err_msg("DEBUG MESSAGE: %s", msg));
- }
-}
-
-void MacroAssembler::print_state64(int64_t pc, int64_t regs[]) {
- ttyLocker ttyl;
- FlagSetting fs(Debugging, true);
- tty->print_cr("rip = 0x%016lx", pc);
-#ifndef PRODUCT
- tty->cr();
- findpc(pc);
- tty->cr();
-#endif
-#define PRINT_REG(rax, value) \
- { tty->print("%s = ", #rax); os::print_location(tty, value); }
- PRINT_REG(rax, regs[15]);
- PRINT_REG(rbx, regs[12]);
- PRINT_REG(rcx, regs[14]);
- PRINT_REG(rdx, regs[13]);
- PRINT_REG(rdi, regs[8]);
- PRINT_REG(rsi, regs[9]);
- PRINT_REG(rbp, regs[10]);
- PRINT_REG(rsp, regs[11]);
- PRINT_REG(r8 , regs[7]);
- PRINT_REG(r9 , regs[6]);
- PRINT_REG(r10, regs[5]);
- PRINT_REG(r11, regs[4]);
- PRINT_REG(r12, regs[3]);
- PRINT_REG(r13, regs[2]);
- PRINT_REG(r14, regs[1]);
- PRINT_REG(r15, regs[0]);
-#undef PRINT_REG
- // Print some words near top of staack.
- int64_t* rsp = (int64_t*) regs[11];
- int64_t* dump_sp = rsp;
- for (int col1 = 0; col1 < 8; col1++) {
- tty->print("(rsp+0x%03x) 0x%016lx: ", (int)((intptr_t)dump_sp - (intptr_t)rsp), (int64_t)dump_sp);
- os::print_location(tty, *dump_sp++);
- }
- for (int row = 0; row < 25; row++) {
- tty->print("(rsp+0x%03x) 0x%016lx: ", (int)((intptr_t)dump_sp - (intptr_t)rsp), (int64_t)dump_sp);
- for (int col = 0; col < 4; col++) {
- tty->print(" 0x%016lx", *dump_sp++);
- }
- tty->cr();
- }
- // Print some instructions around pc:
- Disassembler::decode((address)pc-64, (address)pc);
- tty->print_cr("--------");
- Disassembler::decode((address)pc, (address)pc+32);
-}
-
-#endif // _LP64
-
-// Now versions that are common to 32/64 bit
-
-void MacroAssembler::addptr(Register dst, int32_t imm32) {
- LP64_ONLY(addq(dst, imm32)) NOT_LP64(addl(dst, imm32));
-}
-
-void MacroAssembler::addptr(Register dst, Register src) {
- LP64_ONLY(addq(dst, src)) NOT_LP64(addl(dst, src));
-}
-
-void MacroAssembler::addptr(Address dst, Register src) {
- LP64_ONLY(addq(dst, src)) NOT_LP64(addl(dst, src));
-}
-
-void MacroAssembler::addsd(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- Assembler::addsd(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::addsd(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::addss(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- addss(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- addss(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::align(int modulus) {
- if (offset() % modulus != 0) {
- nop(modulus - (offset() % modulus));
- }
-}
-
-void MacroAssembler::andpd(XMMRegister dst, AddressLiteral src) {
- // Used in sign-masking with aligned address.
- assert((UseAVX > 0) || (((intptr_t)src.target() & 15) == 0), "SSE mode requires address alignment 16 bytes");
- if (reachable(src)) {
- Assembler::andpd(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::andpd(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::andps(XMMRegister dst, AddressLiteral src) {
- // Used in sign-masking with aligned address.
- assert((UseAVX > 0) || (((intptr_t)src.target() & 15) == 0), "SSE mode requires address alignment 16 bytes");
- if (reachable(src)) {
- Assembler::andps(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::andps(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::andptr(Register dst, int32_t imm32) {
- LP64_ONLY(andq(dst, imm32)) NOT_LP64(andl(dst, imm32));
-}
-
-void MacroAssembler::atomic_incl(AddressLiteral counter_addr) {
- pushf();
- if (os::is_MP())
- lock();
- incrementl(counter_addr);
- popf();
-}
-
-// Writes to stack successive pages until offset reached to check for
-// stack overflow + shadow pages. This clobbers tmp.
-void MacroAssembler::bang_stack_size(Register size, Register tmp) {
- movptr(tmp, rsp);
- // Bang stack for total size given plus shadow page size.
- // Bang one page at a time because large size can bang beyond yellow and
- // red zones.
- Label loop;
- bind(loop);
- movl(Address(tmp, (-os::vm_page_size())), size );
- subptr(tmp, os::vm_page_size());
- subl(size, os::vm_page_size());
- jcc(Assembler::greater, loop);
-
- // Bang down shadow pages too.
- // The -1 because we already subtracted 1 page.
- for (int i = 0; i< StackShadowPages-1; i++) {
- // this could be any sized move but this is can be a debugging crumb
- // so the bigger the better.
- movptr(Address(tmp, (-i*os::vm_page_size())), size );
- }
-}
-
-void MacroAssembler::biased_locking_exit(Register obj_reg, Register temp_reg, Label& done) {
- assert(UseBiasedLocking, "why call this otherwise?");
-
- // Check for biased locking unlock case, which is a no-op
- // Note: we do not have to check the thread ID for two reasons.
- // First, the interpreter checks for IllegalMonitorStateException at
- // a higher level. Second, if the bias was revoked while we held the
- // lock, the object could not be rebiased toward another thread, so
- // the bias bit would be clear.
- movptr(temp_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
- andptr(temp_reg, markOopDesc::biased_lock_mask_in_place);
- cmpptr(temp_reg, markOopDesc::biased_lock_pattern);
- jcc(Assembler::equal, done);
-}
-
-void MacroAssembler::c2bool(Register x) {
- // implements x == 0 ? 0 : 1
- // note: must only look at least-significant byte of x
- // since C-style booleans are stored in one byte
- // only! (was bug)
- andl(x, 0xFF);
- setb(Assembler::notZero, x);
-}
-
-// Wouldn't need if AddressLiteral version had new name
-void MacroAssembler::call(Label& L, relocInfo::relocType rtype) {
- Assembler::call(L, rtype);
-}
-
-void MacroAssembler::call(Register entry) {
- Assembler::call(entry);
-}
-
-void MacroAssembler::call(AddressLiteral entry) {
- if (reachable(entry)) {
- Assembler::call_literal(entry.target(), entry.rspec());
- } else {
- lea(rscratch1, entry);
- Assembler::call(rscratch1);
- }
-}
-
-void MacroAssembler::ic_call(address entry) {
- RelocationHolder rh = virtual_call_Relocation::spec(pc());
- movptr(rax, (intptr_t)Universe::non_oop_word());
- call(AddressLiteral(entry, rh));
-}
-
-// Implementation of call_VM versions
-
-void MacroAssembler::call_VM(Register oop_result,
- address entry_point,
- bool check_exceptions) {
- Label C, E;
- call(C, relocInfo::none);
- jmp(E);
-
- bind(C);
- call_VM_helper(oop_result, entry_point, 0, check_exceptions);
- ret(0);
-
- bind(E);
-}
-
-void MacroAssembler::call_VM(Register oop_result,
- address entry_point,
- Register arg_1,
- bool check_exceptions) {
- Label C, E;
- call(C, relocInfo::none);
- jmp(E);
-
- bind(C);
- pass_arg1(this, arg_1);
- call_VM_helper(oop_result, entry_point, 1, check_exceptions);
- ret(0);
-
- bind(E);
-}
-
-void MacroAssembler::call_VM(Register oop_result,
- address entry_point,
- Register arg_1,
- Register arg_2,
- bool check_exceptions) {
- Label C, E;
- call(C, relocInfo::none);
- jmp(E);
-
- bind(C);
-
- LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
-
- pass_arg2(this, arg_2);
- pass_arg1(this, arg_1);
- call_VM_helper(oop_result, entry_point, 2, check_exceptions);
- ret(0);
-
- bind(E);
-}
-
-void MacroAssembler::call_VM(Register oop_result,
- address entry_point,
- Register arg_1,
- Register arg_2,
- Register arg_3,
- bool check_exceptions) {
- Label C, E;
- call(C, relocInfo::none);
- jmp(E);
-
- bind(C);
-
- 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);
- call_VM_helper(oop_result, entry_point, 3, check_exceptions);
- ret(0);
-
- bind(E);
-}
-
-void MacroAssembler::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);
- call_VM_base(oop_result, thread, last_java_sp, entry_point, number_of_arguments, check_exceptions);
-}
-
-void MacroAssembler::call_VM(Register oop_result,
- Register last_java_sp,
- address entry_point,
- Register arg_1,
- bool check_exceptions) {
- pass_arg1(this, arg_1);
- call_VM(oop_result, last_java_sp, entry_point, 1, check_exceptions);
-}
-
-void MacroAssembler::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);
- call_VM(oop_result, last_java_sp, entry_point, 2, check_exceptions);
-}
-
-void MacroAssembler::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);
- 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,
- address entry_point,
- int number_of_arguments,
- bool check_exceptions) {
- // determine java_thread register
- if (!java_thread->is_valid()) {
-#ifdef _LP64
- java_thread = r15_thread;
-#else
- java_thread = rdi;
- get_thread(java_thread);
-#endif // LP64
- }
- // determine last_java_sp register
- if (!last_java_sp->is_valid()) {
- last_java_sp = rsp;
- }
- // debugging support
- assert(number_of_arguments >= 0 , "cannot have negative number of arguments");
- LP64_ONLY(assert(java_thread == r15_thread, "unexpected register"));
-#ifdef ASSERT
- // TraceBytecodes does not use r12 but saves it over the call, so don't verify
- // r12 is the heapbase.
- LP64_ONLY(if ((UseCompressedOops || UseCompressedKlassPointers) && !TraceBytecodes) verify_heapbase("call_VM_base: heap base corrupted?");)
-#endif // ASSERT
-
- assert(java_thread != oop_result , "cannot use the same register for java_thread & oop_result");
- assert(java_thread != last_java_sp, "cannot use the same register for java_thread & last_java_sp");
-
- // push java thread (becomes first argument of C function)
-
- NOT_LP64(push(java_thread); number_of_arguments++);
- LP64_ONLY(mov(c_rarg0, r15_thread));
-
- // set last Java frame before call
- assert(last_java_sp != rbp, "can't use ebp/rbp");
-
- // Only interpreter should have to set fp
- set_last_Java_frame(java_thread, last_java_sp, rbp, NULL);
-
- // do the call, remove parameters
- MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments);
-
- // restore the thread (cannot use the pushed argument since arguments
- // may be overwritten by C code generated by an optimizing compiler);
- // however can use the register value directly if it is callee saved.
- if (LP64_ONLY(true ||) java_thread == rdi || java_thread == rsi) {
- // rdi & rsi (also r15) are callee saved -> nothing to do
-#ifdef ASSERT
- guarantee(java_thread != rax, "change this code");
- push(rax);
- { Label L;
- get_thread(rax);
- cmpptr(java_thread, rax);
- jcc(Assembler::equal, L);
- STOP("MacroAssembler::call_VM_base: rdi not callee saved?");
- bind(L);
- }
- pop(rax);
-#endif
- } else {
- get_thread(java_thread);
- }
- // reset last Java frame
- // Only interpreter should have to clear fp
- reset_last_Java_frame(java_thread, true, false);
-
-#ifndef CC_INTERP
- // C++ interp handles this in the interpreter
- check_and_handle_popframe(java_thread);
- check_and_handle_earlyret(java_thread);
-#endif /* CC_INTERP */
-
- if (check_exceptions) {
- // check for pending exceptions (java_thread is set upon return)
- cmpptr(Address(java_thread, Thread::pending_exception_offset()), (int32_t) NULL_WORD);
-#ifndef _LP64
- jump_cc(Assembler::notEqual,
- RuntimeAddress(StubRoutines::forward_exception_entry()));
-#else
- // This used to conditionally jump to forward_exception however it is
- // possible if we relocate that the branch will not reach. So we must jump
- // around so we can always reach
-
- Label ok;
- jcc(Assembler::equal, ok);
- jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
- bind(ok);
-#endif // LP64
- }
-
- // get oop result if there is one and reset the value in the thread
- if (oop_result->is_valid()) {
- get_vm_result(oop_result, java_thread);
- }
-}
-
-void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) {
-
- // Calculate the value for last_Java_sp
- // somewhat subtle. call_VM does an intermediate call
- // which places a return address on the stack just under the
- // stack pointer as the user finsihed with it. This allows
- // use to retrieve last_Java_pc from last_Java_sp[-1].
- // On 32bit we then have to push additional args on the stack to accomplish
- // the actual requested call. On 64bit call_VM only can use register args
- // so the only extra space is the return address that call_VM created.
- // This hopefully explains the calculations here.
-
-#ifdef _LP64
- // We've pushed one address, correct last_Java_sp
- lea(rax, Address(rsp, wordSize));
-#else
- lea(rax, Address(rsp, (1 + number_of_arguments) * wordSize));
-#endif // LP64
-
- call_VM_base(oop_result, noreg, rax, entry_point, number_of_arguments, check_exceptions);
-
-}
-
-void MacroAssembler::call_VM_leaf(address entry_point, int number_of_arguments) {
- call_VM_leaf_base(entry_point, number_of_arguments);
-}
-
-void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0) {
- pass_arg0(this, arg_0);
- call_VM_leaf(entry_point, 1);
-}
-
-void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0, Register arg_1) {
-
- LP64_ONLY(assert(arg_0 != c_rarg1, "smashed arg"));
- pass_arg1(this, arg_1);
- pass_arg0(this, arg_0);
- call_VM_leaf(entry_point, 2);
-}
-
-void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2) {
- LP64_ONLY(assert(arg_0 != c_rarg2, "smashed arg"));
- LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
- pass_arg2(this, arg_2);
- LP64_ONLY(assert(arg_0 != c_rarg1, "smashed arg"));
- pass_arg1(this, arg_1);
- pass_arg0(this, arg_0);
- call_VM_leaf(entry_point, 3);
-}
-
-void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0) {
- pass_arg0(this, arg_0);
- MacroAssembler::call_VM_leaf_base(entry_point, 1);
-}
-
-void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1) {
-
- LP64_ONLY(assert(arg_0 != c_rarg1, "smashed arg"));
- pass_arg1(this, arg_1);
- pass_arg0(this, arg_0);
- MacroAssembler::call_VM_leaf_base(entry_point, 2);
-}
-
-void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2) {
- LP64_ONLY(assert(arg_0 != c_rarg2, "smashed arg"));
- LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
- pass_arg2(this, arg_2);
- LP64_ONLY(assert(arg_0 != c_rarg1, "smashed arg"));
- pass_arg1(this, arg_1);
- pass_arg0(this, arg_0);
- MacroAssembler::call_VM_leaf_base(entry_point, 3);
-}
-
-void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2, Register arg_3) {
- LP64_ONLY(assert(arg_0 != c_rarg3, "smashed arg"));
- 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_0 != c_rarg2, "smashed arg"));
- LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
- pass_arg2(this, arg_2);
- LP64_ONLY(assert(arg_0 != c_rarg1, "smashed arg"));
- pass_arg1(this, arg_1);
- pass_arg0(this, arg_0);
- MacroAssembler::call_VM_leaf_base(entry_point, 4);
-}
-
-void MacroAssembler::get_vm_result(Register oop_result, Register java_thread) {
- movptr(oop_result, Address(java_thread, JavaThread::vm_result_offset()));
- movptr(Address(java_thread, JavaThread::vm_result_offset()), NULL_WORD);
- verify_oop(oop_result, "broken oop in call_VM_base");
-}
-
-void MacroAssembler::get_vm_result_2(Register metadata_result, Register java_thread) {
- movptr(metadata_result, Address(java_thread, JavaThread::vm_result_2_offset()));
- movptr(Address(java_thread, JavaThread::vm_result_2_offset()), NULL_WORD);
-}
-
-void MacroAssembler::check_and_handle_earlyret(Register java_thread) {
-}
-
-void MacroAssembler::check_and_handle_popframe(Register java_thread) {
-}
-
-void MacroAssembler::cmp32(AddressLiteral src1, int32_t imm) {
- if (reachable(src1)) {
- cmpl(as_Address(src1), imm);
- } else {
- lea(rscratch1, src1);
- cmpl(Address(rscratch1, 0), imm);
- }
-}
-
-void MacroAssembler::cmp32(Register src1, AddressLiteral src2) {
- assert(!src2.is_lval(), "use cmpptr");
- if (reachable(src2)) {
- cmpl(src1, as_Address(src2));
- } else {
- lea(rscratch1, src2);
- cmpl(src1, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::cmp32(Register src1, int32_t imm) {
- Assembler::cmpl(src1, imm);
-}
-
-void MacroAssembler::cmp32(Register src1, Address src2) {
- Assembler::cmpl(src1, src2);
-}
-
-void MacroAssembler::cmpsd2int(XMMRegister opr1, XMMRegister opr2, Register dst, bool unordered_is_less) {
- ucomisd(opr1, opr2);
-
- Label L;
- if (unordered_is_less) {
- movl(dst, -1);
- jcc(Assembler::parity, L);
- jcc(Assembler::below , L);
- movl(dst, 0);
- jcc(Assembler::equal , L);
- increment(dst);
- } else { // unordered is greater
- movl(dst, 1);
- jcc(Assembler::parity, L);
- jcc(Assembler::above , L);
- movl(dst, 0);
- jcc(Assembler::equal , L);
- decrementl(dst);
- }
- bind(L);
-}
-
-void MacroAssembler::cmpss2int(XMMRegister opr1, XMMRegister opr2, Register dst, bool unordered_is_less) {
- ucomiss(opr1, opr2);
-
- Label L;
- if (unordered_is_less) {
- movl(dst, -1);
- jcc(Assembler::parity, L);
- jcc(Assembler::below , L);
- movl(dst, 0);
- jcc(Assembler::equal , L);
- increment(dst);
- } else { // unordered is greater
- movl(dst, 1);
- jcc(Assembler::parity, L);
- jcc(Assembler::above , L);
- movl(dst, 0);
- jcc(Assembler::equal , L);
- decrementl(dst);
- }
- bind(L);
-}
-
-
-void MacroAssembler::cmp8(AddressLiteral src1, int imm) {
- if (reachable(src1)) {
- cmpb(as_Address(src1), imm);
- } else {
- lea(rscratch1, src1);
- cmpb(Address(rscratch1, 0), imm);
- }
-}
-
-void MacroAssembler::cmpptr(Register src1, AddressLiteral src2) {
-#ifdef _LP64
- if (src2.is_lval()) {
- movptr(rscratch1, src2);
- Assembler::cmpq(src1, rscratch1);
- } else if (reachable(src2)) {
- cmpq(src1, as_Address(src2));
- } else {
- lea(rscratch1, src2);
- Assembler::cmpq(src1, Address(rscratch1, 0));
- }
-#else
- if (src2.is_lval()) {
- cmp_literal32(src1, (int32_t) src2.target(), src2.rspec());
- } else {
- cmpl(src1, as_Address(src2));
- }
-#endif // _LP64
-}
-
-void MacroAssembler::cmpptr(Address src1, AddressLiteral src2) {
- assert(src2.is_lval(), "not a mem-mem compare");
-#ifdef _LP64
- // moves src2's literal address
- movptr(rscratch1, src2);
- Assembler::cmpq(src1, rscratch1);
-#else
- cmp_literal32(src1, (int32_t) src2.target(), src2.rspec());
-#endif // _LP64
-}
-
-void MacroAssembler::locked_cmpxchgptr(Register reg, AddressLiteral adr) {
- if (reachable(adr)) {
- if (os::is_MP())
- lock();
- cmpxchgptr(reg, as_Address(adr));
- } else {
- lea(rscratch1, adr);
- if (os::is_MP())
- lock();
- cmpxchgptr(reg, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::cmpxchgptr(Register reg, Address adr) {
- LP64_ONLY(cmpxchgq(reg, adr)) NOT_LP64(cmpxchgl(reg, adr));
-}
-
-void MacroAssembler::comisd(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- Assembler::comisd(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::comisd(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::comiss(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- Assembler::comiss(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::comiss(dst, Address(rscratch1, 0));
- }
-}
-
-
-void MacroAssembler::cond_inc32(Condition cond, AddressLiteral counter_addr) {
- Condition negated_cond = negate_condition(cond);
- Label L;
- jcc(negated_cond, L);
- atomic_incl(counter_addr);
- bind(L);
-}
-
-int MacroAssembler::corrected_idivl(Register reg) {
- // Full implementation of Java idiv and irem; checks for
- // special case as described in JVM spec., p.243 & p.271.
- // The function returns the (pc) offset of the idivl
- // instruction - may be needed for implicit exceptions.
- //
- // normal case special case
- //
- // input : rax,: dividend min_int
- // reg: divisor (may not be rax,/rdx) -1
- //
- // output: rax,: quotient (= rax, idiv reg) min_int
- // rdx: remainder (= rax, irem reg) 0
- assert(reg != rax && reg != rdx, "reg cannot be rax, or rdx register");
- const int min_int = 0x80000000;
- Label normal_case, special_case;
-
- // check for special case
- cmpl(rax, min_int);
- jcc(Assembler::notEqual, normal_case);
- xorl(rdx, rdx); // prepare rdx for possible special case (where remainder = 0)
- cmpl(reg, -1);
- jcc(Assembler::equal, special_case);
-
- // handle normal case
- bind(normal_case);
- cdql();
- int idivl_offset = offset();
- idivl(reg);
-
- // normal and special case exit
- bind(special_case);
-
- return idivl_offset;
-}
-
-
-
-void MacroAssembler::decrementl(Register reg, int value) {
- if (value == min_jint) {subl(reg, value) ; return; }
- if (value < 0) { incrementl(reg, -value); return; }
- if (value == 0) { ; return; }
- if (value == 1 && UseIncDec) { decl(reg) ; return; }
- /* else */ { subl(reg, value) ; return; }
-}
-
-void MacroAssembler::decrementl(Address dst, int value) {
- if (value == min_jint) {subl(dst, value) ; return; }
- if (value < 0) { incrementl(dst, -value); return; }
- if (value == 0) { ; return; }
- if (value == 1 && UseIncDec) { decl(dst) ; return; }
- /* else */ { subl(dst, value) ; return; }
-}
-
-void MacroAssembler::division_with_shift (Register reg, int shift_value) {
- assert (shift_value > 0, "illegal shift value");
- Label _is_positive;
- testl (reg, reg);
- jcc (Assembler::positive, _is_positive);
- int offset = (1 << shift_value) - 1 ;
-
- if (offset == 1) {
- incrementl(reg);
- } else {
- addl(reg, offset);
- }
-
- bind (_is_positive);
- sarl(reg, shift_value);
-}
-
-void MacroAssembler::divsd(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- Assembler::divsd(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::divsd(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::divss(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- Assembler::divss(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::divss(dst, Address(rscratch1, 0));
- }
-}
-
-// !defined(COMPILER2) is because of stupid core builds
-#if !defined(_LP64) || defined(COMPILER1) || !defined(COMPILER2)
-void MacroAssembler::empty_FPU_stack() {
- if (VM_Version::supports_mmx()) {
- emms();
- } else {
- for (int i = 8; i-- > 0; ) ffree(i);
- }
-}
-#endif // !LP64 || C1 || !C2
-
-
-// Defines obj, preserves var_size_in_bytes
-void MacroAssembler::eden_allocate(Register obj,
- Register var_size_in_bytes,
- int con_size_in_bytes,
- Register t1,
- Label& slow_case) {
- assert(obj == rax, "obj must be in rax, for cmpxchg");
- assert_different_registers(obj, var_size_in_bytes, t1);
- if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) {
- jmp(slow_case);
- } else {
- Register end = t1;
- Label retry;
- bind(retry);
- ExternalAddress heap_top((address) Universe::heap()->top_addr());
- movptr(obj, heap_top);
- if (var_size_in_bytes == noreg) {
- lea(end, Address(obj, con_size_in_bytes));
- } else {
- lea(end, Address(obj, var_size_in_bytes, Address::times_1));
- }
- // if end < obj then we wrapped around => object too long => slow case
- cmpptr(end, obj);
- jcc(Assembler::below, slow_case);
- cmpptr(end, ExternalAddress((address) Universe::heap()->end_addr()));
- jcc(Assembler::above, slow_case);
- // Compare obj with the top addr, and if still equal, store the new top addr in
- // end at the address of the top addr pointer. Sets ZF if was equal, and clears
- // it otherwise. Use lock prefix for atomicity on MPs.
- locked_cmpxchgptr(end, heap_top);
- jcc(Assembler::notEqual, retry);
- }
-}
-
-void MacroAssembler::enter() {
- push(rbp);
- mov(rbp, rsp);
-}
-
-// A 5 byte nop that is safe for patching (see patch_verified_entry)
-void MacroAssembler::fat_nop() {
- if (UseAddressNop) {
- addr_nop_5();
- } else {
- emit_byte(0x26); // es:
- emit_byte(0x2e); // cs:
- emit_byte(0x64); // fs:
- emit_byte(0x65); // gs:
- emit_byte(0x90);
- }
-}
-
-void MacroAssembler::fcmp(Register tmp) {
- fcmp(tmp, 1, true, true);
-}
-
-void MacroAssembler::fcmp(Register tmp, int index, bool pop_left, bool pop_right) {
- assert(!pop_right || pop_left, "usage error");
- if (VM_Version::supports_cmov()) {
- assert(tmp == noreg, "unneeded temp");
- if (pop_left) {
- fucomip(index);
- } else {
- fucomi(index);
- }
- if (pop_right) {
- fpop();
- }
- } else {
- assert(tmp != noreg, "need temp");
- if (pop_left) {
- if (pop_right) {
- fcompp();
- } else {
- fcomp(index);
- }
- } else {
- fcom(index);
- }
- // convert FPU condition into eflags condition via rax,
- save_rax(tmp);
- fwait(); fnstsw_ax();
- sahf();
- restore_rax(tmp);
- }
- // condition codes set as follows:
- //
- // CF (corresponds to C0) if x < y
- // PF (corresponds to C2) if unordered
- // ZF (corresponds to C3) if x = y
-}
-
-void MacroAssembler::fcmp2int(Register dst, bool unordered_is_less) {
- fcmp2int(dst, unordered_is_less, 1, true, true);
-}
-
-void MacroAssembler::fcmp2int(Register dst, bool unordered_is_less, int index, bool pop_left, bool pop_right) {
- fcmp(VM_Version::supports_cmov() ? noreg : dst, index, pop_left, pop_right);
- Label L;
- if (unordered_is_less) {
- movl(dst, -1);
- jcc(Assembler::parity, L);
- jcc(Assembler::below , L);
- movl(dst, 0);
- jcc(Assembler::equal , L);
- increment(dst);
- } else { // unordered is greater
- movl(dst, 1);
- jcc(Assembler::parity, L);
- jcc(Assembler::above , L);
- movl(dst, 0);
- jcc(Assembler::equal , L);
- decrementl(dst);
- }
- bind(L);
-}
-
-void MacroAssembler::fld_d(AddressLiteral src) {
- fld_d(as_Address(src));
-}
-
-void MacroAssembler::fld_s(AddressLiteral src) {
- fld_s(as_Address(src));
-}
-
-void MacroAssembler::fld_x(AddressLiteral src) {
- Assembler::fld_x(as_Address(src));
-}
-
-void MacroAssembler::fldcw(AddressLiteral src) {
- Assembler::fldcw(as_Address(src));
-}
-
-void MacroAssembler::pow_exp_core_encoding() {
- // kills rax, rcx, rdx
- subptr(rsp,sizeof(jdouble));
- // computes 2^X. Stack: X ...
- // f2xm1 computes 2^X-1 but only operates on -1<=X<=1. Get int(X) and
- // keep it on the thread's stack to compute 2^int(X) later
- // then compute 2^(X-int(X)) as (2^(X-int(X)-1+1)
- // final result is obtained with: 2^X = 2^int(X) * 2^(X-int(X))
- fld_s(0); // Stack: X X ...
- frndint(); // Stack: int(X) X ...
- fsuba(1); // Stack: int(X) X-int(X) ...
- fistp_s(Address(rsp,0)); // move int(X) as integer to thread's stack. Stack: X-int(X) ...
- f2xm1(); // Stack: 2^(X-int(X))-1 ...
- fld1(); // Stack: 1 2^(X-int(X))-1 ...
- faddp(1); // Stack: 2^(X-int(X))
- // computes 2^(int(X)): add exponent bias (1023) to int(X), then
- // shift int(X)+1023 to exponent position.
- // Exponent is limited to 11 bits if int(X)+1023 does not fit in 11
- // bits, set result to NaN. 0x000 and 0x7FF are reserved exponent
- // values so detect them and set result to NaN.
- movl(rax,Address(rsp,0));
- movl(rcx, -2048); // 11 bit mask and valid NaN binary encoding
- addl(rax, 1023);
- movl(rdx,rax);
- shll(rax,20);
- // Check that 0 < int(X)+1023 < 2047. Otherwise set rax to NaN.
- addl(rdx,1);
- // Check that 1 < int(X)+1023+1 < 2048
- // in 3 steps:
- // 1- (int(X)+1023+1)&-2048 == 0 => 0 <= int(X)+1023+1 < 2048
- // 2- (int(X)+1023+1)&-2048 != 0
- // 3- (int(X)+1023+1)&-2048 != 1
- // Do 2- first because addl just updated the flags.
- cmov32(Assembler::equal,rax,rcx);
- cmpl(rdx,1);
- cmov32(Assembler::equal,rax,rcx);
- testl(rdx,rcx);
- cmov32(Assembler::notEqual,rax,rcx);
- movl(Address(rsp,4),rax);
- movl(Address(rsp,0),0);
- fmul_d(Address(rsp,0)); // Stack: 2^X ...
- addptr(rsp,sizeof(jdouble));
-}
-
-void MacroAssembler::increase_precision() {
- subptr(rsp, BytesPerWord);
- fnstcw(Address(rsp, 0));
- movl(rax, Address(rsp, 0));
- orl(rax, 0x300);
- push(rax);
- fldcw(Address(rsp, 0));
- pop(rax);
-}
-
-void MacroAssembler::restore_precision() {
- fldcw(Address(rsp, 0));
- addptr(rsp, BytesPerWord);
-}
-
-void MacroAssembler::fast_pow() {
- // computes X^Y = 2^(Y * log2(X))
- // if fast computation is not possible, result is NaN. Requires
- // fallback from user of this macro.
- // increase precision for intermediate steps of the computation
- increase_precision();
- fyl2x(); // Stack: (Y*log2(X)) ...
- pow_exp_core_encoding(); // Stack: exp(X) ...
- restore_precision();
-}
-
-void MacroAssembler::fast_exp() {
- // computes exp(X) = 2^(X * log2(e))
- // if fast computation is not possible, result is NaN. Requires
- // fallback from user of this macro.
- // increase precision for intermediate steps of the computation
- increase_precision();
- fldl2e(); // Stack: log2(e) X ...
- fmulp(1); // Stack: (X*log2(e)) ...
- pow_exp_core_encoding(); // Stack: exp(X) ...
- restore_precision();
-}
-
-void MacroAssembler::pow_or_exp(bool is_exp, int num_fpu_regs_in_use) {
- // kills rax, rcx, rdx
- // pow and exp needs 2 extra registers on the fpu stack.
- Label slow_case, done;
- Register tmp = noreg;
- if (!VM_Version::supports_cmov()) {
- // fcmp needs a temporary so preserve rdx,
- tmp = rdx;
- }
- Register tmp2 = rax;
- Register tmp3 = rcx;
-
- if (is_exp) {
- // Stack: X
- fld_s(0); // duplicate argument for runtime call. Stack: X X
- fast_exp(); // Stack: exp(X) X
- fcmp(tmp, 0, false, false); // Stack: exp(X) X
- // exp(X) not equal to itself: exp(X) is NaN go to slow case.
- jcc(Assembler::parity, slow_case);
- // get rid of duplicate argument. Stack: exp(X)
- if (num_fpu_regs_in_use > 0) {
- fxch();
- fpop();
- } else {
- ffree(1);
- }
- jmp(done);
- } else {
- // Stack: X Y
- Label x_negative, y_odd;
-
- fldz(); // Stack: 0 X Y
- fcmp(tmp, 1, true, false); // Stack: X Y
- jcc(Assembler::above, x_negative);
-
- // X >= 0
-
- fld_s(1); // duplicate arguments for runtime call. Stack: Y X Y
- fld_s(1); // Stack: X Y X Y
- fast_pow(); // Stack: X^Y X Y
- fcmp(tmp, 0, false, false); // Stack: X^Y X Y
- // X^Y not equal to itself: X^Y is NaN go to slow case.
- jcc(Assembler::parity, slow_case);
- // get rid of duplicate arguments. Stack: X^Y
- if (num_fpu_regs_in_use > 0) {
- fxch(); fpop();
- fxch(); fpop();
- } else {
- ffree(2);
- ffree(1);
- }
- jmp(done);
-
- // X <= 0
- bind(x_negative);
-
- fld_s(1); // Stack: Y X Y
- frndint(); // Stack: int(Y) X Y
- fcmp(tmp, 2, false, false); // Stack: int(Y) X Y
- jcc(Assembler::notEqual, slow_case);
-
- subptr(rsp, 8);
-
- // For X^Y, when X < 0, Y has to be an integer and the final
- // result depends on whether it's odd or even. We just checked
- // that int(Y) == Y. We move int(Y) to gp registers as a 64 bit
- // integer to test its parity. If int(Y) is huge and doesn't fit
- // in the 64 bit integer range, the integer indefinite value will
- // end up in the gp registers. Huge numbers are all even, the
- // integer indefinite number is even so it's fine.
-
-#ifdef ASSERT
- // Let's check we don't end up with an integer indefinite number
- // when not expected. First test for huge numbers: check whether
- // int(Y)+1 == int(Y) which is true for very large numbers and
- // those are all even. A 64 bit integer is guaranteed to not
- // overflow for numbers where y+1 != y (when precision is set to
- // double precision).
- Label y_not_huge;
-
- fld1(); // Stack: 1 int(Y) X Y
- fadd(1); // Stack: 1+int(Y) int(Y) X Y
-
-#ifdef _LP64
- // trip to memory to force the precision down from double extended
- // precision
- fstp_d(Address(rsp, 0));
- fld_d(Address(rsp, 0));
-#endif
-
- fcmp(tmp, 1, true, false); // Stack: int(Y) X Y
-#endif
-
- // move int(Y) as 64 bit integer to thread's stack
- fistp_d(Address(rsp,0)); // Stack: X Y
-
-#ifdef ASSERT
- jcc(Assembler::notEqual, y_not_huge);
-
- // Y is huge so we know it's even. It may not fit in a 64 bit
- // integer and we don't want the debug code below to see the
- // integer indefinite value so overwrite int(Y) on the thread's
- // stack with 0.
- movl(Address(rsp, 0), 0);
- movl(Address(rsp, 4), 0);
-
- bind(y_not_huge);
-#endif
-
- fld_s(1); // duplicate arguments for runtime call. Stack: Y X Y
- fld_s(1); // Stack: X Y X Y
- fabs(); // Stack: abs(X) Y X Y
- fast_pow(); // Stack: abs(X)^Y X Y
- fcmp(tmp, 0, false, false); // Stack: abs(X)^Y X Y
- // abs(X)^Y not equal to itself: abs(X)^Y is NaN go to slow case.
-
- pop(tmp2);
- NOT_LP64(pop(tmp3));
- jcc(Assembler::parity, slow_case);
-
-#ifdef ASSERT
- // Check that int(Y) is not integer indefinite value (int
- // overflow). Shouldn't happen because for values that would
- // overflow, 1+int(Y)==Y which was tested earlier.
-#ifndef _LP64
- {
- Label integer;
- testl(tmp2, tmp2);
- jcc(Assembler::notZero, integer);
- cmpl(tmp3, 0x80000000);
- jcc(Assembler::notZero, integer);
- STOP("integer indefinite value shouldn't be seen here");
- bind(integer);
- }
-#else
- {
- Label integer;
- mov(tmp3, tmp2); // preserve tmp2 for parity check below
- shlq(tmp3, 1);
- jcc(Assembler::carryClear, integer);
- jcc(Assembler::notZero, integer);
- STOP("integer indefinite value shouldn't be seen here");
- bind(integer);
- }
-#endif
-#endif
-
- // get rid of duplicate arguments. Stack: X^Y
- if (num_fpu_regs_in_use > 0) {
- fxch(); fpop();
- fxch(); fpop();
- } else {
- ffree(2);
- ffree(1);
- }
-
- testl(tmp2, 1);
- jcc(Assembler::zero, done); // X <= 0, Y even: X^Y = abs(X)^Y
- // X <= 0, Y even: X^Y = -abs(X)^Y
-
- fchs(); // Stack: -abs(X)^Y Y
- jmp(done);
- }
-
- // slow case: runtime call
- bind(slow_case);
-
- fpop(); // pop incorrect result or int(Y)
-
- fp_runtime_fallback(is_exp ? CAST_FROM_FN_PTR(address, SharedRuntime::dexp) : CAST_FROM_FN_PTR(address, SharedRuntime::dpow),
- is_exp ? 1 : 2, num_fpu_regs_in_use);
-
- // Come here with result in F-TOS
- bind(done);
-}
-
-void MacroAssembler::fpop() {
- ffree();
- fincstp();
-}
-
-void MacroAssembler::fremr(Register tmp) {
- save_rax(tmp);
- { Label L;
- bind(L);
- fprem();
- fwait(); fnstsw_ax();
-#ifdef _LP64
- testl(rax, 0x400);
- jcc(Assembler::notEqual, L);
-#else
- sahf();
- jcc(Assembler::parity, L);
-#endif // _LP64
- }
- restore_rax(tmp);
- // Result is in ST0.
- // Note: fxch & fpop to get rid of ST1
- // (otherwise FPU stack could overflow eventually)
- fxch(1);
- fpop();
-}
-
-
-void MacroAssembler::incrementl(AddressLiteral dst) {
- if (reachable(dst)) {
- incrementl(as_Address(dst));
- } else {
- lea(rscratch1, dst);
- incrementl(Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::incrementl(ArrayAddress dst) {
- incrementl(as_Address(dst));
-}
-
-void MacroAssembler::incrementl(Register reg, int value) {
- if (value == min_jint) {addl(reg, value) ; return; }
- if (value < 0) { decrementl(reg, -value); return; }
- if (value == 0) { ; return; }
- if (value == 1 && UseIncDec) { incl(reg) ; return; }
- /* else */ { addl(reg, value) ; return; }
-}
-
-void MacroAssembler::incrementl(Address dst, int value) {
- if (value == min_jint) {addl(dst, value) ; return; }
- if (value < 0) { decrementl(dst, -value); return; }
- if (value == 0) { ; return; }
- if (value == 1 && UseIncDec) { incl(dst) ; return; }
- /* else */ { addl(dst, value) ; return; }
-}
-
-void MacroAssembler::jump(AddressLiteral dst) {
- if (reachable(dst)) {
- jmp_literal(dst.target(), dst.rspec());
- } else {
- lea(rscratch1, dst);
- jmp(rscratch1);
- }
-}
-
-void MacroAssembler::jump_cc(Condition cc, AddressLiteral dst) {
- if (reachable(dst)) {
- InstructionMark im(this);
- relocate(dst.reloc());
- const int short_size = 2;
- const int long_size = 6;
- int offs = (intptr_t)dst.target() - ((intptr_t)_code_pos);
- if (dst.reloc() == relocInfo::none && is8bit(offs - short_size)) {
- // 0111 tttn #8-bit disp
- emit_byte(0x70 | cc);
- emit_byte((offs - short_size) & 0xFF);
- } else {
- // 0000 1111 1000 tttn #32-bit disp
- emit_byte(0x0F);
- emit_byte(0x80 | cc);
- emit_long(offs - long_size);
- }
- } else {
-#ifdef ASSERT
- warning("reversing conditional branch");
-#endif /* ASSERT */
- Label skip;
- jccb(reverse[cc], skip);
- lea(rscratch1, dst);
- Assembler::jmp(rscratch1);
- bind(skip);
- }
-}
-
-void MacroAssembler::ldmxcsr(AddressLiteral src) {
- if (reachable(src)) {
- Assembler::ldmxcsr(as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::ldmxcsr(Address(rscratch1, 0));
- }
-}
-
-int MacroAssembler::load_signed_byte(Register dst, Address src) {
- int off;
- if (LP64_ONLY(true ||) VM_Version::is_P6()) {
- off = offset();
- movsbl(dst, src); // movsxb
- } else {
- off = load_unsigned_byte(dst, src);
- shll(dst, 24);
- sarl(dst, 24);
- }
- return off;
-}
-
-// Note: load_signed_short used to be called load_signed_word.
-// Although the 'w' in x86 opcodes refers to the term "word" in the assembler
-// manual, which means 16 bits, that usage is found nowhere in HotSpot code.
-// The term "word" in HotSpot means a 32- or 64-bit machine word.
-int MacroAssembler::load_signed_short(Register dst, Address src) {
- int off;
- if (LP64_ONLY(true ||) VM_Version::is_P6()) {
- // This is dubious to me since it seems safe to do a signed 16 => 64 bit
- // version but this is what 64bit has always done. This seems to imply
- // that users are only using 32bits worth.
- off = offset();
- movswl(dst, src); // movsxw
- } else {
- off = load_unsigned_short(dst, src);
- shll(dst, 16);
- sarl(dst, 16);
- }
- return off;
-}
-
-int MacroAssembler::load_unsigned_byte(Register dst, Address src) {
- // According to Intel Doc. AP-526, "Zero-Extension of Short", p.16,
- // and "3.9 Partial Register Penalties", p. 22).
- int off;
- if (LP64_ONLY(true || ) VM_Version::is_P6() || src.uses(dst)) {
- off = offset();
- movzbl(dst, src); // movzxb
- } else {
- xorl(dst, dst);
- off = offset();
- movb(dst, src);
- }
- return off;
-}
-
-// Note: load_unsigned_short used to be called load_unsigned_word.
-int MacroAssembler::load_unsigned_short(Register dst, Address src) {
- // According to Intel Doc. AP-526, "Zero-Extension of Short", p.16,
- // and "3.9 Partial Register Penalties", p. 22).
- int off;
- if (LP64_ONLY(true ||) VM_Version::is_P6() || src.uses(dst)) {
- off = offset();
- movzwl(dst, src); // movzxw
- } else {
- xorl(dst, dst);
- off = offset();
- movw(dst, src);
- }
- return off;
-}
-
-void MacroAssembler::load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed, Register dst2) {
- switch (size_in_bytes) {
-#ifndef _LP64
- case 8:
- assert(dst2 != noreg, "second dest register required");
- movl(dst, src);
- movl(dst2, src.plus_disp(BytesPerInt));
- break;
-#else
- case 8: movq(dst, src); break;
-#endif
- case 4: movl(dst, src); break;
- case 2: is_signed ? load_signed_short(dst, src) : load_unsigned_short(dst, src); break;
- case 1: is_signed ? load_signed_byte( dst, src) : load_unsigned_byte( dst, src); break;
- default: ShouldNotReachHere();
- }
-}
-
-void MacroAssembler::store_sized_value(Address dst, Register src, size_t size_in_bytes, Register src2) {
- switch (size_in_bytes) {
-#ifndef _LP64
- case 8:
- assert(src2 != noreg, "second source register required");
- movl(dst, src);
- movl(dst.plus_disp(BytesPerInt), src2);
- break;
-#else
- case 8: movq(dst, src); break;
-#endif
- case 4: movl(dst, src); break;
- case 2: movw(dst, src); break;
- case 1: movb(dst, src); break;
- default: ShouldNotReachHere();
- }
-}
-
-void MacroAssembler::mov32(AddressLiteral dst, Register src) {
- if (reachable(dst)) {
- movl(as_Address(dst), src);
- } else {
- lea(rscratch1, dst);
- movl(Address(rscratch1, 0), src);
- }
-}
-
-void MacroAssembler::mov32(Register dst, AddressLiteral src) {
- if (reachable(src)) {
- movl(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- movl(dst, Address(rscratch1, 0));
- }
-}
-
-// C++ bool manipulation
-
-void MacroAssembler::movbool(Register dst, Address src) {
- if(sizeof(bool) == 1)
- movb(dst, src);
- else if(sizeof(bool) == 2)
- movw(dst, src);
- else if(sizeof(bool) == 4)
- movl(dst, src);
- else
- // unsupported
- ShouldNotReachHere();
-}
-
-void MacroAssembler::movbool(Address dst, bool boolconst) {
- if(sizeof(bool) == 1)
- movb(dst, (int) boolconst);
- else if(sizeof(bool) == 2)
- movw(dst, (int) boolconst);
- else if(sizeof(bool) == 4)
- movl(dst, (int) boolconst);
- else
- // unsupported
- ShouldNotReachHere();
-}
-
-void MacroAssembler::movbool(Address dst, Register src) {
- if(sizeof(bool) == 1)
- movb(dst, src);
- else if(sizeof(bool) == 2)
- movw(dst, src);
- else if(sizeof(bool) == 4)
- movl(dst, src);
- else
- // unsupported
- ShouldNotReachHere();
-}
-
-void MacroAssembler::movbyte(ArrayAddress dst, int src) {
- movb(as_Address(dst), src);
-}
-
-void MacroAssembler::movdl(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- movdl(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- movdl(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::movq(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- movq(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- movq(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::movdbl(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- if (UseXmmLoadAndClearUpper) {
- movsd (dst, as_Address(src));
- } else {
- movlpd(dst, as_Address(src));
- }
- } else {
- lea(rscratch1, src);
- if (UseXmmLoadAndClearUpper) {
- movsd (dst, Address(rscratch1, 0));
- } else {
- movlpd(dst, Address(rscratch1, 0));
- }
- }
-}
-
-void MacroAssembler::movflt(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- movss(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- movss(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::movptr(Register dst, Register src) {
- LP64_ONLY(movq(dst, src)) NOT_LP64(movl(dst, src));
-}
-
-void MacroAssembler::movptr(Register dst, Address src) {
- LP64_ONLY(movq(dst, src)) NOT_LP64(movl(dst, src));
-}
-
-// src should NEVER be a real pointer. Use AddressLiteral for true pointers
-void MacroAssembler::movptr(Register dst, intptr_t src) {
- LP64_ONLY(mov64(dst, src)) NOT_LP64(movl(dst, src));
-}
-
-void MacroAssembler::movptr(Address dst, Register src) {
- LP64_ONLY(movq(dst, src)) NOT_LP64(movl(dst, src));
-}
-
-void MacroAssembler::movsd(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- Assembler::movsd(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::movsd(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::movss(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- Assembler::movss(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::movss(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::mulsd(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- Assembler::mulsd(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::mulsd(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::mulss(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- Assembler::mulss(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::mulss(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::null_check(Register reg, int offset) {
- if (needs_explicit_null_check(offset)) {
- // provoke OS NULL exception if reg = NULL by
- // accessing M[reg] w/o changing any (non-CC) registers
- // NOTE: cmpl is plenty here to provoke a segv
- cmpptr(rax, Address(reg, 0));
- // Note: should probably use testl(rax, Address(reg, 0));
- // may be shorter code (however, this version of
- // testl needs to be implemented first)
- } else {
- // nothing to do, (later) access of M[reg + offset]
- // will provoke OS NULL exception if reg = NULL
- }
-}
-
-void MacroAssembler::os_breakpoint() {
- // instead of directly emitting a breakpoint, call os:breakpoint for better debugability
- // (e.g., MSVC can't call ps() otherwise)
- call(RuntimeAddress(CAST_FROM_FN_PTR(address, os::breakpoint)));
-}
-
-void MacroAssembler::pop_CPU_state() {
- pop_FPU_state();
- pop_IU_state();
-}
-
-void MacroAssembler::pop_FPU_state() {
- NOT_LP64(frstor(Address(rsp, 0));)
- LP64_ONLY(fxrstor(Address(rsp, 0));)
- addptr(rsp, FPUStateSizeInWords * wordSize);
-}
-
-void MacroAssembler::pop_IU_state() {
- popa();
- LP64_ONLY(addq(rsp, 8));
- popf();
-}
-
-// Save Integer and Float state
-// Warning: Stack must be 16 byte aligned (64bit)
-void MacroAssembler::push_CPU_state() {
- push_IU_state();
- push_FPU_state();
-}
-
-void MacroAssembler::push_FPU_state() {
- subptr(rsp, FPUStateSizeInWords * wordSize);
-#ifndef _LP64
- fnsave(Address(rsp, 0));
- fwait();
-#else
- fxsave(Address(rsp, 0));
-#endif // LP64
-}
-
-void MacroAssembler::push_IU_state() {
- // Push flags first because pusha kills them
- pushf();
- // Make sure rsp stays 16-byte aligned
- LP64_ONLY(subq(rsp, 8));
- pusha();
-}
-
-void MacroAssembler::reset_last_Java_frame(Register java_thread, bool clear_fp, bool clear_pc) {
- // determine java_thread register
- if (!java_thread->is_valid()) {
- java_thread = rdi;
- get_thread(java_thread);
- }
- // we must set sp to zero to clear frame
- movptr(Address(java_thread, JavaThread::last_Java_sp_offset()), NULL_WORD);
- if (clear_fp) {
- movptr(Address(java_thread, JavaThread::last_Java_fp_offset()), NULL_WORD);
- }
-
- if (clear_pc)
- movptr(Address(java_thread, JavaThread::last_Java_pc_offset()), NULL_WORD);
-
-}
-
-void MacroAssembler::restore_rax(Register tmp) {
- if (tmp == noreg) pop(rax);
- else if (tmp != rax) mov(rax, tmp);
-}
-
-void MacroAssembler::round_to(Register reg, int modulus) {
- addptr(reg, modulus - 1);
- andptr(reg, -modulus);
-}
-
-void MacroAssembler::save_rax(Register tmp) {
- if (tmp == noreg) push(rax);
- else if (tmp != rax) mov(tmp, rax);
-}
-
-// Write serialization page so VM thread can do a pseudo remote membar.
-// We use the current thread pointer to calculate a thread specific
-// offset to write to within the page. This minimizes bus traffic
-// due to cache line collision.
-void MacroAssembler::serialize_memory(Register thread, Register tmp) {
- movl(tmp, thread);
- shrl(tmp, os::get_serialize_page_shift_count());
- andl(tmp, (os::vm_page_size() - sizeof(int)));
-
- Address index(noreg, tmp, Address::times_1);
- ExternalAddress page(os::get_memory_serialize_page());
-
- // Size of store must match masking code above
- movl(as_Address(ArrayAddress(page, index)), tmp);
-}
-
-// Calls to C land
-//
-// When entering C land, the rbp, & rsp of the last Java frame have to be recorded
-// in the (thread-local) JavaThread object. When leaving C land, the last Java fp
-// has to be reset to 0. This is required to allow proper stack traversal.
-void MacroAssembler::set_last_Java_frame(Register java_thread,
- Register last_java_sp,
- Register last_java_fp,
- address last_java_pc) {
- // determine java_thread register
- if (!java_thread->is_valid()) {
- java_thread = rdi;
- get_thread(java_thread);
- }
- // determine last_java_sp register
- if (!last_java_sp->is_valid()) {
- last_java_sp = rsp;
- }
-
- // last_java_fp is optional
-
- if (last_java_fp->is_valid()) {
- movptr(Address(java_thread, JavaThread::last_Java_fp_offset()), last_java_fp);
- }
-
- // last_java_pc is optional
-
- if (last_java_pc != NULL) {
- lea(Address(java_thread,
- JavaThread::frame_anchor_offset() + JavaFrameAnchor::last_Java_pc_offset()),
- InternalAddress(last_java_pc));
-
- }
- movptr(Address(java_thread, JavaThread::last_Java_sp_offset()), last_java_sp);
-}
-
-void MacroAssembler::shlptr(Register dst, int imm8) {
- LP64_ONLY(shlq(dst, imm8)) NOT_LP64(shll(dst, imm8));
-}
-
-void MacroAssembler::shrptr(Register dst, int imm8) {
- LP64_ONLY(shrq(dst, imm8)) NOT_LP64(shrl(dst, imm8));
-}
-
-void MacroAssembler::sign_extend_byte(Register reg) {
- if (LP64_ONLY(true ||) (VM_Version::is_P6() && reg->has_byte_register())) {
- movsbl(reg, reg); // movsxb
- } else {
- shll(reg, 24);
- sarl(reg, 24);
- }
-}
-
-void MacroAssembler::sign_extend_short(Register reg) {
- if (LP64_ONLY(true ||) VM_Version::is_P6()) {
- movswl(reg, reg); // movsxw
- } else {
- shll(reg, 16);
- sarl(reg, 16);
- }
-}
-
-void MacroAssembler::testl(Register dst, AddressLiteral src) {
- assert(reachable(src), "Address should be reachable");
- testl(dst, as_Address(src));
-}
-
-void MacroAssembler::sqrtsd(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- Assembler::sqrtsd(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::sqrtsd(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::sqrtss(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- Assembler::sqrtss(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::sqrtss(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::subsd(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- Assembler::subsd(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::subsd(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::subss(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- Assembler::subss(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::subss(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::ucomisd(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- Assembler::ucomisd(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::ucomisd(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::ucomiss(XMMRegister dst, AddressLiteral src) {
- if (reachable(src)) {
- Assembler::ucomiss(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::ucomiss(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::xorpd(XMMRegister dst, AddressLiteral src) {
- // Used in sign-bit flipping with aligned address.
- assert((UseAVX > 0) || (((intptr_t)src.target() & 15) == 0), "SSE mode requires address alignment 16 bytes");
- if (reachable(src)) {
- Assembler::xorpd(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::xorpd(dst, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::xorps(XMMRegister dst, AddressLiteral src) {
- // Used in sign-bit flipping with aligned address.
- assert((UseAVX > 0) || (((intptr_t)src.target() & 15) == 0), "SSE mode requires address alignment 16 bytes");
- if (reachable(src)) {
- Assembler::xorps(dst, as_Address(src));
- } else {
- lea(rscratch1, src);
- Assembler::xorps(dst, Address(rscratch1, 0));
- }
-}
-
-// AVX 3-operands instructions
-
-void MacroAssembler::vaddsd(XMMRegister dst, XMMRegister nds, AddressLiteral src) {
- if (reachable(src)) {
- vaddsd(dst, nds, as_Address(src));
- } else {
- lea(rscratch1, src);
- vaddsd(dst, nds, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::vaddss(XMMRegister dst, XMMRegister nds, AddressLiteral src) {
- if (reachable(src)) {
- vaddss(dst, nds, as_Address(src));
- } else {
- lea(rscratch1, src);
- vaddss(dst, nds, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::vandpd(XMMRegister dst, XMMRegister nds, AddressLiteral src, bool vector256) {
- if (reachable(src)) {
- vandpd(dst, nds, as_Address(src), vector256);
- } else {
- lea(rscratch1, src);
- vandpd(dst, nds, Address(rscratch1, 0), vector256);
- }
-}
-
-void MacroAssembler::vandps(XMMRegister dst, XMMRegister nds, AddressLiteral src, bool vector256) {
- if (reachable(src)) {
- vandps(dst, nds, as_Address(src), vector256);
- } else {
- lea(rscratch1, src);
- vandps(dst, nds, Address(rscratch1, 0), vector256);
- }
-}
-
-void MacroAssembler::vdivsd(XMMRegister dst, XMMRegister nds, AddressLiteral src) {
- if (reachable(src)) {
- vdivsd(dst, nds, as_Address(src));
- } else {
- lea(rscratch1, src);
- vdivsd(dst, nds, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::vdivss(XMMRegister dst, XMMRegister nds, AddressLiteral src) {
- if (reachable(src)) {
- vdivss(dst, nds, as_Address(src));
- } else {
- lea(rscratch1, src);
- vdivss(dst, nds, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::vmulsd(XMMRegister dst, XMMRegister nds, AddressLiteral src) {
- if (reachable(src)) {
- vmulsd(dst, nds, as_Address(src));
- } else {
- lea(rscratch1, src);
- vmulsd(dst, nds, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::vmulss(XMMRegister dst, XMMRegister nds, AddressLiteral src) {
- if (reachable(src)) {
- vmulss(dst, nds, as_Address(src));
- } else {
- lea(rscratch1, src);
- vmulss(dst, nds, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::vsubsd(XMMRegister dst, XMMRegister nds, AddressLiteral src) {
- if (reachable(src)) {
- vsubsd(dst, nds, as_Address(src));
- } else {
- lea(rscratch1, src);
- vsubsd(dst, nds, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::vsubss(XMMRegister dst, XMMRegister nds, AddressLiteral src) {
- if (reachable(src)) {
- vsubss(dst, nds, as_Address(src));
- } else {
- lea(rscratch1, src);
- vsubss(dst, nds, Address(rscratch1, 0));
- }
-}
-
-void MacroAssembler::vxorpd(XMMRegister dst, XMMRegister nds, AddressLiteral src, bool vector256) {
- if (reachable(src)) {
- vxorpd(dst, nds, as_Address(src), vector256);
- } else {
- lea(rscratch1, src);
- vxorpd(dst, nds, Address(rscratch1, 0), vector256);
- }
-}
-
-void MacroAssembler::vxorps(XMMRegister dst, XMMRegister nds, AddressLiteral src, bool vector256) {
- if (reachable(src)) {
- vxorps(dst, nds, as_Address(src), vector256);
- } else {
- lea(rscratch1, src);
- vxorps(dst, nds, Address(rscratch1, 0), vector256);
- }
-}
-
-
-//////////////////////////////////////////////////////////////////////////////////
-#ifndef SERIALGC
-
-void MacroAssembler::g1_write_barrier_pre(Register obj,
- Register pre_val,
- Register thread,
- Register tmp,
- bool tosca_live,
- bool expand_call) {
-
- // If expand_call is true then we expand the call_VM_leaf macro
- // directly to skip generating the check by
- // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.
-
-#ifdef _LP64
- assert(thread == r15_thread, "must be");
-#endif // _LP64
-
- Label done;
- Label runtime;
-
- assert(pre_val != noreg, "check this code");
-
- if (obj != noreg) {
- assert_different_registers(obj, pre_val, tmp);
- assert(pre_val != rax, "check this code");
- }
-
- Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
- PtrQueue::byte_offset_of_active()));
- Address index(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
- PtrQueue::byte_offset_of_index()));
- Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
- PtrQueue::byte_offset_of_buf()));
-
-
- // Is marking active?
- if (in_bytes(PtrQueue::byte_width_of_active()) == 4) {
- cmpl(in_progress, 0);
- } else {
- assert(in_bytes(PtrQueue::byte_width_of_active()) == 1, "Assumption");
- cmpb(in_progress, 0);
- }
- jcc(Assembler::equal, done);
-
- // Do we need to load the previous value?
- if (obj != noreg) {
- load_heap_oop(pre_val, Address(obj, 0));
- }
-
- // Is the previous value null?
- cmpptr(pre_val, (int32_t) NULL_WORD);
- jcc(Assembler::equal, done);
-
- // Can we store original value in the thread's buffer?
- // Is index == 0?
- // (The index field is typed as size_t.)
-
- movptr(tmp, index); // tmp := *index_adr
- cmpptr(tmp, 0); // tmp == 0?
- jcc(Assembler::equal, runtime); // If yes, goto runtime
-
- subptr(tmp, wordSize); // tmp := tmp - wordSize
- movptr(index, tmp); // *index_adr := tmp
- addptr(tmp, buffer); // tmp := tmp + *buffer_adr
-
- // Record the previous value
- movptr(Address(tmp, 0), pre_val);
- jmp(done);
-
- bind(runtime);
- // save the live input values
- if(tosca_live) push(rax);
-
- if (obj != noreg && obj != rax)
- push(obj);
-
- if (pre_val != rax)
- push(pre_val);
-
- // Calling the runtime using the regular call_VM_leaf mechanism generates
- // code (generated by InterpreterMacroAssember::call_VM_leaf_base)
- // that checks that the *(ebp+frame::interpreter_frame_last_sp) == NULL.
- //
- // If we care generating the pre-barrier without a frame (e.g. in the
- // intrinsified Reference.get() routine) then ebp might be pointing to
- // the caller frame and so this check will most likely fail at runtime.
- //
- // Expanding the call directly bypasses the generation of the check.
- // So when we do not have have a full interpreter frame on the stack
- // expand_call should be passed true.
-
- NOT_LP64( push(thread); )
-
- if (expand_call) {
- LP64_ONLY( assert(pre_val != c_rarg1, "smashed arg"); )
- pass_arg1(this, thread);
- pass_arg0(this, pre_val);
- MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), 2);
- } else {
- call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, thread);
- }
-
- NOT_LP64( pop(thread); )
-
- // save the live input values
- if (pre_val != rax)
- pop(pre_val);
-
- if (obj != noreg && obj != rax)
- pop(obj);
-
- if(tosca_live) pop(rax);
-
- bind(done);
-}
-
-void MacroAssembler::g1_write_barrier_post(Register store_addr,
- Register new_val,
- Register thread,
- Register tmp,
- Register tmp2) {
-#ifdef _LP64
- assert(thread == r15_thread, "must be");
-#endif // _LP64
-
- Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
- PtrQueue::byte_offset_of_index()));
- Address buffer(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
- PtrQueue::byte_offset_of_buf()));
-
- BarrierSet* bs = Universe::heap()->barrier_set();
- CardTableModRefBS* ct = (CardTableModRefBS*)bs;
- Label done;
- Label runtime;
-
- // Does store cross heap regions?
-
- movptr(tmp, store_addr);
- xorptr(tmp, new_val);
- shrptr(tmp, HeapRegion::LogOfHRGrainBytes);
- jcc(Assembler::equal, done);
-
- // crosses regions, storing NULL?
-
- cmpptr(new_val, (int32_t) NULL_WORD);
- jcc(Assembler::equal, done);
-
- // storing region crossing non-NULL, is card already dirty?
-
- ExternalAddress cardtable((address) ct->byte_map_base);
- assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
-#ifdef _LP64
- const Register card_addr = tmp;
-
- movq(card_addr, store_addr);
- shrq(card_addr, CardTableModRefBS::card_shift);
-
- lea(tmp2, cardtable);
-
- // get the address of the card
- addq(card_addr, tmp2);
-#else
- const Register card_index = tmp;
-
- movl(card_index, store_addr);
- shrl(card_index, CardTableModRefBS::card_shift);
-
- Address index(noreg, card_index, Address::times_1);
- const Register card_addr = tmp;
- lea(card_addr, as_Address(ArrayAddress(cardtable, index)));
-#endif
- cmpb(Address(card_addr, 0), 0);
- jcc(Assembler::equal, done);
-
- // storing a region crossing, non-NULL oop, card is clean.
- // dirty card and log.
-
- movb(Address(card_addr, 0), 0);
-
- cmpl(queue_index, 0);
- jcc(Assembler::equal, runtime);
- subl(queue_index, wordSize);
- movptr(tmp2, buffer);
-#ifdef _LP64
- movslq(rscratch1, queue_index);
- addq(tmp2, rscratch1);
- movq(Address(tmp2, 0), card_addr);
-#else
- addl(tmp2, queue_index);
- movl(Address(tmp2, 0), card_index);
-#endif
- jmp(done);
-
- bind(runtime);
- // save the live input values
- push(store_addr);
- push(new_val);
-#ifdef _LP64
- call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, r15_thread);
-#else
- push(thread);
- call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread);
- pop(thread);
-#endif
- pop(new_val);
- pop(store_addr);
-
- bind(done);
-}
-
-#endif // SERIALGC
-//////////////////////////////////////////////////////////////////////////////////
-
-
-void MacroAssembler::store_check(Register obj) {
- // Does a store check for the oop in register obj. The content of
- // register obj is destroyed afterwards.
- store_check_part_1(obj);
- store_check_part_2(obj);
-}
-
-void MacroAssembler::store_check(Register obj, Address dst) {
- store_check(obj);
-}
-
-
-// split the store check operation so that other instructions can be scheduled inbetween
-void MacroAssembler::store_check_part_1(Register obj) {
- BarrierSet* bs = Universe::heap()->barrier_set();
- assert(bs->kind() == BarrierSet::CardTableModRef, "Wrong barrier set kind");
- shrptr(obj, CardTableModRefBS::card_shift);
-}
-
-void MacroAssembler::store_check_part_2(Register obj) {
- BarrierSet* bs = Universe::heap()->barrier_set();
- assert(bs->kind() == BarrierSet::CardTableModRef, "Wrong barrier set kind");
- CardTableModRefBS* ct = (CardTableModRefBS*)bs;
- assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
-
- // The calculation for byte_map_base is as follows:
- // byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift);
- // So this essentially converts an address to a displacement and
- // it will never need to be relocated. On 64bit however the value may be too
- // large for a 32bit displacement
-
- intptr_t disp = (intptr_t) ct->byte_map_base;
- if (is_simm32(disp)) {
- Address cardtable(noreg, obj, Address::times_1, disp);
- movb(cardtable, 0);
- } else {
- // By doing it as an ExternalAddress disp could be converted to a rip-relative
- // displacement and done in a single instruction given favorable mapping and
- // a smarter version of as_Address. Worst case it is two instructions which
- // is no worse off then loading disp into a register and doing as a simple
- // Address() as above.
- // We can't do as ExternalAddress as the only style since if disp == 0 we'll
- // assert since NULL isn't acceptable in a reloci (see 6644928). In any case
- // in some cases we'll get a single instruction version.
-
- ExternalAddress cardtable((address)disp);
- Address index(noreg, obj, Address::times_1);
- movb(as_Address(ArrayAddress(cardtable, index)), 0);
- }
-}
-
-void MacroAssembler::subptr(Register dst, int32_t imm32) {
- LP64_ONLY(subq(dst, imm32)) NOT_LP64(subl(dst, imm32));
-}
-
-// Force generation of a 4 byte immediate value even if it fits into 8bit
-void MacroAssembler::subptr_imm32(Register dst, int32_t imm32) {
- LP64_ONLY(subq_imm32(dst, imm32)) NOT_LP64(subl_imm32(dst, imm32));
-}
-
-void MacroAssembler::subptr(Register dst, Register src) {
- LP64_ONLY(subq(dst, src)) NOT_LP64(subl(dst, src));
-}
-
-// C++ bool manipulation
-void MacroAssembler::testbool(Register dst) {
- if(sizeof(bool) == 1)
- testb(dst, 0xff);
- else if(sizeof(bool) == 2) {
- // testw implementation needed for two byte bools
- ShouldNotReachHere();
- } else if(sizeof(bool) == 4)
- testl(dst, dst);
- else
- // unsupported
- ShouldNotReachHere();
-}
-
-void MacroAssembler::testptr(Register dst, Register src) {
- LP64_ONLY(testq(dst, src)) NOT_LP64(testl(dst, src));
-}
-
-// Defines obj, preserves var_size_in_bytes, okay for t2 == var_size_in_bytes.
-void MacroAssembler::tlab_allocate(Register obj,
- Register var_size_in_bytes,
- int con_size_in_bytes,
- Register t1,
- Register t2,
- Label& slow_case) {
- assert_different_registers(obj, t1, t2);
- assert_different_registers(obj, var_size_in_bytes, t1);
- Register end = t2;
- Register thread = NOT_LP64(t1) LP64_ONLY(r15_thread);
-
- verify_tlab();
-
- NOT_LP64(get_thread(thread));
-
- movptr(obj, Address(thread, JavaThread::tlab_top_offset()));
- if (var_size_in_bytes == noreg) {
- lea(end, Address(obj, con_size_in_bytes));
- } else {
- lea(end, Address(obj, var_size_in_bytes, Address::times_1));
- }
- cmpptr(end, Address(thread, JavaThread::tlab_end_offset()));
- jcc(Assembler::above, slow_case);
-
- // update the tlab top pointer
- movptr(Address(thread, JavaThread::tlab_top_offset()), end);
-
- // recover var_size_in_bytes if necessary
- if (var_size_in_bytes == end) {
- subptr(var_size_in_bytes, obj);
- }
- verify_tlab();
-}
-
-// Preserves rbx, and rdx.
-Register MacroAssembler::tlab_refill(Label& retry,
- Label& try_eden,
- Label& slow_case) {
- Register top = rax;
- Register t1 = rcx;
- Register t2 = rsi;
- Register thread_reg = NOT_LP64(rdi) LP64_ONLY(r15_thread);
- assert_different_registers(top, thread_reg, t1, t2, /* preserve: */ rbx, rdx);
- Label do_refill, discard_tlab;
-
- if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) {
- // No allocation in the shared eden.
- jmp(slow_case);
- }
-
- NOT_LP64(get_thread(thread_reg));
-
- movptr(top, Address(thread_reg, in_bytes(JavaThread::tlab_top_offset())));
- movptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_end_offset())));
-
- // calculate amount of free space
- subptr(t1, top);
- shrptr(t1, LogHeapWordSize);
-
- // Retain tlab and allocate object in shared space if
- // the amount free in the tlab is too large to discard.
- cmpptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_refill_waste_limit_offset())));
- jcc(Assembler::lessEqual, discard_tlab);
-
- // Retain
- // %%% yuck as movptr...
- movptr(t2, (int32_t) ThreadLocalAllocBuffer::refill_waste_limit_increment());
- addptr(Address(thread_reg, in_bytes(JavaThread::tlab_refill_waste_limit_offset())), t2);
- if (TLABStats) {
- // increment number of slow_allocations
- addl(Address(thread_reg, in_bytes(JavaThread::tlab_slow_allocations_offset())), 1);
- }
- jmp(try_eden);
-
- bind(discard_tlab);
- if (TLABStats) {
- // increment number of refills
- addl(Address(thread_reg, in_bytes(JavaThread::tlab_number_of_refills_offset())), 1);
- // accumulate wastage -- t1 is amount free in tlab
- addl(Address(thread_reg, in_bytes(JavaThread::tlab_fast_refill_waste_offset())), t1);
- }
-
- // if tlab is currently allocated (top or end != null) then
- // fill [top, end + alignment_reserve) with array object
- testptr(top, top);
- jcc(Assembler::zero, do_refill);
-
- // set up the mark word
- movptr(Address(top, oopDesc::mark_offset_in_bytes()), (intptr_t)markOopDesc::prototype()->copy_set_hash(0x2));
- // set the length to the remaining space
- subptr(t1, typeArrayOopDesc::header_size(T_INT));
- addptr(t1, (int32_t)ThreadLocalAllocBuffer::alignment_reserve());
- shlptr(t1, log2_intptr(HeapWordSize/sizeof(jint)));
- movl(Address(top, arrayOopDesc::length_offset_in_bytes()), t1);
- // set klass to intArrayKlass
- // dubious reloc why not an oop reloc?
- movptr(t1, ExternalAddress((address)Universe::intArrayKlassObj_addr()));
- // store klass last. concurrent gcs assumes klass length is valid if
- // klass field is not null.
- store_klass(top, t1);
-
- movptr(t1, top);
- subptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_start_offset())));
- incr_allocated_bytes(thread_reg, t1, 0);
-
- // refill the tlab with an eden allocation
- bind(do_refill);
- movptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_size_offset())));
- shlptr(t1, LogHeapWordSize);
- // allocate new tlab, address returned in top
- eden_allocate(top, t1, 0, t2, slow_case);
-
- // Check that t1 was preserved in eden_allocate.
-#ifdef ASSERT
- if (UseTLAB) {
- Label ok;
- Register tsize = rsi;
- assert_different_registers(tsize, thread_reg, t1);
- push(tsize);
- movptr(tsize, Address(thread_reg, in_bytes(JavaThread::tlab_size_offset())));
- shlptr(tsize, LogHeapWordSize);
- cmpptr(t1, tsize);
- jcc(Assembler::equal, ok);
- STOP("assert(t1 != tlab size)");
- should_not_reach_here();
-
- bind(ok);
- pop(tsize);
- }
-#endif
- movptr(Address(thread_reg, in_bytes(JavaThread::tlab_start_offset())), top);
- movptr(Address(thread_reg, in_bytes(JavaThread::tlab_top_offset())), top);
- addptr(top, t1);
- subptr(top, (int32_t)ThreadLocalAllocBuffer::alignment_reserve_in_bytes());
- movptr(Address(thread_reg, in_bytes(JavaThread::tlab_end_offset())), top);
- verify_tlab();
- jmp(retry);
-
- return thread_reg; // for use by caller
-}
-
-void MacroAssembler::incr_allocated_bytes(Register thread,
- Register var_size_in_bytes,
- int con_size_in_bytes,
- Register t1) {
- if (!thread->is_valid()) {
-#ifdef _LP64
- thread = r15_thread;
-#else
- assert(t1->is_valid(), "need temp reg");
- thread = t1;
- get_thread(thread);
-#endif
- }
-
-#ifdef _LP64
- if (var_size_in_bytes->is_valid()) {
- addq(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), var_size_in_bytes);
- } else {
- addq(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), con_size_in_bytes);
- }
-#else
- if (var_size_in_bytes->is_valid()) {
- addl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), var_size_in_bytes);
- } else {
- addl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), con_size_in_bytes);
- }
- adcl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())+4), 0);
-#endif
-}
-
-void MacroAssembler::fp_runtime_fallback(address runtime_entry, int nb_args, int num_fpu_regs_in_use) {
- pusha();
-
- // if we are coming from c1, xmm registers may be live
- int off = 0;
- if (UseSSE == 1) {
- subptr(rsp, sizeof(jdouble)*8);
- movflt(Address(rsp,off++*sizeof(jdouble)),xmm0);
- movflt(Address(rsp,off++*sizeof(jdouble)),xmm1);
- movflt(Address(rsp,off++*sizeof(jdouble)),xmm2);
- movflt(Address(rsp,off++*sizeof(jdouble)),xmm3);
- movflt(Address(rsp,off++*sizeof(jdouble)),xmm4);
- movflt(Address(rsp,off++*sizeof(jdouble)),xmm5);
- movflt(Address(rsp,off++*sizeof(jdouble)),xmm6);
- movflt(Address(rsp,off++*sizeof(jdouble)),xmm7);
- } else if (UseSSE >= 2) {
-#ifdef COMPILER2
- if (MaxVectorSize > 16) {
- assert(UseAVX > 0, "256bit vectors are supported only with AVX");
- // Save upper half of YMM registes
- subptr(rsp, 16 * LP64_ONLY(16) NOT_LP64(8));
- vextractf128h(Address(rsp, 0),xmm0);
- vextractf128h(Address(rsp, 16),xmm1);
- vextractf128h(Address(rsp, 32),xmm2);
- vextractf128h(Address(rsp, 48),xmm3);
- vextractf128h(Address(rsp, 64),xmm4);
- vextractf128h(Address(rsp, 80),xmm5);
- vextractf128h(Address(rsp, 96),xmm6);
- vextractf128h(Address(rsp,112),xmm7);
-#ifdef _LP64
- vextractf128h(Address(rsp,128),xmm8);
- vextractf128h(Address(rsp,144),xmm9);
- vextractf128h(Address(rsp,160),xmm10);
- vextractf128h(Address(rsp,176),xmm11);
- vextractf128h(Address(rsp,192),xmm12);
- vextractf128h(Address(rsp,208),xmm13);
- vextractf128h(Address(rsp,224),xmm14);
- vextractf128h(Address(rsp,240),xmm15);
-#endif
- }
-#endif
- // Save whole 128bit (16 bytes) XMM regiters
- subptr(rsp, 16 * LP64_ONLY(16) NOT_LP64(8));
- movdqu(Address(rsp,off++*16),xmm0);
- movdqu(Address(rsp,off++*16),xmm1);
- movdqu(Address(rsp,off++*16),xmm2);
- movdqu(Address(rsp,off++*16),xmm3);
- movdqu(Address(rsp,off++*16),xmm4);
- movdqu(Address(rsp,off++*16),xmm5);
- movdqu(Address(rsp,off++*16),xmm6);
- movdqu(Address(rsp,off++*16),xmm7);
-#ifdef _LP64
- movdqu(Address(rsp,off++*16),xmm8);
- movdqu(Address(rsp,off++*16),xmm9);
- movdqu(Address(rsp,off++*16),xmm10);
- movdqu(Address(rsp,off++*16),xmm11);
- movdqu(Address(rsp,off++*16),xmm12);
- movdqu(Address(rsp,off++*16),xmm13);
- movdqu(Address(rsp,off++*16),xmm14);
- movdqu(Address(rsp,off++*16),xmm15);
-#endif
- }
-
- // Preserve registers across runtime call
- int incoming_argument_and_return_value_offset = -1;
- if (num_fpu_regs_in_use > 1) {
- // Must preserve all other FPU regs (could alternatively convert
- // SharedRuntime::dsin, dcos etc. into assembly routines known not to trash
- // FPU state, but can not trust C compiler)
- NEEDS_CLEANUP;
- // NOTE that in this case we also push the incoming argument(s) to
- // the stack and restore it later; we also use this stack slot to
- // hold the return value from dsin, dcos etc.
- for (int i = 0; i < num_fpu_regs_in_use; i++) {
- subptr(rsp, sizeof(jdouble));
- fstp_d(Address(rsp, 0));
- }
- incoming_argument_and_return_value_offset = sizeof(jdouble)*(num_fpu_regs_in_use-1);
- for (int i = nb_args-1; i >= 0; i--) {
- fld_d(Address(rsp, incoming_argument_and_return_value_offset-i*sizeof(jdouble)));
- }
- }
-
- subptr(rsp, nb_args*sizeof(jdouble));
- for (int i = 0; i < nb_args; i++) {
- fstp_d(Address(rsp, i*sizeof(jdouble)));
- }
-
-#ifdef _LP64
- if (nb_args > 0) {
- movdbl(xmm0, Address(rsp, 0));
- }
- if (nb_args > 1) {
- movdbl(xmm1, Address(rsp, sizeof(jdouble)));
- }
- assert(nb_args <= 2, "unsupported number of args");
-#endif // _LP64
-
- // NOTE: we must not use call_VM_leaf here because that requires a
- // complete interpreter frame in debug mode -- same bug as 4387334
- // MacroAssembler::call_VM_leaf_base is perfectly safe and will
- // do proper 64bit abi
-
- NEEDS_CLEANUP;
- // Need to add stack banging before this runtime call if it needs to
- // be taken; however, there is no generic stack banging routine at
- // the MacroAssembler level
-
- MacroAssembler::call_VM_leaf_base(runtime_entry, 0);
-
-#ifdef _LP64
- movsd(Address(rsp, 0), xmm0);
- fld_d(Address(rsp, 0));
-#endif // _LP64
- addptr(rsp, sizeof(jdouble) * nb_args);
- if (num_fpu_regs_in_use > 1) {
- // Must save return value to stack and then restore entire FPU
- // stack except incoming arguments
- fstp_d(Address(rsp, incoming_argument_and_return_value_offset));
- for (int i = 0; i < num_fpu_regs_in_use - nb_args; i++) {
- fld_d(Address(rsp, 0));
- addptr(rsp, sizeof(jdouble));
- }
- fld_d(Address(rsp, (nb_args-1)*sizeof(jdouble)));
- addptr(rsp, sizeof(jdouble) * nb_args);
- }
-
- off = 0;
- if (UseSSE == 1) {
- movflt(xmm0, Address(rsp,off++*sizeof(jdouble)));
- movflt(xmm1, Address(rsp,off++*sizeof(jdouble)));
- movflt(xmm2, Address(rsp,off++*sizeof(jdouble)));
- movflt(xmm3, Address(rsp,off++*sizeof(jdouble)));
- movflt(xmm4, Address(rsp,off++*sizeof(jdouble)));
- movflt(xmm5, Address(rsp,off++*sizeof(jdouble)));
- movflt(xmm6, Address(rsp,off++*sizeof(jdouble)));
- movflt(xmm7, Address(rsp,off++*sizeof(jdouble)));
- addptr(rsp, sizeof(jdouble)*8);
- } else if (UseSSE >= 2) {
- // Restore whole 128bit (16 bytes) XMM regiters
- movdqu(xmm0, Address(rsp,off++*16));
- movdqu(xmm1, Address(rsp,off++*16));
- movdqu(xmm2, Address(rsp,off++*16));
- movdqu(xmm3, Address(rsp,off++*16));
- movdqu(xmm4, Address(rsp,off++*16));
- movdqu(xmm5, Address(rsp,off++*16));
- movdqu(xmm6, Address(rsp,off++*16));
- movdqu(xmm7, Address(rsp,off++*16));
-#ifdef _LP64
- movdqu(xmm8, Address(rsp,off++*16));
- movdqu(xmm9, Address(rsp,off++*16));
- movdqu(xmm10, Address(rsp,off++*16));
- movdqu(xmm11, Address(rsp,off++*16));
- movdqu(xmm12, Address(rsp,off++*16));
- movdqu(xmm13, Address(rsp,off++*16));
- movdqu(xmm14, Address(rsp,off++*16));
- movdqu(xmm15, Address(rsp,off++*16));
-#endif
- addptr(rsp, 16 * LP64_ONLY(16) NOT_LP64(8));
-#ifdef COMPILER2
- if (MaxVectorSize > 16) {
- // Restore upper half of YMM registes.
- vinsertf128h(xmm0, Address(rsp, 0));
- vinsertf128h(xmm1, Address(rsp, 16));
- vinsertf128h(xmm2, Address(rsp, 32));
- vinsertf128h(xmm3, Address(rsp, 48));
- vinsertf128h(xmm4, Address(rsp, 64));
- vinsertf128h(xmm5, Address(rsp, 80));
- vinsertf128h(xmm6, Address(rsp, 96));
- vinsertf128h(xmm7, Address(rsp,112));
-#ifdef _LP64
- vinsertf128h(xmm8, Address(rsp,128));
- vinsertf128h(xmm9, Address(rsp,144));
- vinsertf128h(xmm10, Address(rsp,160));
- vinsertf128h(xmm11, Address(rsp,176));
- vinsertf128h(xmm12, Address(rsp,192));
- vinsertf128h(xmm13, Address(rsp,208));
- vinsertf128h(xmm14, Address(rsp,224));
- vinsertf128h(xmm15, Address(rsp,240));
-#endif
- addptr(rsp, 16 * LP64_ONLY(16) NOT_LP64(8));
- }
-#endif
- }
- popa();
-}
-
-static const double pi_4 = 0.7853981633974483;
-
-void MacroAssembler::trigfunc(char trig, int num_fpu_regs_in_use) {
- // A hand-coded argument reduction for values in fabs(pi/4, pi/2)
- // was attempted in this code; unfortunately it appears that the
- // switch to 80-bit precision and back causes this to be
- // unprofitable compared with simply performing a runtime call if
- // the argument is out of the (-pi/4, pi/4) range.
-
- Register tmp = noreg;
- if (!VM_Version::supports_cmov()) {
- // fcmp needs a temporary so preserve rbx,
- tmp = rbx;
- push(tmp);
- }
-
- Label slow_case, done;
-
- ExternalAddress pi4_adr = (address)&pi_4;
- if (reachable(pi4_adr)) {
- // x ?<= pi/4
- fld_d(pi4_adr);
- fld_s(1); // Stack: X PI/4 X
- fabs(); // Stack: |X| PI/4 X
- fcmp(tmp);
- jcc(Assembler::above, slow_case);
-
- // fastest case: -pi/4 <= x <= pi/4
- switch(trig) {
- case 's':
- fsin();
- break;
- case 'c':
- fcos();
- break;
- case 't':
- ftan();
- break;
- default:
- assert(false, "bad intrinsic");
- break;
- }
- jmp(done);
- }
-
- // slow case: runtime call
- bind(slow_case);
-
- switch(trig) {
- case 's':
- {
- fp_runtime_fallback(CAST_FROM_FN_PTR(address, SharedRuntime::dsin), 1, num_fpu_regs_in_use);
- }
- break;
- case 'c':
- {
- fp_runtime_fallback(CAST_FROM_FN_PTR(address, SharedRuntime::dcos), 1, num_fpu_regs_in_use);
- }
- break;
- case 't':
- {
- fp_runtime_fallback(CAST_FROM_FN_PTR(address, SharedRuntime::dtan), 1, num_fpu_regs_in_use);
- }
- break;
- default:
- assert(false, "bad intrinsic");
- break;
- }
-
- // Come here with result in F-TOS
- bind(done);
-
- if (tmp != noreg) {
- pop(tmp);
- }
-}
-
-
-// Look up the method for a megamorphic invokeinterface call.
-// The target method is determined by .
-// The receiver klass is in recv_klass.
-// On success, the result will be in method_result, and execution falls through.
-// On failure, execution transfers to the given label.
-void MacroAssembler::lookup_interface_method(Register recv_klass,
- Register intf_klass,
- RegisterOrConstant itable_index,
- Register method_result,
- Register scan_temp,
- Label& L_no_such_interface) {
- assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
- assert(itable_index.is_constant() || itable_index.as_register() == method_result,
- "caller must use same register for non-constant itable index as for method");
-
- // Compute start of first itableOffsetEntry (which is at the end of the vtable)
- int vtable_base = InstanceKlass::vtable_start_offset() * wordSize;
- int itentry_off = itableMethodEntry::method_offset_in_bytes();
- int scan_step = itableOffsetEntry::size() * wordSize;
- int vte_size = vtableEntry::size() * wordSize;
- Address::ScaleFactor times_vte_scale = Address::times_ptr;
- assert(vte_size == wordSize, "else adjust times_vte_scale");
-
- movl(scan_temp, Address(recv_klass, InstanceKlass::vtable_length_offset() * wordSize));
-
- // %%% Could store the aligned, prescaled offset in the klassoop.
- lea(scan_temp, Address(recv_klass, scan_temp, times_vte_scale, vtable_base));
- if (HeapWordsPerLong > 1) {
- // Round up to align_object_offset boundary
- // see code for InstanceKlass::start_of_itable!
- round_to(scan_temp, BytesPerLong);
- }
-
- // Adjust recv_klass by scaled itable_index, so we can free itable_index.
- assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
- lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off));
-
- // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
- // if (scan->interface() == intf) {
- // result = (klass + scan->offset() + itable_index);
- // }
- // }
- Label search, found_method;
-
- for (int peel = 1; peel >= 0; peel--) {
- movptr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
- cmpptr(intf_klass, method_result);
-
- if (peel) {
- jccb(Assembler::equal, found_method);
- } else {
- jccb(Assembler::notEqual, search);
- // (invert the test to fall through to found_method...)
- }
-
- if (!peel) break;
-
- bind(search);
-
- // Check that the previous entry is non-null. A null entry means that
- // the receiver class doesn't implement the interface, and wasn't the
- // same as when the caller was compiled.
- testptr(method_result, method_result);
- jcc(Assembler::zero, L_no_such_interface);
- addptr(scan_temp, scan_step);
- }
-
- bind(found_method);
-
- // Got a hit.
- movl(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
- movptr(method_result, Address(recv_klass, scan_temp, Address::times_1));
-}
-
-
-// virtual method calling
-void MacroAssembler::lookup_virtual_method(Register recv_klass,
- RegisterOrConstant vtable_index,
- Register method_result) {
- const int base = InstanceKlass::vtable_start_offset() * wordSize;
- assert(vtableEntry::size() * wordSize == wordSize, "else adjust the scaling in the code below");
- Address vtable_entry_addr(recv_klass,
- vtable_index, Address::times_ptr,
- base + vtableEntry::method_offset_in_bytes());
- movptr(method_result, vtable_entry_addr);
-}
-
-
-void MacroAssembler::check_klass_subtype(Register sub_klass,
- Register super_klass,
- Register temp_reg,
- Label& L_success) {
- Label L_failure;
- check_klass_subtype_fast_path(sub_klass, super_klass, temp_reg, &L_success, &L_failure, NULL);
- check_klass_subtype_slow_path(sub_klass, super_klass, temp_reg, noreg, &L_success, NULL);
- bind(L_failure);
-}
-
-
-void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass,
- Register super_klass,
- Register temp_reg,
- Label* L_success,
- Label* L_failure,
- Label* L_slow_path,
- RegisterOrConstant super_check_offset) {
- assert_different_registers(sub_klass, super_klass, temp_reg);
- bool must_load_sco = (super_check_offset.constant_or_zero() == -1);
- if (super_check_offset.is_register()) {
- assert_different_registers(sub_klass, super_klass,
- super_check_offset.as_register());
- } else if (must_load_sco) {
- assert(temp_reg != noreg, "supply either a temp or a register offset");
- }
-
- Label L_fallthrough;
- int label_nulls = 0;
- if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; }
- if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; }
- if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; }
- assert(label_nulls <= 1, "at most one NULL in the batch");
-
- int sc_offset = in_bytes(Klass::secondary_super_cache_offset());
- int sco_offset = in_bytes(Klass::super_check_offset_offset());
- Address super_check_offset_addr(super_klass, sco_offset);
-
- // Hacked jcc, which "knows" that L_fallthrough, at least, is in
- // range of a jccb. If this routine grows larger, reconsider at
- // least some of these.
-#define local_jcc(assembler_cond, label) \
- if (&(label) == &L_fallthrough) jccb(assembler_cond, label); \
- else jcc( assembler_cond, label) /*omit semi*/
-
- // Hacked jmp, which may only be used just before L_fallthrough.
-#define final_jmp(label) \
- if (&(label) == &L_fallthrough) { /*do nothing*/ } \
- else jmp(label) /*omit semi*/
-
- // If the pointers are equal, we are done (e.g., String[] elements).
- // This self-check enables sharing of secondary supertype arrays among
- // non-primary types such as array-of-interface. Otherwise, each such
- // type would need its own customized SSA.
- // We move this check to the front of the fast path because many
- // type checks are in fact trivially successful in this manner,
- // so we get a nicely predicted branch right at the start of the check.
- cmpptr(sub_klass, super_klass);
- local_jcc(Assembler::equal, *L_success);
-
- // Check the supertype display:
- if (must_load_sco) {
- // Positive movl does right thing on LP64.
- movl(temp_reg, super_check_offset_addr);
- super_check_offset = RegisterOrConstant(temp_reg);
- }
- Address super_check_addr(sub_klass, super_check_offset, Address::times_1, 0);
- cmpptr(super_klass, super_check_addr); // load displayed supertype
-
- // This check has worked decisively for primary supers.
- // Secondary supers are sought in the super_cache ('super_cache_addr').
- // (Secondary supers are interfaces and very deeply nested subtypes.)
- // This works in the same check above because of a tricky aliasing
- // between the super_cache and the primary super display elements.
- // (The 'super_check_addr' can address either, as the case requires.)
- // Note that the cache is updated below if it does not help us find
- // what we need immediately.
- // So if it was a primary super, we can just fail immediately.
- // Otherwise, it's the slow path for us (no success at this point).
-
- if (super_check_offset.is_register()) {
- local_jcc(Assembler::equal, *L_success);
- cmpl(super_check_offset.as_register(), sc_offset);
- if (L_failure == &L_fallthrough) {
- local_jcc(Assembler::equal, *L_slow_path);
- } else {
- local_jcc(Assembler::notEqual, *L_failure);
- final_jmp(*L_slow_path);
- }
- } else if (super_check_offset.as_constant() == sc_offset) {
- // Need a slow path; fast failure is impossible.
- if (L_slow_path == &L_fallthrough) {
- local_jcc(Assembler::equal, *L_success);
- } else {
- local_jcc(Assembler::notEqual, *L_slow_path);
- final_jmp(*L_success);
- }
- } else {
- // No slow path; it's a fast decision.
- if (L_failure == &L_fallthrough) {
- local_jcc(Assembler::equal, *L_success);
- } else {
- local_jcc(Assembler::notEqual, *L_failure);
- final_jmp(*L_success);
- }
- }
-
- bind(L_fallthrough);
-
-#undef local_jcc
-#undef final_jmp
-}
-
-
-void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass,
- Register super_klass,
- Register temp_reg,
- Register temp2_reg,
- Label* L_success,
- Label* L_failure,
- bool set_cond_codes) {
- assert_different_registers(sub_klass, super_klass, temp_reg);
- if (temp2_reg != noreg)
- assert_different_registers(sub_klass, super_klass, temp_reg, temp2_reg);
-#define IS_A_TEMP(reg) ((reg) == temp_reg || (reg) == temp2_reg)
-
- Label L_fallthrough;
- int label_nulls = 0;
- if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; }
- if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; }
- assert(label_nulls <= 1, "at most one NULL in the batch");
-
- // a couple of useful fields in sub_klass:
- int ss_offset = in_bytes(Klass::secondary_supers_offset());
- int sc_offset = in_bytes(Klass::secondary_super_cache_offset());
- Address secondary_supers_addr(sub_klass, ss_offset);
- Address super_cache_addr( sub_klass, sc_offset);
-
- // Do a linear scan of the secondary super-klass chain.
- // This code is rarely used, so simplicity is a virtue here.
- // The repne_scan instruction uses fixed registers, which we must spill.
- // Don't worry too much about pre-existing connections with the input regs.
-
- assert(sub_klass != rax, "killed reg"); // killed by mov(rax, super)
- assert(sub_klass != rcx, "killed reg"); // killed by lea(rcx, &pst_counter)
-
- // Get super_klass value into rax (even if it was in rdi or rcx).
- bool pushed_rax = false, pushed_rcx = false, pushed_rdi = false;
- if (super_klass != rax || UseCompressedOops) {
- if (!IS_A_TEMP(rax)) { push(rax); pushed_rax = true; }
- mov(rax, super_klass);
- }
- if (!IS_A_TEMP(rcx)) { push(rcx); pushed_rcx = true; }
- if (!IS_A_TEMP(rdi)) { push(rdi); pushed_rdi = true; }
-
-#ifndef PRODUCT
- int* pst_counter = &SharedRuntime::_partial_subtype_ctr;
- ExternalAddress pst_counter_addr((address) pst_counter);
- NOT_LP64( incrementl(pst_counter_addr) );
- LP64_ONLY( lea(rcx, pst_counter_addr) );
- LP64_ONLY( incrementl(Address(rcx, 0)) );
-#endif //PRODUCT
-
- // We will consult the secondary-super array.
- movptr(rdi, secondary_supers_addr);
- // Load the array length. (Positive movl does right thing on LP64.)
- movl(rcx, Address(rdi, Array::length_offset_in_bytes()));
- // Skip to start of data.
- addptr(rdi, Array::base_offset_in_bytes());
-
- // Scan RCX words at [RDI] for an occurrence of RAX.
- // Set NZ/Z based on last compare.
- // Z flag value will not be set by 'repne' if RCX == 0 since 'repne' does
- // not change flags (only scas instruction which is repeated sets flags).
- // Set Z = 0 (not equal) before 'repne' to indicate that class was not found.
-
- testptr(rax,rax); // Set Z = 0
- repne_scan();
-
- // Unspill the temp. registers:
- if (pushed_rdi) pop(rdi);
- if (pushed_rcx) pop(rcx);
- if (pushed_rax) pop(rax);
-
- if (set_cond_codes) {
- // Special hack for the AD files: rdi is guaranteed non-zero.
- assert(!pushed_rdi, "rdi must be left non-NULL");
- // Also, the condition codes are properly set Z/NZ on succeed/failure.
- }
-
- if (L_failure == &L_fallthrough)
- jccb(Assembler::notEqual, *L_failure);
- else jcc(Assembler::notEqual, *L_failure);
-
- // Success. Cache the super we found and proceed in triumph.
- movptr(super_cache_addr, super_klass);
-
- if (L_success != &L_fallthrough) {
- jmp(*L_success);
- }
-
-#undef IS_A_TEMP
-
- bind(L_fallthrough);
-}
-
-
-void MacroAssembler::cmov32(Condition cc, Register dst, Address src) {
- if (VM_Version::supports_cmov()) {
- cmovl(cc, dst, src);
- } else {
- Label L;
- jccb(negate_condition(cc), L);
- movl(dst, src);
- bind(L);
- }
-}
-
-void MacroAssembler::cmov32(Condition cc, Register dst, Register src) {
- if (VM_Version::supports_cmov()) {
- cmovl(cc, dst, src);
- } else {
- Label L;
- jccb(negate_condition(cc), L);
- movl(dst, src);
- bind(L);
- }
-}
-
-void MacroAssembler::verify_oop(Register reg, const char* s) {
- if (!VerifyOops) return;
-
- // Pass register number to verify_oop_subroutine
- char* b = new char[strlen(s) + 50];
- sprintf(b, "verify_oop: %s: %s", reg->name(), s);
- BLOCK_COMMENT("verify_oop {");
-#ifdef _LP64
- push(rscratch1); // save r10, trashed by movptr()
-#endif
- push(rax); // save rax,
- push(reg); // pass register argument
- ExternalAddress buffer((address) b);
- // avoid using pushptr, as it modifies scratch registers
- // and our contract is not to modify anything
- movptr(rax, buffer.addr());
- push(rax);
- // call indirectly to solve generation ordering problem
- movptr(rax, ExternalAddress(StubRoutines::verify_oop_subroutine_entry_address()));
- call(rax);
- // Caller pops the arguments (oop, message) and restores rax, r10
- BLOCK_COMMENT("} verify_oop");
-}
-
-
-RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr,
- Register tmp,
- int offset) {
- intptr_t value = *delayed_value_addr;
- if (value != 0)
- return RegisterOrConstant(value + offset);
-
- // load indirectly to solve generation ordering problem
- movptr(tmp, ExternalAddress((address) delayed_value_addr));
-
-#ifdef ASSERT
- { Label L;
- testptr(tmp, tmp);
- if (WizardMode) {
- jcc(Assembler::notZero, L);
- char* buf = new char[40];
- sprintf(buf, "DelayedValue="INTPTR_FORMAT, delayed_value_addr[1]);
- STOP(buf);
- } else {
- jccb(Assembler::notZero, L);
- hlt();
- }
- bind(L);
- }
-#endif
-
- if (offset != 0)
- addptr(tmp, offset);
-
- return RegisterOrConstant(tmp);
-}
-
-
-Address MacroAssembler::argument_address(RegisterOrConstant arg_slot,
- int extra_slot_offset) {
- // cf. TemplateTable::prepare_invoke(), if (load_receiver).
- int stackElementSize = Interpreter::stackElementSize;
- int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
-#ifdef ASSERT
- int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1);
- assert(offset1 - offset == stackElementSize, "correct arithmetic");
-#endif
- Register scale_reg = noreg;
- Address::ScaleFactor scale_factor = Address::no_scale;
- if (arg_slot.is_constant()) {
- offset += arg_slot.as_constant() * stackElementSize;
- } else {
- scale_reg = arg_slot.as_register();
- scale_factor = Address::times(stackElementSize);
- }
- offset += wordSize; // return PC is on stack
- return Address(rsp, scale_reg, scale_factor, offset);
-}
-
-
-void MacroAssembler::verify_oop_addr(Address addr, const char* s) {
- if (!VerifyOops) return;
-
- // Address adjust(addr.base(), addr.index(), addr.scale(), addr.disp() + BytesPerWord);
- // Pass register number to verify_oop_subroutine
- char* b = new char[strlen(s) + 50];
- sprintf(b, "verify_oop_addr: %s", s);
-
-#ifdef _LP64
- push(rscratch1); // save r10, trashed by movptr()
-#endif
- push(rax); // save rax,
- // addr may contain rsp so we will have to adjust it based on the push
- // we just did (and on 64 bit we do two pushes)
- // NOTE: 64bit seemed to have had a bug in that it did movq(addr, rax); which
- // stores rax into addr which is backwards of what was intended.
- if (addr.uses(rsp)) {
- lea(rax, addr);
- pushptr(Address(rax, LP64_ONLY(2 *) BytesPerWord));
- } else {
- pushptr(addr);
- }
-
- ExternalAddress buffer((address) b);
- // pass msg argument
- // avoid using pushptr, as it modifies scratch registers
- // and our contract is not to modify anything
- movptr(rax, buffer.addr());
- push(rax);
-
- // call indirectly to solve generation ordering problem
- movptr(rax, ExternalAddress(StubRoutines::verify_oop_subroutine_entry_address()));
- call(rax);
- // Caller pops the arguments (addr, message) and restores rax, r10.
-}
-
-void MacroAssembler::verify_tlab() {
-#ifdef ASSERT
- if (UseTLAB && VerifyOops) {
- Label next, ok;
- Register t1 = rsi;
- Register thread_reg = NOT_LP64(rbx) LP64_ONLY(r15_thread);
-
- push(t1);
- NOT_LP64(push(thread_reg));
- NOT_LP64(get_thread(thread_reg));
-
- movptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_top_offset())));
- cmpptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_start_offset())));
- jcc(Assembler::aboveEqual, next);
- STOP("assert(top >= start)");
- should_not_reach_here();
-
- bind(next);
- movptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_end_offset())));
- cmpptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_top_offset())));
- jcc(Assembler::aboveEqual, ok);
- STOP("assert(top <= end)");
- should_not_reach_here();
-
- bind(ok);
- NOT_LP64(pop(thread_reg));
- pop(t1);
- }
-#endif
-}
-
-class ControlWord {
- public:
- int32_t _value;
-
- int rounding_control() const { return (_value >> 10) & 3 ; }
- int precision_control() const { return (_value >> 8) & 3 ; }
- bool precision() const { return ((_value >> 5) & 1) != 0; }
- bool underflow() const { return ((_value >> 4) & 1) != 0; }
- bool overflow() const { return ((_value >> 3) & 1) != 0; }
- bool zero_divide() const { return ((_value >> 2) & 1) != 0; }
- bool denormalized() const { return ((_value >> 1) & 1) != 0; }
- bool invalid() const { return ((_value >> 0) & 1) != 0; }
-
- void print() const {
- // rounding control
- const char* rc;
- switch (rounding_control()) {
- case 0: rc = "round near"; break;
- case 1: rc = "round down"; break;
- case 2: rc = "round up "; break;
- case 3: rc = "chop "; break;
- };
- // precision control
- const char* pc;
- switch (precision_control()) {
- case 0: pc = "24 bits "; break;
- case 1: pc = "reserved"; break;
- case 2: pc = "53 bits "; break;
- case 3: pc = "64 bits "; break;
- };
- // flags
- char f[9];
- f[0] = ' ';
- f[1] = ' ';
- f[2] = (precision ()) ? 'P' : 'p';
- f[3] = (underflow ()) ? 'U' : 'u';
- f[4] = (overflow ()) ? 'O' : 'o';
- f[5] = (zero_divide ()) ? 'Z' : 'z';
- f[6] = (denormalized()) ? 'D' : 'd';
- f[7] = (invalid ()) ? 'I' : 'i';
- f[8] = '\x0';
- // output
- printf("%04x masks = %s, %s, %s", _value & 0xFFFF, f, rc, pc);
- }
-
-};
-
-class StatusWord {
- public:
- int32_t _value;
-
- bool busy() const { return ((_value >> 15) & 1) != 0; }
- bool C3() const { return ((_value >> 14) & 1) != 0; }
- bool C2() const { return ((_value >> 10) & 1) != 0; }
- bool C1() const { return ((_value >> 9) & 1) != 0; }
- bool C0() const { return ((_value >> 8) & 1) != 0; }
- int top() const { return (_value >> 11) & 7 ; }
- bool error_status() const { return ((_value >> 7) & 1) != 0; }
- bool stack_fault() const { return ((_value >> 6) & 1) != 0; }
- bool precision() const { return ((_value >> 5) & 1) != 0; }
- bool underflow() const { return ((_value >> 4) & 1) != 0; }
- bool overflow() const { return ((_value >> 3) & 1) != 0; }
- bool zero_divide() const { return ((_value >> 2) & 1) != 0; }
- bool denormalized() const { return ((_value >> 1) & 1) != 0; }
- bool invalid() const { return ((_value >> 0) & 1) != 0; }
-
- void print() const {
- // condition codes
- char c[5];
- c[0] = (C3()) ? '3' : '-';
- c[1] = (C2()) ? '2' : '-';
- c[2] = (C1()) ? '1' : '-';
- c[3] = (C0()) ? '0' : '-';
- c[4] = '\x0';
- // flags
- char f[9];
- f[0] = (error_status()) ? 'E' : '-';
- f[1] = (stack_fault ()) ? 'S' : '-';
- f[2] = (precision ()) ? 'P' : '-';
- f[3] = (underflow ()) ? 'U' : '-';
- f[4] = (overflow ()) ? 'O' : '-';
- f[5] = (zero_divide ()) ? 'Z' : '-';
- f[6] = (denormalized()) ? 'D' : '-';
- f[7] = (invalid ()) ? 'I' : '-';
- f[8] = '\x0';
- // output
- printf("%04x flags = %s, cc = %s, top = %d", _value & 0xFFFF, f, c, top());
- }
-
-};
-
-class TagWord {
- public:
- int32_t _value;
-
- int tag_at(int i) const { return (_value >> (i*2)) & 3; }
-
- void print() const {
- printf("%04x", _value & 0xFFFF);
- }
-
-};
-
-class FPU_Register {
- public:
- int32_t _m0;
- int32_t _m1;
- int16_t _ex;
-
- bool is_indefinite() const {
- return _ex == -1 && _m1 == (int32_t)0xC0000000 && _m0 == 0;
- }
-
- void print() const {
- char sign = (_ex < 0) ? '-' : '+';
- const char* kind = (_ex == 0x7FFF || _ex == (int16_t)-1) ? "NaN" : " ";
- printf("%c%04hx.%08x%08x %s", sign, _ex, _m1, _m0, kind);
- };
-
-};
-
-class FPU_State {
- public:
- enum {
- register_size = 10,
- number_of_registers = 8,
- register_mask = 7
- };
-
- ControlWord _control_word;
- StatusWord _status_word;
- TagWord _tag_word;
- int32_t _error_offset;
- int32_t _error_selector;
- int32_t _data_offset;
- int32_t _data_selector;
- int8_t _register[register_size * number_of_registers];
-
- int tag_for_st(int i) const { return _tag_word.tag_at((_status_word.top() + i) & register_mask); }
- FPU_Register* st(int i) const { return (FPU_Register*)&_register[register_size * i]; }
-
- const char* tag_as_string(int tag) const {
- switch (tag) {
- case 0: return "valid";
- case 1: return "zero";
- case 2: return "special";
- case 3: return "empty";
- }
- ShouldNotReachHere();
- return NULL;
- }
-
- void print() const {
- // print computation registers
- { int t = _status_word.top();
- for (int i = 0; i < number_of_registers; i++) {
- int j = (i - t) & register_mask;
- printf("%c r%d = ST%d = ", (j == 0 ? '*' : ' '), i, j);
- st(j)->print();
- printf(" %s\n", tag_as_string(_tag_word.tag_at(i)));
- }
- }
- printf("\n");
- // print control registers
- printf("ctrl = "); _control_word.print(); printf("\n");
- printf("stat = "); _status_word .print(); printf("\n");
- printf("tags = "); _tag_word .print(); printf("\n");
- }
-
-};
-
-class Flag_Register {
- public:
- int32_t _value;
-
- bool overflow() const { return ((_value >> 11) & 1) != 0; }
- bool direction() const { return ((_value >> 10) & 1) != 0; }
- bool sign() const { return ((_value >> 7) & 1) != 0; }
- bool zero() const { return ((_value >> 6) & 1) != 0; }
- bool auxiliary_carry() const { return ((_value >> 4) & 1) != 0; }
- bool parity() const { return ((_value >> 2) & 1) != 0; }
- bool carry() const { return ((_value >> 0) & 1) != 0; }
-
- void print() const {
- // flags
- char f[8];
- f[0] = (overflow ()) ? 'O' : '-';
- f[1] = (direction ()) ? 'D' : '-';
- f[2] = (sign ()) ? 'S' : '-';
- f[3] = (zero ()) ? 'Z' : '-';
- f[4] = (auxiliary_carry()) ? 'A' : '-';
- f[5] = (parity ()) ? 'P' : '-';
- f[6] = (carry ()) ? 'C' : '-';
- f[7] = '\x0';
- // output
- printf("%08x flags = %s", _value, f);
- }
-
-};
-
-class IU_Register {
- public:
- int32_t _value;
-
- void print() const {
- printf("%08x %11d", _value, _value);
- }
-
-};
-
-class IU_State {
- public:
- Flag_Register _eflags;
- IU_Register _rdi;
- IU_Register _rsi;
- IU_Register _rbp;
- IU_Register _rsp;
- IU_Register _rbx;
- IU_Register _rdx;
- IU_Register _rcx;
- IU_Register _rax;
-
- void print() const {
- // computation registers
- printf("rax, = "); _rax.print(); printf("\n");
- printf("rbx, = "); _rbx.print(); printf("\n");
- printf("rcx = "); _rcx.print(); printf("\n");
- printf("rdx = "); _rdx.print(); printf("\n");
- printf("rdi = "); _rdi.print(); printf("\n");
- printf("rsi = "); _rsi.print(); printf("\n");
- printf("rbp, = "); _rbp.print(); printf("\n");
- printf("rsp = "); _rsp.print(); printf("\n");
- printf("\n");
- // control registers
- printf("flgs = "); _eflags.print(); printf("\n");
- }
-};
-
-
-class CPU_State {
- public:
- FPU_State _fpu_state;
- IU_State _iu_state;
-
- void print() const {
- printf("--------------------------------------------------\n");
- _iu_state .print();
- printf("\n");
- _fpu_state.print();
- printf("--------------------------------------------------\n");
- }
-
-};
-
-
-static void _print_CPU_state(CPU_State* state) {
- state->print();
-};
-
-
-void MacroAssembler::print_CPU_state() {
- push_CPU_state();
- push(rsp); // pass CPU state
- call(RuntimeAddress(CAST_FROM_FN_PTR(address, _print_CPU_state)));
- addptr(rsp, wordSize); // discard argument
- pop_CPU_state();
-}
-
-
-static bool _verify_FPU(int stack_depth, char* s, CPU_State* state) {
- static int counter = 0;
- FPU_State* fs = &state->_fpu_state;
- counter++;
- // For leaf calls, only verify that the top few elements remain empty.
- // We only need 1 empty at the top for C2 code.
- if( stack_depth < 0 ) {
- if( fs->tag_for_st(7) != 3 ) {
- printf("FPR7 not empty\n");
- state->print();
- assert(false, "error");
- return false;
- }
- return true; // All other stack states do not matter
- }
-
- assert((fs->_control_word._value & 0xffff) == StubRoutines::_fpu_cntrl_wrd_std,
- "bad FPU control word");
-
- // compute stack depth
- int i = 0;
- while (i < FPU_State::number_of_registers && fs->tag_for_st(i) < 3) i++;
- int d = i;
- while (i < FPU_State::number_of_registers && fs->tag_for_st(i) == 3) i++;
- // verify findings
- if (i != FPU_State::number_of_registers) {
- // stack not contiguous
- printf("%s: stack not contiguous at ST%d\n", s, i);
- state->print();
- assert(false, "error");
- return false;
- }
- // check if computed stack depth corresponds to expected stack depth
- if (stack_depth < 0) {
- // expected stack depth is -stack_depth or less
- if (d > -stack_depth) {
- // too many elements on the stack
- printf("%s: <= %d stack elements expected but found %d\n", s, -stack_depth, d);
- state->print();
- assert(false, "error");
- return false;
- }
- } else {
- // expected stack depth is stack_depth
- if (d != stack_depth) {
- // wrong stack depth
- printf("%s: %d stack elements expected but found %d\n", s, stack_depth, d);
- state->print();
- assert(false, "error");
- return false;
- }
- }
- // everything is cool
- return true;
-}
-
-
-void MacroAssembler::verify_FPU(int stack_depth, const char* s) {
- if (!VerifyFPU) return;
- push_CPU_state();
- push(rsp); // pass CPU state
- ExternalAddress msg((address) s);
- // pass message string s
- pushptr(msg.addr());
- push(stack_depth); // pass stack depth
- call(RuntimeAddress(CAST_FROM_FN_PTR(address, _verify_FPU)));
- addptr(rsp, 3 * wordSize); // discard arguments
- // check for error
- { Label L;
- testl(rax, rax);
- jcc(Assembler::notZero, L);
- int3(); // break if error condition
- bind(L);
- }
- pop_CPU_state();
-}
-
-void MacroAssembler::load_klass(Register dst, Register src) {
-#ifdef _LP64
- if (UseCompressedKlassPointers) {
- movl(dst, Address(src, oopDesc::klass_offset_in_bytes()));
- decode_klass_not_null(dst);
- } else
-#endif
- movptr(dst, Address(src, oopDesc::klass_offset_in_bytes()));
-}
-
-void MacroAssembler::load_prototype_header(Register dst, Register src) {
-#ifdef _LP64
- if (UseCompressedKlassPointers) {
- assert (Universe::heap() != NULL, "java heap should be initialized");
- movl(dst, Address(src, oopDesc::klass_offset_in_bytes()));
- if (Universe::narrow_klass_shift() != 0) {
- assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
- assert(LogKlassAlignmentInBytes == Address::times_8, "klass not aligned on 64bits?");
- movq(dst, Address(r12_heapbase, dst, Address::times_8, Klass::prototype_header_offset()));
- } else {
- movq(dst, Address(dst, Klass::prototype_header_offset()));
- }
- } else
-#endif
- {
- movptr(dst, Address(src, oopDesc::klass_offset_in_bytes()));
- movptr(dst, Address(dst, Klass::prototype_header_offset()));
- }
-}
-
-void MacroAssembler::store_klass(Register dst, Register src) {
-#ifdef _LP64
- if (UseCompressedKlassPointers) {
- encode_klass_not_null(src);
- movl(Address(dst, oopDesc::klass_offset_in_bytes()), src);
- } else
-#endif
- movptr(Address(dst, oopDesc::klass_offset_in_bytes()), src);
-}
-
-void MacroAssembler::load_heap_oop(Register dst, Address src) {
-#ifdef _LP64
- // FIXME: Must change all places where we try to load the klass.
- if (UseCompressedOops) {
- movl(dst, src);
- decode_heap_oop(dst);
- } else
-#endif
- movptr(dst, src);
-}
-
-// Doesn't do verfication, generates fixed size code
-void MacroAssembler::load_heap_oop_not_null(Register dst, Address src) {
-#ifdef _LP64
- if (UseCompressedOops) {
- movl(dst, src);
- decode_heap_oop_not_null(dst);
- } else
-#endif
- movptr(dst, src);
-}
-
-void MacroAssembler::store_heap_oop(Address dst, Register src) {
-#ifdef _LP64
- if (UseCompressedOops) {
- assert(!dst.uses(src), "not enough registers");
- encode_heap_oop(src);
- movl(dst, src);
- } else
-#endif
- movptr(dst, src);
-}
-
-void MacroAssembler::cmp_heap_oop(Register src1, Address src2, Register tmp) {
- assert_different_registers(src1, tmp);
-#ifdef _LP64
- if (UseCompressedOops) {
- bool did_push = false;
- if (tmp == noreg) {
- tmp = rax;
- push(tmp);
- did_push = true;
- assert(!src2.uses(rsp), "can't push");
- }
- load_heap_oop(tmp, src2);
- cmpptr(src1, tmp);
- if (did_push) pop(tmp);
- } else
-#endif
- cmpptr(src1, src2);
-}
-
-// Used for storing NULLs.
-void MacroAssembler::store_heap_oop_null(Address dst) {
-#ifdef _LP64
- if (UseCompressedOops) {
- movl(dst, (int32_t)NULL_WORD);
- } else {
- movslq(dst, (int32_t)NULL_WORD);
- }
-#else
- movl(dst, (int32_t)NULL_WORD);
-#endif
-}
-
-#ifdef _LP64
-void MacroAssembler::store_klass_gap(Register dst, Register src) {
- if (UseCompressedKlassPointers) {
- // Store to klass gap in destination
- movl(Address(dst, oopDesc::klass_gap_offset_in_bytes()), src);
- }
-}
-
-#ifdef ASSERT
-void MacroAssembler::verify_heapbase(const char* msg) {
- assert (UseCompressedOops || UseCompressedKlassPointers, "should be compressed");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- if (CheckCompressedOops) {
- Label ok;
- push(rscratch1); // cmpptr trashes rscratch1
- cmpptr(r12_heapbase, ExternalAddress((address)Universe::narrow_ptrs_base_addr()));
- jcc(Assembler::equal, ok);
- STOP(msg);
- bind(ok);
- pop(rscratch1);
- }
-}
-#endif
-
-// Algorithm must match oop.inline.hpp encode_heap_oop.
-void MacroAssembler::encode_heap_oop(Register r) {
-#ifdef ASSERT
- verify_heapbase("MacroAssembler::encode_heap_oop: heap base corrupted?");
-#endif
- verify_oop(r, "broken oop in encode_heap_oop");
- if (Universe::narrow_oop_base() == NULL) {
- if (Universe::narrow_oop_shift() != 0) {
- assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
- shrq(r, LogMinObjAlignmentInBytes);
- }
- return;
- }
- testq(r, r);
- cmovq(Assembler::equal, r, r12_heapbase);
- subq(r, r12_heapbase);
- shrq(r, LogMinObjAlignmentInBytes);
-}
-
-void MacroAssembler::encode_heap_oop_not_null(Register r) {
-#ifdef ASSERT
- verify_heapbase("MacroAssembler::encode_heap_oop_not_null: heap base corrupted?");
- if (CheckCompressedOops) {
- Label ok;
- testq(r, r);
- jcc(Assembler::notEqual, ok);
- STOP("null oop passed to encode_heap_oop_not_null");
- bind(ok);
- }
-#endif
- verify_oop(r, "broken oop in encode_heap_oop_not_null");
- if (Universe::narrow_oop_base() != NULL) {
- subq(r, r12_heapbase);
- }
- if (Universe::narrow_oop_shift() != 0) {
- assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
- shrq(r, LogMinObjAlignmentInBytes);
- }
-}
-
-void MacroAssembler::encode_heap_oop_not_null(Register dst, Register src) {
-#ifdef ASSERT
- verify_heapbase("MacroAssembler::encode_heap_oop_not_null2: heap base corrupted?");
- if (CheckCompressedOops) {
- Label ok;
- testq(src, src);
- jcc(Assembler::notEqual, ok);
- STOP("null oop passed to encode_heap_oop_not_null2");
- bind(ok);
- }
-#endif
- verify_oop(src, "broken oop in encode_heap_oop_not_null2");
- if (dst != src) {
- movq(dst, src);
- }
- if (Universe::narrow_oop_base() != NULL) {
- subq(dst, r12_heapbase);
- }
- if (Universe::narrow_oop_shift() != 0) {
- assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
- shrq(dst, LogMinObjAlignmentInBytes);
- }
-}
-
-void MacroAssembler::decode_heap_oop(Register r) {
-#ifdef ASSERT
- verify_heapbase("MacroAssembler::decode_heap_oop: heap base corrupted?");
-#endif
- if (Universe::narrow_oop_base() == NULL) {
- if (Universe::narrow_oop_shift() != 0) {
- assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
- shlq(r, LogMinObjAlignmentInBytes);
- }
- } else {
- Label done;
- shlq(r, LogMinObjAlignmentInBytes);
- jccb(Assembler::equal, done);
- addq(r, r12_heapbase);
- bind(done);
- }
- verify_oop(r, "broken oop in decode_heap_oop");
-}
-
-void MacroAssembler::decode_heap_oop_not_null(Register r) {
- // Note: it will change flags
- assert (UseCompressedOops, "should only be used for compressed headers");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- // Cannot assert, unverified entry point counts instructions (see .ad file)
- // vtableStubs also counts instructions in pd_code_size_limit.
- // Also do not verify_oop as this is called by verify_oop.
- if (Universe::narrow_oop_shift() != 0) {
- assert(LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
- shlq(r, LogMinObjAlignmentInBytes);
- if (Universe::narrow_oop_base() != NULL) {
- addq(r, r12_heapbase);
- }
- } else {
- assert (Universe::narrow_oop_base() == NULL, "sanity");
- }
-}
-
-void MacroAssembler::decode_heap_oop_not_null(Register dst, Register src) {
- // Note: it will change flags
- assert (UseCompressedOops, "should only be used for compressed headers");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- // Cannot assert, unverified entry point counts instructions (see .ad file)
- // vtableStubs also counts instructions in pd_code_size_limit.
- // Also do not verify_oop as this is called by verify_oop.
- if (Universe::narrow_oop_shift() != 0) {
- assert(LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
- if (LogMinObjAlignmentInBytes == Address::times_8) {
- leaq(dst, Address(r12_heapbase, src, Address::times_8, 0));
- } else {
- if (dst != src) {
- movq(dst, src);
- }
- shlq(dst, LogMinObjAlignmentInBytes);
- if (Universe::narrow_oop_base() != NULL) {
- addq(dst, r12_heapbase);
- }
- }
- } else {
- assert (Universe::narrow_oop_base() == NULL, "sanity");
- if (dst != src) {
- movq(dst, src);
- }
- }
-}
-
-void MacroAssembler::encode_klass_not_null(Register r) {
- assert(Metaspace::is_initialized(), "metaspace should be initialized");
-#ifdef ASSERT
- verify_heapbase("MacroAssembler::encode_klass_not_null: heap base corrupted?");
-#endif
- if (Universe::narrow_klass_base() != NULL) {
- subq(r, r12_heapbase);
- }
- if (Universe::narrow_klass_shift() != 0) {
- assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
- shrq(r, LogKlassAlignmentInBytes);
- }
-}
-
-void MacroAssembler::encode_klass_not_null(Register dst, Register src) {
- assert(Metaspace::is_initialized(), "metaspace should be initialized");
-#ifdef ASSERT
- verify_heapbase("MacroAssembler::encode_klass_not_null2: heap base corrupted?");
-#endif
- if (dst != src) {
- movq(dst, src);
- }
- if (Universe::narrow_klass_base() != NULL) {
- subq(dst, r12_heapbase);
- }
- if (Universe::narrow_klass_shift() != 0) {
- assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
- shrq(dst, LogKlassAlignmentInBytes);
- }
-}
-
-void MacroAssembler::decode_klass_not_null(Register r) {
- assert(Metaspace::is_initialized(), "metaspace should be initialized");
- // Note: it will change flags
- assert (UseCompressedKlassPointers, "should only be used for compressed headers");
- // Cannot assert, unverified entry point counts instructions (see .ad file)
- // vtableStubs also counts instructions in pd_code_size_limit.
- // Also do not verify_oop as this is called by verify_oop.
- if (Universe::narrow_klass_shift() != 0) {
- assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
- shlq(r, LogKlassAlignmentInBytes);
- if (Universe::narrow_klass_base() != NULL) {
- addq(r, r12_heapbase);
- }
- } else {
- assert (Universe::narrow_klass_base() == NULL, "sanity");
- }
-}
-
-void MacroAssembler::decode_klass_not_null(Register dst, Register src) {
- assert(Metaspace::is_initialized(), "metaspace should be initialized");
- // Note: it will change flags
- assert (UseCompressedKlassPointers, "should only be used for compressed headers");
- // Cannot assert, unverified entry point counts instructions (see .ad file)
- // vtableStubs also counts instructions in pd_code_size_limit.
- // Also do not verify_oop as this is called by verify_oop.
- if (Universe::narrow_klass_shift() != 0) {
- assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
- assert(LogKlassAlignmentInBytes == Address::times_8, "klass not aligned on 64bits?");
- leaq(dst, Address(r12_heapbase, src, Address::times_8, 0));
- } else {
- assert (Universe::narrow_klass_base() == NULL, "sanity");
- if (dst != src) {
- movq(dst, src);
- }
- }
-}
-
-void MacroAssembler::set_narrow_oop(Register dst, jobject obj) {
- assert (UseCompressedOops, "should only be used for compressed headers");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
- int oop_index = oop_recorder()->find_index(obj);
- RelocationHolder rspec = oop_Relocation::spec(oop_index);
- mov_narrow_oop(dst, oop_index, rspec);
-}
-
-void MacroAssembler::set_narrow_oop(Address dst, jobject obj) {
- assert (UseCompressedOops, "should only be used for compressed headers");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
- int oop_index = oop_recorder()->find_index(obj);
- RelocationHolder rspec = oop_Relocation::spec(oop_index);
- mov_narrow_oop(dst, oop_index, rspec);
-}
-
-void MacroAssembler::set_narrow_klass(Register dst, Klass* k) {
- assert (UseCompressedKlassPointers, "should only be used for compressed headers");
- assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
- int klass_index = oop_recorder()->find_index(k);
- RelocationHolder rspec = metadata_Relocation::spec(klass_index);
- mov_narrow_oop(dst, oopDesc::encode_klass(k), rspec);
-}
-
-void MacroAssembler::set_narrow_klass(Address dst, Klass* k) {
- assert (UseCompressedKlassPointers, "should only be used for compressed headers");
- assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
- int klass_index = oop_recorder()->find_index(k);
- RelocationHolder rspec = metadata_Relocation::spec(klass_index);
- mov_narrow_oop(dst, oopDesc::encode_klass(k), rspec);
-}
-
-void MacroAssembler::cmp_narrow_oop(Register dst, jobject obj) {
- assert (UseCompressedOops, "should only be used for compressed headers");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
- int oop_index = oop_recorder()->find_index(obj);
- RelocationHolder rspec = oop_Relocation::spec(oop_index);
- Assembler::cmp_narrow_oop(dst, oop_index, rspec);
-}
-
-void MacroAssembler::cmp_narrow_oop(Address dst, jobject obj) {
- assert (UseCompressedOops, "should only be used for compressed headers");
- assert (Universe::heap() != NULL, "java heap should be initialized");
- assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
- int oop_index = oop_recorder()->find_index(obj);
- RelocationHolder rspec = oop_Relocation::spec(oop_index);
- Assembler::cmp_narrow_oop(dst, oop_index, rspec);
-}
-
-void MacroAssembler::cmp_narrow_klass(Register dst, Klass* k) {
- assert (UseCompressedKlassPointers, "should only be used for compressed headers");
- assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
- int klass_index = oop_recorder()->find_index(k);
- RelocationHolder rspec = metadata_Relocation::spec(klass_index);
- Assembler::cmp_narrow_oop(dst, oopDesc::encode_klass(k), rspec);
-}
-
-void MacroAssembler::cmp_narrow_klass(Address dst, Klass* k) {
- assert (UseCompressedKlassPointers, "should only be used for compressed headers");
- assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
- int klass_index = oop_recorder()->find_index(k);
- RelocationHolder rspec = metadata_Relocation::spec(klass_index);
- Assembler::cmp_narrow_oop(dst, oopDesc::encode_klass(k), rspec);
-}
-
-void MacroAssembler::reinit_heapbase() {
- if (UseCompressedOops || UseCompressedKlassPointers) {
- movptr(r12_heapbase, ExternalAddress((address)Universe::narrow_ptrs_base_addr()));
- }
-}
-#endif // _LP64
-
-
-// C2 compiled method's prolog code.
-void MacroAssembler::verified_entry(int framesize, bool stack_bang, bool fp_mode_24b) {
-
- // WARNING: Initial instruction MUST be 5 bytes or longer so that
- // NativeJump::patch_verified_entry will be able to patch out the entry
- // code safely. The push to verify stack depth is ok at 5 bytes,
- // the frame allocation can be either 3 or 6 bytes. So if we don't do
- // stack bang then we must use the 6 byte frame allocation even if
- // we have no frame. :-(
-
- assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
- // Remove word for return addr
- framesize -= wordSize;
-
- // Calls to C2R adapters often do not accept exceptional returns.
- // We require that their callers must bang for them. But be careful, because
- // some VM calls (such as call site linkage) can use several kilobytes of
- // stack. But the stack safety zone should account for that.
- // See bugs 4446381, 4468289, 4497237.
- if (stack_bang) {
- generate_stack_overflow_check(framesize);
-
- // We always push rbp, so that on return to interpreter rbp, will be
- // restored correctly and we can correct the stack.
- push(rbp);
- // Remove word for ebp
- framesize -= wordSize;
-
- // Create frame
- if (framesize) {
- subptr(rsp, framesize);
- }
- } else {
- // Create frame (force generation of a 4 byte immediate value)
- subptr_imm32(rsp, framesize);
-
- // Save RBP register now.
- framesize -= wordSize;
- movptr(Address(rsp, framesize), rbp);
- }
-
- if (VerifyStackAtCalls) { // Majik cookie to verify stack depth
- framesize -= wordSize;
- movptr(Address(rsp, framesize), (int32_t)0xbadb100d);
- }
-
-#ifndef _LP64
- // If method sets FPU control word do it now
- if (fp_mode_24b) {
- fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_24()));
- }
- if (UseSSE >= 2 && VerifyFPU) {
- verify_FPU(0, "FPU stack must be clean on entry");
- }
-#endif
-
-#ifdef ASSERT
- if (VerifyStackAtCalls) {
- Label L;
- push(rax);
- mov(rax, rsp);
- andptr(rax, StackAlignmentInBytes-1);
- cmpptr(rax, StackAlignmentInBytes-wordSize);
- pop(rax);
- jcc(Assembler::equal, L);
- STOP("Stack is not properly aligned!");
- bind(L);
- }
-#endif
-
-}
-
-
-// IndexOf for constant substrings with size >= 8 chars
-// which don't need to be loaded through stack.
-void MacroAssembler::string_indexofC8(Register str1, Register str2,
- Register cnt1, Register cnt2,
- int int_cnt2, Register result,
- XMMRegister vec, Register tmp) {
- ShortBranchVerifier sbv(this);
- assert(UseSSE42Intrinsics, "SSE4.2 is required");
-
- // This method uses pcmpestri inxtruction with bound registers
- // inputs:
- // xmm - substring
- // rax - substring length (elements count)
- // mem - scanned string
- // rdx - string length (elements count)
- // 0xd - mode: 1100 (substring search) + 01 (unsigned shorts)
- // outputs:
- // rcx - matched index in string
- assert(cnt1 == rdx && cnt2 == rax && tmp == rcx, "pcmpestri");
-
- Label RELOAD_SUBSTR, SCAN_TO_SUBSTR, SCAN_SUBSTR,
- RET_FOUND, RET_NOT_FOUND, EXIT, FOUND_SUBSTR,
- MATCH_SUBSTR_HEAD, RELOAD_STR, FOUND_CANDIDATE;
-
- // Note, inline_string_indexOf() generates checks:
- // if (substr.count > string.count) return -1;
- // if (substr.count == 0) return 0;
- assert(int_cnt2 >= 8, "this code isused only for cnt2 >= 8 chars");
-
- // Load substring.
- movdqu(vec, Address(str2, 0));
- movl(cnt2, int_cnt2);
- movptr(result, str1); // string addr
-
- if (int_cnt2 > 8) {
- jmpb(SCAN_TO_SUBSTR);
-
- // Reload substr for rescan, this code
- // is executed only for large substrings (> 8 chars)
- bind(RELOAD_SUBSTR);
- movdqu(vec, Address(str2, 0));
- negptr(cnt2); // Jumped here with negative cnt2, convert to positive
-
- bind(RELOAD_STR);
- // We came here after the beginning of the substring was
- // matched but the rest of it was not so we need to search
- // again. Start from the next element after the previous match.
-
- // cnt2 is number of substring reminding elements and
- // cnt1 is number of string reminding elements when cmp failed.
- // Restored cnt1 = cnt1 - cnt2 + int_cnt2
- subl(cnt1, cnt2);
- addl(cnt1, int_cnt2);
- movl(cnt2, int_cnt2); // Now restore cnt2
-
- decrementl(cnt1); // Shift to next element
- cmpl(cnt1, cnt2);
- jccb(Assembler::negative, RET_NOT_FOUND); // Left less then substring
-
- addptr(result, 2);
-
- } // (int_cnt2 > 8)
-
- // Scan string for start of substr in 16-byte vectors
- bind(SCAN_TO_SUBSTR);
- pcmpestri(vec, Address(result, 0), 0x0d);
- jccb(Assembler::below, FOUND_CANDIDATE); // CF == 1
- subl(cnt1, 8);
- jccb(Assembler::lessEqual, RET_NOT_FOUND); // Scanned full string
- cmpl(cnt1, cnt2);
- jccb(Assembler::negative, RET_NOT_FOUND); // Left less then substring
- addptr(result, 16);
- jmpb(SCAN_TO_SUBSTR);
-
- // Found a potential substr
- bind(FOUND_CANDIDATE);
- // Matched whole vector if first element matched (tmp(rcx) == 0).
- if (int_cnt2 == 8) {
- jccb(Assembler::overflow, RET_FOUND); // OF == 1
- } else { // int_cnt2 > 8
- jccb(Assembler::overflow, FOUND_SUBSTR);
- }
- // After pcmpestri tmp(rcx) contains matched element index
- // Compute start addr of substr
- lea(result, Address(result, tmp, Address::times_2));
-
- // Make sure string is still long enough
- subl(cnt1, tmp);
- cmpl(cnt1, cnt2);
- if (int_cnt2 == 8) {
- jccb(Assembler::greaterEqual, SCAN_TO_SUBSTR);
- } else { // int_cnt2 > 8
- jccb(Assembler::greaterEqual, MATCH_SUBSTR_HEAD);
- }
- // Left less then substring.
-
- bind(RET_NOT_FOUND);
- movl(result, -1);
- jmpb(EXIT);
-
- if (int_cnt2 > 8) {
- // This code is optimized for the case when whole substring
- // is matched if its head is matched.
- bind(MATCH_SUBSTR_HEAD);
- pcmpestri(vec, Address(result, 0), 0x0d);
- // Reload only string if does not match
- jccb(Assembler::noOverflow, RELOAD_STR); // OF == 0
-
- Label CONT_SCAN_SUBSTR;
- // Compare the rest of substring (> 8 chars).
- bind(FOUND_SUBSTR);
- // First 8 chars are already matched.
- negptr(cnt2);
- addptr(cnt2, 8);
-
- bind(SCAN_SUBSTR);
- subl(cnt1, 8);
- cmpl(cnt2, -8); // Do not read beyond substring
- jccb(Assembler::lessEqual, CONT_SCAN_SUBSTR);
- // Back-up strings to avoid reading beyond substring:
- // cnt1 = cnt1 - cnt2 + 8
- addl(cnt1, cnt2); // cnt2 is negative
- addl(cnt1, 8);
- movl(cnt2, 8); negptr(cnt2);
- bind(CONT_SCAN_SUBSTR);
- if (int_cnt2 < (int)G) {
- movdqu(vec, Address(str2, cnt2, Address::times_2, int_cnt2*2));
- pcmpestri(vec, Address(result, cnt2, Address::times_2, int_cnt2*2), 0x0d);
- } else {
- // calculate index in register to avoid integer overflow (int_cnt2*2)
- movl(tmp, int_cnt2);
- addptr(tmp, cnt2);
- movdqu(vec, Address(str2, tmp, Address::times_2, 0));
- pcmpestri(vec, Address(result, tmp, Address::times_2, 0), 0x0d);
- }
- // Need to reload strings pointers if not matched whole vector
- jcc(Assembler::noOverflow, RELOAD_SUBSTR); // OF == 0
- addptr(cnt2, 8);
- jcc(Assembler::negative, SCAN_SUBSTR);
- // Fall through if found full substring
-
- } // (int_cnt2 > 8)
-
- bind(RET_FOUND);
- // Found result if we matched full small substring.
- // Compute substr offset
- subptr(result, str1);
- shrl(result, 1); // index
- bind(EXIT);
-
-} // string_indexofC8
-
-// Small strings are loaded through stack if they cross page boundary.
-void MacroAssembler::string_indexof(Register str1, Register str2,
- Register cnt1, Register cnt2,
- int int_cnt2, Register result,
- XMMRegister vec, Register tmp) {
- ShortBranchVerifier sbv(this);
- assert(UseSSE42Intrinsics, "SSE4.2 is required");
- //
- // int_cnt2 is length of small (< 8 chars) constant substring
- // or (-1) for non constant substring in which case its length
- // is in cnt2 register.
- //
- // Note, inline_string_indexOf() generates checks:
- // if (substr.count > string.count) return -1;
- // if (substr.count == 0) return 0;
- //
- assert(int_cnt2 == -1 || (0 < int_cnt2 && int_cnt2 < 8), "should be != 0");
-
- // This method uses pcmpestri inxtruction with bound registers
- // inputs:
- // xmm - substring
- // rax - substring length (elements count)
- // mem - scanned string
- // rdx - string length (elements count)
- // 0xd - mode: 1100 (substring search) + 01 (unsigned shorts)
- // outputs:
- // rcx - matched index in string
- assert(cnt1 == rdx && cnt2 == rax && tmp == rcx, "pcmpestri");
-
- Label RELOAD_SUBSTR, SCAN_TO_SUBSTR, SCAN_SUBSTR, ADJUST_STR,
- RET_FOUND, RET_NOT_FOUND, CLEANUP, FOUND_SUBSTR,
- FOUND_CANDIDATE;
-
- { //========================================================
- // We don't know where these strings are located
- // and we can't read beyond them. Load them through stack.
- Label BIG_STRINGS, CHECK_STR, COPY_SUBSTR, COPY_STR;
-
- movptr(tmp, rsp); // save old SP
-
- if (int_cnt2 > 0) { // small (< 8 chars) constant substring
- if (int_cnt2 == 1) { // One char
- load_unsigned_short(result, Address(str2, 0));
- movdl(vec, result); // move 32 bits
- } else if (int_cnt2 == 2) { // Two chars
- movdl(vec, Address(str2, 0)); // move 32 bits
- } else if (int_cnt2 == 4) { // Four chars
- movq(vec, Address(str2, 0)); // move 64 bits
- } else { // cnt2 = { 3, 5, 6, 7 }
- // Array header size is 12 bytes in 32-bit VM
- // + 6 bytes for 3 chars == 18 bytes,
- // enough space to load vec and shift.
- assert(HeapWordSize*TypeArrayKlass::header_size() >= 12,"sanity");
- movdqu(vec, Address(str2, (int_cnt2*2)-16));
- psrldq(vec, 16-(int_cnt2*2));
- }
- } else { // not constant substring
- cmpl(cnt2, 8);
- jccb(Assembler::aboveEqual, BIG_STRINGS); // Both strings are big enough
-
- // We can read beyond string if srt+16 does not cross page boundary
- // since heaps are aligned and mapped by pages.
- assert(os::vm_page_size() < (int)G, "default page should be small");
- movl(result, str2); // We need only low 32 bits
- andl(result, (os::vm_page_size()-1));
- cmpl(result, (os::vm_page_size()-16));
- jccb(Assembler::belowEqual, CHECK_STR);
-
- // Move small strings to stack to allow load 16 bytes into vec.
- subptr(rsp, 16);
- int stk_offset = wordSize-2;
- push(cnt2);
-
- bind(COPY_SUBSTR);
- load_unsigned_short(result, Address(str2, cnt2, Address::times_2, -2));
- movw(Address(rsp, cnt2, Address::times_2, stk_offset), result);
- decrement(cnt2);
- jccb(Assembler::notZero, COPY_SUBSTR);
-
- pop(cnt2);
- movptr(str2, rsp); // New substring address
- } // non constant
-
- bind(CHECK_STR);
- cmpl(cnt1, 8);
- jccb(Assembler::aboveEqual, BIG_STRINGS);
-
- // Check cross page boundary.
- movl(result, str1); // We need only low 32 bits
- andl(result, (os::vm_page_size()-1));
- cmpl(result, (os::vm_page_size()-16));
- jccb(Assembler::belowEqual, BIG_STRINGS);
-
- subptr(rsp, 16);
- int stk_offset = -2;
- if (int_cnt2 < 0) { // not constant
- push(cnt2);
- stk_offset += wordSize;
- }
- movl(cnt2, cnt1);
-
- bind(COPY_STR);
- load_unsigned_short(result, Address(str1, cnt2, Address::times_2, -2));
- movw(Address(rsp, cnt2, Address::times_2, stk_offset), result);
- decrement(cnt2);
- jccb(Assembler::notZero, COPY_STR);
-
- if (int_cnt2 < 0) { // not constant
- pop(cnt2);
- }
- movptr(str1, rsp); // New string address
-
- bind(BIG_STRINGS);
- // Load substring.
- if (int_cnt2 < 0) { // -1
- movdqu(vec, Address(str2, 0));
- push(cnt2); // substr count
- push(str2); // substr addr
- push(str1); // string addr
- } else {
- // Small (< 8 chars) constant substrings are loaded already.
- movl(cnt2, int_cnt2);
- }
- push(tmp); // original SP
-
- } // Finished loading
-
- //========================================================
- // Start search
- //
-
- movptr(result, str1); // string addr
-
- if (int_cnt2 < 0) { // Only for non constant substring
- jmpb(SCAN_TO_SUBSTR);
-
- // SP saved at sp+0
- // String saved at sp+1*wordSize
- // Substr saved at sp+2*wordSize
- // Substr count saved at sp+3*wordSize
-
- // Reload substr for rescan, this code
- // is executed only for large substrings (> 8 chars)
- bind(RELOAD_SUBSTR);
- movptr(str2, Address(rsp, 2*wordSize));
- movl(cnt2, Address(rsp, 3*wordSize));
- movdqu(vec, Address(str2, 0));
- // We came here after the beginning of the substring was
- // matched but the rest of it was not so we need to search
- // again. Start from the next element after the previous match.
- subptr(str1, result); // Restore counter
- shrl(str1, 1);
- addl(cnt1, str1);
- decrementl(cnt1); // Shift to next element
- cmpl(cnt1, cnt2);
- jccb(Assembler::negative, RET_NOT_FOUND); // Left less then substring
-
- addptr(result, 2);
- } // non constant
-
- // Scan string for start of substr in 16-byte vectors
- bind(SCAN_TO_SUBSTR);
- assert(cnt1 == rdx && cnt2 == rax && tmp == rcx, "pcmpestri");
- pcmpestri(vec, Address(result, 0), 0x0d);
- jccb(Assembler::below, FOUND_CANDIDATE); // CF == 1
- subl(cnt1, 8);
- jccb(Assembler::lessEqual, RET_NOT_FOUND); // Scanned full string
- cmpl(cnt1, cnt2);
- jccb(Assembler::negative, RET_NOT_FOUND); // Left less then substring
- addptr(result, 16);
-
- bind(ADJUST_STR);
- cmpl(cnt1, 8); // Do not read beyond string
- jccb(Assembler::greaterEqual, SCAN_TO_SUBSTR);
- // Back-up string to avoid reading beyond string.
- lea(result, Address(result, cnt1, Address::times_2, -16));
- movl(cnt1, 8);
- jmpb(SCAN_TO_SUBSTR);
-
- // Found a potential substr
- bind(FOUND_CANDIDATE);
- // After pcmpestri tmp(rcx) contains matched element index
-
- // Make sure string is still long enough
- subl(cnt1, tmp);
- cmpl(cnt1, cnt2);
- jccb(Assembler::greaterEqual, FOUND_SUBSTR);
- // Left less then substring.
-
- bind(RET_NOT_FOUND);
- movl(result, -1);
- jmpb(CLEANUP);
-
- bind(FOUND_SUBSTR);
- // Compute start addr of substr
- lea(result, Address(result, tmp, Address::times_2));
-
- if (int_cnt2 > 0) { // Constant substring
- // Repeat search for small substring (< 8 chars)
- // from new point without reloading substring.
- // Have to check that we don't read beyond string.
- cmpl(tmp, 8-int_cnt2);
- jccb(Assembler::greater, ADJUST_STR);
- // Fall through if matched whole substring.
- } else { // non constant
- assert(int_cnt2 == -1, "should be != 0");
-
- addl(tmp, cnt2);
- // Found result if we matched whole substring.
- cmpl(tmp, 8);
- jccb(Assembler::lessEqual, RET_FOUND);
-
- // Repeat search for small substring (<= 8 chars)
- // from new point 'str1' without reloading substring.
- cmpl(cnt2, 8);
- // Have to check that we don't read beyond string.
- jccb(Assembler::lessEqual, ADJUST_STR);
-
- Label CHECK_NEXT, CONT_SCAN_SUBSTR, RET_FOUND_LONG;
- // Compare the rest of substring (> 8 chars).
- movptr(str1, result);
-
- cmpl(tmp, cnt2);
- // First 8 chars are already matched.
- jccb(Assembler::equal, CHECK_NEXT);
-
- bind(SCAN_SUBSTR);
- pcmpestri(vec, Address(str1, 0), 0x0d);
- // Need to reload strings pointers if not matched whole vector
- jcc(Assembler::noOverflow, RELOAD_SUBSTR); // OF == 0
-
- bind(CHECK_NEXT);
- subl(cnt2, 8);
- jccb(Assembler::lessEqual, RET_FOUND_LONG); // Found full substring
- addptr(str1, 16);
- addptr(str2, 16);
- subl(cnt1, 8);
- cmpl(cnt2, 8); // Do not read beyond substring
- jccb(Assembler::greaterEqual, CONT_SCAN_SUBSTR);
- // Back-up strings to avoid reading beyond substring.
- lea(str2, Address(str2, cnt2, Address::times_2, -16));
- lea(str1, Address(str1, cnt2, Address::times_2, -16));
- subl(cnt1, cnt2);
- movl(cnt2, 8);
- addl(cnt1, 8);
- bind(CONT_SCAN_SUBSTR);
- movdqu(vec, Address(str2, 0));
- jmpb(SCAN_SUBSTR);
-
- bind(RET_FOUND_LONG);
- movptr(str1, Address(rsp, wordSize));
- } // non constant
-
- bind(RET_FOUND);
- // Compute substr offset
- subptr(result, str1);
- shrl(result, 1); // index
-
- bind(CLEANUP);
- pop(rsp); // restore SP
-
-} // string_indexof
-
-// Compare strings.
-void MacroAssembler::string_compare(Register str1, Register str2,
- Register cnt1, Register cnt2, Register result,
- XMMRegister vec1) {
- ShortBranchVerifier sbv(this);
- Label LENGTH_DIFF_LABEL, POP_LABEL, DONE_LABEL, WHILE_HEAD_LABEL;
-
- // Compute the minimum of the string lengths and the
- // difference of the string lengths (stack).
- // Do the conditional move stuff
- movl(result, cnt1);
- subl(cnt1, cnt2);
- push(cnt1);
- cmov32(Assembler::lessEqual, cnt2, result);
-
- // Is the minimum length zero?
- testl(cnt2, cnt2);
- jcc(Assembler::zero, LENGTH_DIFF_LABEL);
-
- // Load first characters
- load_unsigned_short(result, Address(str1, 0));
- load_unsigned_short(cnt1, Address(str2, 0));
-
- // Compare first characters
- subl(result, cnt1);
- jcc(Assembler::notZero, POP_LABEL);
- decrementl(cnt2);
- jcc(Assembler::zero, LENGTH_DIFF_LABEL);
-
- {
- // Check after comparing first character to see if strings are equivalent
- Label LSkip2;
- // Check if the strings start at same location
- cmpptr(str1, str2);
- jccb(Assembler::notEqual, LSkip2);
-
- // Check if the length difference is zero (from stack)
- cmpl(Address(rsp, 0), 0x0);
- jcc(Assembler::equal, LENGTH_DIFF_LABEL);
-
- // Strings might not be equivalent
- bind(LSkip2);
- }
-
- Address::ScaleFactor scale = Address::times_2;
- int stride = 8;
-
- // Advance to next element
- addptr(str1, 16/stride);
- addptr(str2, 16/stride);
-
- if (UseSSE42Intrinsics) {
- Label COMPARE_WIDE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL;
- int pcmpmask = 0x19;
- // Setup to compare 16-byte vectors
- movl(result, cnt2);
- andl(cnt2, ~(stride - 1)); // cnt2 holds the vector count
- jccb(Assembler::zero, COMPARE_TAIL);
-
- lea(str1, Address(str1, result, scale));
- lea(str2, Address(str2, result, scale));
- negptr(result);
-
- // pcmpestri
- // inputs:
- // vec1- substring
- // rax - negative string length (elements count)
- // mem - scaned string
- // rdx - string length (elements count)
- // pcmpmask - cmp mode: 11000 (string compare with negated result)
- // + 00 (unsigned bytes) or + 01 (unsigned shorts)
- // outputs:
- // rcx - first mismatched element index
- assert(result == rax && cnt2 == rdx && cnt1 == rcx, "pcmpestri");
-
- bind(COMPARE_WIDE_VECTORS);
- movdqu(vec1, Address(str1, result, scale));
- pcmpestri(vec1, Address(str2, result, scale), pcmpmask);
- // After pcmpestri cnt1(rcx) contains mismatched element index
-
- jccb(Assembler::below, VECTOR_NOT_EQUAL); // CF==1
- addptr(result, stride);
- subptr(cnt2, stride);
- jccb(Assembler::notZero, COMPARE_WIDE_VECTORS);
-
- // compare wide vectors tail
- testl(result, result);
- jccb(Assembler::zero, LENGTH_DIFF_LABEL);
-
- movl(cnt2, stride);
- movl(result, stride);
- negptr(result);
- movdqu(vec1, Address(str1, result, scale));
- pcmpestri(vec1, Address(str2, result, scale), pcmpmask);
- jccb(Assembler::aboveEqual, LENGTH_DIFF_LABEL);
-
- // Mismatched characters in the vectors
- bind(VECTOR_NOT_EQUAL);
- addptr(result, cnt1);
- movptr(cnt2, result);
- load_unsigned_short(result, Address(str1, cnt2, scale));
- load_unsigned_short(cnt1, Address(str2, cnt2, scale));
- subl(result, cnt1);
- jmpb(POP_LABEL);
-
- bind(COMPARE_TAIL); // limit is zero
- movl(cnt2, result);
- // Fallthru to tail compare
- }
-
- // Shift str2 and str1 to the end of the arrays, negate min
- lea(str1, Address(str1, cnt2, scale, 0));
- lea(str2, Address(str2, cnt2, scale, 0));
- negptr(cnt2);
-
- // Compare the rest of the elements
- bind(WHILE_HEAD_LABEL);
- load_unsigned_short(result, Address(str1, cnt2, scale, 0));
- load_unsigned_short(cnt1, Address(str2, cnt2, scale, 0));
- subl(result, cnt1);
- jccb(Assembler::notZero, POP_LABEL);
- increment(cnt2);
- jccb(Assembler::notZero, WHILE_HEAD_LABEL);
-
- // Strings are equal up to min length. Return the length difference.
- bind(LENGTH_DIFF_LABEL);
- pop(result);
- jmpb(DONE_LABEL);
-
- // Discard the stored length difference
- bind(POP_LABEL);
- pop(cnt1);
-
- // That's it
- bind(DONE_LABEL);
-}
-
-// Compare char[] arrays aligned to 4 bytes or substrings.
-void MacroAssembler::char_arrays_equals(bool is_array_equ, Register ary1, Register ary2,
- Register limit, Register result, Register chr,
- XMMRegister vec1, XMMRegister vec2) {
- ShortBranchVerifier sbv(this);
- Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_VECTORS, COMPARE_CHAR;
-
- int length_offset = arrayOopDesc::length_offset_in_bytes();
- int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
-
- // Check the input args
- cmpptr(ary1, ary2);
- jcc(Assembler::equal, TRUE_LABEL);
-
- if (is_array_equ) {
- // Need additional checks for arrays_equals.
- testptr(ary1, ary1);
- jcc(Assembler::zero, FALSE_LABEL);
- testptr(ary2, ary2);
- jcc(Assembler::zero, FALSE_LABEL);
-
- // Check the lengths
- movl(limit, Address(ary1, length_offset));
- cmpl(limit, Address(ary2, length_offset));
- jcc(Assembler::notEqual, FALSE_LABEL);
- }
-
- // count == 0
- testl(limit, limit);
- jcc(Assembler::zero, TRUE_LABEL);
-
- if (is_array_equ) {
- // Load array address
- lea(ary1, Address(ary1, base_offset));
- lea(ary2, Address(ary2, base_offset));
- }
-
- shll(limit, 1); // byte count != 0
- movl(result, limit); // copy
-
- if (UseSSE42Intrinsics) {
- // With SSE4.2, use double quad vector compare
- Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
-
- // Compare 16-byte vectors
- andl(result, 0x0000000e); // tail count (in bytes)
- andl(limit, 0xfffffff0); // vector count (in bytes)
- jccb(Assembler::zero, COMPARE_TAIL);
-
- lea(ary1, Address(ary1, limit, Address::times_1));
- lea(ary2, Address(ary2, limit, Address::times_1));
- negptr(limit);
-
- bind(COMPARE_WIDE_VECTORS);
- movdqu(vec1, Address(ary1, limit, Address::times_1));
- movdqu(vec2, Address(ary2, limit, Address::times_1));
- pxor(vec1, vec2);
-
- ptest(vec1, vec1);
- jccb(Assembler::notZero, FALSE_LABEL);
- addptr(limit, 16);
- jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
-
- testl(result, result);
- jccb(Assembler::zero, TRUE_LABEL);
-
- movdqu(vec1, Address(ary1, result, Address::times_1, -16));
- movdqu(vec2, Address(ary2, result, Address::times_1, -16));
- pxor(vec1, vec2);
-
- ptest(vec1, vec1);
- jccb(Assembler::notZero, FALSE_LABEL);
- jmpb(TRUE_LABEL);
-
- bind(COMPARE_TAIL); // limit is zero
- movl(limit, result);
- // Fallthru to tail compare
- }
-
- // Compare 4-byte vectors
- andl(limit, 0xfffffffc); // vector count (in bytes)
- jccb(Assembler::zero, COMPARE_CHAR);
-
- lea(ary1, Address(ary1, limit, Address::times_1));
- lea(ary2, Address(ary2, limit, Address::times_1));
- negptr(limit);
-
- bind(COMPARE_VECTORS);
- movl(chr, Address(ary1, limit, Address::times_1));
- cmpl(chr, Address(ary2, limit, Address::times_1));
- jccb(Assembler::notEqual, FALSE_LABEL);
- addptr(limit, 4);
- jcc(Assembler::notZero, COMPARE_VECTORS);
-
- // Compare trailing char (final 2 bytes), if any
- bind(COMPARE_CHAR);
- testl(result, 0x2); // tail char
- jccb(Assembler::zero, TRUE_LABEL);
- load_unsigned_short(chr, Address(ary1, 0));
- load_unsigned_short(limit, Address(ary2, 0));
- cmpl(chr, limit);
- jccb(Assembler::notEqual, FALSE_LABEL);
-
- bind(TRUE_LABEL);
- movl(result, 1); // return true
- jmpb(DONE);
-
- bind(FALSE_LABEL);
- xorl(result, result); // return false
-
- // That's it
- bind(DONE);
-}
-
-void MacroAssembler::generate_fill(BasicType t, bool aligned,
- Register to, Register value, Register count,
- Register rtmp, XMMRegister xtmp) {
- ShortBranchVerifier sbv(this);
- assert_different_registers(to, value, count, rtmp);
- Label L_exit, L_skip_align1, L_skip_align2, L_fill_byte;
- Label L_fill_2_bytes, L_fill_4_bytes;
-
- int shift = -1;
- switch (t) {
- case T_BYTE:
- shift = 2;
- break;
- case T_SHORT:
- shift = 1;
- break;
- case T_INT:
- shift = 0;
- break;
- default: ShouldNotReachHere();
- }
-
- if (t == T_BYTE) {
- andl(value, 0xff);
- movl(rtmp, value);
- shll(rtmp, 8);
- orl(value, rtmp);
- }
- if (t == T_SHORT) {
- andl(value, 0xffff);
- }
- if (t == T_BYTE || t == T_SHORT) {
- movl(rtmp, value);
- shll(rtmp, 16);
- orl(value, rtmp);
- }
-
- cmpl(count, 2<= 2, "supported cpu only" );
- Label L_fill_32_bytes_loop, L_check_fill_8_bytes, L_fill_8_bytes_loop, L_fill_8_bytes;
- // Fill 32-byte chunks
- movdl(xtmp, value);
- pshufd(xtmp, xtmp, 0);
-
- subl(count, 8 << shift);
- jcc(Assembler::less, L_check_fill_8_bytes);
- align(16);
-
- BIND(L_fill_32_bytes_loop);
-
- if (UseUnalignedLoadStores) {
- movdqu(Address(to, 0), xtmp);
- movdqu(Address(to, 16), xtmp);
- } else {
- movq(Address(to, 0), xtmp);
- movq(Address(to, 8), xtmp);
- movq(Address(to, 16), xtmp);
- movq(Address(to, 24), xtmp);
- }
-
- addptr(to, 32);
- subl(count, 8 << shift);
- jcc(Assembler::greaterEqual, L_fill_32_bytes_loop);
- BIND(L_check_fill_8_bytes);
- addl(count, 8 << shift);
- jccb(Assembler::zero, L_exit);
- jmpb(L_fill_8_bytes);
-
- //
- // length is too short, just fill qwords
- //
- BIND(L_fill_8_bytes_loop);
- movq(Address(to, 0), xtmp);
- addptr(to, 8);
- BIND(L_fill_8_bytes);
- subl(count, 1 << (shift + 1));
- jcc(Assembler::greaterEqual, L_fill_8_bytes_loop);
- }
- }
- // fill trailing 4 bytes
- BIND(L_fill_4_bytes);
- testl(count, 1<cmp8(ExternalAddress((address)flag_addr), value);
- _masm->jcc(Assembler::equal, _label);
-}
-
-SkipIfEqual::~SkipIfEqual() {
- _masm->bind(_label);
-}
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/assembler_x86.hpp
--- a/src/cpu/x86/vm/assembler_x86.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/assembler_x86.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,6 +25,8 @@
#ifndef CPU_X86_VM_ASSEMBLER_X86_HPP
#define CPU_X86_VM_ASSEMBLER_X86_HPP
+#include "asm/register.hpp"
+
class BiasedLockingCounters;
// Contains all the definitions needed for x86 assembly code generation.
@@ -706,8 +708,6 @@
void check_relocation(RelocationHolder const& rspec, int format);
#endif
- inline void emit_long64(jlong x);
-
void emit_data(jint data, relocInfo::relocType rtype, int format);
void emit_data(jint data, RelocationHolder const& rspec, int format);
void emit_data64(jlong data, relocInfo::relocType rtype, int format = 0);
@@ -832,7 +832,8 @@
// These do register sized moves/scans
void rep_mov();
- void rep_set();
+ void rep_stos();
+ void rep_stosb();
void repne_scan();
#ifdef _LP64
void repne_scanl();
@@ -875,6 +876,17 @@
void addss(XMMRegister dst, Address src);
void addss(XMMRegister dst, XMMRegister src);
+ // AES instructions
+ void aesdec(XMMRegister dst, Address src);
+ void aesdec(XMMRegister dst, XMMRegister src);
+ void aesdeclast(XMMRegister dst, Address src);
+ void aesdeclast(XMMRegister dst, XMMRegister src);
+ void aesenc(XMMRegister dst, Address src);
+ void aesenc(XMMRegister dst, XMMRegister src);
+ void aesenclast(XMMRegister dst, Address src);
+ void aesenclast(XMMRegister dst, XMMRegister src);
+
+
void andl(Address dst, int32_t imm32);
void andl(Register dst, int32_t imm32);
void andl(Register dst, Address src);
@@ -905,7 +917,7 @@
void cdqq();
- void cld() { emit_byte(0xfc); }
+ void cld();
void clflush(Address adr);
@@ -952,10 +964,7 @@
void comiss(XMMRegister dst, XMMRegister src);
// Identify processor type and features
- void cpuid() {
- emit_byte(0x0F);
- emit_byte(0xA2);
- }
+ void cpuid();
// Convert Scalar Double-Precision Floating-Point Value to Scalar Single-Precision Floating-Point Value
void cvtsd2ss(XMMRegister dst, XMMRegister src);
@@ -1200,11 +1209,7 @@
void leaq(Register dst, Address src);
- void lfence() {
- emit_byte(0x0F);
- emit_byte(0xAE);
- emit_byte(0xE8);
- }
+ void lfence();
void lock();
@@ -1390,6 +1395,10 @@
// Pack with unsigned saturation
void packuswb(XMMRegister dst, XMMRegister src);
void packuswb(XMMRegister dst, Address src);
+ void vpackuswb(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256);
+
+ // Pemutation of 64bit words
+ void vpermq(XMMRegister dst, XMMRegister src, int imm8, bool vector256);
// SSE4.2 string instructions
void pcmpestri(XMMRegister xmm1, XMMRegister xmm2, int imm8);
@@ -1424,6 +1433,10 @@
void prefetcht2(Address src);
void prefetchw(Address src);
+ // Shuffle Bytes
+ void pshufb(XMMRegister dst, XMMRegister src);
+ void pshufb(XMMRegister dst, Address src);
+
// Shuffle Packed Doublewords
void pshufd(XMMRegister dst, XMMRegister src, int mode);
void pshufd(XMMRegister dst, Address src, int mode);
@@ -1435,9 +1448,12 @@
// Shift Right by bytes Logical DoubleQuadword Immediate
void psrldq(XMMRegister dst, int shift);
- // Logical Compare Double Quadword
+ // Logical Compare 128bit
void ptest(XMMRegister dst, XMMRegister src);
void ptest(XMMRegister dst, Address src);
+ // Logical Compare 256bit
+ void vptest(XMMRegister dst, XMMRegister src);
+ void vptest(XMMRegister dst, Address src);
// Interleave Low Bytes
void punpcklbw(XMMRegister dst, XMMRegister src);
@@ -1508,7 +1524,7 @@
void sqrtss(XMMRegister dst, Address src);
void sqrtss(XMMRegister dst, XMMRegister src);
- void std() { emit_byte(0xfd); }
+ void std();
void stmxcsr( Address dst );
@@ -1565,11 +1581,7 @@
void xchgq(Register dst, Register src);
// Get Value of Extended Control Register
- void xgetbv() {
- emit_byte(0x0F);
- emit_byte(0x01);
- emit_byte(0xD0);
- }
+ void xgetbv();
void xorl(Register dst, int32_t imm32);
void xorl(Register dst, Address src);
@@ -1749,6 +1761,9 @@
void vextractf128h(Address dst, XMMRegister src);
void vextracti128h(Address dst, XMMRegister src);
+ // duplicate 4-bytes integer data from src into 8 locations in dest
+ void vpbroadcastd(XMMRegister dst, XMMRegister src);
+
// AVX instruction which is used to clear upper 128 bits of YMM registers and
// to avoid transaction penalty between AVX and SSE states. There is no
// penalty if legacy SSE instructions are encoded using VEX prefix because
@@ -1766,1104 +1781,4 @@
};
-
-// MacroAssembler extends Assembler by frequently used macros.
-//
-// Instructions for which a 'better' code sequence exists depending
-// on arguments should also go in here.
-
-class MacroAssembler: public Assembler {
- friend class LIR_Assembler;
- friend class Runtime1; // as_Address()
-
- protected:
-
- Address as_Address(AddressLiteral adr);
- Address as_Address(ArrayAddress adr);
-
- // Support for VM calls
- //
- // This is the base routine called by the different versions of call_VM_leaf. The interpreter
- // may customize this version by overriding it for its purposes (e.g., to save/restore
- // additional registers when doing a VM call).
-#ifdef CC_INTERP
- // c++ interpreter never wants to use interp_masm version of call_VM
- #define VIRTUAL
-#else
- #define VIRTUAL virtual
-#endif
-
- VIRTUAL void call_VM_leaf_base(
- address entry_point, // the entry point
- int number_of_arguments // the number of arguments to pop after the call
- );
-
- // This is the base routine called by the different versions of call_VM. The interpreter
- // may customize this version by overriding it for its purposes (e.g., to save/restore
- // additional registers when doing a VM call).
- //
- // If no java_thread register is specified (noreg) than rdi will be used instead. call_VM_base
- // returns the register which contains the thread upon return. If a thread register has been
- // specified, the return value will correspond to that register. If no last_java_sp is specified
- // (noreg) than rsp will be used instead.
- VIRTUAL void call_VM_base( // returns the register containing the thread upon return
- Register oop_result, // where an oop-result ends up if any; use noreg otherwise
- Register java_thread, // the thread if computed before ; use noreg otherwise
- Register last_java_sp, // to set up last_Java_frame in stubs; use noreg otherwise
- address entry_point, // the entry point
- int number_of_arguments, // the number of arguments (w/o thread) to pop after the call
- bool check_exceptions // whether to check for pending exceptions after return
- );
-
- // These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code.
- // The implementation is only non-empty for the InterpreterMacroAssembler,
- // as only the interpreter handles PopFrame and ForceEarlyReturn requests.
- virtual void check_and_handle_popframe(Register java_thread);
- virtual void check_and_handle_earlyret(Register java_thread);
-
- void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions = true);
-
- // helpers for FPU flag access
- // tmp is a temporary register, if none is available use noreg
- void save_rax (Register tmp);
- void restore_rax(Register tmp);
-
- public:
- MacroAssembler(CodeBuffer* code) : Assembler(code) {}
-
- // Support for NULL-checks
- //
- // Generates code that causes a NULL OS exception if the content of reg is NULL.
- // If the accessed location is M[reg + offset] and the offset is known, provide the
- // offset. No explicit code generation is needed if the offset is within a certain
- // range (0 <= offset <= page_size).
-
- void null_check(Register reg, int offset = -1);
- static bool needs_explicit_null_check(intptr_t offset);
-
- // Required platform-specific helpers for Label::patch_instructions.
- // They _shadow_ the declarations in AbstractAssembler, which are undefined.
- void pd_patch_instruction(address branch, address target);
-#ifndef PRODUCT
- static void pd_print_patched_instruction(address branch);
-#endif
-
- // The following 4 methods return the offset of the appropriate move instruction
-
- // Support for fast byte/short loading with zero extension (depending on particular CPU)
- int load_unsigned_byte(Register dst, Address src);
- int load_unsigned_short(Register dst, Address src);
-
- // Support for fast byte/short loading with sign extension (depending on particular CPU)
- int load_signed_byte(Register dst, Address src);
- int load_signed_short(Register dst, Address src);
-
- // Support for sign-extension (hi:lo = extend_sign(lo))
- void extend_sign(Register hi, Register lo);
-
- // Load and store values by size and signed-ness
- void load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed, Register dst2 = noreg);
- void store_sized_value(Address dst, Register src, size_t size_in_bytes, Register src2 = noreg);
-
- // Support for inc/dec with optimal instruction selection depending on value
-
- void increment(Register reg, int value = 1) { LP64_ONLY(incrementq(reg, value)) NOT_LP64(incrementl(reg, value)) ; }
- void decrement(Register reg, int value = 1) { LP64_ONLY(decrementq(reg, value)) NOT_LP64(decrementl(reg, value)) ; }
-
- void decrementl(Address dst, int value = 1);
- void decrementl(Register reg, int value = 1);
-
- void decrementq(Register reg, int value = 1);
- void decrementq(Address dst, int value = 1);
-
- void incrementl(Address dst, int value = 1);
- void incrementl(Register reg, int value = 1);
-
- void incrementq(Register reg, int value = 1);
- void incrementq(Address dst, int value = 1);
-
-
- // Support optimal SSE move instructions.
- void movflt(XMMRegister dst, XMMRegister src) {
- if (UseXmmRegToRegMoveAll) { movaps(dst, src); return; }
- else { movss (dst, src); return; }
- }
- void movflt(XMMRegister dst, Address src) { movss(dst, src); }
- void movflt(XMMRegister dst, AddressLiteral src);
- void movflt(Address dst, XMMRegister src) { movss(dst, src); }
-
- void movdbl(XMMRegister dst, XMMRegister src) {
- if (UseXmmRegToRegMoveAll) { movapd(dst, src); return; }
- else { movsd (dst, src); return; }
- }
-
- void movdbl(XMMRegister dst, AddressLiteral src);
-
- void movdbl(XMMRegister dst, Address src) {
- if (UseXmmLoadAndClearUpper) { movsd (dst, src); return; }
- else { movlpd(dst, src); return; }
- }
- void movdbl(Address dst, XMMRegister src) { movsd(dst, src); }
-
- void incrementl(AddressLiteral dst);
- void incrementl(ArrayAddress dst);
-
- // Alignment
- void align(int modulus);
-
- // A 5 byte nop that is safe for patching (see patch_verified_entry)
- void fat_nop();
-
- // Stack frame creation/removal
- void enter();
- void leave();
-
- // Support for getting the JavaThread pointer (i.e.; a reference to thread-local information)
- // The pointer will be loaded into the thread register.
- void get_thread(Register thread);
-
-
- // Support for VM calls
- //
- // It is imperative that all calls into the VM are handled via the call_VM macros.
- // They make sure that the stack linkage is setup correctly. call_VM's correspond
- // to ENTRY/ENTRY_X entry points while call_VM_leaf's correspond to LEAF entry points.
-
-
- void call_VM(Register oop_result,
- address entry_point,
- bool check_exceptions = true);
- void call_VM(Register oop_result,
- address entry_point,
- Register arg_1,
- bool check_exceptions = true);
- void call_VM(Register oop_result,
- address entry_point,
- Register arg_1, Register arg_2,
- bool check_exceptions = true);
- void call_VM(Register oop_result,
- address entry_point,
- Register arg_1, Register arg_2, Register arg_3,
- bool check_exceptions = true);
-
- // Overloadings with last_Java_sp
- void call_VM(Register oop_result,
- Register last_java_sp,
- address entry_point,
- int number_of_arguments = 0,
- bool check_exceptions = true);
- void call_VM(Register oop_result,
- Register last_java_sp,
- address entry_point,
- Register arg_1, bool
- check_exceptions = true);
- void call_VM(Register oop_result,
- Register last_java_sp,
- address entry_point,
- Register arg_1, Register arg_2,
- bool check_exceptions = true);
- void 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 get_vm_result (Register oop_result, Register thread);
- void get_vm_result_2(Register metadata_result, Register thread);
-
- // 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,
- Register arg_1);
- void call_VM_leaf(address entry_point,
- Register arg_1, Register arg_2);
- void call_VM_leaf(address entry_point,
- Register arg_1, Register arg_2, Register arg_3);
-
- // These always tightly bind to MacroAssembler::call_VM_leaf_base
- // bypassing the virtual implementation
- void super_call_VM_leaf(address entry_point);
- void super_call_VM_leaf(address entry_point, Register arg_1);
- void super_call_VM_leaf(address entry_point, Register arg_1, Register arg_2);
- void super_call_VM_leaf(address entry_point, Register arg_1, Register arg_2, Register arg_3);
- void super_call_VM_leaf(address entry_point, Register arg_1, Register arg_2, Register arg_3, Register arg_4);
-
- // last Java Frame (fills frame anchor)
- void set_last_Java_frame(Register thread,
- Register last_java_sp,
- Register last_java_fp,
- address last_java_pc);
-
- // thread in the default location (r15_thread on 64bit)
- void set_last_Java_frame(Register last_java_sp,
- Register last_java_fp,
- address last_java_pc);
-
- void reset_last_Java_frame(Register thread, bool clear_fp, bool clear_pc);
-
- // thread in the default location (r15_thread on 64bit)
- void reset_last_Java_frame(bool clear_fp, bool clear_pc);
-
- // Stores
- void store_check(Register obj); // store check for obj - register is destroyed afterwards
- void store_check(Register obj, Address dst); // same as above, dst is exact store location (reg. is destroyed)
-
-#ifndef SERIALGC
-
- void g1_write_barrier_pre(Register obj,
- Register pre_val,
- Register thread,
- Register tmp,
- bool tosca_live,
- bool expand_call);
-
- void g1_write_barrier_post(Register store_addr,
- Register new_val,
- Register thread,
- Register tmp,
- Register tmp2);
-
-#endif // SERIALGC
-
- // split store_check(Register obj) to enhance instruction interleaving
- void store_check_part_1(Register obj);
- void store_check_part_2(Register obj);
-
- // C 'boolean' to Java boolean: x == 0 ? 0 : 1
- void c2bool(Register x);
-
- // C++ bool manipulation
-
- void movbool(Register dst, Address src);
- void movbool(Address dst, bool boolconst);
- void movbool(Address dst, Register src);
- void testbool(Register dst);
-
- // oop manipulations
- void load_klass(Register dst, Register src);
- void store_klass(Register dst, Register src);
-
- void load_heap_oop(Register dst, Address src);
- void load_heap_oop_not_null(Register dst, Address src);
- void store_heap_oop(Address dst, Register src);
- void cmp_heap_oop(Register src1, Address src2, Register tmp = noreg);
-
- // Used for storing NULL. All other oop constants should be
- // stored using routines that take a jobject.
- void store_heap_oop_null(Address dst);
-
- void load_prototype_header(Register dst, Register src);
-
-#ifdef _LP64
- void store_klass_gap(Register dst, Register src);
-
- // This dummy is to prevent a call to store_heap_oop from
- // converting a zero (like NULL) into a Register by giving
- // the compiler two choices it can't resolve
-
- void store_heap_oop(Address dst, void* dummy);
-
- void encode_heap_oop(Register r);
- void decode_heap_oop(Register r);
- void encode_heap_oop_not_null(Register r);
- void decode_heap_oop_not_null(Register r);
- void encode_heap_oop_not_null(Register dst, Register src);
- void decode_heap_oop_not_null(Register dst, Register src);
-
- void set_narrow_oop(Register dst, jobject obj);
- void set_narrow_oop(Address dst, jobject obj);
- void cmp_narrow_oop(Register dst, jobject obj);
- void cmp_narrow_oop(Address dst, jobject obj);
-
- void encode_klass_not_null(Register r);
- void decode_klass_not_null(Register r);
- void encode_klass_not_null(Register dst, Register src);
- void decode_klass_not_null(Register dst, Register src);
- void set_narrow_klass(Register dst, Klass* k);
- void set_narrow_klass(Address dst, Klass* k);
- void cmp_narrow_klass(Register dst, Klass* k);
- void cmp_narrow_klass(Address dst, Klass* k);
-
- // if heap base register is used - reinit it with the correct value
- void reinit_heapbase();
-
- DEBUG_ONLY(void verify_heapbase(const char* msg);)
-
-#endif // _LP64
-
- // Int division/remainder for Java
- // (as idivl, but checks for special case as described in JVM spec.)
- // returns idivl instruction offset for implicit exception handling
- int corrected_idivl(Register reg);
-
- // Long division/remainder for Java
- // (as idivq, but checks for special case as described in JVM spec.)
- // returns idivq instruction offset for implicit exception handling
- int corrected_idivq(Register reg);
-
- void int3();
-
- // Long operation macros for a 32bit cpu
- // Long negation for Java
- void lneg(Register hi, Register lo);
-
- // Long multiplication for Java
- // (destroys contents of eax, ebx, ecx and edx)
- void lmul(int x_rsp_offset, int y_rsp_offset); // rdx:rax = x * y
-
- // Long shifts for Java
- // (semantics as described in JVM spec.)
- void lshl(Register hi, Register lo); // hi:lo << (rcx & 0x3f)
- void lshr(Register hi, Register lo, bool sign_extension = false); // hi:lo >> (rcx & 0x3f)
-
- // Long compare for Java
- // (semantics as described in JVM spec.)
- void lcmp2int(Register x_hi, Register x_lo, Register y_hi, Register y_lo); // x_hi = lcmp(x, y)
-
-
- // misc
-
- // Sign extension
- void sign_extend_short(Register reg);
- void sign_extend_byte(Register reg);
-
- // Division by power of 2, rounding towards 0
- void division_with_shift(Register reg, int shift_value);
-
- // Compares the top-most stack entries on the FPU stack and sets the eflags as follows:
- //
- // CF (corresponds to C0) if x < y
- // PF (corresponds to C2) if unordered
- // ZF (corresponds to C3) if x = y
- //
- // The arguments are in reversed order on the stack (i.e., top of stack is first argument).
- // tmp is a temporary register, if none is available use noreg (only matters for non-P6 code)
- void fcmp(Register tmp);
- // Variant of the above which allows y to be further down the stack
- // and which only pops x and y if specified. If pop_right is
- // specified then pop_left must also be specified.
- void fcmp(Register tmp, int index, bool pop_left, bool pop_right);
-
- // Floating-point comparison for Java
- // Compares the top-most stack entries on the FPU stack and stores the result in dst.
- // The arguments are in reversed order on the stack (i.e., top of stack is first argument).
- // (semantics as described in JVM spec.)
- void fcmp2int(Register dst, bool unordered_is_less);
- // Variant of the above which allows y to be further down the stack
- // and which only pops x and y if specified. If pop_right is
- // specified then pop_left must also be specified.
- void fcmp2int(Register dst, bool unordered_is_less, int index, bool pop_left, bool pop_right);
-
- // Floating-point remainder for Java (ST0 = ST0 fremr ST1, ST1 is empty afterwards)
- // tmp is a temporary register, if none is available use noreg
- void fremr(Register tmp);
-
-
- // same as fcmp2int, but using SSE2
- void cmpss2int(XMMRegister opr1, XMMRegister opr2, Register dst, bool unordered_is_less);
- void cmpsd2int(XMMRegister opr1, XMMRegister opr2, Register dst, bool unordered_is_less);
-
- // Inlined sin/cos generator for Java; must not use CPU instruction
- // directly on Intel as it does not have high enough precision
- // outside of the range [-pi/4, pi/4]. Extra argument indicate the
- // number of FPU stack slots in use; all but the topmost will
- // require saving if a slow case is necessary. Assumes argument is
- // on FP TOS; result is on FP TOS. No cpu registers are changed by
- // this code.
- void trigfunc(char trig, int num_fpu_regs_in_use = 1);
-
- // branch to L if FPU flag C2 is set/not set
- // tmp is a temporary register, if none is available use noreg
- void jC2 (Register tmp, Label& L);
- void jnC2(Register tmp, Label& L);
-
- // Pop ST (ffree & fincstp combined)
- void fpop();
-
- // pushes double TOS element of FPU stack on CPU stack; pops from FPU stack
- void push_fTOS();
-
- // pops double TOS element from CPU stack and pushes on FPU stack
- void pop_fTOS();
-
- void empty_FPU_stack();
-
- void push_IU_state();
- void pop_IU_state();
-
- void push_FPU_state();
- void pop_FPU_state();
-
- void push_CPU_state();
- void pop_CPU_state();
-
- // Round up to a power of two
- void round_to(Register reg, int modulus);
-
- // Callee saved registers handling
- void push_callee_saved_registers();
- void pop_callee_saved_registers();
-
- // allocation
- void eden_allocate(
- Register obj, // result: pointer to object after successful allocation
- Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
- int con_size_in_bytes, // object size in bytes if known at compile time
- Register t1, // temp register
- Label& slow_case // continuation point if fast allocation fails
- );
- void tlab_allocate(
- Register obj, // result: pointer to object after successful allocation
- Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
- int con_size_in_bytes, // object size in bytes if known at compile time
- Register t1, // temp register
- Register t2, // temp register
- Label& slow_case // continuation point if fast allocation fails
- );
- Register tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case); // returns TLS address
- void incr_allocated_bytes(Register thread,
- Register var_size_in_bytes, int con_size_in_bytes,
- Register t1 = noreg);
-
- // interface method calling
- void lookup_interface_method(Register recv_klass,
- Register intf_klass,
- RegisterOrConstant itable_index,
- Register method_result,
- Register scan_temp,
- Label& no_such_interface);
-
- // virtual method calling
- void lookup_virtual_method(Register recv_klass,
- RegisterOrConstant vtable_index,
- Register method_result);
-
- // Test sub_klass against super_klass, with fast and slow paths.
-
- // The fast path produces a tri-state answer: yes / no / maybe-slow.
- // One of the three labels can be NULL, meaning take the fall-through.
- // If super_check_offset is -1, the value is loaded up from super_klass.
- // No registers are killed, except temp_reg.
- void check_klass_subtype_fast_path(Register sub_klass,
- Register super_klass,
- Register temp_reg,
- Label* L_success,
- Label* L_failure,
- Label* L_slow_path,
- RegisterOrConstant super_check_offset = RegisterOrConstant(-1));
-
- // The rest of the type check; must be wired to a corresponding fast path.
- // It does not repeat the fast path logic, so don't use it standalone.
- // The temp_reg and temp2_reg can be noreg, if no temps are available.
- // Updates the sub's secondary super cache as necessary.
- // If set_cond_codes, condition codes will be Z on success, NZ on failure.
- void check_klass_subtype_slow_path(Register sub_klass,
- Register super_klass,
- Register temp_reg,
- Register temp2_reg,
- Label* L_success,
- Label* L_failure,
- bool set_cond_codes = false);
-
- // Simplified, combined version, good for typical uses.
- // Falls through on failure.
- void check_klass_subtype(Register sub_klass,
- Register super_klass,
- Register temp_reg,
- Label& L_success);
-
- // method handles (JSR 292)
- Address argument_address(RegisterOrConstant arg_slot, int extra_slot_offset = 0);
-
- //----
- void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0
-
- // Debugging
-
- // only if +VerifyOops
- // TODO: Make these macros with file and line like sparc version!
- void verify_oop(Register reg, const char* s = "broken oop");
- void verify_oop_addr(Address addr, const char * s = "broken oop addr");
-
- // TODO: verify method and klass metadata (compare against vptr?)
- void _verify_method_ptr(Register reg, const char * msg, const char * file, int line) {}
- void _verify_klass_ptr(Register reg, const char * msg, const char * file, int line){}
-
-#define verify_method_ptr(reg) _verify_method_ptr(reg, "broken method " #reg, __FILE__, __LINE__)
-#define verify_klass_ptr(reg) _verify_klass_ptr(reg, "broken klass " #reg, __FILE__, __LINE__)
-
- // only if +VerifyFPU
- void verify_FPU(int stack_depth, const char* s = "illegal FPU state");
-
- // prints msg, dumps registers and stops execution
- void stop(const char* msg);
-
- // prints msg and continues
- void warn(const char* msg);
-
- // dumps registers and other state
- void print_state();
-
- static void debug32(int rdi, int rsi, int rbp, int rsp, int rbx, int rdx, int rcx, int rax, int eip, char* msg);
- static void debug64(char* msg, int64_t pc, int64_t regs[]);
- static void print_state32(int rdi, int rsi, int rbp, int rsp, int rbx, int rdx, int rcx, int rax, int eip);
- static void print_state64(int64_t pc, int64_t regs[]);
-
- void os_breakpoint();
-
- void untested() { stop("untested"); }
-
- void unimplemented(const char* what = "") { char* b = new char[1024]; jio_snprintf(b, 1024, "unimplemented: %s", what); stop(b); }
-
- void should_not_reach_here() { stop("should not reach here"); }
-
- void print_CPU_state();
-
- // Stack overflow checking
- void bang_stack_with_offset(int offset) {
- // stack grows down, caller passes positive offset
- assert(offset > 0, "must bang with negative offset");
- movl(Address(rsp, (-offset)), rax);
- }
-
- // Writes to stack successive pages until offset reached to check for
- // stack overflow + shadow pages. Also, clobbers tmp
- void bang_stack_size(Register size, Register tmp);
-
- virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr,
- Register tmp,
- int offset);
-
- // Support for serializing memory accesses between threads
- void serialize_memory(Register thread, Register tmp);
-
- void verify_tlab();
-
- // Biased locking support
- // lock_reg and obj_reg must be loaded up with the appropriate values.
- // swap_reg must be rax, and is killed.
- // tmp_reg is optional. If it is supplied (i.e., != noreg) it will
- // be killed; if not supplied, push/pop will be used internally to
- // allocate a temporary (inefficient, avoid if possible).
- // Optional slow case is for implementations (interpreter and C1) which branch to
- // slow case directly. Leaves condition codes set for C2's Fast_Lock node.
- // Returns offset of first potentially-faulting instruction for null
- // check info (currently consumed only by C1). If
- // swap_reg_contains_mark is true then returns -1 as it is assumed
- // the calling code has already passed any potential faults.
- int biased_locking_enter(Register lock_reg, Register obj_reg,
- Register swap_reg, Register tmp_reg,
- bool swap_reg_contains_mark,
- Label& done, Label* slow_case = NULL,
- BiasedLockingCounters* counters = NULL);
- void biased_locking_exit (Register obj_reg, Register temp_reg, Label& done);
-
-
- Condition negate_condition(Condition cond);
-
- // Instructions that use AddressLiteral operands. These instruction can handle 32bit/64bit
- // operands. In general the names are modified to avoid hiding the instruction in Assembler
- // so that we don't need to implement all the varieties in the Assembler with trivial wrappers
- // here in MacroAssembler. The major exception to this rule is call
-
- // Arithmetics
-
-
- void addptr(Address dst, int32_t src) { LP64_ONLY(addq(dst, src)) NOT_LP64(addl(dst, src)) ; }
- void addptr(Address dst, Register src);
-
- void addptr(Register dst, Address src) { LP64_ONLY(addq(dst, src)) NOT_LP64(addl(dst, src)); }
- void addptr(Register dst, int32_t src);
- void addptr(Register dst, Register src);
- void addptr(Register dst, RegisterOrConstant src) {
- if (src.is_constant()) addptr(dst, (int) src.as_constant());
- else addptr(dst, src.as_register());
- }
-
- void andptr(Register dst, int32_t src);
- void andptr(Register src1, Register src2) { LP64_ONLY(andq(src1, src2)) NOT_LP64(andl(src1, src2)) ; }
-
- void cmp8(AddressLiteral src1, int imm);
-
- // renamed to drag out the casting of address to int32_t/intptr_t
- void cmp32(Register src1, int32_t imm);
-
- void cmp32(AddressLiteral src1, int32_t imm);
- // compare reg - mem, or reg - &mem
- void cmp32(Register src1, AddressLiteral src2);
-
- void cmp32(Register src1, Address src2);
-
-#ifndef _LP64
- void cmpklass(Address dst, Metadata* obj);
- void cmpklass(Register dst, Metadata* obj);
- void cmpoop(Address dst, jobject obj);
- void cmpoop(Register dst, jobject obj);
-#endif // _LP64
-
- // NOTE src2 must be the lval. This is NOT an mem-mem compare
- void cmpptr(Address src1, AddressLiteral src2);
-
- void cmpptr(Register src1, AddressLiteral src2);
-
- void cmpptr(Register src1, Register src2) { LP64_ONLY(cmpq(src1, src2)) NOT_LP64(cmpl(src1, src2)) ; }
- void cmpptr(Register src1, Address src2) { LP64_ONLY(cmpq(src1, src2)) NOT_LP64(cmpl(src1, src2)) ; }
- // void cmpptr(Address src1, Register src2) { LP64_ONLY(cmpq(src1, src2)) NOT_LP64(cmpl(src1, src2)) ; }
-
- void cmpptr(Register src1, int32_t src2) { LP64_ONLY(cmpq(src1, src2)) NOT_LP64(cmpl(src1, src2)) ; }
- void cmpptr(Address src1, int32_t src2) { LP64_ONLY(cmpq(src1, src2)) NOT_LP64(cmpl(src1, src2)) ; }
-
- // cmp64 to avoild hiding cmpq
- void cmp64(Register src1, AddressLiteral src);
-
- void cmpxchgptr(Register reg, Address adr);
-
- void locked_cmpxchgptr(Register reg, AddressLiteral adr);
-
-
- void imulptr(Register dst, Register src) { LP64_ONLY(imulq(dst, src)) NOT_LP64(imull(dst, src)); }
-
-
- void negptr(Register dst) { LP64_ONLY(negq(dst)) NOT_LP64(negl(dst)); }
-
- void notptr(Register dst) { LP64_ONLY(notq(dst)) NOT_LP64(notl(dst)); }
-
- void shlptr(Register dst, int32_t shift);
- void shlptr(Register dst) { LP64_ONLY(shlq(dst)) NOT_LP64(shll(dst)); }
-
- void shrptr(Register dst, int32_t shift);
- void shrptr(Register dst) { LP64_ONLY(shrq(dst)) NOT_LP64(shrl(dst)); }
-
- void sarptr(Register dst) { LP64_ONLY(sarq(dst)) NOT_LP64(sarl(dst)); }
- void sarptr(Register dst, int32_t src) { LP64_ONLY(sarq(dst, src)) NOT_LP64(sarl(dst, src)); }
-
- void subptr(Address dst, int32_t src) { LP64_ONLY(subq(dst, src)) NOT_LP64(subl(dst, src)); }
-
- void subptr(Register dst, Address src) { LP64_ONLY(subq(dst, src)) NOT_LP64(subl(dst, src)); }
- void subptr(Register dst, int32_t src);
- // Force generation of a 4 byte immediate value even if it fits into 8bit
- void subptr_imm32(Register dst, int32_t src);
- void subptr(Register dst, Register src);
- void subptr(Register dst, RegisterOrConstant src) {
- if (src.is_constant()) subptr(dst, (int) src.as_constant());
- else subptr(dst, src.as_register());
- }
-
- void sbbptr(Address dst, int32_t src) { LP64_ONLY(sbbq(dst, src)) NOT_LP64(sbbl(dst, src)); }
- void sbbptr(Register dst, int32_t src) { LP64_ONLY(sbbq(dst, src)) NOT_LP64(sbbl(dst, src)); }
-
- void xchgptr(Register src1, Register src2) { LP64_ONLY(xchgq(src1, src2)) NOT_LP64(xchgl(src1, src2)) ; }
- void xchgptr(Register src1, Address src2) { LP64_ONLY(xchgq(src1, src2)) NOT_LP64(xchgl(src1, src2)) ; }
-
- void xaddptr(Address src1, Register src2) { LP64_ONLY(xaddq(src1, src2)) NOT_LP64(xaddl(src1, src2)) ; }
-
-
-
- // Helper functions for statistics gathering.
- // Conditionally (atomically, on MPs) increments passed counter address, preserving condition codes.
- void cond_inc32(Condition cond, AddressLiteral counter_addr);
- // Unconditional atomic increment.
- void atomic_incl(AddressLiteral counter_addr);
-
- void lea(Register dst, AddressLiteral adr);
- void lea(Address dst, AddressLiteral adr);
- void lea(Register dst, Address adr) { Assembler::lea(dst, adr); }
-
- void leal32(Register dst, Address src) { leal(dst, src); }
-
- // Import other testl() methods from the parent class or else
- // they will be hidden by the following overriding declaration.
- using Assembler::testl;
- void testl(Register dst, AddressLiteral src);
-
- void orptr(Register dst, Address src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); }
- void orptr(Register dst, Register src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); }
- void orptr(Register dst, int32_t src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); }
-
- void testptr(Register src, int32_t imm32) { LP64_ONLY(testq(src, imm32)) NOT_LP64(testl(src, imm32)); }
- void testptr(Register src1, Register src2);
-
- void xorptr(Register dst, Register src) { LP64_ONLY(xorq(dst, src)) NOT_LP64(xorl(dst, src)); }
- void xorptr(Register dst, Address src) { LP64_ONLY(xorq(dst, src)) NOT_LP64(xorl(dst, src)); }
-
- // Calls
-
- void call(Label& L, relocInfo::relocType rtype);
- void call(Register entry);
-
- // NOTE: this call tranfers to the effective address of entry NOT
- // the address contained by entry. This is because this is more natural
- // for jumps/calls.
- void call(AddressLiteral entry);
-
- // Emit the CompiledIC call idiom
- void ic_call(address entry);
-
- // Jumps
-
- // NOTE: these jumps tranfer to the effective address of dst NOT
- // the address contained by dst. This is because this is more natural
- // for jumps/calls.
- void jump(AddressLiteral dst);
- void jump_cc(Condition cc, AddressLiteral dst);
-
- // 32bit can do a case table jump in one instruction but we no longer allow the base
- // to be installed in the Address class. This jump will tranfers to the address
- // contained in the location described by entry (not the address of entry)
- void jump(ArrayAddress entry);
-
- // Floating
-
- void andpd(XMMRegister dst, Address src) { Assembler::andpd(dst, src); }
- void andpd(XMMRegister dst, AddressLiteral src);
-
- void andps(XMMRegister dst, XMMRegister src) { Assembler::andps(dst, src); }
- void andps(XMMRegister dst, Address src) { Assembler::andps(dst, src); }
- void andps(XMMRegister dst, AddressLiteral src);
-
- void comiss(XMMRegister dst, XMMRegister src) { Assembler::comiss(dst, src); }
- void comiss(XMMRegister dst, Address src) { Assembler::comiss(dst, src); }
- void comiss(XMMRegister dst, AddressLiteral src);
-
- void comisd(XMMRegister dst, XMMRegister src) { Assembler::comisd(dst, src); }
- void comisd(XMMRegister dst, Address src) { Assembler::comisd(dst, src); }
- void comisd(XMMRegister dst, AddressLiteral src);
-
- void fadd_s(Address src) { Assembler::fadd_s(src); }
- void fadd_s(AddressLiteral src) { Assembler::fadd_s(as_Address(src)); }
-
- void fldcw(Address src) { Assembler::fldcw(src); }
- void fldcw(AddressLiteral src);
-
- void fld_s(int index) { Assembler::fld_s(index); }
- void fld_s(Address src) { Assembler::fld_s(src); }
- void fld_s(AddressLiteral src);
-
- void fld_d(Address src) { Assembler::fld_d(src); }
- void fld_d(AddressLiteral src);
-
- void fld_x(Address src) { Assembler::fld_x(src); }
- void fld_x(AddressLiteral src);
-
- void fmul_s(Address src) { Assembler::fmul_s(src); }
- void fmul_s(AddressLiteral src) { Assembler::fmul_s(as_Address(src)); }
-
- void ldmxcsr(Address src) { Assembler::ldmxcsr(src); }
- void ldmxcsr(AddressLiteral src);
-
- // compute pow(x,y) and exp(x) with x86 instructions. Don't cover
- // all corner cases and may result in NaN and require fallback to a
- // runtime call.
- void fast_pow();
- void fast_exp();
- void increase_precision();
- void restore_precision();
-
- // computes exp(x). Fallback to runtime call included.
- void exp_with_fallback(int num_fpu_regs_in_use) { pow_or_exp(true, num_fpu_regs_in_use); }
- // computes pow(x,y). Fallback to runtime call included.
- void pow_with_fallback(int num_fpu_regs_in_use) { pow_or_exp(false, num_fpu_regs_in_use); }
-
-private:
-
- // call runtime as a fallback for trig functions and pow/exp.
- void fp_runtime_fallback(address runtime_entry, int nb_args, int num_fpu_regs_in_use);
-
- // computes 2^(Ylog2X); Ylog2X in ST(0)
- void pow_exp_core_encoding();
-
- // computes pow(x,y) or exp(x). Fallback to runtime call included.
- void pow_or_exp(bool is_exp, int num_fpu_regs_in_use);
-
- // these are private because users should be doing movflt/movdbl
-
- void movss(Address dst, XMMRegister src) { Assembler::movss(dst, src); }
- void movss(XMMRegister dst, XMMRegister src) { Assembler::movss(dst, src); }
- void movss(XMMRegister dst, Address src) { Assembler::movss(dst, src); }
- void movss(XMMRegister dst, AddressLiteral src);
-
- void movlpd(XMMRegister dst, Address src) {Assembler::movlpd(dst, src); }
- void movlpd(XMMRegister dst, AddressLiteral src);
-
-public:
-
- void addsd(XMMRegister dst, XMMRegister src) { Assembler::addsd(dst, src); }
- void addsd(XMMRegister dst, Address src) { Assembler::addsd(dst, src); }
- void addsd(XMMRegister dst, AddressLiteral src);
-
- void addss(XMMRegister dst, XMMRegister src) { Assembler::addss(dst, src); }
- void addss(XMMRegister dst, Address src) { Assembler::addss(dst, src); }
- void addss(XMMRegister dst, AddressLiteral src);
-
- void divsd(XMMRegister dst, XMMRegister src) { Assembler::divsd(dst, src); }
- void divsd(XMMRegister dst, Address src) { Assembler::divsd(dst, src); }
- void divsd(XMMRegister dst, AddressLiteral src);
-
- void divss(XMMRegister dst, XMMRegister src) { Assembler::divss(dst, src); }
- void divss(XMMRegister dst, Address src) { Assembler::divss(dst, src); }
- void divss(XMMRegister dst, AddressLiteral src);
-
- void movsd(XMMRegister dst, XMMRegister src) { Assembler::movsd(dst, src); }
- void movsd(Address dst, XMMRegister src) { Assembler::movsd(dst, src); }
- void movsd(XMMRegister dst, Address src) { Assembler::movsd(dst, src); }
- void movsd(XMMRegister dst, AddressLiteral src);
-
- void mulsd(XMMRegister dst, XMMRegister src) { Assembler::mulsd(dst, src); }
- void mulsd(XMMRegister dst, Address src) { Assembler::mulsd(dst, src); }
- void mulsd(XMMRegister dst, AddressLiteral src);
-
- void mulss(XMMRegister dst, XMMRegister src) { Assembler::mulss(dst, src); }
- void mulss(XMMRegister dst, Address src) { Assembler::mulss(dst, src); }
- void mulss(XMMRegister dst, AddressLiteral src);
-
- void sqrtsd(XMMRegister dst, XMMRegister src) { Assembler::sqrtsd(dst, src); }
- void sqrtsd(XMMRegister dst, Address src) { Assembler::sqrtsd(dst, src); }
- void sqrtsd(XMMRegister dst, AddressLiteral src);
-
- void sqrtss(XMMRegister dst, XMMRegister src) { Assembler::sqrtss(dst, src); }
- void sqrtss(XMMRegister dst, Address src) { Assembler::sqrtss(dst, src); }
- void sqrtss(XMMRegister dst, AddressLiteral src);
-
- void subsd(XMMRegister dst, XMMRegister src) { Assembler::subsd(dst, src); }
- void subsd(XMMRegister dst, Address src) { Assembler::subsd(dst, src); }
- void subsd(XMMRegister dst, AddressLiteral src);
-
- void subss(XMMRegister dst, XMMRegister src) { Assembler::subss(dst, src); }
- void subss(XMMRegister dst, Address src) { Assembler::subss(dst, src); }
- void subss(XMMRegister dst, AddressLiteral src);
-
- void ucomiss(XMMRegister dst, XMMRegister src) { Assembler::ucomiss(dst, src); }
- void ucomiss(XMMRegister dst, Address src) { Assembler::ucomiss(dst, src); }
- void ucomiss(XMMRegister dst, AddressLiteral src);
-
- void ucomisd(XMMRegister dst, XMMRegister src) { Assembler::ucomisd(dst, src); }
- void ucomisd(XMMRegister dst, Address src) { Assembler::ucomisd(dst, src); }
- void ucomisd(XMMRegister dst, AddressLiteral src);
-
- // Bitwise Logical XOR of Packed Double-Precision Floating-Point Values
- void xorpd(XMMRegister dst, XMMRegister src) { Assembler::xorpd(dst, src); }
- void xorpd(XMMRegister dst, Address src) { Assembler::xorpd(dst, src); }
- void xorpd(XMMRegister dst, AddressLiteral src);
-
- // Bitwise Logical XOR of Packed Single-Precision Floating-Point Values
- void xorps(XMMRegister dst, XMMRegister src) { Assembler::xorps(dst, src); }
- void xorps(XMMRegister dst, Address src) { Assembler::xorps(dst, src); }
- void xorps(XMMRegister dst, AddressLiteral src);
-
- // AVX 3-operands instructions
-
- void vaddsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { Assembler::vaddsd(dst, nds, src); }
- void vaddsd(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vaddsd(dst, nds, src); }
- void vaddsd(XMMRegister dst, XMMRegister nds, AddressLiteral src);
-
- void vaddss(XMMRegister dst, XMMRegister nds, XMMRegister src) { Assembler::vaddss(dst, nds, src); }
- void vaddss(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vaddss(dst, nds, src); }
- void vaddss(XMMRegister dst, XMMRegister nds, AddressLiteral src);
-
- void vandpd(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { Assembler::vandpd(dst, nds, src, vector256); }
- void vandpd(XMMRegister dst, XMMRegister nds, Address src, bool vector256) { Assembler::vandpd(dst, nds, src, vector256); }
- void vandpd(XMMRegister dst, XMMRegister nds, AddressLiteral src, bool vector256);
-
- void vandps(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { Assembler::vandps(dst, nds, src, vector256); }
- void vandps(XMMRegister dst, XMMRegister nds, Address src, bool vector256) { Assembler::vandps(dst, nds, src, vector256); }
- void vandps(XMMRegister dst, XMMRegister nds, AddressLiteral src, bool vector256);
-
- void vdivsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { Assembler::vdivsd(dst, nds, src); }
- void vdivsd(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vdivsd(dst, nds, src); }
- void vdivsd(XMMRegister dst, XMMRegister nds, AddressLiteral src);
-
- void vdivss(XMMRegister dst, XMMRegister nds, XMMRegister src) { Assembler::vdivss(dst, nds, src); }
- void vdivss(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vdivss(dst, nds, src); }
- void vdivss(XMMRegister dst, XMMRegister nds, AddressLiteral src);
-
- void vmulsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { Assembler::vmulsd(dst, nds, src); }
- void vmulsd(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vmulsd(dst, nds, src); }
- void vmulsd(XMMRegister dst, XMMRegister nds, AddressLiteral src);
-
- void vmulss(XMMRegister dst, XMMRegister nds, XMMRegister src) { Assembler::vmulss(dst, nds, src); }
- void vmulss(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vmulss(dst, nds, src); }
- void vmulss(XMMRegister dst, XMMRegister nds, AddressLiteral src);
-
- void vsubsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { Assembler::vsubsd(dst, nds, src); }
- void vsubsd(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vsubsd(dst, nds, src); }
- void vsubsd(XMMRegister dst, XMMRegister nds, AddressLiteral src);
-
- void vsubss(XMMRegister dst, XMMRegister nds, XMMRegister src) { Assembler::vsubss(dst, nds, src); }
- void vsubss(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vsubss(dst, nds, src); }
- void vsubss(XMMRegister dst, XMMRegister nds, AddressLiteral src);
-
- // AVX Vector instructions
-
- void vxorpd(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { Assembler::vxorpd(dst, nds, src, vector256); }
- void vxorpd(XMMRegister dst, XMMRegister nds, Address src, bool vector256) { Assembler::vxorpd(dst, nds, src, vector256); }
- void vxorpd(XMMRegister dst, XMMRegister nds, AddressLiteral src, bool vector256);
-
- void vxorps(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { Assembler::vxorps(dst, nds, src, vector256); }
- void vxorps(XMMRegister dst, XMMRegister nds, Address src, bool vector256) { Assembler::vxorps(dst, nds, src, vector256); }
- void vxorps(XMMRegister dst, XMMRegister nds, AddressLiteral src, bool vector256);
-
- void vpxor(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) {
- if (UseAVX > 1 || !vector256) // vpxor 256 bit is available only in AVX2
- Assembler::vpxor(dst, nds, src, vector256);
- else
- Assembler::vxorpd(dst, nds, src, vector256);
- }
- void vpxor(XMMRegister dst, XMMRegister nds, Address src, bool vector256) {
- if (UseAVX > 1 || !vector256) // vpxor 256 bit is available only in AVX2
- Assembler::vpxor(dst, nds, src, vector256);
- else
- Assembler::vxorpd(dst, nds, src, vector256);
- }
-
- // Move packed integer values from low 128 bit to hign 128 bit in 256 bit vector.
- void vinserti128h(XMMRegister dst, XMMRegister nds, XMMRegister src) {
- if (UseAVX > 1) // vinserti128h is available only in AVX2
- Assembler::vinserti128h(dst, nds, src);
- else
- Assembler::vinsertf128h(dst, nds, src);
- }
-
- // Data
-
- void cmov32( Condition cc, Register dst, Address src);
- void cmov32( Condition cc, Register dst, Register src);
-
- void cmov( Condition cc, Register dst, Register src) { cmovptr(cc, dst, src); }
-
- void cmovptr(Condition cc, Register dst, Address src) { LP64_ONLY(cmovq(cc, dst, src)) NOT_LP64(cmov32(cc, dst, src)); }
- void cmovptr(Condition cc, Register dst, Register src) { LP64_ONLY(cmovq(cc, dst, src)) NOT_LP64(cmov32(cc, dst, src)); }
-
- void movoop(Register dst, jobject obj);
- void movoop(Address dst, jobject obj);
-
- void mov_metadata(Register dst, Metadata* obj);
- void mov_metadata(Address dst, Metadata* obj);
-
- void movptr(ArrayAddress dst, Register src);
- // can this do an lea?
- void movptr(Register dst, ArrayAddress src);
-
- void movptr(Register dst, Address src);
-
- void movptr(Register dst, AddressLiteral src);
-
- void movptr(Register dst, intptr_t src);
- void movptr(Register dst, Register src);
- void movptr(Address dst, intptr_t src);
-
- void movptr(Address dst, Register src);
-
- void movptr(Register dst, RegisterOrConstant src) {
- if (src.is_constant()) movptr(dst, src.as_constant());
- else movptr(dst, src.as_register());
- }
-
-#ifdef _LP64
- // Generally the next two are only used for moving NULL
- // Although there are situations in initializing the mark word where
- // they could be used. They are dangerous.
-
- // They only exist on LP64 so that int32_t and intptr_t are not the same
- // and we have ambiguous declarations.
-
- void movptr(Address dst, int32_t imm32);
- void movptr(Register dst, int32_t imm32);
-#endif // _LP64
-
- // to avoid hiding movl
- void mov32(AddressLiteral dst, Register src);
- void mov32(Register dst, AddressLiteral src);
-
- // to avoid hiding movb
- void movbyte(ArrayAddress dst, int src);
-
- // Import other mov() methods from the parent class or else
- // they will be hidden by the following overriding declaration.
- using Assembler::movdl;
- using Assembler::movq;
- void movdl(XMMRegister dst, AddressLiteral src);
- void movq(XMMRegister dst, AddressLiteral src);
-
- // Can push value or effective address
- void pushptr(AddressLiteral src);
-
- void pushptr(Address src) { LP64_ONLY(pushq(src)) NOT_LP64(pushl(src)); }
- void popptr(Address src) { LP64_ONLY(popq(src)) NOT_LP64(popl(src)); }
-
- void pushoop(jobject obj);
- void pushklass(Metadata* obj);
-
- // sign extend as need a l to ptr sized element
- void movl2ptr(Register dst, Address src) { LP64_ONLY(movslq(dst, src)) NOT_LP64(movl(dst, src)); }
- void movl2ptr(Register dst, Register src) { LP64_ONLY(movslq(dst, src)) NOT_LP64(if (dst != src) movl(dst, src)); }
-
- // C2 compiled method's prolog code.
- void verified_entry(int framesize, bool stack_bang, bool fp_mode_24b);
-
- // IndexOf strings.
- // Small strings are loaded through stack if they cross page boundary.
- void string_indexof(Register str1, Register str2,
- Register cnt1, Register cnt2,
- int int_cnt2, Register result,
- XMMRegister vec, Register tmp);
-
- // IndexOf for constant substrings with size >= 8 elements
- // which don't need to be loaded through stack.
- void string_indexofC8(Register str1, Register str2,
- Register cnt1, Register cnt2,
- int int_cnt2, Register result,
- XMMRegister vec, Register tmp);
-
- // Smallest code: we don't need to load through stack,
- // check string tail.
-
- // Compare strings.
- void string_compare(Register str1, Register str2,
- Register cnt1, Register cnt2, Register result,
- XMMRegister vec1);
-
- // Compare char[] arrays.
- void char_arrays_equals(bool is_array_equ, Register ary1, Register ary2,
- Register limit, Register result, Register chr,
- XMMRegister vec1, XMMRegister vec2);
-
- // Fill primitive arrays
- void generate_fill(BasicType t, bool aligned,
- Register to, Register value, Register count,
- Register rtmp, XMMRegister xtmp);
-
-#undef VIRTUAL
-
-};
-
-/**
- * class SkipIfEqual:
- *
- * Instantiating this class will result in assembly code being output that will
- * jump around any code emitted between the creation of the instance and it's
- * automatic destruction at the end of a scope block, depending on the value of
- * the flag passed to the constructor, which will be checked at run-time.
- */
-class SkipIfEqual {
- private:
- MacroAssembler* _masm;
- Label _label;
-
- public:
- SkipIfEqual(MacroAssembler*, const bool* flag_addr, bool value);
- ~SkipIfEqual();
-};
-
-#ifdef ASSERT
-inline bool AbstractAssembler::pd_check_instruction_mark() { return true; }
-#endif
-
#endif // CPU_X86_VM_ASSEMBLER_X86_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/assembler_x86.inline.hpp
--- a/src/cpu/x86/vm/assembler_x86.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/assembler_x86.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -28,48 +28,6 @@
#include "asm/assembler.inline.hpp"
#include "asm/codeBuffer.hpp"
#include "code/codeCache.hpp"
-#include "runtime/handles.inline.hpp"
-
-inline void MacroAssembler::pd_patch_instruction(address branch, address target) {
- unsigned char op = branch[0];
- assert(op == 0xE8 /* call */ ||
- op == 0xE9 /* jmp */ ||
- op == 0xEB /* short jmp */ ||
- (op & 0xF0) == 0x70 /* short jcc */ ||
- op == 0x0F && (branch[1] & 0xF0) == 0x80 /* jcc */,
- "Invalid opcode at patch point");
-
- if (op == 0xEB || (op & 0xF0) == 0x70) {
- // short offset operators (jmp and jcc)
- char* disp = (char*) &branch[1];
- int imm8 = target - (address) &disp[1];
- guarantee(this->is8bit(imm8), "Short forward jump exceeds 8-bit offset");
- *disp = imm8;
- } else {
- int* disp = (int*) &branch[(op == 0x0F)? 2: 1];
- int imm32 = target - (address) &disp[1];
- *disp = imm32;
- }
-}
-
-#ifndef PRODUCT
-inline void MacroAssembler::pd_print_patched_instruction(address branch) {
- const char* s;
- unsigned char op = branch[0];
- if (op == 0xE8) {
- s = "call";
- } else if (op == 0xE9 || op == 0xEB) {
- s = "jmp";
- } else if ((op & 0xF0) == 0x70) {
- s = "jcc";
- } else if (op == 0x0F) {
- s = "jcc";
- } else {
- s = "????";
- }
- tty->print("%s (unresolved)", s);
-}
-#endif // ndef PRODUCT
#ifndef _LP64
inline int Assembler::prefix_and_encode(int reg_enc, bool byteinst) { return reg_enc; }
@@ -87,12 +45,6 @@
inline void Assembler::prefix(Address adr, XMMRegister reg) {}
inline void Assembler::prefixq(Address adr, XMMRegister reg) {}
-#else
-inline void Assembler::emit_long64(jlong x) {
- *(jlong*) _code_pos = x;
- _code_pos += sizeof(jlong);
- code_section()->set_end(_code_pos);
-}
#endif // _LP64
#endif // CPU_X86_VM_ASSEMBLER_X86_INLINE_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/c1_CodeStubs_x86.cpp
--- a/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/c1_CodeStubs_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -313,10 +313,10 @@
#endif
} else {
// make a copy the code which is going to be patched.
- for ( int i = 0; i < _bytes_to_copy; i++) {
+ for (int i = 0; i < _bytes_to_copy; i++) {
address ptr = (address)(_pc_start + i);
int a_byte = (*ptr) & 0xFF;
- __ a_byte (a_byte);
+ __ emit_int8(a_byte);
*ptr = 0x90; // make the site look like a nop
}
}
@@ -363,11 +363,11 @@
// emit the offsets needed to find the code to patch
int being_initialized_entry_offset = __ pc() - being_initialized_entry + sizeof_patch_record;
- __ a_byte(0xB8);
- __ a_byte(0);
- __ a_byte(being_initialized_entry_offset);
- __ a_byte(bytes_to_skip);
- __ a_byte(_bytes_to_copy);
+ __ emit_int8((unsigned char)0xB8);
+ __ emit_int8(0);
+ __ emit_int8(being_initialized_entry_offset);
+ __ emit_int8(bytes_to_skip);
+ __ emit_int8(_bytes_to_copy);
address patch_info_pc = __ pc();
assert(patch_info_pc - end_of_patch == bytes_to_skip, "incorrect patch info");
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/c1_LIRAssembler_x86.cpp
--- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,8 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "c1/c1_Compilation.hpp"
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_MacroAssembler.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/cppInterpreter_x86.cpp
--- a/src/cpu/x86/vm/cppInterpreter_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/cppInterpreter_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
+#include "asm/macroAssembler.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/cppInterpreter.hpp"
#include "interpreter/interpreter.hpp"
@@ -538,9 +538,9 @@
// compute full expression stack limit
- const Address size_of_stack (rbx, Method::max_stack_offset());
const int extra_stack = 0; //6815692//Method::extra_stack_words();
- __ load_unsigned_short(rdx, size_of_stack); // get size of expression stack in words
+ __ movptr(rdx, Address(rbx, Method::const_offset()));
+ __ load_unsigned_short(rdx, Address(rdx, ConstMethod::max_stack_offset())); // get size of expression stack in words
__ negptr(rdx); // so we can subtract in next step
// Allocate expression stack
__ lea(rsp, Address(rsp, rdx, Address::times_ptr, -extra_stack));
@@ -611,8 +611,6 @@
// C++ interpreter only
// rsi/r13 - previous interpreter state pointer
- const Address size_of_parameters(rbx, Method::size_of_parameters_offset());
-
// InterpreterRuntime::frequency_counter_overflow takes one argument
// indicating if the counter overflow occurs at a backwards branch (non-NULL bcp).
// The call returns the address of the verified entry point for the method or NULL
@@ -682,12 +680,12 @@
const Address stack_size(thread, Thread::stack_size_offset());
// locals + overhead, in bytes
- const Address size_of_stack (rbx, Method::max_stack_offset());
- // Always give one monitor to allow us to start interp if sync method.
- // Any additional monitors need a check when moving the expression stack
- const int one_monitor = frame::interpreter_frame_monitor_size() * wordSize;
- const int extra_stack = 0; //6815692//Method::extra_stack_entries();
- __ load_unsigned_short(rax, size_of_stack); // get size of expression stack in words
+ // Always give one monitor to allow us to start interp if sync method.
+ // Any additional monitors need a check when moving the expression stack
+ const int one_monitor = frame::interpreter_frame_monitor_size() * wordSize;
+ const int extra_stack = 0; //6815692//Method::extra_stack_entries();
+ __ movptr(rax, Address(rbx, Method::const_offset()));
+ __ load_unsigned_short(rax, Address(rax, ConstMethod::max_stack_offset())); // get size of expression stack in words
__ lea(rax, Address(noreg, rax, Interpreter::stackElementScale(), extra_stack + one_monitor));
__ lea(rax, Address(rax, rdx, Interpreter::stackElementScale(), overhead_size));
@@ -977,15 +975,16 @@
// to save/restore.
address entry_point = __ pc();
- const Address size_of_parameters(rbx, Method::size_of_parameters_offset());
- const Address size_of_locals (rbx, Method::size_of_locals_offset());
+ const Address constMethod (rbx, Method::const_offset());
const Address invocation_counter(rbx, Method::invocation_counter_offset() + InvocationCounter::counter_offset());
const Address access_flags (rbx, Method::access_flags_offset());
+ const Address size_of_parameters(rcx, ConstMethod::size_of_parameters_offset());
// rsi/r13 == state/locals rdi == prevstate
const Register locals = rdi;
// get parameter size (always needed)
+ __ movptr(rcx, constMethod);
__ load_unsigned_short(rcx, size_of_parameters);
// rbx: Method*
@@ -994,6 +993,7 @@
// for natives the size of locals is zero
// compute beginning of parameters /locals
+
__ lea(locals, Address(rsp, rcx, Address::times_ptr, -wordSize));
// initialize fixed part of activation frame
@@ -1107,11 +1107,14 @@
const Register method = rbx;
const Register thread = LP64_ONLY(r15_thread) NOT_LP64(rdi);
const Register t = InterpreterRuntime::SignatureHandlerGenerator::temp(); // rcx|rscratch1
+ const Address constMethod (method, Method::const_offset());
+ const Address size_of_parameters(t, ConstMethod::size_of_parameters_offset());
// allocate space for parameters
__ movptr(method, STATE(_method));
__ verify_method_ptr(method);
- __ load_unsigned_short(t, Address(method, Method::size_of_parameters_offset()));
+ __ movptr(t, constMethod);
+ __ load_unsigned_short(t, size_of_parameters);
__ shll(t, 2);
#ifdef _LP64
__ subptr(rsp, t);
@@ -1700,15 +1703,17 @@
// save sender sp
__ push(rcx);
- const Address size_of_parameters(rbx, Method::size_of_parameters_offset());
- const Address size_of_locals (rbx, Method::size_of_locals_offset());
+ const Address constMethod (rbx, Method::const_offset());
const Address access_flags (rbx, Method::access_flags_offset());
+ const Address size_of_parameters(rdx, ConstMethod::size_of_parameters_offset());
+ const Address size_of_locals (rdx, ConstMethod::size_of_locals_offset());
// const Address monitor_block_top (rbp, frame::interpreter_frame_monitor_block_top_offset * wordSize);
// const Address monitor_block_bot (rbp, frame::interpreter_frame_initial_sp_offset * wordSize);
// const Address monitor(rbp, frame::interpreter_frame_initial_sp_offset * wordSize - (int)sizeof(BasicObjectLock));
// get parameter size (always needed)
+ __ movptr(rdx, constMethod);
__ load_unsigned_short(rcx, size_of_parameters);
// rbx: Method*
@@ -1989,7 +1994,9 @@
__ movptr(rbx, STATE(_result._to_call._callee));
// callee left args on top of expression stack, remove them
- __ load_unsigned_short(rcx, Address(rbx, Method::size_of_parameters_offset()));
+ __ movptr(rcx, constMethod);
+ __ load_unsigned_short(rcx, Address(rcx, ConstMethod::size_of_parameters_offset()));
+
__ lea(rsp, Address(rsp, rcx, Address::times_ptr));
__ movl(rcx, Address(rbx, Method::result_index_offset()));
@@ -2159,7 +2166,9 @@
// Make it look like call_stub calling conventions
// Get (potential) receiver
- __ load_unsigned_short(rcx, size_of_parameters); // get size of parameters in words
+ // get size of parameters in words
+ __ movptr(rcx, constMethod);
+ __ load_unsigned_short(rcx, Address(rcx, ConstMethod::size_of_parameters_offset()));
ExternalAddress recursive(CAST_FROM_FN_PTR(address, RecursiveInterpreterActivation));
__ pushptr(recursive.addr()); // make it look good in the debugger
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/frame_x86.cpp
--- a/src/cpu/x86/vm/frame_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/frame_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -534,7 +534,7 @@
Method* m = *interpreter_frame_method_addr();
// validate the method we'd find in this potential sender
- if (!Universe::heap()->is_valid_method(m)) return false;
+ if (!m->is_valid_method()) return false;
// stack frames shouldn't be much larger than max_stack elements
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/frame_x86.inline.hpp
--- a/src/cpu/x86/vm/frame_x86.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/frame_x86.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,6 +25,8 @@
#ifndef CPU_X86_VM_FRAME_X86_INLINE_HPP
#define CPU_X86_VM_FRAME_X86_INLINE_HPP
+#include "code/codeCache.hpp"
+
// Inline functions for Intel frames:
// Constructors:
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/globals_x86.hpp
--- a/src/cpu/x86/vm/globals_x86.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/globals_x86.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -120,6 +120,9 @@
product(bool, UseUnalignedLoadStores, false, \
"Use SSE2 MOVDQU instruction for Arraycopy") \
\
+ product(bool, UseFastStosb, false, \
+ "Use fast-string operation for zeroing: rep stosb") \
+ \
/* assembler */ \
product(bool, Use486InstrsOnly, false, \
"Use 80486 Compliant instruction subset") \
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/icBuffer_x86.cpp
--- a/src/cpu/x86/vm/icBuffer_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/icBuffer_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "code/icBuffer.hpp"
#include "gc_interface/collectedHeap.inline.hpp"
#include "interpreter/bytecodes.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/icache_x86.cpp
--- a/src/cpu/x86/vm/icache_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/icache_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
#include "runtime/icache.hpp"
#define __ _masm->
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/interp_masm_x86_32.cpp
--- a/src/cpu/x86/vm/interp_masm_x86_32.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -36,18 +36,7 @@
#include "runtime/basicLock.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/sharedRuntime.hpp"
-#ifdef TARGET_OS_FAMILY_linux
-# include "thread_linux.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_solaris
-# include "thread_solaris.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_windows
-# include "thread_windows.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_bsd
-# include "thread_bsd.inline.hpp"
-#endif
+#include "runtime/thread.inline.hpp"
// Implementation of InterpreterMacroAssembler
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/interp_masm_x86_32.hpp
--- a/src/cpu/x86/vm/interp_masm_x86_32.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/interp_masm_x86_32.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,8 +25,10 @@
#ifndef CPU_X86_VM_INTERP_MASM_X86_32_HPP
#define CPU_X86_VM_INTERP_MASM_X86_32_HPP
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "interpreter/invocationCounter.hpp"
+#include "runtime/frame.hpp"
// This file specializes the assember with interpreter-specific macros
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/interp_masm_x86_64.cpp
--- a/src/cpu/x86/vm/interp_masm_x86_64.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -36,18 +36,7 @@
#include "runtime/basicLock.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/sharedRuntime.hpp"
-#ifdef TARGET_OS_FAMILY_linux
-# include "thread_linux.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_solaris
-# include "thread_solaris.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_windows
-# include "thread_windows.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_bsd
-# include "thread_bsd.inline.hpp"
-#endif
+#include "runtime/thread.inline.hpp"
// Implementation of InterpreterMacroAssembler
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/interp_masm_x86_64.hpp
--- a/src/cpu/x86/vm/interp_masm_x86_64.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/interp_masm_x86_64.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,8 +25,10 @@
#ifndef CPU_X86_VM_INTERP_MASM_X86_64_HPP
#define CPU_X86_VM_INTERP_MASM_X86_64_HPP
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "interpreter/invocationCounter.hpp"
+#include "runtime/frame.hpp"
// This file specializes the assember with interpreter-specific macros
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/interpreter_x86_32.cpp
--- a/src/cpu/x86/vm/interpreter_x86_32.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/interpreter_x86_32.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
+#include "asm/macroAssembler.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterGenerator.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/interpreter_x86_64.cpp
--- a/src/cpu/x86/vm/interpreter_x86_64.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/interpreter_x86_64.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
+#include "asm/macroAssembler.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterGenerator.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/jniFastGetField_x86_32.cpp
--- a/src/cpu/x86/vm/jniFastGetField_x86_32.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/jniFastGetField_x86_32.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
#include "memory/resourceArea.hpp"
#include "prims/jniFastGetField.hpp"
#include "prims/jvm_misc.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/jniFastGetField_x86_64.cpp
--- a/src/cpu/x86/vm/jniFastGetField_x86_64.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/jniFastGetField_x86_64.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
#include "memory/resourceArea.hpp"
#include "prims/jniFastGetField.hpp"
#include "prims/jvm_misc.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/jni_x86.h
--- a/src/cpu/x86/vm/jni_x86.h Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/jni_x86.h Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,14 +38,9 @@
#define JNICALL
typedef int jint;
-#if defined(_LP64) && !defined(__APPLE__)
+#if defined(_LP64)
typedef long jlong;
#else
- /*
- * On _LP64 __APPLE__ "long" and "long long" are both 64 bits,
- * but we use the "long long" typedef to avoid complaints from
- * the __APPLE__ compiler about fprintf formats.
- */
typedef long long jlong;
#endif
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/macroAssembler_x86.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cpu/x86/vm/macroAssembler_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -0,0 +1,6370 @@
+/*
+ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/assembler.hpp"
+#include "asm/assembler.inline.hpp"
+#include "compiler/disassembler.hpp"
+#include "gc_interface/collectedHeap.inline.hpp"
+#include "interpreter/interpreter.hpp"
+#include "memory/cardTableModRefBS.hpp"
+#include "memory/resourceArea.hpp"
+#include "prims/methodHandles.hpp"
+#include "runtime/biasedLocking.hpp"
+#include "runtime/interfaceSupport.hpp"
+#include "runtime/objectMonitor.hpp"
+#include "runtime/os.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#ifndef SERIALGC
+#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
+#include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp"
+#include "gc_implementation/g1/heapRegion.hpp"
+#endif
+
+#ifdef PRODUCT
+#define BLOCK_COMMENT(str) /* nothing */
+#define STOP(error) stop(error)
+#else
+#define BLOCK_COMMENT(str) block_comment(str)
+#define STOP(error) block_comment(error); stop(error)
+#endif
+
+#define BIND(label) bind(label); BLOCK_COMMENT(#label ":")
+
+
+#ifdef ASSERT
+bool AbstractAssembler::pd_check_instruction_mark() { return true; }
+#endif
+
+static Assembler::Condition reverse[] = {
+ Assembler::noOverflow /* overflow = 0x0 */ ,
+ Assembler::overflow /* noOverflow = 0x1 */ ,
+ Assembler::aboveEqual /* carrySet = 0x2, below = 0x2 */ ,
+ Assembler::below /* aboveEqual = 0x3, carryClear = 0x3 */ ,
+ Assembler::notZero /* zero = 0x4, equal = 0x4 */ ,
+ Assembler::zero /* notZero = 0x5, notEqual = 0x5 */ ,
+ Assembler::above /* belowEqual = 0x6 */ ,
+ Assembler::belowEqual /* above = 0x7 */ ,
+ Assembler::positive /* negative = 0x8 */ ,
+ Assembler::negative /* positive = 0x9 */ ,
+ Assembler::noParity /* parity = 0xa */ ,
+ Assembler::parity /* noParity = 0xb */ ,
+ Assembler::greaterEqual /* less = 0xc */ ,
+ Assembler::less /* greaterEqual = 0xd */ ,
+ Assembler::greater /* lessEqual = 0xe */ ,
+ Assembler::lessEqual /* greater = 0xf, */
+
+};
+
+
+// Implementation of MacroAssembler
+
+// First all the versions that have distinct versions depending on 32/64 bit
+// Unless the difference is trivial (1 line or so).
+
+#ifndef _LP64
+
+// 32bit versions
+
+Address MacroAssembler::as_Address(AddressLiteral adr) {
+ return Address(adr.target(), adr.rspec());
+}
+
+Address MacroAssembler::as_Address(ArrayAddress adr) {
+ return Address::make_array(adr);
+}
+
+int MacroAssembler::biased_locking_enter(Register lock_reg,
+ Register obj_reg,
+ Register swap_reg,
+ Register tmp_reg,
+ bool swap_reg_contains_mark,
+ Label& done,
+ Label* slow_case,
+ BiasedLockingCounters* counters) {
+ assert(UseBiasedLocking, "why call this otherwise?");
+ assert(swap_reg == rax, "swap_reg must be rax, for cmpxchg");
+ assert_different_registers(lock_reg, obj_reg, swap_reg);
+
+ if (PrintBiasedLockingStatistics && counters == NULL)
+ counters = BiasedLocking::counters();
+
+ bool need_tmp_reg = false;
+ if (tmp_reg == noreg) {
+ need_tmp_reg = true;
+ tmp_reg = lock_reg;
+ } else {
+ assert_different_registers(lock_reg, obj_reg, swap_reg, tmp_reg);
+ }
+ assert(markOopDesc::age_shift == markOopDesc::lock_bits + markOopDesc::biased_lock_bits, "biased locking makes assumptions about bit layout");
+ Address mark_addr (obj_reg, oopDesc::mark_offset_in_bytes());
+ Address klass_addr (obj_reg, oopDesc::klass_offset_in_bytes());
+ Address saved_mark_addr(lock_reg, 0);
+
+ // Biased locking
+ // See whether the lock is currently biased toward our thread and
+ // whether the epoch is still valid
+ // Note that the runtime guarantees sufficient alignment of JavaThread
+ // pointers to allow age to be placed into low bits
+ // First check to see whether biasing is even enabled for this object
+ Label cas_label;
+ int null_check_offset = -1;
+ if (!swap_reg_contains_mark) {
+ null_check_offset = offset();
+ movl(swap_reg, mark_addr);
+ }
+ if (need_tmp_reg) {
+ push(tmp_reg);
+ }
+ movl(tmp_reg, swap_reg);
+ andl(tmp_reg, markOopDesc::biased_lock_mask_in_place);
+ cmpl(tmp_reg, markOopDesc::biased_lock_pattern);
+ if (need_tmp_reg) {
+ pop(tmp_reg);
+ }
+ jcc(Assembler::notEqual, cas_label);
+ // The bias pattern is present in the object's header. Need to check
+ // whether the bias owner and the epoch are both still current.
+ // Note that because there is no current thread register on x86 we
+ // need to store off the mark word we read out of the object to
+ // avoid reloading it and needing to recheck invariants below. This
+ // store is unfortunate but it makes the overall code shorter and
+ // simpler.
+ movl(saved_mark_addr, swap_reg);
+ if (need_tmp_reg) {
+ push(tmp_reg);
+ }
+ get_thread(tmp_reg);
+ xorl(swap_reg, tmp_reg);
+ if (swap_reg_contains_mark) {
+ null_check_offset = offset();
+ }
+ movl(tmp_reg, klass_addr);
+ xorl(swap_reg, Address(tmp_reg, Klass::prototype_header_offset()));
+ andl(swap_reg, ~((int) markOopDesc::age_mask_in_place));
+ if (need_tmp_reg) {
+ pop(tmp_reg);
+ }
+ if (counters != NULL) {
+ cond_inc32(Assembler::zero,
+ ExternalAddress((address)counters->biased_lock_entry_count_addr()));
+ }
+ jcc(Assembler::equal, done);
+
+ Label try_revoke_bias;
+ Label try_rebias;
+
+ // At this point we know that the header has the bias pattern and
+ // that we are not the bias owner in the current epoch. We need to
+ // figure out more details about the state of the header in order to
+ // know what operations can be legally performed on the object's
+ // header.
+
+ // If the low three bits in the xor result aren't clear, that means
+ // the prototype header is no longer biased and we have to revoke
+ // the bias on this object.
+ testl(swap_reg, markOopDesc::biased_lock_mask_in_place);
+ jcc(Assembler::notZero, try_revoke_bias);
+
+ // Biasing is still enabled for this data type. See whether the
+ // epoch of the current bias is still valid, meaning that the epoch
+ // bits of the mark word are equal to the epoch bits of the
+ // prototype header. (Note that the prototype header's epoch bits
+ // only change at a safepoint.) If not, attempt to rebias the object
+ // toward the current thread. Note that we must be absolutely sure
+ // that the current epoch is invalid in order to do this because
+ // otherwise the manipulations it performs on the mark word are
+ // illegal.
+ testl(swap_reg, markOopDesc::epoch_mask_in_place);
+ jcc(Assembler::notZero, try_rebias);
+
+ // The epoch of the current bias is still valid but we know nothing
+ // about the owner; it might be set or it might be clear. Try to
+ // acquire the bias of the object using an atomic operation. If this
+ // fails we will go in to the runtime to revoke the object's bias.
+ // Note that we first construct the presumed unbiased header so we
+ // don't accidentally blow away another thread's valid bias.
+ movl(swap_reg, saved_mark_addr);
+ andl(swap_reg,
+ markOopDesc::biased_lock_mask_in_place | markOopDesc::age_mask_in_place | markOopDesc::epoch_mask_in_place);
+ if (need_tmp_reg) {
+ push(tmp_reg);
+ }
+ get_thread(tmp_reg);
+ orl(tmp_reg, swap_reg);
+ if (os::is_MP()) {
+ lock();
+ }
+ cmpxchgptr(tmp_reg, Address(obj_reg, 0));
+ if (need_tmp_reg) {
+ pop(tmp_reg);
+ }
+ // If the biasing toward our thread failed, this means that
+ // another thread succeeded in biasing it toward itself and we
+ // need to revoke that bias. The revocation will occur in the
+ // interpreter runtime in the slow case.
+ if (counters != NULL) {
+ cond_inc32(Assembler::zero,
+ ExternalAddress((address)counters->anonymously_biased_lock_entry_count_addr()));
+ }
+ if (slow_case != NULL) {
+ jcc(Assembler::notZero, *slow_case);
+ }
+ jmp(done);
+
+ bind(try_rebias);
+ // At this point we know the epoch has expired, meaning that the
+ // current "bias owner", if any, is actually invalid. Under these
+ // circumstances _only_, we are allowed to use the current header's
+ // value as the comparison value when doing the cas to acquire the
+ // bias in the current epoch. In other words, we allow transfer of
+ // the bias from one thread to another directly in this situation.
+ //
+ // FIXME: due to a lack of registers we currently blow away the age
+ // bits in this situation. Should attempt to preserve them.
+ if (need_tmp_reg) {
+ push(tmp_reg);
+ }
+ get_thread(tmp_reg);
+ movl(swap_reg, klass_addr);
+ orl(tmp_reg, Address(swap_reg, Klass::prototype_header_offset()));
+ movl(swap_reg, saved_mark_addr);
+ if (os::is_MP()) {
+ lock();
+ }
+ cmpxchgptr(tmp_reg, Address(obj_reg, 0));
+ if (need_tmp_reg) {
+ pop(tmp_reg);
+ }
+ // If the biasing toward our thread failed, then another thread
+ // succeeded in biasing it toward itself and we need to revoke that
+ // bias. The revocation will occur in the runtime in the slow case.
+ if (counters != NULL) {
+ cond_inc32(Assembler::zero,
+ ExternalAddress((address)counters->rebiased_lock_entry_count_addr()));
+ }
+ if (slow_case != NULL) {
+ jcc(Assembler::notZero, *slow_case);
+ }
+ jmp(done);
+
+ bind(try_revoke_bias);
+ // The prototype mark in the klass doesn't have the bias bit set any
+ // more, indicating that objects of this data type are not supposed
+ // to be biased any more. We are going to try to reset the mark of
+ // this object to the prototype value and fall through to the
+ // CAS-based locking scheme. Note that if our CAS fails, it means
+ // that another thread raced us for the privilege of revoking the
+ // bias of this particular object, so it's okay to continue in the
+ // normal locking code.
+ //
+ // FIXME: due to a lack of registers we currently blow away the age
+ // bits in this situation. Should attempt to preserve them.
+ movl(swap_reg, saved_mark_addr);
+ if (need_tmp_reg) {
+ push(tmp_reg);
+ }
+ movl(tmp_reg, klass_addr);
+ movl(tmp_reg, Address(tmp_reg, Klass::prototype_header_offset()));
+ if (os::is_MP()) {
+ lock();
+ }
+ cmpxchgptr(tmp_reg, Address(obj_reg, 0));
+ if (need_tmp_reg) {
+ pop(tmp_reg);
+ }
+ // Fall through to the normal CAS-based lock, because no matter what
+ // the result of the above CAS, some thread must have succeeded in
+ // removing the bias bit from the object's header.
+ if (counters != NULL) {
+ cond_inc32(Assembler::zero,
+ ExternalAddress((address)counters->revoked_lock_entry_count_addr()));
+ }
+
+ bind(cas_label);
+
+ return null_check_offset;
+}
+void MacroAssembler::call_VM_leaf_base(address entry_point,
+ int number_of_arguments) {
+ call(RuntimeAddress(entry_point));
+ increment(rsp, number_of_arguments * wordSize);
+}
+
+void MacroAssembler::cmpklass(Address src1, Metadata* obj) {
+ cmp_literal32(src1, (int32_t)obj, metadata_Relocation::spec_for_immediate());
+}
+
+void MacroAssembler::cmpklass(Register src1, Metadata* obj) {
+ cmp_literal32(src1, (int32_t)obj, metadata_Relocation::spec_for_immediate());
+}
+
+void MacroAssembler::cmpoop(Address src1, jobject obj) {
+ cmp_literal32(src1, (int32_t)obj, oop_Relocation::spec_for_immediate());
+}
+
+void MacroAssembler::cmpoop(Register src1, jobject obj) {
+ cmp_literal32(src1, (int32_t)obj, oop_Relocation::spec_for_immediate());
+}
+
+void MacroAssembler::extend_sign(Register hi, Register lo) {
+ // According to Intel Doc. AP-526, "Integer Divide", p.18.
+ if (VM_Version::is_P6() && hi == rdx && lo == rax) {
+ cdql();
+ } else {
+ movl(hi, lo);
+ sarl(hi, 31);
+ }
+}
+
+void MacroAssembler::jC2(Register tmp, Label& L) {
+ // set parity bit if FPU flag C2 is set (via rax)
+ save_rax(tmp);
+ fwait(); fnstsw_ax();
+ sahf();
+ restore_rax(tmp);
+ // branch
+ jcc(Assembler::parity, L);
+}
+
+void MacroAssembler::jnC2(Register tmp, Label& L) {
+ // set parity bit if FPU flag C2 is set (via rax)
+ save_rax(tmp);
+ fwait(); fnstsw_ax();
+ sahf();
+ restore_rax(tmp);
+ // branch
+ jcc(Assembler::noParity, L);
+}
+
+// 32bit can do a case table jump in one instruction but we no longer allow the base
+// to be installed in the Address class
+void MacroAssembler::jump(ArrayAddress entry) {
+ jmp(as_Address(entry));
+}
+
+// Note: y_lo will be destroyed
+void MacroAssembler::lcmp2int(Register x_hi, Register x_lo, Register y_hi, Register y_lo) {
+ // Long compare for Java (semantics as described in JVM spec.)
+ Label high, low, done;
+
+ cmpl(x_hi, y_hi);
+ jcc(Assembler::less, low);
+ jcc(Assembler::greater, high);
+ // x_hi is the return register
+ xorl(x_hi, x_hi);
+ cmpl(x_lo, y_lo);
+ jcc(Assembler::below, low);
+ jcc(Assembler::equal, done);
+
+ bind(high);
+ xorl(x_hi, x_hi);
+ increment(x_hi);
+ jmp(done);
+
+ bind(low);
+ xorl(x_hi, x_hi);
+ decrementl(x_hi);
+
+ bind(done);
+}
+
+void MacroAssembler::lea(Register dst, AddressLiteral src) {
+ mov_literal32(dst, (int32_t)src.target(), src.rspec());
+}
+
+void MacroAssembler::lea(Address dst, AddressLiteral adr) {
+ // leal(dst, as_Address(adr));
+ // see note in movl as to why we must use a move
+ mov_literal32(dst, (int32_t) adr.target(), adr.rspec());
+}
+
+void MacroAssembler::leave() {
+ mov(rsp, rbp);
+ pop(rbp);
+}
+
+void MacroAssembler::lmul(int x_rsp_offset, int y_rsp_offset) {
+ // Multiplication of two Java long values stored on the stack
+ // as illustrated below. Result is in rdx:rax.
+ //
+ // rsp ---> [ ?? ] \ \
+ // .... | y_rsp_offset |
+ // [ y_lo ] / (in bytes) | x_rsp_offset
+ // [ y_hi ] | (in bytes)
+ // .... |
+ // [ x_lo ] /
+ // [ x_hi ]
+ // ....
+ //
+ // Basic idea: lo(result) = lo(x_lo * y_lo)
+ // hi(result) = hi(x_lo * y_lo) + lo(x_hi * y_lo) + lo(x_lo * y_hi)
+ Address x_hi(rsp, x_rsp_offset + wordSize); Address x_lo(rsp, x_rsp_offset);
+ Address y_hi(rsp, y_rsp_offset + wordSize); Address y_lo(rsp, y_rsp_offset);
+ Label quick;
+ // load x_hi, y_hi and check if quick
+ // multiplication is possible
+ movl(rbx, x_hi);
+ movl(rcx, y_hi);
+ movl(rax, rbx);
+ orl(rbx, rcx); // rbx, = 0 <=> x_hi = 0 and y_hi = 0
+ jcc(Assembler::zero, quick); // if rbx, = 0 do quick multiply
+ // do full multiplication
+ // 1st step
+ mull(y_lo); // x_hi * y_lo
+ movl(rbx, rax); // save lo(x_hi * y_lo) in rbx,
+ // 2nd step
+ movl(rax, x_lo);
+ mull(rcx); // x_lo * y_hi
+ addl(rbx, rax); // add lo(x_lo * y_hi) to rbx,
+ // 3rd step
+ bind(quick); // note: rbx, = 0 if quick multiply!
+ movl(rax, x_lo);
+ mull(y_lo); // x_lo * y_lo
+ addl(rdx, rbx); // correct hi(x_lo * y_lo)
+}
+
+void MacroAssembler::lneg(Register hi, Register lo) {
+ negl(lo);
+ adcl(hi, 0);
+ negl(hi);
+}
+
+void MacroAssembler::lshl(Register hi, Register lo) {
+ // Java shift left long support (semantics as described in JVM spec., p.305)
+ // (basic idea for shift counts s >= n: x << s == (x << n) << (s - n))
+ // shift value is in rcx !
+ assert(hi != rcx, "must not use rcx");
+ assert(lo != rcx, "must not use rcx");
+ const Register s = rcx; // shift count
+ const int n = BitsPerWord;
+ Label L;
+ andl(s, 0x3f); // s := s & 0x3f (s < 0x40)
+ cmpl(s, n); // if (s < n)
+ jcc(Assembler::less, L); // else (s >= n)
+ movl(hi, lo); // x := x << n
+ xorl(lo, lo);
+ // Note: subl(s, n) is not needed since the Intel shift instructions work rcx mod n!
+ bind(L); // s (mod n) < n
+ shldl(hi, lo); // x := x << s
+ shll(lo);
+}
+
+
+void MacroAssembler::lshr(Register hi, Register lo, bool sign_extension) {
+ // Java shift right long support (semantics as described in JVM spec., p.306 & p.310)
+ // (basic idea for shift counts s >= n: x >> s == (x >> n) >> (s - n))
+ assert(hi != rcx, "must not use rcx");
+ assert(lo != rcx, "must not use rcx");
+ const Register s = rcx; // shift count
+ const int n = BitsPerWord;
+ Label L;
+ andl(s, 0x3f); // s := s & 0x3f (s < 0x40)
+ cmpl(s, n); // if (s < n)
+ jcc(Assembler::less, L); // else (s >= n)
+ movl(lo, hi); // x := x >> n
+ if (sign_extension) sarl(hi, 31);
+ else xorl(hi, hi);
+ // Note: subl(s, n) is not needed since the Intel shift instructions work rcx mod n!
+ bind(L); // s (mod n) < n
+ shrdl(lo, hi); // x := x >> s
+ if (sign_extension) sarl(hi);
+ else shrl(hi);
+}
+
+void MacroAssembler::movoop(Register dst, jobject obj) {
+ mov_literal32(dst, (int32_t)obj, oop_Relocation::spec_for_immediate());
+}
+
+void MacroAssembler::movoop(Address dst, jobject obj) {
+ mov_literal32(dst, (int32_t)obj, oop_Relocation::spec_for_immediate());
+}
+
+void MacroAssembler::mov_metadata(Register dst, Metadata* obj) {
+ mov_literal32(dst, (int32_t)obj, metadata_Relocation::spec_for_immediate());
+}
+
+void MacroAssembler::mov_metadata(Address dst, Metadata* obj) {
+ mov_literal32(dst, (int32_t)obj, metadata_Relocation::spec_for_immediate());
+}
+
+void MacroAssembler::movptr(Register dst, AddressLiteral src) {
+ if (src.is_lval()) {
+ mov_literal32(dst, (intptr_t)src.target(), src.rspec());
+ } else {
+ movl(dst, as_Address(src));
+ }
+}
+
+void MacroAssembler::movptr(ArrayAddress dst, Register src) {
+ movl(as_Address(dst), src);
+}
+
+void MacroAssembler::movptr(Register dst, ArrayAddress src) {
+ movl(dst, as_Address(src));
+}
+
+// src should NEVER be a real pointer. Use AddressLiteral for true pointers
+void MacroAssembler::movptr(Address dst, intptr_t src) {
+ movl(dst, src);
+}
+
+
+void MacroAssembler::pop_callee_saved_registers() {
+ pop(rcx);
+ pop(rdx);
+ pop(rdi);
+ pop(rsi);
+}
+
+void MacroAssembler::pop_fTOS() {
+ fld_d(Address(rsp, 0));
+ addl(rsp, 2 * wordSize);
+}
+
+void MacroAssembler::push_callee_saved_registers() {
+ push(rsi);
+ push(rdi);
+ push(rdx);
+ push(rcx);
+}
+
+void MacroAssembler::push_fTOS() {
+ subl(rsp, 2 * wordSize);
+ fstp_d(Address(rsp, 0));
+}
+
+
+void MacroAssembler::pushoop(jobject obj) {
+ push_literal32((int32_t)obj, oop_Relocation::spec_for_immediate());
+}
+
+void MacroAssembler::pushklass(Metadata* obj) {
+ push_literal32((int32_t)obj, metadata_Relocation::spec_for_immediate());
+}
+
+void MacroAssembler::pushptr(AddressLiteral src) {
+ if (src.is_lval()) {
+ push_literal32((int32_t)src.target(), src.rspec());
+ } else {
+ pushl(as_Address(src));
+ }
+}
+
+void MacroAssembler::set_word_if_not_zero(Register dst) {
+ xorl(dst, dst);
+ set_byte_if_not_zero(dst);
+}
+
+static void pass_arg0(MacroAssembler* masm, Register arg) {
+ masm->push(arg);
+}
+
+static void pass_arg1(MacroAssembler* masm, Register arg) {
+ masm->push(arg);
+}
+
+static void pass_arg2(MacroAssembler* masm, Register arg) {
+ masm->push(arg);
+}
+
+static void pass_arg3(MacroAssembler* masm, Register arg) {
+ masm->push(arg);
+}
+
+#ifndef PRODUCT
+extern "C" void findpc(intptr_t x);
+#endif
+
+void MacroAssembler::debug32(int rdi, int rsi, int rbp, int rsp, int rbx, int rdx, int rcx, int rax, int eip, char* msg) {
+ // In order to get locks to work, we need to fake a in_VM state
+ JavaThread* thread = JavaThread::current();
+ JavaThreadState saved_state = thread->thread_state();
+ thread->set_thread_state(_thread_in_vm);
+ if (ShowMessageBoxOnError) {
+ JavaThread* thread = JavaThread::current();
+ JavaThreadState saved_state = thread->thread_state();
+ thread->set_thread_state(_thread_in_vm);
+ if (CountBytecodes || TraceBytecodes || StopInterpreterAt) {
+ ttyLocker ttyl;
+ BytecodeCounter::print();
+ }
+ // To see where a verify_oop failed, get $ebx+40/X for this frame.
+ // This is the value of eip which points to where verify_oop will return.
+ if (os::message_box(msg, "Execution stopped, print registers?")) {
+ print_state32(rdi, rsi, rbp, rsp, rbx, rdx, rcx, rax, eip);
+ BREAKPOINT;
+ }
+ } else {
+ ttyLocker ttyl;
+ ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n", msg);
+ }
+ // Don't assert holding the ttyLock
+ assert(false, err_msg("DEBUG MESSAGE: %s", msg));
+ ThreadStateTransition::transition(thread, _thread_in_vm, saved_state);
+}
+
+void MacroAssembler::print_state32(int rdi, int rsi, int rbp, int rsp, int rbx, int rdx, int rcx, int rax, int eip) {
+ ttyLocker ttyl;
+ FlagSetting fs(Debugging, true);
+ tty->print_cr("eip = 0x%08x", eip);
+#ifndef PRODUCT
+ if ((WizardMode || Verbose) && PrintMiscellaneous) {
+ tty->cr();
+ findpc(eip);
+ tty->cr();
+ }
+#endif
+#define PRINT_REG(rax) \
+ { tty->print("%s = ", #rax); os::print_location(tty, rax); }
+ PRINT_REG(rax);
+ PRINT_REG(rbx);
+ PRINT_REG(rcx);
+ PRINT_REG(rdx);
+ PRINT_REG(rdi);
+ PRINT_REG(rsi);
+ PRINT_REG(rbp);
+ PRINT_REG(rsp);
+#undef PRINT_REG
+ // Print some words near top of staack.
+ int* dump_sp = (int*) rsp;
+ for (int col1 = 0; col1 < 8; col1++) {
+ tty->print("(rsp+0x%03x) 0x%08x: ", (int)((intptr_t)dump_sp - (intptr_t)rsp), (intptr_t)dump_sp);
+ os::print_location(tty, *dump_sp++);
+ }
+ for (int row = 0; row < 16; row++) {
+ tty->print("(rsp+0x%03x) 0x%08x: ", (int)((intptr_t)dump_sp - (intptr_t)rsp), (intptr_t)dump_sp);
+ for (int col = 0; col < 8; col++) {
+ tty->print(" 0x%08x", *dump_sp++);
+ }
+ tty->cr();
+ }
+ // Print some instructions around pc:
+ Disassembler::decode((address)eip-64, (address)eip);
+ tty->print_cr("--------");
+ Disassembler::decode((address)eip, (address)eip+32);
+}
+
+void MacroAssembler::stop(const char* msg) {
+ ExternalAddress message((address)msg);
+ // push address of message
+ pushptr(message.addr());
+ { Label L; call(L, relocInfo::none); bind(L); } // push eip
+ pusha(); // push registers
+ call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug32)));
+ hlt();
+}
+
+void MacroAssembler::warn(const char* msg) {
+ push_CPU_state();
+
+ ExternalAddress message((address) msg);
+ // push address of message
+ pushptr(message.addr());
+
+ call(RuntimeAddress(CAST_FROM_FN_PTR(address, warning)));
+ addl(rsp, wordSize); // discard argument
+ pop_CPU_state();
+}
+
+void MacroAssembler::print_state() {
+ { Label L; call(L, relocInfo::none); bind(L); } // push eip
+ pusha(); // push registers
+
+ push_CPU_state();
+ call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::print_state32)));
+ pop_CPU_state();
+
+ popa();
+ addl(rsp, wordSize);
+}
+
+#else // _LP64
+
+// 64 bit versions
+
+Address MacroAssembler::as_Address(AddressLiteral adr) {
+ // amd64 always does this as a pc-rel
+ // we can be absolute or disp based on the instruction type
+ // jmp/call are displacements others are absolute
+ assert(!adr.is_lval(), "must be rval");
+ assert(reachable(adr), "must be");
+ return Address((int32_t)(intptr_t)(adr.target() - pc()), adr.target(), adr.reloc());
+
+}
+
+Address MacroAssembler::as_Address(ArrayAddress adr) {
+ AddressLiteral base = adr.base();
+ lea(rscratch1, base);
+ Address index = adr.index();
+ assert(index._disp == 0, "must not have disp"); // maybe it can?
+ Address array(rscratch1, index._index, index._scale, index._disp);
+ return array;
+}
+
+int MacroAssembler::biased_locking_enter(Register lock_reg,
+ Register obj_reg,
+ Register swap_reg,
+ Register tmp_reg,
+ bool swap_reg_contains_mark,
+ Label& done,
+ Label* slow_case,
+ BiasedLockingCounters* counters) {
+ assert(UseBiasedLocking, "why call this otherwise?");
+ assert(swap_reg == rax, "swap_reg must be rax for cmpxchgq");
+ assert(tmp_reg != noreg, "tmp_reg must be supplied");
+ assert_different_registers(lock_reg, obj_reg, swap_reg, tmp_reg);
+ assert(markOopDesc::age_shift == markOopDesc::lock_bits + markOopDesc::biased_lock_bits, "biased locking makes assumptions about bit layout");
+ Address mark_addr (obj_reg, oopDesc::mark_offset_in_bytes());
+ Address saved_mark_addr(lock_reg, 0);
+
+ if (PrintBiasedLockingStatistics && counters == NULL)
+ counters = BiasedLocking::counters();
+
+ // Biased locking
+ // See whether the lock is currently biased toward our thread and
+ // whether the epoch is still valid
+ // Note that the runtime guarantees sufficient alignment of JavaThread
+ // pointers to allow age to be placed into low bits
+ // First check to see whether biasing is even enabled for this object
+ Label cas_label;
+ int null_check_offset = -1;
+ if (!swap_reg_contains_mark) {
+ null_check_offset = offset();
+ movq(swap_reg, mark_addr);
+ }
+ movq(tmp_reg, swap_reg);
+ andq(tmp_reg, markOopDesc::biased_lock_mask_in_place);
+ cmpq(tmp_reg, markOopDesc::biased_lock_pattern);
+ jcc(Assembler::notEqual, cas_label);
+ // The bias pattern is present in the object's header. Need to check
+ // whether the bias owner and the epoch are both still current.
+ load_prototype_header(tmp_reg, obj_reg);
+ orq(tmp_reg, r15_thread);
+ xorq(tmp_reg, swap_reg);
+ andq(tmp_reg, ~((int) markOopDesc::age_mask_in_place));
+ if (counters != NULL) {
+ cond_inc32(Assembler::zero,
+ ExternalAddress((address) counters->anonymously_biased_lock_entry_count_addr()));
+ }
+ jcc(Assembler::equal, done);
+
+ Label try_revoke_bias;
+ Label try_rebias;
+
+ // At this point we know that the header has the bias pattern and
+ // that we are not the bias owner in the current epoch. We need to
+ // figure out more details about the state of the header in order to
+ // know what operations can be legally performed on the object's
+ // header.
+
+ // If the low three bits in the xor result aren't clear, that means
+ // the prototype header is no longer biased and we have to revoke
+ // the bias on this object.
+ testq(tmp_reg, markOopDesc::biased_lock_mask_in_place);
+ jcc(Assembler::notZero, try_revoke_bias);
+
+ // Biasing is still enabled for this data type. See whether the
+ // epoch of the current bias is still valid, meaning that the epoch
+ // bits of the mark word are equal to the epoch bits of the
+ // prototype header. (Note that the prototype header's epoch bits
+ // only change at a safepoint.) If not, attempt to rebias the object
+ // toward the current thread. Note that we must be absolutely sure
+ // that the current epoch is invalid in order to do this because
+ // otherwise the manipulations it performs on the mark word are
+ // illegal.
+ testq(tmp_reg, markOopDesc::epoch_mask_in_place);
+ jcc(Assembler::notZero, try_rebias);
+
+ // The epoch of the current bias is still valid but we know nothing
+ // about the owner; it might be set or it might be clear. Try to
+ // acquire the bias of the object using an atomic operation. If this
+ // fails we will go in to the runtime to revoke the object's bias.
+ // Note that we first construct the presumed unbiased header so we
+ // don't accidentally blow away another thread's valid bias.
+ andq(swap_reg,
+ markOopDesc::biased_lock_mask_in_place | markOopDesc::age_mask_in_place | markOopDesc::epoch_mask_in_place);
+ movq(tmp_reg, swap_reg);
+ orq(tmp_reg, r15_thread);
+ if (os::is_MP()) {
+ lock();
+ }
+ cmpxchgq(tmp_reg, Address(obj_reg, 0));
+ // If the biasing toward our thread failed, this means that
+ // another thread succeeded in biasing it toward itself and we
+ // need to revoke that bias. The revocation will occur in the
+ // interpreter runtime in the slow case.
+ if (counters != NULL) {
+ cond_inc32(Assembler::zero,
+ ExternalAddress((address) counters->anonymously_biased_lock_entry_count_addr()));
+ }
+ if (slow_case != NULL) {
+ jcc(Assembler::notZero, *slow_case);
+ }
+ jmp(done);
+
+ bind(try_rebias);
+ // At this point we know the epoch has expired, meaning that the
+ // current "bias owner", if any, is actually invalid. Under these
+ // circumstances _only_, we are allowed to use the current header's
+ // value as the comparison value when doing the cas to acquire the
+ // bias in the current epoch. In other words, we allow transfer of
+ // the bias from one thread to another directly in this situation.
+ //
+ // FIXME: due to a lack of registers we currently blow away the age
+ // bits in this situation. Should attempt to preserve them.
+ load_prototype_header(tmp_reg, obj_reg);
+ orq(tmp_reg, r15_thread);
+ if (os::is_MP()) {
+ lock();
+ }
+ cmpxchgq(tmp_reg, Address(obj_reg, 0));
+ // If the biasing toward our thread failed, then another thread
+ // succeeded in biasing it toward itself and we need to revoke that
+ // bias. The revocation will occur in the runtime in the slow case.
+ if (counters != NULL) {
+ cond_inc32(Assembler::zero,
+ ExternalAddress((address) counters->rebiased_lock_entry_count_addr()));
+ }
+ if (slow_case != NULL) {
+ jcc(Assembler::notZero, *slow_case);
+ }
+ jmp(done);
+
+ bind(try_revoke_bias);
+ // The prototype mark in the klass doesn't have the bias bit set any
+ // more, indicating that objects of this data type are not supposed
+ // to be biased any more. We are going to try to reset the mark of
+ // this object to the prototype value and fall through to the
+ // CAS-based locking scheme. Note that if our CAS fails, it means
+ // that another thread raced us for the privilege of revoking the
+ // bias of this particular object, so it's okay to continue in the
+ // normal locking code.
+ //
+ // FIXME: due to a lack of registers we currently blow away the age
+ // bits in this situation. Should attempt to preserve them.
+ load_prototype_header(tmp_reg, obj_reg);
+ if (os::is_MP()) {
+ lock();
+ }
+ cmpxchgq(tmp_reg, Address(obj_reg, 0));
+ // Fall through to the normal CAS-based lock, because no matter what
+ // the result of the above CAS, some thread must have succeeded in
+ // removing the bias bit from the object's header.
+ if (counters != NULL) {
+ cond_inc32(Assembler::zero,
+ ExternalAddress((address) counters->revoked_lock_entry_count_addr()));
+ }
+
+ bind(cas_label);
+
+ return null_check_offset;
+}
+
+void MacroAssembler::call_VM_leaf_base(address entry_point, int num_args) {
+ Label L, E;
+
+#ifdef _WIN64
+ // Windows always allocates space for it's register args
+ assert(num_args <= 4, "only register arguments supported");
+ subq(rsp, frame::arg_reg_save_area_bytes);
+#endif
+
+ // Align stack if necessary
+ testl(rsp, 15);
+ jcc(Assembler::zero, L);
+
+ subq(rsp, 8);
+ {
+ call(RuntimeAddress(entry_point));
+ }
+ addq(rsp, 8);
+ jmp(E);
+
+ bind(L);
+ {
+ call(RuntimeAddress(entry_point));
+ }
+
+ bind(E);
+
+#ifdef _WIN64
+ // restore stack pointer
+ addq(rsp, frame::arg_reg_save_area_bytes);
+#endif
+
+}
+
+void MacroAssembler::cmp64(Register src1, AddressLiteral src2) {
+ assert(!src2.is_lval(), "should use cmpptr");
+
+ if (reachable(src2)) {
+ cmpq(src1, as_Address(src2));
+ } else {
+ lea(rscratch1, src2);
+ Assembler::cmpq(src1, Address(rscratch1, 0));
+ }
+}
+
+int MacroAssembler::corrected_idivq(Register reg) {
+ // Full implementation of Java ldiv and lrem; checks for special
+ // case as described in JVM spec., p.243 & p.271. The function
+ // returns the (pc) offset of the idivl instruction - may be needed
+ // for implicit exceptions.
+ //
+ // normal case special case
+ //
+ // input : rax: dividend min_long
+ // reg: divisor (may not be eax/edx) -1
+ //
+ // output: rax: quotient (= rax idiv reg) min_long
+ // rdx: remainder (= rax irem reg) 0
+ assert(reg != rax && reg != rdx, "reg cannot be rax or rdx register");
+ static const int64_t min_long = 0x8000000000000000;
+ Label normal_case, special_case;
+
+ // check for special case
+ cmp64(rax, ExternalAddress((address) &min_long));
+ jcc(Assembler::notEqual, normal_case);
+ xorl(rdx, rdx); // prepare rdx for possible special case (where
+ // remainder = 0)
+ cmpq(reg, -1);
+ jcc(Assembler::equal, special_case);
+
+ // handle normal case
+ bind(normal_case);
+ cdqq();
+ int idivq_offset = offset();
+ idivq(reg);
+
+ // normal and special case exit
+ bind(special_case);
+
+ return idivq_offset;
+}
+
+void MacroAssembler::decrementq(Register reg, int value) {
+ if (value == min_jint) { subq(reg, value); return; }
+ if (value < 0) { incrementq(reg, -value); return; }
+ if (value == 0) { ; return; }
+ if (value == 1 && UseIncDec) { decq(reg) ; return; }
+ /* else */ { subq(reg, value) ; return; }
+}
+
+void MacroAssembler::decrementq(Address dst, int value) {
+ if (value == min_jint) { subq(dst, value); return; }
+ if (value < 0) { incrementq(dst, -value); return; }
+ if (value == 0) { ; return; }
+ if (value == 1 && UseIncDec) { decq(dst) ; return; }
+ /* else */ { subq(dst, value) ; return; }
+}
+
+void MacroAssembler::incrementq(Register reg, int value) {
+ if (value == min_jint) { addq(reg, value); return; }
+ if (value < 0) { decrementq(reg, -value); return; }
+ if (value == 0) { ; return; }
+ if (value == 1 && UseIncDec) { incq(reg) ; return; }
+ /* else */ { addq(reg, value) ; return; }
+}
+
+void MacroAssembler::incrementq(Address dst, int value) {
+ if (value == min_jint) { addq(dst, value); return; }
+ if (value < 0) { decrementq(dst, -value); return; }
+ if (value == 0) { ; return; }
+ if (value == 1 && UseIncDec) { incq(dst) ; return; }
+ /* else */ { addq(dst, value) ; return; }
+}
+
+// 32bit can do a case table jump in one instruction but we no longer allow the base
+// to be installed in the Address class
+void MacroAssembler::jump(ArrayAddress entry) {
+ lea(rscratch1, entry.base());
+ Address dispatch = entry.index();
+ assert(dispatch._base == noreg, "must be");
+ dispatch._base = rscratch1;
+ jmp(dispatch);
+}
+
+void MacroAssembler::lcmp2int(Register x_hi, Register x_lo, Register y_hi, Register y_lo) {
+ ShouldNotReachHere(); // 64bit doesn't use two regs
+ cmpq(x_lo, y_lo);
+}
+
+void MacroAssembler::lea(Register dst, AddressLiteral src) {
+ mov_literal64(dst, (intptr_t)src.target(), src.rspec());
+}
+
+void MacroAssembler::lea(Address dst, AddressLiteral adr) {
+ mov_literal64(rscratch1, (intptr_t)adr.target(), adr.rspec());
+ movptr(dst, rscratch1);
+}
+
+void MacroAssembler::leave() {
+ // %%% is this really better? Why not on 32bit too?
+ emit_int8((unsigned char)0xC9); // LEAVE
+}
+
+void MacroAssembler::lneg(Register hi, Register lo) {
+ ShouldNotReachHere(); // 64bit doesn't use two regs
+ negq(lo);
+}
+
+void MacroAssembler::movoop(Register dst, jobject obj) {
+ mov_literal64(dst, (intptr_t)obj, oop_Relocation::spec_for_immediate());
+}
+
+void MacroAssembler::movoop(Address dst, jobject obj) {
+ mov_literal64(rscratch1, (intptr_t)obj, oop_Relocation::spec_for_immediate());
+ movq(dst, rscratch1);
+}
+
+void MacroAssembler::mov_metadata(Register dst, Metadata* obj) {
+ mov_literal64(dst, (intptr_t)obj, metadata_Relocation::spec_for_immediate());
+}
+
+void MacroAssembler::mov_metadata(Address dst, Metadata* obj) {
+ mov_literal64(rscratch1, (intptr_t)obj, metadata_Relocation::spec_for_immediate());
+ movq(dst, rscratch1);
+}
+
+void MacroAssembler::movptr(Register dst, AddressLiteral src) {
+ if (src.is_lval()) {
+ mov_literal64(dst, (intptr_t)src.target(), src.rspec());
+ } else {
+ if (reachable(src)) {
+ movq(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ movq(dst, Address(rscratch1,0));
+ }
+ }
+}
+
+void MacroAssembler::movptr(ArrayAddress dst, Register src) {
+ movq(as_Address(dst), src);
+}
+
+void MacroAssembler::movptr(Register dst, ArrayAddress src) {
+ movq(dst, as_Address(src));
+}
+
+// src should NEVER be a real pointer. Use AddressLiteral for true pointers
+void MacroAssembler::movptr(Address dst, intptr_t src) {
+ mov64(rscratch1, src);
+ movq(dst, rscratch1);
+}
+
+// These are mostly for initializing NULL
+void MacroAssembler::movptr(Address dst, int32_t src) {
+ movslq(dst, src);
+}
+
+void MacroAssembler::movptr(Register dst, int32_t src) {
+ mov64(dst, (intptr_t)src);
+}
+
+void MacroAssembler::pushoop(jobject obj) {
+ movoop(rscratch1, obj);
+ push(rscratch1);
+}
+
+void MacroAssembler::pushklass(Metadata* obj) {
+ mov_metadata(rscratch1, obj);
+ push(rscratch1);
+}
+
+void MacroAssembler::pushptr(AddressLiteral src) {
+ lea(rscratch1, src);
+ if (src.is_lval()) {
+ push(rscratch1);
+ } else {
+ pushq(Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::reset_last_Java_frame(bool clear_fp,
+ bool clear_pc) {
+ // we must set sp to zero to clear frame
+ movptr(Address(r15_thread, JavaThread::last_Java_sp_offset()), NULL_WORD);
+ // must clear fp, so that compiled frames are not confused; it is
+ // possible that we need it only for debugging
+ if (clear_fp) {
+ movptr(Address(r15_thread, JavaThread::last_Java_fp_offset()), NULL_WORD);
+ }
+
+ if (clear_pc) {
+ movptr(Address(r15_thread, JavaThread::last_Java_pc_offset()), NULL_WORD);
+ }
+}
+
+void MacroAssembler::set_last_Java_frame(Register last_java_sp,
+ Register last_java_fp,
+ address last_java_pc) {
+ // determine last_java_sp register
+ if (!last_java_sp->is_valid()) {
+ last_java_sp = rsp;
+ }
+
+ // last_java_fp is optional
+ if (last_java_fp->is_valid()) {
+ movptr(Address(r15_thread, JavaThread::last_Java_fp_offset()),
+ last_java_fp);
+ }
+
+ // last_java_pc is optional
+ if (last_java_pc != NULL) {
+ Address java_pc(r15_thread,
+ JavaThread::frame_anchor_offset() + JavaFrameAnchor::last_Java_pc_offset());
+ lea(rscratch1, InternalAddress(last_java_pc));
+ movptr(java_pc, rscratch1);
+ }
+
+ movptr(Address(r15_thread, JavaThread::last_Java_sp_offset()), last_java_sp);
+}
+
+static void pass_arg0(MacroAssembler* masm, Register arg) {
+ if (c_rarg0 != arg ) {
+ masm->mov(c_rarg0, arg);
+ }
+}
+
+static void pass_arg1(MacroAssembler* masm, Register arg) {
+ if (c_rarg1 != arg ) {
+ masm->mov(c_rarg1, arg);
+ }
+}
+
+static void pass_arg2(MacroAssembler* masm, Register arg) {
+ if (c_rarg2 != arg ) {
+ masm->mov(c_rarg2, arg);
+ }
+}
+
+static void pass_arg3(MacroAssembler* masm, Register arg) {
+ if (c_rarg3 != arg ) {
+ masm->mov(c_rarg3, arg);
+ }
+}
+
+void MacroAssembler::stop(const char* msg) {
+ address rip = pc();
+ pusha(); // get regs on stack
+ lea(c_rarg0, ExternalAddress((address) msg));
+ lea(c_rarg1, InternalAddress(rip));
+ movq(c_rarg2, rsp); // pass pointer to regs array
+ andq(rsp, -16); // align stack as required by ABI
+ call(RuntimeAddress(CAST_FROM_FN_PTR(address, MacroAssembler::debug64)));
+ hlt();
+}
+
+void MacroAssembler::warn(const char* msg) {
+ push(rbp);
+ movq(rbp, rsp);
+ andq(rsp, -16); // align stack as required by push_CPU_state and call
+ push_CPU_state(); // keeps alignment at 16 bytes
+ lea(c_rarg0, ExternalAddress((address) msg));
+ call_VM_leaf(CAST_FROM_FN_PTR(address, warning), c_rarg0);
+ pop_CPU_state();
+ mov(rsp, rbp);
+ pop(rbp);
+}
+
+void MacroAssembler::print_state() {
+ address rip = pc();
+ pusha(); // get regs on stack
+ push(rbp);
+ movq(rbp, rsp);
+ andq(rsp, -16); // align stack as required by push_CPU_state and call
+ push_CPU_state(); // keeps alignment at 16 bytes
+
+ lea(c_rarg0, InternalAddress(rip));
+ lea(c_rarg1, Address(rbp, wordSize)); // pass pointer to regs array
+ call_VM_leaf(CAST_FROM_FN_PTR(address, MacroAssembler::print_state64), c_rarg0, c_rarg1);
+
+ pop_CPU_state();
+ mov(rsp, rbp);
+ pop(rbp);
+ popa();
+}
+
+#ifndef PRODUCT
+extern "C" void findpc(intptr_t x);
+#endif
+
+void MacroAssembler::debug64(char* msg, int64_t pc, int64_t regs[]) {
+ // In order to get locks to work, we need to fake a in_VM state
+ if (ShowMessageBoxOnError) {
+ JavaThread* thread = JavaThread::current();
+ JavaThreadState saved_state = thread->thread_state();
+ thread->set_thread_state(_thread_in_vm);
+#ifndef PRODUCT
+ if (CountBytecodes || TraceBytecodes || StopInterpreterAt) {
+ ttyLocker ttyl;
+ BytecodeCounter::print();
+ }
+#endif
+ // To see where a verify_oop failed, get $ebx+40/X for this frame.
+ // XXX correct this offset for amd64
+ // This is the value of eip which points to where verify_oop will return.
+ if (os::message_box(msg, "Execution stopped, print registers?")) {
+ print_state64(pc, regs);
+ BREAKPOINT;
+ assert(false, "start up GDB");
+ }
+ ThreadStateTransition::transition(thread, _thread_in_vm, saved_state);
+ } else {
+ ttyLocker ttyl;
+ ::tty->print_cr("=============== DEBUG MESSAGE: %s ================\n",
+ msg);
+ assert(false, err_msg("DEBUG MESSAGE: %s", msg));
+ }
+}
+
+void MacroAssembler::print_state64(int64_t pc, int64_t regs[]) {
+ ttyLocker ttyl;
+ FlagSetting fs(Debugging, true);
+ tty->print_cr("rip = 0x%016lx", pc);
+#ifndef PRODUCT
+ tty->cr();
+ findpc(pc);
+ tty->cr();
+#endif
+#define PRINT_REG(rax, value) \
+ { tty->print("%s = ", #rax); os::print_location(tty, value); }
+ PRINT_REG(rax, regs[15]);
+ PRINT_REG(rbx, regs[12]);
+ PRINT_REG(rcx, regs[14]);
+ PRINT_REG(rdx, regs[13]);
+ PRINT_REG(rdi, regs[8]);
+ PRINT_REG(rsi, regs[9]);
+ PRINT_REG(rbp, regs[10]);
+ PRINT_REG(rsp, regs[11]);
+ PRINT_REG(r8 , regs[7]);
+ PRINT_REG(r9 , regs[6]);
+ PRINT_REG(r10, regs[5]);
+ PRINT_REG(r11, regs[4]);
+ PRINT_REG(r12, regs[3]);
+ PRINT_REG(r13, regs[2]);
+ PRINT_REG(r14, regs[1]);
+ PRINT_REG(r15, regs[0]);
+#undef PRINT_REG
+ // Print some words near top of staack.
+ int64_t* rsp = (int64_t*) regs[11];
+ int64_t* dump_sp = rsp;
+ for (int col1 = 0; col1 < 8; col1++) {
+ tty->print("(rsp+0x%03x) 0x%016lx: ", (int)((intptr_t)dump_sp - (intptr_t)rsp), (int64_t)dump_sp);
+ os::print_location(tty, *dump_sp++);
+ }
+ for (int row = 0; row < 25; row++) {
+ tty->print("(rsp+0x%03x) 0x%016lx: ", (int)((intptr_t)dump_sp - (intptr_t)rsp), (int64_t)dump_sp);
+ for (int col = 0; col < 4; col++) {
+ tty->print(" 0x%016lx", *dump_sp++);
+ }
+ tty->cr();
+ }
+ // Print some instructions around pc:
+ Disassembler::decode((address)pc-64, (address)pc);
+ tty->print_cr("--------");
+ Disassembler::decode((address)pc, (address)pc+32);
+}
+
+#endif // _LP64
+
+// Now versions that are common to 32/64 bit
+
+void MacroAssembler::addptr(Register dst, int32_t imm32) {
+ LP64_ONLY(addq(dst, imm32)) NOT_LP64(addl(dst, imm32));
+}
+
+void MacroAssembler::addptr(Register dst, Register src) {
+ LP64_ONLY(addq(dst, src)) NOT_LP64(addl(dst, src));
+}
+
+void MacroAssembler::addptr(Address dst, Register src) {
+ LP64_ONLY(addq(dst, src)) NOT_LP64(addl(dst, src));
+}
+
+void MacroAssembler::addsd(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::addsd(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::addsd(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::addss(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ addss(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ addss(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::align(int modulus) {
+ if (offset() % modulus != 0) {
+ nop(modulus - (offset() % modulus));
+ }
+}
+
+void MacroAssembler::andpd(XMMRegister dst, AddressLiteral src) {
+ // Used in sign-masking with aligned address.
+ assert((UseAVX > 0) || (((intptr_t)src.target() & 15) == 0), "SSE mode requires address alignment 16 bytes");
+ if (reachable(src)) {
+ Assembler::andpd(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::andpd(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::andps(XMMRegister dst, AddressLiteral src) {
+ // Used in sign-masking with aligned address.
+ assert((UseAVX > 0) || (((intptr_t)src.target() & 15) == 0), "SSE mode requires address alignment 16 bytes");
+ if (reachable(src)) {
+ Assembler::andps(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::andps(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::andptr(Register dst, int32_t imm32) {
+ LP64_ONLY(andq(dst, imm32)) NOT_LP64(andl(dst, imm32));
+}
+
+void MacroAssembler::atomic_incl(AddressLiteral counter_addr) {
+ pushf();
+ if (os::is_MP())
+ lock();
+ incrementl(counter_addr);
+ popf();
+}
+
+// Writes to stack successive pages until offset reached to check for
+// stack overflow + shadow pages. This clobbers tmp.
+void MacroAssembler::bang_stack_size(Register size, Register tmp) {
+ movptr(tmp, rsp);
+ // Bang stack for total size given plus shadow page size.
+ // Bang one page at a time because large size can bang beyond yellow and
+ // red zones.
+ Label loop;
+ bind(loop);
+ movl(Address(tmp, (-os::vm_page_size())), size );
+ subptr(tmp, os::vm_page_size());
+ subl(size, os::vm_page_size());
+ jcc(Assembler::greater, loop);
+
+ // Bang down shadow pages too.
+ // The -1 because we already subtracted 1 page.
+ for (int i = 0; i< StackShadowPages-1; i++) {
+ // this could be any sized move but this is can be a debugging crumb
+ // so the bigger the better.
+ movptr(Address(tmp, (-i*os::vm_page_size())), size );
+ }
+}
+
+void MacroAssembler::biased_locking_exit(Register obj_reg, Register temp_reg, Label& done) {
+ assert(UseBiasedLocking, "why call this otherwise?");
+
+ // Check for biased locking unlock case, which is a no-op
+ // Note: we do not have to check the thread ID for two reasons.
+ // First, the interpreter checks for IllegalMonitorStateException at
+ // a higher level. Second, if the bias was revoked while we held the
+ // lock, the object could not be rebiased toward another thread, so
+ // the bias bit would be clear.
+ movptr(temp_reg, Address(obj_reg, oopDesc::mark_offset_in_bytes()));
+ andptr(temp_reg, markOopDesc::biased_lock_mask_in_place);
+ cmpptr(temp_reg, markOopDesc::biased_lock_pattern);
+ jcc(Assembler::equal, done);
+}
+
+void MacroAssembler::c2bool(Register x) {
+ // implements x == 0 ? 0 : 1
+ // note: must only look at least-significant byte of x
+ // since C-style booleans are stored in one byte
+ // only! (was bug)
+ andl(x, 0xFF);
+ setb(Assembler::notZero, x);
+}
+
+// Wouldn't need if AddressLiteral version had new name
+void MacroAssembler::call(Label& L, relocInfo::relocType rtype) {
+ Assembler::call(L, rtype);
+}
+
+void MacroAssembler::call(Register entry) {
+ Assembler::call(entry);
+}
+
+void MacroAssembler::call(AddressLiteral entry) {
+ if (reachable(entry)) {
+ Assembler::call_literal(entry.target(), entry.rspec());
+ } else {
+ lea(rscratch1, entry);
+ Assembler::call(rscratch1);
+ }
+}
+
+void MacroAssembler::ic_call(address entry) {
+ RelocationHolder rh = virtual_call_Relocation::spec(pc());
+ movptr(rax, (intptr_t)Universe::non_oop_word());
+ call(AddressLiteral(entry, rh));
+}
+
+// Implementation of call_VM versions
+
+void MacroAssembler::call_VM(Register oop_result,
+ address entry_point,
+ bool check_exceptions) {
+ Label C, E;
+ call(C, relocInfo::none);
+ jmp(E);
+
+ bind(C);
+ call_VM_helper(oop_result, entry_point, 0, check_exceptions);
+ ret(0);
+
+ bind(E);
+}
+
+void MacroAssembler::call_VM(Register oop_result,
+ address entry_point,
+ Register arg_1,
+ bool check_exceptions) {
+ Label C, E;
+ call(C, relocInfo::none);
+ jmp(E);
+
+ bind(C);
+ pass_arg1(this, arg_1);
+ call_VM_helper(oop_result, entry_point, 1, check_exceptions);
+ ret(0);
+
+ bind(E);
+}
+
+void MacroAssembler::call_VM(Register oop_result,
+ address entry_point,
+ Register arg_1,
+ Register arg_2,
+ bool check_exceptions) {
+ Label C, E;
+ call(C, relocInfo::none);
+ jmp(E);
+
+ bind(C);
+
+ LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
+
+ pass_arg2(this, arg_2);
+ pass_arg1(this, arg_1);
+ call_VM_helper(oop_result, entry_point, 2, check_exceptions);
+ ret(0);
+
+ bind(E);
+}
+
+void MacroAssembler::call_VM(Register oop_result,
+ address entry_point,
+ Register arg_1,
+ Register arg_2,
+ Register arg_3,
+ bool check_exceptions) {
+ Label C, E;
+ call(C, relocInfo::none);
+ jmp(E);
+
+ bind(C);
+
+ 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);
+ call_VM_helper(oop_result, entry_point, 3, check_exceptions);
+ ret(0);
+
+ bind(E);
+}
+
+void MacroAssembler::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);
+ call_VM_base(oop_result, thread, last_java_sp, entry_point, number_of_arguments, check_exceptions);
+}
+
+void MacroAssembler::call_VM(Register oop_result,
+ Register last_java_sp,
+ address entry_point,
+ Register arg_1,
+ bool check_exceptions) {
+ pass_arg1(this, arg_1);
+ call_VM(oop_result, last_java_sp, entry_point, 1, check_exceptions);
+}
+
+void MacroAssembler::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);
+ call_VM(oop_result, last_java_sp, entry_point, 2, check_exceptions);
+}
+
+void MacroAssembler::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);
+ 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,
+ address entry_point,
+ int number_of_arguments,
+ bool check_exceptions) {
+ // determine java_thread register
+ if (!java_thread->is_valid()) {
+#ifdef _LP64
+ java_thread = r15_thread;
+#else
+ java_thread = rdi;
+ get_thread(java_thread);
+#endif // LP64
+ }
+ // determine last_java_sp register
+ if (!last_java_sp->is_valid()) {
+ last_java_sp = rsp;
+ }
+ // debugging support
+ assert(number_of_arguments >= 0 , "cannot have negative number of arguments");
+ LP64_ONLY(assert(java_thread == r15_thread, "unexpected register"));
+#ifdef ASSERT
+ // TraceBytecodes does not use r12 but saves it over the call, so don't verify
+ // r12 is the heapbase.
+ LP64_ONLY(if ((UseCompressedOops || UseCompressedKlassPointers) && !TraceBytecodes) verify_heapbase("call_VM_base: heap base corrupted?");)
+#endif // ASSERT
+
+ assert(java_thread != oop_result , "cannot use the same register for java_thread & oop_result");
+ assert(java_thread != last_java_sp, "cannot use the same register for java_thread & last_java_sp");
+
+ // push java thread (becomes first argument of C function)
+
+ NOT_LP64(push(java_thread); number_of_arguments++);
+ LP64_ONLY(mov(c_rarg0, r15_thread));
+
+ // set last Java frame before call
+ assert(last_java_sp != rbp, "can't use ebp/rbp");
+
+ // Only interpreter should have to set fp
+ set_last_Java_frame(java_thread, last_java_sp, rbp, NULL);
+
+ // do the call, remove parameters
+ MacroAssembler::call_VM_leaf_base(entry_point, number_of_arguments);
+
+ // restore the thread (cannot use the pushed argument since arguments
+ // may be overwritten by C code generated by an optimizing compiler);
+ // however can use the register value directly if it is callee saved.
+ if (LP64_ONLY(true ||) java_thread == rdi || java_thread == rsi) {
+ // rdi & rsi (also r15) are callee saved -> nothing to do
+#ifdef ASSERT
+ guarantee(java_thread != rax, "change this code");
+ push(rax);
+ { Label L;
+ get_thread(rax);
+ cmpptr(java_thread, rax);
+ jcc(Assembler::equal, L);
+ STOP("MacroAssembler::call_VM_base: rdi not callee saved?");
+ bind(L);
+ }
+ pop(rax);
+#endif
+ } else {
+ get_thread(java_thread);
+ }
+ // reset last Java frame
+ // Only interpreter should have to clear fp
+ reset_last_Java_frame(java_thread, true, false);
+
+#ifndef CC_INTERP
+ // C++ interp handles this in the interpreter
+ check_and_handle_popframe(java_thread);
+ check_and_handle_earlyret(java_thread);
+#endif /* CC_INTERP */
+
+ if (check_exceptions) {
+ // check for pending exceptions (java_thread is set upon return)
+ cmpptr(Address(java_thread, Thread::pending_exception_offset()), (int32_t) NULL_WORD);
+#ifndef _LP64
+ jump_cc(Assembler::notEqual,
+ RuntimeAddress(StubRoutines::forward_exception_entry()));
+#else
+ // This used to conditionally jump to forward_exception however it is
+ // possible if we relocate that the branch will not reach. So we must jump
+ // around so we can always reach
+
+ Label ok;
+ jcc(Assembler::equal, ok);
+ jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
+ bind(ok);
+#endif // LP64
+ }
+
+ // get oop result if there is one and reset the value in the thread
+ if (oop_result->is_valid()) {
+ get_vm_result(oop_result, java_thread);
+ }
+}
+
+void MacroAssembler::call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions) {
+
+ // Calculate the value for last_Java_sp
+ // somewhat subtle. call_VM does an intermediate call
+ // which places a return address on the stack just under the
+ // stack pointer as the user finsihed with it. This allows
+ // use to retrieve last_Java_pc from last_Java_sp[-1].
+ // On 32bit we then have to push additional args on the stack to accomplish
+ // the actual requested call. On 64bit call_VM only can use register args
+ // so the only extra space is the return address that call_VM created.
+ // This hopefully explains the calculations here.
+
+#ifdef _LP64
+ // We've pushed one address, correct last_Java_sp
+ lea(rax, Address(rsp, wordSize));
+#else
+ lea(rax, Address(rsp, (1 + number_of_arguments) * wordSize));
+#endif // LP64
+
+ call_VM_base(oop_result, noreg, rax, entry_point, number_of_arguments, check_exceptions);
+
+}
+
+void MacroAssembler::call_VM_leaf(address entry_point, int number_of_arguments) {
+ call_VM_leaf_base(entry_point, number_of_arguments);
+}
+
+void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0) {
+ pass_arg0(this, arg_0);
+ call_VM_leaf(entry_point, 1);
+}
+
+void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0, Register arg_1) {
+
+ LP64_ONLY(assert(arg_0 != c_rarg1, "smashed arg"));
+ pass_arg1(this, arg_1);
+ pass_arg0(this, arg_0);
+ call_VM_leaf(entry_point, 2);
+}
+
+void MacroAssembler::call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2) {
+ LP64_ONLY(assert(arg_0 != c_rarg2, "smashed arg"));
+ LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
+ pass_arg2(this, arg_2);
+ LP64_ONLY(assert(arg_0 != c_rarg1, "smashed arg"));
+ pass_arg1(this, arg_1);
+ pass_arg0(this, arg_0);
+ call_VM_leaf(entry_point, 3);
+}
+
+void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0) {
+ pass_arg0(this, arg_0);
+ MacroAssembler::call_VM_leaf_base(entry_point, 1);
+}
+
+void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1) {
+
+ LP64_ONLY(assert(arg_0 != c_rarg1, "smashed arg"));
+ pass_arg1(this, arg_1);
+ pass_arg0(this, arg_0);
+ MacroAssembler::call_VM_leaf_base(entry_point, 2);
+}
+
+void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2) {
+ LP64_ONLY(assert(arg_0 != c_rarg2, "smashed arg"));
+ LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
+ pass_arg2(this, arg_2);
+ LP64_ONLY(assert(arg_0 != c_rarg1, "smashed arg"));
+ pass_arg1(this, arg_1);
+ pass_arg0(this, arg_0);
+ MacroAssembler::call_VM_leaf_base(entry_point, 3);
+}
+
+void MacroAssembler::super_call_VM_leaf(address entry_point, Register arg_0, Register arg_1, Register arg_2, Register arg_3) {
+ LP64_ONLY(assert(arg_0 != c_rarg3, "smashed arg"));
+ 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_0 != c_rarg2, "smashed arg"));
+ LP64_ONLY(assert(arg_1 != c_rarg2, "smashed arg"));
+ pass_arg2(this, arg_2);
+ LP64_ONLY(assert(arg_0 != c_rarg1, "smashed arg"));
+ pass_arg1(this, arg_1);
+ pass_arg0(this, arg_0);
+ MacroAssembler::call_VM_leaf_base(entry_point, 4);
+}
+
+void MacroAssembler::get_vm_result(Register oop_result, Register java_thread) {
+ movptr(oop_result, Address(java_thread, JavaThread::vm_result_offset()));
+ movptr(Address(java_thread, JavaThread::vm_result_offset()), NULL_WORD);
+ verify_oop(oop_result, "broken oop in call_VM_base");
+}
+
+void MacroAssembler::get_vm_result_2(Register metadata_result, Register java_thread) {
+ movptr(metadata_result, Address(java_thread, JavaThread::vm_result_2_offset()));
+ movptr(Address(java_thread, JavaThread::vm_result_2_offset()), NULL_WORD);
+}
+
+void MacroAssembler::check_and_handle_earlyret(Register java_thread) {
+}
+
+void MacroAssembler::check_and_handle_popframe(Register java_thread) {
+}
+
+void MacroAssembler::cmp32(AddressLiteral src1, int32_t imm) {
+ if (reachable(src1)) {
+ cmpl(as_Address(src1), imm);
+ } else {
+ lea(rscratch1, src1);
+ cmpl(Address(rscratch1, 0), imm);
+ }
+}
+
+void MacroAssembler::cmp32(Register src1, AddressLiteral src2) {
+ assert(!src2.is_lval(), "use cmpptr");
+ if (reachable(src2)) {
+ cmpl(src1, as_Address(src2));
+ } else {
+ lea(rscratch1, src2);
+ cmpl(src1, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::cmp32(Register src1, int32_t imm) {
+ Assembler::cmpl(src1, imm);
+}
+
+void MacroAssembler::cmp32(Register src1, Address src2) {
+ Assembler::cmpl(src1, src2);
+}
+
+void MacroAssembler::cmpsd2int(XMMRegister opr1, XMMRegister opr2, Register dst, bool unordered_is_less) {
+ ucomisd(opr1, opr2);
+
+ Label L;
+ if (unordered_is_less) {
+ movl(dst, -1);
+ jcc(Assembler::parity, L);
+ jcc(Assembler::below , L);
+ movl(dst, 0);
+ jcc(Assembler::equal , L);
+ increment(dst);
+ } else { // unordered is greater
+ movl(dst, 1);
+ jcc(Assembler::parity, L);
+ jcc(Assembler::above , L);
+ movl(dst, 0);
+ jcc(Assembler::equal , L);
+ decrementl(dst);
+ }
+ bind(L);
+}
+
+void MacroAssembler::cmpss2int(XMMRegister opr1, XMMRegister opr2, Register dst, bool unordered_is_less) {
+ ucomiss(opr1, opr2);
+
+ Label L;
+ if (unordered_is_less) {
+ movl(dst, -1);
+ jcc(Assembler::parity, L);
+ jcc(Assembler::below , L);
+ movl(dst, 0);
+ jcc(Assembler::equal , L);
+ increment(dst);
+ } else { // unordered is greater
+ movl(dst, 1);
+ jcc(Assembler::parity, L);
+ jcc(Assembler::above , L);
+ movl(dst, 0);
+ jcc(Assembler::equal , L);
+ decrementl(dst);
+ }
+ bind(L);
+}
+
+
+void MacroAssembler::cmp8(AddressLiteral src1, int imm) {
+ if (reachable(src1)) {
+ cmpb(as_Address(src1), imm);
+ } else {
+ lea(rscratch1, src1);
+ cmpb(Address(rscratch1, 0), imm);
+ }
+}
+
+void MacroAssembler::cmpptr(Register src1, AddressLiteral src2) {
+#ifdef _LP64
+ if (src2.is_lval()) {
+ movptr(rscratch1, src2);
+ Assembler::cmpq(src1, rscratch1);
+ } else if (reachable(src2)) {
+ cmpq(src1, as_Address(src2));
+ } else {
+ lea(rscratch1, src2);
+ Assembler::cmpq(src1, Address(rscratch1, 0));
+ }
+#else
+ if (src2.is_lval()) {
+ cmp_literal32(src1, (int32_t) src2.target(), src2.rspec());
+ } else {
+ cmpl(src1, as_Address(src2));
+ }
+#endif // _LP64
+}
+
+void MacroAssembler::cmpptr(Address src1, AddressLiteral src2) {
+ assert(src2.is_lval(), "not a mem-mem compare");
+#ifdef _LP64
+ // moves src2's literal address
+ movptr(rscratch1, src2);
+ Assembler::cmpq(src1, rscratch1);
+#else
+ cmp_literal32(src1, (int32_t) src2.target(), src2.rspec());
+#endif // _LP64
+}
+
+void MacroAssembler::locked_cmpxchgptr(Register reg, AddressLiteral adr) {
+ if (reachable(adr)) {
+ if (os::is_MP())
+ lock();
+ cmpxchgptr(reg, as_Address(adr));
+ } else {
+ lea(rscratch1, adr);
+ if (os::is_MP())
+ lock();
+ cmpxchgptr(reg, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::cmpxchgptr(Register reg, Address adr) {
+ LP64_ONLY(cmpxchgq(reg, adr)) NOT_LP64(cmpxchgl(reg, adr));
+}
+
+void MacroAssembler::comisd(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::comisd(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::comisd(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::comiss(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::comiss(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::comiss(dst, Address(rscratch1, 0));
+ }
+}
+
+
+void MacroAssembler::cond_inc32(Condition cond, AddressLiteral counter_addr) {
+ Condition negated_cond = negate_condition(cond);
+ Label L;
+ jcc(negated_cond, L);
+ atomic_incl(counter_addr);
+ bind(L);
+}
+
+int MacroAssembler::corrected_idivl(Register reg) {
+ // Full implementation of Java idiv and irem; checks for
+ // special case as described in JVM spec., p.243 & p.271.
+ // The function returns the (pc) offset of the idivl
+ // instruction - may be needed for implicit exceptions.
+ //
+ // normal case special case
+ //
+ // input : rax,: dividend min_int
+ // reg: divisor (may not be rax,/rdx) -1
+ //
+ // output: rax,: quotient (= rax, idiv reg) min_int
+ // rdx: remainder (= rax, irem reg) 0
+ assert(reg != rax && reg != rdx, "reg cannot be rax, or rdx register");
+ const int min_int = 0x80000000;
+ Label normal_case, special_case;
+
+ // check for special case
+ cmpl(rax, min_int);
+ jcc(Assembler::notEqual, normal_case);
+ xorl(rdx, rdx); // prepare rdx for possible special case (where remainder = 0)
+ cmpl(reg, -1);
+ jcc(Assembler::equal, special_case);
+
+ // handle normal case
+ bind(normal_case);
+ cdql();
+ int idivl_offset = offset();
+ idivl(reg);
+
+ // normal and special case exit
+ bind(special_case);
+
+ return idivl_offset;
+}
+
+
+
+void MacroAssembler::decrementl(Register reg, int value) {
+ if (value == min_jint) {subl(reg, value) ; return; }
+ if (value < 0) { incrementl(reg, -value); return; }
+ if (value == 0) { ; return; }
+ if (value == 1 && UseIncDec) { decl(reg) ; return; }
+ /* else */ { subl(reg, value) ; return; }
+}
+
+void MacroAssembler::decrementl(Address dst, int value) {
+ if (value == min_jint) {subl(dst, value) ; return; }
+ if (value < 0) { incrementl(dst, -value); return; }
+ if (value == 0) { ; return; }
+ if (value == 1 && UseIncDec) { decl(dst) ; return; }
+ /* else */ { subl(dst, value) ; return; }
+}
+
+void MacroAssembler::division_with_shift (Register reg, int shift_value) {
+ assert (shift_value > 0, "illegal shift value");
+ Label _is_positive;
+ testl (reg, reg);
+ jcc (Assembler::positive, _is_positive);
+ int offset = (1 << shift_value) - 1 ;
+
+ if (offset == 1) {
+ incrementl(reg);
+ } else {
+ addl(reg, offset);
+ }
+
+ bind (_is_positive);
+ sarl(reg, shift_value);
+}
+
+void MacroAssembler::divsd(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::divsd(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::divsd(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::divss(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::divss(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::divss(dst, Address(rscratch1, 0));
+ }
+}
+
+// !defined(COMPILER2) is because of stupid core builds
+#if !defined(_LP64) || defined(COMPILER1) || !defined(COMPILER2)
+void MacroAssembler::empty_FPU_stack() {
+ if (VM_Version::supports_mmx()) {
+ emms();
+ } else {
+ for (int i = 8; i-- > 0; ) ffree(i);
+ }
+}
+#endif // !LP64 || C1 || !C2
+
+
+// Defines obj, preserves var_size_in_bytes
+void MacroAssembler::eden_allocate(Register obj,
+ Register var_size_in_bytes,
+ int con_size_in_bytes,
+ Register t1,
+ Label& slow_case) {
+ assert(obj == rax, "obj must be in rax, for cmpxchg");
+ assert_different_registers(obj, var_size_in_bytes, t1);
+ if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) {
+ jmp(slow_case);
+ } else {
+ Register end = t1;
+ Label retry;
+ bind(retry);
+ ExternalAddress heap_top((address) Universe::heap()->top_addr());
+ movptr(obj, heap_top);
+ if (var_size_in_bytes == noreg) {
+ lea(end, Address(obj, con_size_in_bytes));
+ } else {
+ lea(end, Address(obj, var_size_in_bytes, Address::times_1));
+ }
+ // if end < obj then we wrapped around => object too long => slow case
+ cmpptr(end, obj);
+ jcc(Assembler::below, slow_case);
+ cmpptr(end, ExternalAddress((address) Universe::heap()->end_addr()));
+ jcc(Assembler::above, slow_case);
+ // Compare obj with the top addr, and if still equal, store the new top addr in
+ // end at the address of the top addr pointer. Sets ZF if was equal, and clears
+ // it otherwise. Use lock prefix for atomicity on MPs.
+ locked_cmpxchgptr(end, heap_top);
+ jcc(Assembler::notEqual, retry);
+ }
+}
+
+void MacroAssembler::enter() {
+ push(rbp);
+ mov(rbp, rsp);
+}
+
+// A 5 byte nop that is safe for patching (see patch_verified_entry)
+void MacroAssembler::fat_nop() {
+ if (UseAddressNop) {
+ addr_nop_5();
+ } else {
+ emit_int8(0x26); // es:
+ emit_int8(0x2e); // cs:
+ emit_int8(0x64); // fs:
+ emit_int8(0x65); // gs:
+ emit_int8((unsigned char)0x90);
+ }
+}
+
+void MacroAssembler::fcmp(Register tmp) {
+ fcmp(tmp, 1, true, true);
+}
+
+void MacroAssembler::fcmp(Register tmp, int index, bool pop_left, bool pop_right) {
+ assert(!pop_right || pop_left, "usage error");
+ if (VM_Version::supports_cmov()) {
+ assert(tmp == noreg, "unneeded temp");
+ if (pop_left) {
+ fucomip(index);
+ } else {
+ fucomi(index);
+ }
+ if (pop_right) {
+ fpop();
+ }
+ } else {
+ assert(tmp != noreg, "need temp");
+ if (pop_left) {
+ if (pop_right) {
+ fcompp();
+ } else {
+ fcomp(index);
+ }
+ } else {
+ fcom(index);
+ }
+ // convert FPU condition into eflags condition via rax,
+ save_rax(tmp);
+ fwait(); fnstsw_ax();
+ sahf();
+ restore_rax(tmp);
+ }
+ // condition codes set as follows:
+ //
+ // CF (corresponds to C0) if x < y
+ // PF (corresponds to C2) if unordered
+ // ZF (corresponds to C3) if x = y
+}
+
+void MacroAssembler::fcmp2int(Register dst, bool unordered_is_less) {
+ fcmp2int(dst, unordered_is_less, 1, true, true);
+}
+
+void MacroAssembler::fcmp2int(Register dst, bool unordered_is_less, int index, bool pop_left, bool pop_right) {
+ fcmp(VM_Version::supports_cmov() ? noreg : dst, index, pop_left, pop_right);
+ Label L;
+ if (unordered_is_less) {
+ movl(dst, -1);
+ jcc(Assembler::parity, L);
+ jcc(Assembler::below , L);
+ movl(dst, 0);
+ jcc(Assembler::equal , L);
+ increment(dst);
+ } else { // unordered is greater
+ movl(dst, 1);
+ jcc(Assembler::parity, L);
+ jcc(Assembler::above , L);
+ movl(dst, 0);
+ jcc(Assembler::equal , L);
+ decrementl(dst);
+ }
+ bind(L);
+}
+
+void MacroAssembler::fld_d(AddressLiteral src) {
+ fld_d(as_Address(src));
+}
+
+void MacroAssembler::fld_s(AddressLiteral src) {
+ fld_s(as_Address(src));
+}
+
+void MacroAssembler::fld_x(AddressLiteral src) {
+ Assembler::fld_x(as_Address(src));
+}
+
+void MacroAssembler::fldcw(AddressLiteral src) {
+ Assembler::fldcw(as_Address(src));
+}
+
+void MacroAssembler::pow_exp_core_encoding() {
+ // kills rax, rcx, rdx
+ subptr(rsp,sizeof(jdouble));
+ // computes 2^X. Stack: X ...
+ // f2xm1 computes 2^X-1 but only operates on -1<=X<=1. Get int(X) and
+ // keep it on the thread's stack to compute 2^int(X) later
+ // then compute 2^(X-int(X)) as (2^(X-int(X)-1+1)
+ // final result is obtained with: 2^X = 2^int(X) * 2^(X-int(X))
+ fld_s(0); // Stack: X X ...
+ frndint(); // Stack: int(X) X ...
+ fsuba(1); // Stack: int(X) X-int(X) ...
+ fistp_s(Address(rsp,0)); // move int(X) as integer to thread's stack. Stack: X-int(X) ...
+ f2xm1(); // Stack: 2^(X-int(X))-1 ...
+ fld1(); // Stack: 1 2^(X-int(X))-1 ...
+ faddp(1); // Stack: 2^(X-int(X))
+ // computes 2^(int(X)): add exponent bias (1023) to int(X), then
+ // shift int(X)+1023 to exponent position.
+ // Exponent is limited to 11 bits if int(X)+1023 does not fit in 11
+ // bits, set result to NaN. 0x000 and 0x7FF are reserved exponent
+ // values so detect them and set result to NaN.
+ movl(rax,Address(rsp,0));
+ movl(rcx, -2048); // 11 bit mask and valid NaN binary encoding
+ addl(rax, 1023);
+ movl(rdx,rax);
+ shll(rax,20);
+ // Check that 0 < int(X)+1023 < 2047. Otherwise set rax to NaN.
+ addl(rdx,1);
+ // Check that 1 < int(X)+1023+1 < 2048
+ // in 3 steps:
+ // 1- (int(X)+1023+1)&-2048 == 0 => 0 <= int(X)+1023+1 < 2048
+ // 2- (int(X)+1023+1)&-2048 != 0
+ // 3- (int(X)+1023+1)&-2048 != 1
+ // Do 2- first because addl just updated the flags.
+ cmov32(Assembler::equal,rax,rcx);
+ cmpl(rdx,1);
+ cmov32(Assembler::equal,rax,rcx);
+ testl(rdx,rcx);
+ cmov32(Assembler::notEqual,rax,rcx);
+ movl(Address(rsp,4),rax);
+ movl(Address(rsp,0),0);
+ fmul_d(Address(rsp,0)); // Stack: 2^X ...
+ addptr(rsp,sizeof(jdouble));
+}
+
+void MacroAssembler::increase_precision() {
+ subptr(rsp, BytesPerWord);
+ fnstcw(Address(rsp, 0));
+ movl(rax, Address(rsp, 0));
+ orl(rax, 0x300);
+ push(rax);
+ fldcw(Address(rsp, 0));
+ pop(rax);
+}
+
+void MacroAssembler::restore_precision() {
+ fldcw(Address(rsp, 0));
+ addptr(rsp, BytesPerWord);
+}
+
+void MacroAssembler::fast_pow() {
+ // computes X^Y = 2^(Y * log2(X))
+ // if fast computation is not possible, result is NaN. Requires
+ // fallback from user of this macro.
+ // increase precision for intermediate steps of the computation
+ increase_precision();
+ fyl2x(); // Stack: (Y*log2(X)) ...
+ pow_exp_core_encoding(); // Stack: exp(X) ...
+ restore_precision();
+}
+
+void MacroAssembler::fast_exp() {
+ // computes exp(X) = 2^(X * log2(e))
+ // if fast computation is not possible, result is NaN. Requires
+ // fallback from user of this macro.
+ // increase precision for intermediate steps of the computation
+ increase_precision();
+ fldl2e(); // Stack: log2(e) X ...
+ fmulp(1); // Stack: (X*log2(e)) ...
+ pow_exp_core_encoding(); // Stack: exp(X) ...
+ restore_precision();
+}
+
+void MacroAssembler::pow_or_exp(bool is_exp, int num_fpu_regs_in_use) {
+ // kills rax, rcx, rdx
+ // pow and exp needs 2 extra registers on the fpu stack.
+ Label slow_case, done;
+ Register tmp = noreg;
+ if (!VM_Version::supports_cmov()) {
+ // fcmp needs a temporary so preserve rdx,
+ tmp = rdx;
+ }
+ Register tmp2 = rax;
+ Register tmp3 = rcx;
+
+ if (is_exp) {
+ // Stack: X
+ fld_s(0); // duplicate argument for runtime call. Stack: X X
+ fast_exp(); // Stack: exp(X) X
+ fcmp(tmp, 0, false, false); // Stack: exp(X) X
+ // exp(X) not equal to itself: exp(X) is NaN go to slow case.
+ jcc(Assembler::parity, slow_case);
+ // get rid of duplicate argument. Stack: exp(X)
+ if (num_fpu_regs_in_use > 0) {
+ fxch();
+ fpop();
+ } else {
+ ffree(1);
+ }
+ jmp(done);
+ } else {
+ // Stack: X Y
+ Label x_negative, y_odd;
+
+ fldz(); // Stack: 0 X Y
+ fcmp(tmp, 1, true, false); // Stack: X Y
+ jcc(Assembler::above, x_negative);
+
+ // X >= 0
+
+ fld_s(1); // duplicate arguments for runtime call. Stack: Y X Y
+ fld_s(1); // Stack: X Y X Y
+ fast_pow(); // Stack: X^Y X Y
+ fcmp(tmp, 0, false, false); // Stack: X^Y X Y
+ // X^Y not equal to itself: X^Y is NaN go to slow case.
+ jcc(Assembler::parity, slow_case);
+ // get rid of duplicate arguments. Stack: X^Y
+ if (num_fpu_regs_in_use > 0) {
+ fxch(); fpop();
+ fxch(); fpop();
+ } else {
+ ffree(2);
+ ffree(1);
+ }
+ jmp(done);
+
+ // X <= 0
+ bind(x_negative);
+
+ fld_s(1); // Stack: Y X Y
+ frndint(); // Stack: int(Y) X Y
+ fcmp(tmp, 2, false, false); // Stack: int(Y) X Y
+ jcc(Assembler::notEqual, slow_case);
+
+ subptr(rsp, 8);
+
+ // For X^Y, when X < 0, Y has to be an integer and the final
+ // result depends on whether it's odd or even. We just checked
+ // that int(Y) == Y. We move int(Y) to gp registers as a 64 bit
+ // integer to test its parity. If int(Y) is huge and doesn't fit
+ // in the 64 bit integer range, the integer indefinite value will
+ // end up in the gp registers. Huge numbers are all even, the
+ // integer indefinite number is even so it's fine.
+
+#ifdef ASSERT
+ // Let's check we don't end up with an integer indefinite number
+ // when not expected. First test for huge numbers: check whether
+ // int(Y)+1 == int(Y) which is true for very large numbers and
+ // those are all even. A 64 bit integer is guaranteed to not
+ // overflow for numbers where y+1 != y (when precision is set to
+ // double precision).
+ Label y_not_huge;
+
+ fld1(); // Stack: 1 int(Y) X Y
+ fadd(1); // Stack: 1+int(Y) int(Y) X Y
+
+#ifdef _LP64
+ // trip to memory to force the precision down from double extended
+ // precision
+ fstp_d(Address(rsp, 0));
+ fld_d(Address(rsp, 0));
+#endif
+
+ fcmp(tmp, 1, true, false); // Stack: int(Y) X Y
+#endif
+
+ // move int(Y) as 64 bit integer to thread's stack
+ fistp_d(Address(rsp,0)); // Stack: X Y
+
+#ifdef ASSERT
+ jcc(Assembler::notEqual, y_not_huge);
+
+ // Y is huge so we know it's even. It may not fit in a 64 bit
+ // integer and we don't want the debug code below to see the
+ // integer indefinite value so overwrite int(Y) on the thread's
+ // stack with 0.
+ movl(Address(rsp, 0), 0);
+ movl(Address(rsp, 4), 0);
+
+ bind(y_not_huge);
+#endif
+
+ fld_s(1); // duplicate arguments for runtime call. Stack: Y X Y
+ fld_s(1); // Stack: X Y X Y
+ fabs(); // Stack: abs(X) Y X Y
+ fast_pow(); // Stack: abs(X)^Y X Y
+ fcmp(tmp, 0, false, false); // Stack: abs(X)^Y X Y
+ // abs(X)^Y not equal to itself: abs(X)^Y is NaN go to slow case.
+
+ pop(tmp2);
+ NOT_LP64(pop(tmp3));
+ jcc(Assembler::parity, slow_case);
+
+#ifdef ASSERT
+ // Check that int(Y) is not integer indefinite value (int
+ // overflow). Shouldn't happen because for values that would
+ // overflow, 1+int(Y)==Y which was tested earlier.
+#ifndef _LP64
+ {
+ Label integer;
+ testl(tmp2, tmp2);
+ jcc(Assembler::notZero, integer);
+ cmpl(tmp3, 0x80000000);
+ jcc(Assembler::notZero, integer);
+ STOP("integer indefinite value shouldn't be seen here");
+ bind(integer);
+ }
+#else
+ {
+ Label integer;
+ mov(tmp3, tmp2); // preserve tmp2 for parity check below
+ shlq(tmp3, 1);
+ jcc(Assembler::carryClear, integer);
+ jcc(Assembler::notZero, integer);
+ STOP("integer indefinite value shouldn't be seen here");
+ bind(integer);
+ }
+#endif
+#endif
+
+ // get rid of duplicate arguments. Stack: X^Y
+ if (num_fpu_regs_in_use > 0) {
+ fxch(); fpop();
+ fxch(); fpop();
+ } else {
+ ffree(2);
+ ffree(1);
+ }
+
+ testl(tmp2, 1);
+ jcc(Assembler::zero, done); // X <= 0, Y even: X^Y = abs(X)^Y
+ // X <= 0, Y even: X^Y = -abs(X)^Y
+
+ fchs(); // Stack: -abs(X)^Y Y
+ jmp(done);
+ }
+
+ // slow case: runtime call
+ bind(slow_case);
+
+ fpop(); // pop incorrect result or int(Y)
+
+ fp_runtime_fallback(is_exp ? CAST_FROM_FN_PTR(address, SharedRuntime::dexp) : CAST_FROM_FN_PTR(address, SharedRuntime::dpow),
+ is_exp ? 1 : 2, num_fpu_regs_in_use);
+
+ // Come here with result in F-TOS
+ bind(done);
+}
+
+void MacroAssembler::fpop() {
+ ffree();
+ fincstp();
+}
+
+void MacroAssembler::fremr(Register tmp) {
+ save_rax(tmp);
+ { Label L;
+ bind(L);
+ fprem();
+ fwait(); fnstsw_ax();
+#ifdef _LP64
+ testl(rax, 0x400);
+ jcc(Assembler::notEqual, L);
+#else
+ sahf();
+ jcc(Assembler::parity, L);
+#endif // _LP64
+ }
+ restore_rax(tmp);
+ // Result is in ST0.
+ // Note: fxch & fpop to get rid of ST1
+ // (otherwise FPU stack could overflow eventually)
+ fxch(1);
+ fpop();
+}
+
+
+void MacroAssembler::incrementl(AddressLiteral dst) {
+ if (reachable(dst)) {
+ incrementl(as_Address(dst));
+ } else {
+ lea(rscratch1, dst);
+ incrementl(Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::incrementl(ArrayAddress dst) {
+ incrementl(as_Address(dst));
+}
+
+void MacroAssembler::incrementl(Register reg, int value) {
+ if (value == min_jint) {addl(reg, value) ; return; }
+ if (value < 0) { decrementl(reg, -value); return; }
+ if (value == 0) { ; return; }
+ if (value == 1 && UseIncDec) { incl(reg) ; return; }
+ /* else */ { addl(reg, value) ; return; }
+}
+
+void MacroAssembler::incrementl(Address dst, int value) {
+ if (value == min_jint) {addl(dst, value) ; return; }
+ if (value < 0) { decrementl(dst, -value); return; }
+ if (value == 0) { ; return; }
+ if (value == 1 && UseIncDec) { incl(dst) ; return; }
+ /* else */ { addl(dst, value) ; return; }
+}
+
+void MacroAssembler::jump(AddressLiteral dst) {
+ if (reachable(dst)) {
+ jmp_literal(dst.target(), dst.rspec());
+ } else {
+ lea(rscratch1, dst);
+ jmp(rscratch1);
+ }
+}
+
+void MacroAssembler::jump_cc(Condition cc, AddressLiteral dst) {
+ if (reachable(dst)) {
+ InstructionMark im(this);
+ relocate(dst.reloc());
+ const int short_size = 2;
+ const int long_size = 6;
+ int offs = (intptr_t)dst.target() - ((intptr_t)pc());
+ if (dst.reloc() == relocInfo::none && is8bit(offs - short_size)) {
+ // 0111 tttn #8-bit disp
+ emit_int8(0x70 | cc);
+ emit_int8((offs - short_size) & 0xFF);
+ } else {
+ // 0000 1111 1000 tttn #32-bit disp
+ emit_int8(0x0F);
+ emit_int8((unsigned char)(0x80 | cc));
+ emit_int32(offs - long_size);
+ }
+ } else {
+#ifdef ASSERT
+ warning("reversing conditional branch");
+#endif /* ASSERT */
+ Label skip;
+ jccb(reverse[cc], skip);
+ lea(rscratch1, dst);
+ Assembler::jmp(rscratch1);
+ bind(skip);
+ }
+}
+
+void MacroAssembler::ldmxcsr(AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::ldmxcsr(as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::ldmxcsr(Address(rscratch1, 0));
+ }
+}
+
+int MacroAssembler::load_signed_byte(Register dst, Address src) {
+ int off;
+ if (LP64_ONLY(true ||) VM_Version::is_P6()) {
+ off = offset();
+ movsbl(dst, src); // movsxb
+ } else {
+ off = load_unsigned_byte(dst, src);
+ shll(dst, 24);
+ sarl(dst, 24);
+ }
+ return off;
+}
+
+// Note: load_signed_short used to be called load_signed_word.
+// Although the 'w' in x86 opcodes refers to the term "word" in the assembler
+// manual, which means 16 bits, that usage is found nowhere in HotSpot code.
+// The term "word" in HotSpot means a 32- or 64-bit machine word.
+int MacroAssembler::load_signed_short(Register dst, Address src) {
+ int off;
+ if (LP64_ONLY(true ||) VM_Version::is_P6()) {
+ // This is dubious to me since it seems safe to do a signed 16 => 64 bit
+ // version but this is what 64bit has always done. This seems to imply
+ // that users are only using 32bits worth.
+ off = offset();
+ movswl(dst, src); // movsxw
+ } else {
+ off = load_unsigned_short(dst, src);
+ shll(dst, 16);
+ sarl(dst, 16);
+ }
+ return off;
+}
+
+int MacroAssembler::load_unsigned_byte(Register dst, Address src) {
+ // According to Intel Doc. AP-526, "Zero-Extension of Short", p.16,
+ // and "3.9 Partial Register Penalties", p. 22).
+ int off;
+ if (LP64_ONLY(true || ) VM_Version::is_P6() || src.uses(dst)) {
+ off = offset();
+ movzbl(dst, src); // movzxb
+ } else {
+ xorl(dst, dst);
+ off = offset();
+ movb(dst, src);
+ }
+ return off;
+}
+
+// Note: load_unsigned_short used to be called load_unsigned_word.
+int MacroAssembler::load_unsigned_short(Register dst, Address src) {
+ // According to Intel Doc. AP-526, "Zero-Extension of Short", p.16,
+ // and "3.9 Partial Register Penalties", p. 22).
+ int off;
+ if (LP64_ONLY(true ||) VM_Version::is_P6() || src.uses(dst)) {
+ off = offset();
+ movzwl(dst, src); // movzxw
+ } else {
+ xorl(dst, dst);
+ off = offset();
+ movw(dst, src);
+ }
+ return off;
+}
+
+void MacroAssembler::load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed, Register dst2) {
+ switch (size_in_bytes) {
+#ifndef _LP64
+ case 8:
+ assert(dst2 != noreg, "second dest register required");
+ movl(dst, src);
+ movl(dst2, src.plus_disp(BytesPerInt));
+ break;
+#else
+ case 8: movq(dst, src); break;
+#endif
+ case 4: movl(dst, src); break;
+ case 2: is_signed ? load_signed_short(dst, src) : load_unsigned_short(dst, src); break;
+ case 1: is_signed ? load_signed_byte( dst, src) : load_unsigned_byte( dst, src); break;
+ default: ShouldNotReachHere();
+ }
+}
+
+void MacroAssembler::store_sized_value(Address dst, Register src, size_t size_in_bytes, Register src2) {
+ switch (size_in_bytes) {
+#ifndef _LP64
+ case 8:
+ assert(src2 != noreg, "second source register required");
+ movl(dst, src);
+ movl(dst.plus_disp(BytesPerInt), src2);
+ break;
+#else
+ case 8: movq(dst, src); break;
+#endif
+ case 4: movl(dst, src); break;
+ case 2: movw(dst, src); break;
+ case 1: movb(dst, src); break;
+ default: ShouldNotReachHere();
+ }
+}
+
+void MacroAssembler::mov32(AddressLiteral dst, Register src) {
+ if (reachable(dst)) {
+ movl(as_Address(dst), src);
+ } else {
+ lea(rscratch1, dst);
+ movl(Address(rscratch1, 0), src);
+ }
+}
+
+void MacroAssembler::mov32(Register dst, AddressLiteral src) {
+ if (reachable(src)) {
+ movl(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ movl(dst, Address(rscratch1, 0));
+ }
+}
+
+// C++ bool manipulation
+
+void MacroAssembler::movbool(Register dst, Address src) {
+ if(sizeof(bool) == 1)
+ movb(dst, src);
+ else if(sizeof(bool) == 2)
+ movw(dst, src);
+ else if(sizeof(bool) == 4)
+ movl(dst, src);
+ else
+ // unsupported
+ ShouldNotReachHere();
+}
+
+void MacroAssembler::movbool(Address dst, bool boolconst) {
+ if(sizeof(bool) == 1)
+ movb(dst, (int) boolconst);
+ else if(sizeof(bool) == 2)
+ movw(dst, (int) boolconst);
+ else if(sizeof(bool) == 4)
+ movl(dst, (int) boolconst);
+ else
+ // unsupported
+ ShouldNotReachHere();
+}
+
+void MacroAssembler::movbool(Address dst, Register src) {
+ if(sizeof(bool) == 1)
+ movb(dst, src);
+ else if(sizeof(bool) == 2)
+ movw(dst, src);
+ else if(sizeof(bool) == 4)
+ movl(dst, src);
+ else
+ // unsupported
+ ShouldNotReachHere();
+}
+
+void MacroAssembler::movbyte(ArrayAddress dst, int src) {
+ movb(as_Address(dst), src);
+}
+
+void MacroAssembler::movdl(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ movdl(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ movdl(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::movq(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ movq(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ movq(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::movdbl(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ if (UseXmmLoadAndClearUpper) {
+ movsd (dst, as_Address(src));
+ } else {
+ movlpd(dst, as_Address(src));
+ }
+ } else {
+ lea(rscratch1, src);
+ if (UseXmmLoadAndClearUpper) {
+ movsd (dst, Address(rscratch1, 0));
+ } else {
+ movlpd(dst, Address(rscratch1, 0));
+ }
+ }
+}
+
+void MacroAssembler::movflt(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ movss(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ movss(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::movptr(Register dst, Register src) {
+ LP64_ONLY(movq(dst, src)) NOT_LP64(movl(dst, src));
+}
+
+void MacroAssembler::movptr(Register dst, Address src) {
+ LP64_ONLY(movq(dst, src)) NOT_LP64(movl(dst, src));
+}
+
+// src should NEVER be a real pointer. Use AddressLiteral for true pointers
+void MacroAssembler::movptr(Register dst, intptr_t src) {
+ LP64_ONLY(mov64(dst, src)) NOT_LP64(movl(dst, src));
+}
+
+void MacroAssembler::movptr(Address dst, Register src) {
+ LP64_ONLY(movq(dst, src)) NOT_LP64(movl(dst, src));
+}
+
+void MacroAssembler::movdqu(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::movdqu(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::movdqu(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::movsd(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::movsd(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::movsd(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::movss(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::movss(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::movss(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::mulsd(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::mulsd(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::mulsd(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::mulss(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::mulss(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::mulss(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::null_check(Register reg, int offset) {
+ if (needs_explicit_null_check(offset)) {
+ // provoke OS NULL exception if reg = NULL by
+ // accessing M[reg] w/o changing any (non-CC) registers
+ // NOTE: cmpl is plenty here to provoke a segv
+ cmpptr(rax, Address(reg, 0));
+ // Note: should probably use testl(rax, Address(reg, 0));
+ // may be shorter code (however, this version of
+ // testl needs to be implemented first)
+ } else {
+ // nothing to do, (later) access of M[reg + offset]
+ // will provoke OS NULL exception if reg = NULL
+ }
+}
+
+void MacroAssembler::os_breakpoint() {
+ // instead of directly emitting a breakpoint, call os:breakpoint for better debugability
+ // (e.g., MSVC can't call ps() otherwise)
+ call(RuntimeAddress(CAST_FROM_FN_PTR(address, os::breakpoint)));
+}
+
+void MacroAssembler::pop_CPU_state() {
+ pop_FPU_state();
+ pop_IU_state();
+}
+
+void MacroAssembler::pop_FPU_state() {
+ NOT_LP64(frstor(Address(rsp, 0));)
+ LP64_ONLY(fxrstor(Address(rsp, 0));)
+ addptr(rsp, FPUStateSizeInWords * wordSize);
+}
+
+void MacroAssembler::pop_IU_state() {
+ popa();
+ LP64_ONLY(addq(rsp, 8));
+ popf();
+}
+
+// Save Integer and Float state
+// Warning: Stack must be 16 byte aligned (64bit)
+void MacroAssembler::push_CPU_state() {
+ push_IU_state();
+ push_FPU_state();
+}
+
+void MacroAssembler::push_FPU_state() {
+ subptr(rsp, FPUStateSizeInWords * wordSize);
+#ifndef _LP64
+ fnsave(Address(rsp, 0));
+ fwait();
+#else
+ fxsave(Address(rsp, 0));
+#endif // LP64
+}
+
+void MacroAssembler::push_IU_state() {
+ // Push flags first because pusha kills them
+ pushf();
+ // Make sure rsp stays 16-byte aligned
+ LP64_ONLY(subq(rsp, 8));
+ pusha();
+}
+
+void MacroAssembler::reset_last_Java_frame(Register java_thread, bool clear_fp, bool clear_pc) {
+ // determine java_thread register
+ if (!java_thread->is_valid()) {
+ java_thread = rdi;
+ get_thread(java_thread);
+ }
+ // we must set sp to zero to clear frame
+ movptr(Address(java_thread, JavaThread::last_Java_sp_offset()), NULL_WORD);
+ if (clear_fp) {
+ movptr(Address(java_thread, JavaThread::last_Java_fp_offset()), NULL_WORD);
+ }
+
+ if (clear_pc)
+ movptr(Address(java_thread, JavaThread::last_Java_pc_offset()), NULL_WORD);
+
+}
+
+void MacroAssembler::restore_rax(Register tmp) {
+ if (tmp == noreg) pop(rax);
+ else if (tmp != rax) mov(rax, tmp);
+}
+
+void MacroAssembler::round_to(Register reg, int modulus) {
+ addptr(reg, modulus - 1);
+ andptr(reg, -modulus);
+}
+
+void MacroAssembler::save_rax(Register tmp) {
+ if (tmp == noreg) push(rax);
+ else if (tmp != rax) mov(tmp, rax);
+}
+
+// Write serialization page so VM thread can do a pseudo remote membar.
+// We use the current thread pointer to calculate a thread specific
+// offset to write to within the page. This minimizes bus traffic
+// due to cache line collision.
+void MacroAssembler::serialize_memory(Register thread, Register tmp) {
+ movl(tmp, thread);
+ shrl(tmp, os::get_serialize_page_shift_count());
+ andl(tmp, (os::vm_page_size() - sizeof(int)));
+
+ Address index(noreg, tmp, Address::times_1);
+ ExternalAddress page(os::get_memory_serialize_page());
+
+ // Size of store must match masking code above
+ movl(as_Address(ArrayAddress(page, index)), tmp);
+}
+
+// Calls to C land
+//
+// When entering C land, the rbp, & rsp of the last Java frame have to be recorded
+// in the (thread-local) JavaThread object. When leaving C land, the last Java fp
+// has to be reset to 0. This is required to allow proper stack traversal.
+void MacroAssembler::set_last_Java_frame(Register java_thread,
+ Register last_java_sp,
+ Register last_java_fp,
+ address last_java_pc) {
+ // determine java_thread register
+ if (!java_thread->is_valid()) {
+ java_thread = rdi;
+ get_thread(java_thread);
+ }
+ // determine last_java_sp register
+ if (!last_java_sp->is_valid()) {
+ last_java_sp = rsp;
+ }
+
+ // last_java_fp is optional
+
+ if (last_java_fp->is_valid()) {
+ movptr(Address(java_thread, JavaThread::last_Java_fp_offset()), last_java_fp);
+ }
+
+ // last_java_pc is optional
+
+ if (last_java_pc != NULL) {
+ lea(Address(java_thread,
+ JavaThread::frame_anchor_offset() + JavaFrameAnchor::last_Java_pc_offset()),
+ InternalAddress(last_java_pc));
+
+ }
+ movptr(Address(java_thread, JavaThread::last_Java_sp_offset()), last_java_sp);
+}
+
+void MacroAssembler::shlptr(Register dst, int imm8) {
+ LP64_ONLY(shlq(dst, imm8)) NOT_LP64(shll(dst, imm8));
+}
+
+void MacroAssembler::shrptr(Register dst, int imm8) {
+ LP64_ONLY(shrq(dst, imm8)) NOT_LP64(shrl(dst, imm8));
+}
+
+void MacroAssembler::sign_extend_byte(Register reg) {
+ if (LP64_ONLY(true ||) (VM_Version::is_P6() && reg->has_byte_register())) {
+ movsbl(reg, reg); // movsxb
+ } else {
+ shll(reg, 24);
+ sarl(reg, 24);
+ }
+}
+
+void MacroAssembler::sign_extend_short(Register reg) {
+ if (LP64_ONLY(true ||) VM_Version::is_P6()) {
+ movswl(reg, reg); // movsxw
+ } else {
+ shll(reg, 16);
+ sarl(reg, 16);
+ }
+}
+
+void MacroAssembler::testl(Register dst, AddressLiteral src) {
+ assert(reachable(src), "Address should be reachable");
+ testl(dst, as_Address(src));
+}
+
+void MacroAssembler::sqrtsd(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::sqrtsd(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::sqrtsd(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::sqrtss(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::sqrtss(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::sqrtss(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::subsd(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::subsd(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::subsd(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::subss(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::subss(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::subss(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::ucomisd(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::ucomisd(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::ucomisd(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::ucomiss(XMMRegister dst, AddressLiteral src) {
+ if (reachable(src)) {
+ Assembler::ucomiss(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::ucomiss(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::xorpd(XMMRegister dst, AddressLiteral src) {
+ // Used in sign-bit flipping with aligned address.
+ assert((UseAVX > 0) || (((intptr_t)src.target() & 15) == 0), "SSE mode requires address alignment 16 bytes");
+ if (reachable(src)) {
+ Assembler::xorpd(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::xorpd(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::xorps(XMMRegister dst, AddressLiteral src) {
+ // Used in sign-bit flipping with aligned address.
+ assert((UseAVX > 0) || (((intptr_t)src.target() & 15) == 0), "SSE mode requires address alignment 16 bytes");
+ if (reachable(src)) {
+ Assembler::xorps(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::xorps(dst, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::pshufb(XMMRegister dst, AddressLiteral src) {
+ // Used in sign-bit flipping with aligned address.
+ bool aligned_adr = (((intptr_t)src.target() & 15) == 0);
+ assert((UseAVX > 0) || aligned_adr, "SSE mode requires address alignment 16 bytes");
+ if (reachable(src)) {
+ Assembler::pshufb(dst, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ Assembler::pshufb(dst, Address(rscratch1, 0));
+ }
+}
+
+// AVX 3-operands instructions
+
+void MacroAssembler::vaddsd(XMMRegister dst, XMMRegister nds, AddressLiteral src) {
+ if (reachable(src)) {
+ vaddsd(dst, nds, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ vaddsd(dst, nds, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::vaddss(XMMRegister dst, XMMRegister nds, AddressLiteral src) {
+ if (reachable(src)) {
+ vaddss(dst, nds, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ vaddss(dst, nds, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::vandpd(XMMRegister dst, XMMRegister nds, AddressLiteral src, bool vector256) {
+ if (reachable(src)) {
+ vandpd(dst, nds, as_Address(src), vector256);
+ } else {
+ lea(rscratch1, src);
+ vandpd(dst, nds, Address(rscratch1, 0), vector256);
+ }
+}
+
+void MacroAssembler::vandps(XMMRegister dst, XMMRegister nds, AddressLiteral src, bool vector256) {
+ if (reachable(src)) {
+ vandps(dst, nds, as_Address(src), vector256);
+ } else {
+ lea(rscratch1, src);
+ vandps(dst, nds, Address(rscratch1, 0), vector256);
+ }
+}
+
+void MacroAssembler::vdivsd(XMMRegister dst, XMMRegister nds, AddressLiteral src) {
+ if (reachable(src)) {
+ vdivsd(dst, nds, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ vdivsd(dst, nds, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::vdivss(XMMRegister dst, XMMRegister nds, AddressLiteral src) {
+ if (reachable(src)) {
+ vdivss(dst, nds, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ vdivss(dst, nds, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::vmulsd(XMMRegister dst, XMMRegister nds, AddressLiteral src) {
+ if (reachable(src)) {
+ vmulsd(dst, nds, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ vmulsd(dst, nds, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::vmulss(XMMRegister dst, XMMRegister nds, AddressLiteral src) {
+ if (reachable(src)) {
+ vmulss(dst, nds, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ vmulss(dst, nds, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::vsubsd(XMMRegister dst, XMMRegister nds, AddressLiteral src) {
+ if (reachable(src)) {
+ vsubsd(dst, nds, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ vsubsd(dst, nds, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::vsubss(XMMRegister dst, XMMRegister nds, AddressLiteral src) {
+ if (reachable(src)) {
+ vsubss(dst, nds, as_Address(src));
+ } else {
+ lea(rscratch1, src);
+ vsubss(dst, nds, Address(rscratch1, 0));
+ }
+}
+
+void MacroAssembler::vxorpd(XMMRegister dst, XMMRegister nds, AddressLiteral src, bool vector256) {
+ if (reachable(src)) {
+ vxorpd(dst, nds, as_Address(src), vector256);
+ } else {
+ lea(rscratch1, src);
+ vxorpd(dst, nds, Address(rscratch1, 0), vector256);
+ }
+}
+
+void MacroAssembler::vxorps(XMMRegister dst, XMMRegister nds, AddressLiteral src, bool vector256) {
+ if (reachable(src)) {
+ vxorps(dst, nds, as_Address(src), vector256);
+ } else {
+ lea(rscratch1, src);
+ vxorps(dst, nds, Address(rscratch1, 0), vector256);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////
+#ifndef SERIALGC
+
+void MacroAssembler::g1_write_barrier_pre(Register obj,
+ Register pre_val,
+ Register thread,
+ Register tmp,
+ bool tosca_live,
+ bool expand_call) {
+
+ // If expand_call is true then we expand the call_VM_leaf macro
+ // directly to skip generating the check by
+ // InterpreterMacroAssembler::call_VM_leaf_base that checks _last_sp.
+
+#ifdef _LP64
+ assert(thread == r15_thread, "must be");
+#endif // _LP64
+
+ Label done;
+ Label runtime;
+
+ assert(pre_val != noreg, "check this code");
+
+ if (obj != noreg) {
+ assert_different_registers(obj, pre_val, tmp);
+ assert(pre_val != rax, "check this code");
+ }
+
+ Address in_progress(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
+ PtrQueue::byte_offset_of_active()));
+ Address index(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
+ PtrQueue::byte_offset_of_index()));
+ Address buffer(thread, in_bytes(JavaThread::satb_mark_queue_offset() +
+ PtrQueue::byte_offset_of_buf()));
+
+
+ // Is marking active?
+ if (in_bytes(PtrQueue::byte_width_of_active()) == 4) {
+ cmpl(in_progress, 0);
+ } else {
+ assert(in_bytes(PtrQueue::byte_width_of_active()) == 1, "Assumption");
+ cmpb(in_progress, 0);
+ }
+ jcc(Assembler::equal, done);
+
+ // Do we need to load the previous value?
+ if (obj != noreg) {
+ load_heap_oop(pre_val, Address(obj, 0));
+ }
+
+ // Is the previous value null?
+ cmpptr(pre_val, (int32_t) NULL_WORD);
+ jcc(Assembler::equal, done);
+
+ // Can we store original value in the thread's buffer?
+ // Is index == 0?
+ // (The index field is typed as size_t.)
+
+ movptr(tmp, index); // tmp := *index_adr
+ cmpptr(tmp, 0); // tmp == 0?
+ jcc(Assembler::equal, runtime); // If yes, goto runtime
+
+ subptr(tmp, wordSize); // tmp := tmp - wordSize
+ movptr(index, tmp); // *index_adr := tmp
+ addptr(tmp, buffer); // tmp := tmp + *buffer_adr
+
+ // Record the previous value
+ movptr(Address(tmp, 0), pre_val);
+ jmp(done);
+
+ bind(runtime);
+ // save the live input values
+ if(tosca_live) push(rax);
+
+ if (obj != noreg && obj != rax)
+ push(obj);
+
+ if (pre_val != rax)
+ push(pre_val);
+
+ // Calling the runtime using the regular call_VM_leaf mechanism generates
+ // code (generated by InterpreterMacroAssember::call_VM_leaf_base)
+ // that checks that the *(ebp+frame::interpreter_frame_last_sp) == NULL.
+ //
+ // If we care generating the pre-barrier without a frame (e.g. in the
+ // intrinsified Reference.get() routine) then ebp might be pointing to
+ // the caller frame and so this check will most likely fail at runtime.
+ //
+ // Expanding the call directly bypasses the generation of the check.
+ // So when we do not have have a full interpreter frame on the stack
+ // expand_call should be passed true.
+
+ NOT_LP64( push(thread); )
+
+ if (expand_call) {
+ LP64_ONLY( assert(pre_val != c_rarg1, "smashed arg"); )
+ pass_arg1(this, thread);
+ pass_arg0(this, pre_val);
+ MacroAssembler::call_VM_leaf_base(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), 2);
+ } else {
+ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), pre_val, thread);
+ }
+
+ NOT_LP64( pop(thread); )
+
+ // save the live input values
+ if (pre_val != rax)
+ pop(pre_val);
+
+ if (obj != noreg && obj != rax)
+ pop(obj);
+
+ if(tosca_live) pop(rax);
+
+ bind(done);
+}
+
+void MacroAssembler::g1_write_barrier_post(Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp,
+ Register tmp2) {
+#ifdef _LP64
+ assert(thread == r15_thread, "must be");
+#endif // _LP64
+
+ Address queue_index(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
+ PtrQueue::byte_offset_of_index()));
+ Address buffer(thread, in_bytes(JavaThread::dirty_card_queue_offset() +
+ PtrQueue::byte_offset_of_buf()));
+
+ BarrierSet* bs = Universe::heap()->barrier_set();
+ CardTableModRefBS* ct = (CardTableModRefBS*)bs;
+ Label done;
+ Label runtime;
+
+ // Does store cross heap regions?
+
+ movptr(tmp, store_addr);
+ xorptr(tmp, new_val);
+ shrptr(tmp, HeapRegion::LogOfHRGrainBytes);
+ jcc(Assembler::equal, done);
+
+ // crosses regions, storing NULL?
+
+ cmpptr(new_val, (int32_t) NULL_WORD);
+ jcc(Assembler::equal, done);
+
+ // storing region crossing non-NULL, is card already dirty?
+
+ ExternalAddress cardtable((address) ct->byte_map_base);
+ assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
+#ifdef _LP64
+ const Register card_addr = tmp;
+
+ movq(card_addr, store_addr);
+ shrq(card_addr, CardTableModRefBS::card_shift);
+
+ lea(tmp2, cardtable);
+
+ // get the address of the card
+ addq(card_addr, tmp2);
+#else
+ const Register card_index = tmp;
+
+ movl(card_index, store_addr);
+ shrl(card_index, CardTableModRefBS::card_shift);
+
+ Address index(noreg, card_index, Address::times_1);
+ const Register card_addr = tmp;
+ lea(card_addr, as_Address(ArrayAddress(cardtable, index)));
+#endif
+ cmpb(Address(card_addr, 0), 0);
+ jcc(Assembler::equal, done);
+
+ // storing a region crossing, non-NULL oop, card is clean.
+ // dirty card and log.
+
+ movb(Address(card_addr, 0), 0);
+
+ cmpl(queue_index, 0);
+ jcc(Assembler::equal, runtime);
+ subl(queue_index, wordSize);
+ movptr(tmp2, buffer);
+#ifdef _LP64
+ movslq(rscratch1, queue_index);
+ addq(tmp2, rscratch1);
+ movq(Address(tmp2, 0), card_addr);
+#else
+ addl(tmp2, queue_index);
+ movl(Address(tmp2, 0), card_index);
+#endif
+ jmp(done);
+
+ bind(runtime);
+ // save the live input values
+ push(store_addr);
+ push(new_val);
+#ifdef _LP64
+ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, r15_thread);
+#else
+ push(thread);
+ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), card_addr, thread);
+ pop(thread);
+#endif
+ pop(new_val);
+ pop(store_addr);
+
+ bind(done);
+}
+
+#endif // SERIALGC
+//////////////////////////////////////////////////////////////////////////////////
+
+
+void MacroAssembler::store_check(Register obj) {
+ // Does a store check for the oop in register obj. The content of
+ // register obj is destroyed afterwards.
+ store_check_part_1(obj);
+ store_check_part_2(obj);
+}
+
+void MacroAssembler::store_check(Register obj, Address dst) {
+ store_check(obj);
+}
+
+
+// split the store check operation so that other instructions can be scheduled inbetween
+void MacroAssembler::store_check_part_1(Register obj) {
+ BarrierSet* bs = Universe::heap()->barrier_set();
+ assert(bs->kind() == BarrierSet::CardTableModRef, "Wrong barrier set kind");
+ shrptr(obj, CardTableModRefBS::card_shift);
+}
+
+void MacroAssembler::store_check_part_2(Register obj) {
+ BarrierSet* bs = Universe::heap()->barrier_set();
+ assert(bs->kind() == BarrierSet::CardTableModRef, "Wrong barrier set kind");
+ CardTableModRefBS* ct = (CardTableModRefBS*)bs;
+ assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
+
+ // The calculation for byte_map_base is as follows:
+ // byte_map_base = _byte_map - (uintptr_t(low_bound) >> card_shift);
+ // So this essentially converts an address to a displacement and
+ // it will never need to be relocated. On 64bit however the value may be too
+ // large for a 32bit displacement
+
+ intptr_t disp = (intptr_t) ct->byte_map_base;
+ if (is_simm32(disp)) {
+ Address cardtable(noreg, obj, Address::times_1, disp);
+ movb(cardtable, 0);
+ } else {
+ // By doing it as an ExternalAddress disp could be converted to a rip-relative
+ // displacement and done in a single instruction given favorable mapping and
+ // a smarter version of as_Address. Worst case it is two instructions which
+ // is no worse off then loading disp into a register and doing as a simple
+ // Address() as above.
+ // We can't do as ExternalAddress as the only style since if disp == 0 we'll
+ // assert since NULL isn't acceptable in a reloci (see 6644928). In any case
+ // in some cases we'll get a single instruction version.
+
+ ExternalAddress cardtable((address)disp);
+ Address index(noreg, obj, Address::times_1);
+ movb(as_Address(ArrayAddress(cardtable, index)), 0);
+ }
+}
+
+void MacroAssembler::subptr(Register dst, int32_t imm32) {
+ LP64_ONLY(subq(dst, imm32)) NOT_LP64(subl(dst, imm32));
+}
+
+// Force generation of a 4 byte immediate value even if it fits into 8bit
+void MacroAssembler::subptr_imm32(Register dst, int32_t imm32) {
+ LP64_ONLY(subq_imm32(dst, imm32)) NOT_LP64(subl_imm32(dst, imm32));
+}
+
+void MacroAssembler::subptr(Register dst, Register src) {
+ LP64_ONLY(subq(dst, src)) NOT_LP64(subl(dst, src));
+}
+
+// C++ bool manipulation
+void MacroAssembler::testbool(Register dst) {
+ if(sizeof(bool) == 1)
+ testb(dst, 0xff);
+ else if(sizeof(bool) == 2) {
+ // testw implementation needed for two byte bools
+ ShouldNotReachHere();
+ } else if(sizeof(bool) == 4)
+ testl(dst, dst);
+ else
+ // unsupported
+ ShouldNotReachHere();
+}
+
+void MacroAssembler::testptr(Register dst, Register src) {
+ LP64_ONLY(testq(dst, src)) NOT_LP64(testl(dst, src));
+}
+
+// Defines obj, preserves var_size_in_bytes, okay for t2 == var_size_in_bytes.
+void MacroAssembler::tlab_allocate(Register obj,
+ Register var_size_in_bytes,
+ int con_size_in_bytes,
+ Register t1,
+ Register t2,
+ Label& slow_case) {
+ assert_different_registers(obj, t1, t2);
+ assert_different_registers(obj, var_size_in_bytes, t1);
+ Register end = t2;
+ Register thread = NOT_LP64(t1) LP64_ONLY(r15_thread);
+
+ verify_tlab();
+
+ NOT_LP64(get_thread(thread));
+
+ movptr(obj, Address(thread, JavaThread::tlab_top_offset()));
+ if (var_size_in_bytes == noreg) {
+ lea(end, Address(obj, con_size_in_bytes));
+ } else {
+ lea(end, Address(obj, var_size_in_bytes, Address::times_1));
+ }
+ cmpptr(end, Address(thread, JavaThread::tlab_end_offset()));
+ jcc(Assembler::above, slow_case);
+
+ // update the tlab top pointer
+ movptr(Address(thread, JavaThread::tlab_top_offset()), end);
+
+ // recover var_size_in_bytes if necessary
+ if (var_size_in_bytes == end) {
+ subptr(var_size_in_bytes, obj);
+ }
+ verify_tlab();
+}
+
+// Preserves rbx, and rdx.
+Register MacroAssembler::tlab_refill(Label& retry,
+ Label& try_eden,
+ Label& slow_case) {
+ Register top = rax;
+ Register t1 = rcx;
+ Register t2 = rsi;
+ Register thread_reg = NOT_LP64(rdi) LP64_ONLY(r15_thread);
+ assert_different_registers(top, thread_reg, t1, t2, /* preserve: */ rbx, rdx);
+ Label do_refill, discard_tlab;
+
+ if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) {
+ // No allocation in the shared eden.
+ jmp(slow_case);
+ }
+
+ NOT_LP64(get_thread(thread_reg));
+
+ movptr(top, Address(thread_reg, in_bytes(JavaThread::tlab_top_offset())));
+ movptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_end_offset())));
+
+ // calculate amount of free space
+ subptr(t1, top);
+ shrptr(t1, LogHeapWordSize);
+
+ // Retain tlab and allocate object in shared space if
+ // the amount free in the tlab is too large to discard.
+ cmpptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_refill_waste_limit_offset())));
+ jcc(Assembler::lessEqual, discard_tlab);
+
+ // Retain
+ // %%% yuck as movptr...
+ movptr(t2, (int32_t) ThreadLocalAllocBuffer::refill_waste_limit_increment());
+ addptr(Address(thread_reg, in_bytes(JavaThread::tlab_refill_waste_limit_offset())), t2);
+ if (TLABStats) {
+ // increment number of slow_allocations
+ addl(Address(thread_reg, in_bytes(JavaThread::tlab_slow_allocations_offset())), 1);
+ }
+ jmp(try_eden);
+
+ bind(discard_tlab);
+ if (TLABStats) {
+ // increment number of refills
+ addl(Address(thread_reg, in_bytes(JavaThread::tlab_number_of_refills_offset())), 1);
+ // accumulate wastage -- t1 is amount free in tlab
+ addl(Address(thread_reg, in_bytes(JavaThread::tlab_fast_refill_waste_offset())), t1);
+ }
+
+ // if tlab is currently allocated (top or end != null) then
+ // fill [top, end + alignment_reserve) with array object
+ testptr(top, top);
+ jcc(Assembler::zero, do_refill);
+
+ // set up the mark word
+ movptr(Address(top, oopDesc::mark_offset_in_bytes()), (intptr_t)markOopDesc::prototype()->copy_set_hash(0x2));
+ // set the length to the remaining space
+ subptr(t1, typeArrayOopDesc::header_size(T_INT));
+ addptr(t1, (int32_t)ThreadLocalAllocBuffer::alignment_reserve());
+ shlptr(t1, log2_intptr(HeapWordSize/sizeof(jint)));
+ movl(Address(top, arrayOopDesc::length_offset_in_bytes()), t1);
+ // set klass to intArrayKlass
+ // dubious reloc why not an oop reloc?
+ movptr(t1, ExternalAddress((address)Universe::intArrayKlassObj_addr()));
+ // store klass last. concurrent gcs assumes klass length is valid if
+ // klass field is not null.
+ store_klass(top, t1);
+
+ movptr(t1, top);
+ subptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_start_offset())));
+ incr_allocated_bytes(thread_reg, t1, 0);
+
+ // refill the tlab with an eden allocation
+ bind(do_refill);
+ movptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_size_offset())));
+ shlptr(t1, LogHeapWordSize);
+ // allocate new tlab, address returned in top
+ eden_allocate(top, t1, 0, t2, slow_case);
+
+ // Check that t1 was preserved in eden_allocate.
+#ifdef ASSERT
+ if (UseTLAB) {
+ Label ok;
+ Register tsize = rsi;
+ assert_different_registers(tsize, thread_reg, t1);
+ push(tsize);
+ movptr(tsize, Address(thread_reg, in_bytes(JavaThread::tlab_size_offset())));
+ shlptr(tsize, LogHeapWordSize);
+ cmpptr(t1, tsize);
+ jcc(Assembler::equal, ok);
+ STOP("assert(t1 != tlab size)");
+ should_not_reach_here();
+
+ bind(ok);
+ pop(tsize);
+ }
+#endif
+ movptr(Address(thread_reg, in_bytes(JavaThread::tlab_start_offset())), top);
+ movptr(Address(thread_reg, in_bytes(JavaThread::tlab_top_offset())), top);
+ addptr(top, t1);
+ subptr(top, (int32_t)ThreadLocalAllocBuffer::alignment_reserve_in_bytes());
+ movptr(Address(thread_reg, in_bytes(JavaThread::tlab_end_offset())), top);
+ verify_tlab();
+ jmp(retry);
+
+ return thread_reg; // for use by caller
+}
+
+void MacroAssembler::incr_allocated_bytes(Register thread,
+ Register var_size_in_bytes,
+ int con_size_in_bytes,
+ Register t1) {
+ if (!thread->is_valid()) {
+#ifdef _LP64
+ thread = r15_thread;
+#else
+ assert(t1->is_valid(), "need temp reg");
+ thread = t1;
+ get_thread(thread);
+#endif
+ }
+
+#ifdef _LP64
+ if (var_size_in_bytes->is_valid()) {
+ addq(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), var_size_in_bytes);
+ } else {
+ addq(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), con_size_in_bytes);
+ }
+#else
+ if (var_size_in_bytes->is_valid()) {
+ addl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), var_size_in_bytes);
+ } else {
+ addl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())), con_size_in_bytes);
+ }
+ adcl(Address(thread, in_bytes(JavaThread::allocated_bytes_offset())+4), 0);
+#endif
+}
+
+void MacroAssembler::fp_runtime_fallback(address runtime_entry, int nb_args, int num_fpu_regs_in_use) {
+ pusha();
+
+ // if we are coming from c1, xmm registers may be live
+ int off = 0;
+ if (UseSSE == 1) {
+ subptr(rsp, sizeof(jdouble)*8);
+ movflt(Address(rsp,off++*sizeof(jdouble)),xmm0);
+ movflt(Address(rsp,off++*sizeof(jdouble)),xmm1);
+ movflt(Address(rsp,off++*sizeof(jdouble)),xmm2);
+ movflt(Address(rsp,off++*sizeof(jdouble)),xmm3);
+ movflt(Address(rsp,off++*sizeof(jdouble)),xmm4);
+ movflt(Address(rsp,off++*sizeof(jdouble)),xmm5);
+ movflt(Address(rsp,off++*sizeof(jdouble)),xmm6);
+ movflt(Address(rsp,off++*sizeof(jdouble)),xmm7);
+ } else if (UseSSE >= 2) {
+#ifdef COMPILER2
+ if (MaxVectorSize > 16) {
+ assert(UseAVX > 0, "256bit vectors are supported only with AVX");
+ // Save upper half of YMM registes
+ subptr(rsp, 16 * LP64_ONLY(16) NOT_LP64(8));
+ vextractf128h(Address(rsp, 0),xmm0);
+ vextractf128h(Address(rsp, 16),xmm1);
+ vextractf128h(Address(rsp, 32),xmm2);
+ vextractf128h(Address(rsp, 48),xmm3);
+ vextractf128h(Address(rsp, 64),xmm4);
+ vextractf128h(Address(rsp, 80),xmm5);
+ vextractf128h(Address(rsp, 96),xmm6);
+ vextractf128h(Address(rsp,112),xmm7);
+#ifdef _LP64
+ vextractf128h(Address(rsp,128),xmm8);
+ vextractf128h(Address(rsp,144),xmm9);
+ vextractf128h(Address(rsp,160),xmm10);
+ vextractf128h(Address(rsp,176),xmm11);
+ vextractf128h(Address(rsp,192),xmm12);
+ vextractf128h(Address(rsp,208),xmm13);
+ vextractf128h(Address(rsp,224),xmm14);
+ vextractf128h(Address(rsp,240),xmm15);
+#endif
+ }
+#endif
+ // Save whole 128bit (16 bytes) XMM regiters
+ subptr(rsp, 16 * LP64_ONLY(16) NOT_LP64(8));
+ movdqu(Address(rsp,off++*16),xmm0);
+ movdqu(Address(rsp,off++*16),xmm1);
+ movdqu(Address(rsp,off++*16),xmm2);
+ movdqu(Address(rsp,off++*16),xmm3);
+ movdqu(Address(rsp,off++*16),xmm4);
+ movdqu(Address(rsp,off++*16),xmm5);
+ movdqu(Address(rsp,off++*16),xmm6);
+ movdqu(Address(rsp,off++*16),xmm7);
+#ifdef _LP64
+ movdqu(Address(rsp,off++*16),xmm8);
+ movdqu(Address(rsp,off++*16),xmm9);
+ movdqu(Address(rsp,off++*16),xmm10);
+ movdqu(Address(rsp,off++*16),xmm11);
+ movdqu(Address(rsp,off++*16),xmm12);
+ movdqu(Address(rsp,off++*16),xmm13);
+ movdqu(Address(rsp,off++*16),xmm14);
+ movdqu(Address(rsp,off++*16),xmm15);
+#endif
+ }
+
+ // Preserve registers across runtime call
+ int incoming_argument_and_return_value_offset = -1;
+ if (num_fpu_regs_in_use > 1) {
+ // Must preserve all other FPU regs (could alternatively convert
+ // SharedRuntime::dsin, dcos etc. into assembly routines known not to trash
+ // FPU state, but can not trust C compiler)
+ NEEDS_CLEANUP;
+ // NOTE that in this case we also push the incoming argument(s) to
+ // the stack and restore it later; we also use this stack slot to
+ // hold the return value from dsin, dcos etc.
+ for (int i = 0; i < num_fpu_regs_in_use; i++) {
+ subptr(rsp, sizeof(jdouble));
+ fstp_d(Address(rsp, 0));
+ }
+ incoming_argument_and_return_value_offset = sizeof(jdouble)*(num_fpu_regs_in_use-1);
+ for (int i = nb_args-1; i >= 0; i--) {
+ fld_d(Address(rsp, incoming_argument_and_return_value_offset-i*sizeof(jdouble)));
+ }
+ }
+
+ subptr(rsp, nb_args*sizeof(jdouble));
+ for (int i = 0; i < nb_args; i++) {
+ fstp_d(Address(rsp, i*sizeof(jdouble)));
+ }
+
+#ifdef _LP64
+ if (nb_args > 0) {
+ movdbl(xmm0, Address(rsp, 0));
+ }
+ if (nb_args > 1) {
+ movdbl(xmm1, Address(rsp, sizeof(jdouble)));
+ }
+ assert(nb_args <= 2, "unsupported number of args");
+#endif // _LP64
+
+ // NOTE: we must not use call_VM_leaf here because that requires a
+ // complete interpreter frame in debug mode -- same bug as 4387334
+ // MacroAssembler::call_VM_leaf_base is perfectly safe and will
+ // do proper 64bit abi
+
+ NEEDS_CLEANUP;
+ // Need to add stack banging before this runtime call if it needs to
+ // be taken; however, there is no generic stack banging routine at
+ // the MacroAssembler level
+
+ MacroAssembler::call_VM_leaf_base(runtime_entry, 0);
+
+#ifdef _LP64
+ movsd(Address(rsp, 0), xmm0);
+ fld_d(Address(rsp, 0));
+#endif // _LP64
+ addptr(rsp, sizeof(jdouble) * nb_args);
+ if (num_fpu_regs_in_use > 1) {
+ // Must save return value to stack and then restore entire FPU
+ // stack except incoming arguments
+ fstp_d(Address(rsp, incoming_argument_and_return_value_offset));
+ for (int i = 0; i < num_fpu_regs_in_use - nb_args; i++) {
+ fld_d(Address(rsp, 0));
+ addptr(rsp, sizeof(jdouble));
+ }
+ fld_d(Address(rsp, (nb_args-1)*sizeof(jdouble)));
+ addptr(rsp, sizeof(jdouble) * nb_args);
+ }
+
+ off = 0;
+ if (UseSSE == 1) {
+ movflt(xmm0, Address(rsp,off++*sizeof(jdouble)));
+ movflt(xmm1, Address(rsp,off++*sizeof(jdouble)));
+ movflt(xmm2, Address(rsp,off++*sizeof(jdouble)));
+ movflt(xmm3, Address(rsp,off++*sizeof(jdouble)));
+ movflt(xmm4, Address(rsp,off++*sizeof(jdouble)));
+ movflt(xmm5, Address(rsp,off++*sizeof(jdouble)));
+ movflt(xmm6, Address(rsp,off++*sizeof(jdouble)));
+ movflt(xmm7, Address(rsp,off++*sizeof(jdouble)));
+ addptr(rsp, sizeof(jdouble)*8);
+ } else if (UseSSE >= 2) {
+ // Restore whole 128bit (16 bytes) XMM regiters
+ movdqu(xmm0, Address(rsp,off++*16));
+ movdqu(xmm1, Address(rsp,off++*16));
+ movdqu(xmm2, Address(rsp,off++*16));
+ movdqu(xmm3, Address(rsp,off++*16));
+ movdqu(xmm4, Address(rsp,off++*16));
+ movdqu(xmm5, Address(rsp,off++*16));
+ movdqu(xmm6, Address(rsp,off++*16));
+ movdqu(xmm7, Address(rsp,off++*16));
+#ifdef _LP64
+ movdqu(xmm8, Address(rsp,off++*16));
+ movdqu(xmm9, Address(rsp,off++*16));
+ movdqu(xmm10, Address(rsp,off++*16));
+ movdqu(xmm11, Address(rsp,off++*16));
+ movdqu(xmm12, Address(rsp,off++*16));
+ movdqu(xmm13, Address(rsp,off++*16));
+ movdqu(xmm14, Address(rsp,off++*16));
+ movdqu(xmm15, Address(rsp,off++*16));
+#endif
+ addptr(rsp, 16 * LP64_ONLY(16) NOT_LP64(8));
+#ifdef COMPILER2
+ if (MaxVectorSize > 16) {
+ // Restore upper half of YMM registes.
+ vinsertf128h(xmm0, Address(rsp, 0));
+ vinsertf128h(xmm1, Address(rsp, 16));
+ vinsertf128h(xmm2, Address(rsp, 32));
+ vinsertf128h(xmm3, Address(rsp, 48));
+ vinsertf128h(xmm4, Address(rsp, 64));
+ vinsertf128h(xmm5, Address(rsp, 80));
+ vinsertf128h(xmm6, Address(rsp, 96));
+ vinsertf128h(xmm7, Address(rsp,112));
+#ifdef _LP64
+ vinsertf128h(xmm8, Address(rsp,128));
+ vinsertf128h(xmm9, Address(rsp,144));
+ vinsertf128h(xmm10, Address(rsp,160));
+ vinsertf128h(xmm11, Address(rsp,176));
+ vinsertf128h(xmm12, Address(rsp,192));
+ vinsertf128h(xmm13, Address(rsp,208));
+ vinsertf128h(xmm14, Address(rsp,224));
+ vinsertf128h(xmm15, Address(rsp,240));
+#endif
+ addptr(rsp, 16 * LP64_ONLY(16) NOT_LP64(8));
+ }
+#endif
+ }
+ popa();
+}
+
+static const double pi_4 = 0.7853981633974483;
+
+void MacroAssembler::trigfunc(char trig, int num_fpu_regs_in_use) {
+ // A hand-coded argument reduction for values in fabs(pi/4, pi/2)
+ // was attempted in this code; unfortunately it appears that the
+ // switch to 80-bit precision and back causes this to be
+ // unprofitable compared with simply performing a runtime call if
+ // the argument is out of the (-pi/4, pi/4) range.
+
+ Register tmp = noreg;
+ if (!VM_Version::supports_cmov()) {
+ // fcmp needs a temporary so preserve rbx,
+ tmp = rbx;
+ push(tmp);
+ }
+
+ Label slow_case, done;
+
+ ExternalAddress pi4_adr = (address)&pi_4;
+ if (reachable(pi4_adr)) {
+ // x ?<= pi/4
+ fld_d(pi4_adr);
+ fld_s(1); // Stack: X PI/4 X
+ fabs(); // Stack: |X| PI/4 X
+ fcmp(tmp);
+ jcc(Assembler::above, slow_case);
+
+ // fastest case: -pi/4 <= x <= pi/4
+ switch(trig) {
+ case 's':
+ fsin();
+ break;
+ case 'c':
+ fcos();
+ break;
+ case 't':
+ ftan();
+ break;
+ default:
+ assert(false, "bad intrinsic");
+ break;
+ }
+ jmp(done);
+ }
+
+ // slow case: runtime call
+ bind(slow_case);
+
+ switch(trig) {
+ case 's':
+ {
+ fp_runtime_fallback(CAST_FROM_FN_PTR(address, SharedRuntime::dsin), 1, num_fpu_regs_in_use);
+ }
+ break;
+ case 'c':
+ {
+ fp_runtime_fallback(CAST_FROM_FN_PTR(address, SharedRuntime::dcos), 1, num_fpu_regs_in_use);
+ }
+ break;
+ case 't':
+ {
+ fp_runtime_fallback(CAST_FROM_FN_PTR(address, SharedRuntime::dtan), 1, num_fpu_regs_in_use);
+ }
+ break;
+ default:
+ assert(false, "bad intrinsic");
+ break;
+ }
+
+ // Come here with result in F-TOS
+ bind(done);
+
+ if (tmp != noreg) {
+ pop(tmp);
+ }
+}
+
+
+// Look up the method for a megamorphic invokeinterface call.
+// The target method is determined by .
+// The receiver klass is in recv_klass.
+// On success, the result will be in method_result, and execution falls through.
+// On failure, execution transfers to the given label.
+void MacroAssembler::lookup_interface_method(Register recv_klass,
+ Register intf_klass,
+ RegisterOrConstant itable_index,
+ Register method_result,
+ Register scan_temp,
+ Label& L_no_such_interface) {
+ assert_different_registers(recv_klass, intf_klass, method_result, scan_temp);
+ assert(itable_index.is_constant() || itable_index.as_register() == method_result,
+ "caller must use same register for non-constant itable index as for method");
+
+ // Compute start of first itableOffsetEntry (which is at the end of the vtable)
+ int vtable_base = InstanceKlass::vtable_start_offset() * wordSize;
+ int itentry_off = itableMethodEntry::method_offset_in_bytes();
+ int scan_step = itableOffsetEntry::size() * wordSize;
+ int vte_size = vtableEntry::size() * wordSize;
+ Address::ScaleFactor times_vte_scale = Address::times_ptr;
+ assert(vte_size == wordSize, "else adjust times_vte_scale");
+
+ movl(scan_temp, Address(recv_klass, InstanceKlass::vtable_length_offset() * wordSize));
+
+ // %%% Could store the aligned, prescaled offset in the klassoop.
+ lea(scan_temp, Address(recv_klass, scan_temp, times_vte_scale, vtable_base));
+ if (HeapWordsPerLong > 1) {
+ // Round up to align_object_offset boundary
+ // see code for InstanceKlass::start_of_itable!
+ round_to(scan_temp, BytesPerLong);
+ }
+
+ // Adjust recv_klass by scaled itable_index, so we can free itable_index.
+ assert(itableMethodEntry::size() * wordSize == wordSize, "adjust the scaling in the code below");
+ lea(recv_klass, Address(recv_klass, itable_index, Address::times_ptr, itentry_off));
+
+ // for (scan = klass->itable(); scan->interface() != NULL; scan += scan_step) {
+ // if (scan->interface() == intf) {
+ // result = (klass + scan->offset() + itable_index);
+ // }
+ // }
+ Label search, found_method;
+
+ for (int peel = 1; peel >= 0; peel--) {
+ movptr(method_result, Address(scan_temp, itableOffsetEntry::interface_offset_in_bytes()));
+ cmpptr(intf_klass, method_result);
+
+ if (peel) {
+ jccb(Assembler::equal, found_method);
+ } else {
+ jccb(Assembler::notEqual, search);
+ // (invert the test to fall through to found_method...)
+ }
+
+ if (!peel) break;
+
+ bind(search);
+
+ // Check that the previous entry is non-null. A null entry means that
+ // the receiver class doesn't implement the interface, and wasn't the
+ // same as when the caller was compiled.
+ testptr(method_result, method_result);
+ jcc(Assembler::zero, L_no_such_interface);
+ addptr(scan_temp, scan_step);
+ }
+
+ bind(found_method);
+
+ // Got a hit.
+ movl(scan_temp, Address(scan_temp, itableOffsetEntry::offset_offset_in_bytes()));
+ movptr(method_result, Address(recv_klass, scan_temp, Address::times_1));
+}
+
+
+// virtual method calling
+void MacroAssembler::lookup_virtual_method(Register recv_klass,
+ RegisterOrConstant vtable_index,
+ Register method_result) {
+ const int base = InstanceKlass::vtable_start_offset() * wordSize;
+ assert(vtableEntry::size() * wordSize == wordSize, "else adjust the scaling in the code below");
+ Address vtable_entry_addr(recv_klass,
+ vtable_index, Address::times_ptr,
+ base + vtableEntry::method_offset_in_bytes());
+ movptr(method_result, vtable_entry_addr);
+}
+
+
+void MacroAssembler::check_klass_subtype(Register sub_klass,
+ Register super_klass,
+ Register temp_reg,
+ Label& L_success) {
+ Label L_failure;
+ check_klass_subtype_fast_path(sub_klass, super_klass, temp_reg, &L_success, &L_failure, NULL);
+ check_klass_subtype_slow_path(sub_klass, super_klass, temp_reg, noreg, &L_success, NULL);
+ bind(L_failure);
+}
+
+
+void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass,
+ Register super_klass,
+ Register temp_reg,
+ Label* L_success,
+ Label* L_failure,
+ Label* L_slow_path,
+ RegisterOrConstant super_check_offset) {
+ assert_different_registers(sub_klass, super_klass, temp_reg);
+ bool must_load_sco = (super_check_offset.constant_or_zero() == -1);
+ if (super_check_offset.is_register()) {
+ assert_different_registers(sub_klass, super_klass,
+ super_check_offset.as_register());
+ } else if (must_load_sco) {
+ assert(temp_reg != noreg, "supply either a temp or a register offset");
+ }
+
+ Label L_fallthrough;
+ int label_nulls = 0;
+ if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; }
+ if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; }
+ if (L_slow_path == NULL) { L_slow_path = &L_fallthrough; label_nulls++; }
+ assert(label_nulls <= 1, "at most one NULL in the batch");
+
+ int sc_offset = in_bytes(Klass::secondary_super_cache_offset());
+ int sco_offset = in_bytes(Klass::super_check_offset_offset());
+ Address super_check_offset_addr(super_klass, sco_offset);
+
+ // Hacked jcc, which "knows" that L_fallthrough, at least, is in
+ // range of a jccb. If this routine grows larger, reconsider at
+ // least some of these.
+#define local_jcc(assembler_cond, label) \
+ if (&(label) == &L_fallthrough) jccb(assembler_cond, label); \
+ else jcc( assembler_cond, label) /*omit semi*/
+
+ // Hacked jmp, which may only be used just before L_fallthrough.
+#define final_jmp(label) \
+ if (&(label) == &L_fallthrough) { /*do nothing*/ } \
+ else jmp(label) /*omit semi*/
+
+ // If the pointers are equal, we are done (e.g., String[] elements).
+ // This self-check enables sharing of secondary supertype arrays among
+ // non-primary types such as array-of-interface. Otherwise, each such
+ // type would need its own customized SSA.
+ // We move this check to the front of the fast path because many
+ // type checks are in fact trivially successful in this manner,
+ // so we get a nicely predicted branch right at the start of the check.
+ cmpptr(sub_klass, super_klass);
+ local_jcc(Assembler::equal, *L_success);
+
+ // Check the supertype display:
+ if (must_load_sco) {
+ // Positive movl does right thing on LP64.
+ movl(temp_reg, super_check_offset_addr);
+ super_check_offset = RegisterOrConstant(temp_reg);
+ }
+ Address super_check_addr(sub_klass, super_check_offset, Address::times_1, 0);
+ cmpptr(super_klass, super_check_addr); // load displayed supertype
+
+ // This check has worked decisively for primary supers.
+ // Secondary supers are sought in the super_cache ('super_cache_addr').
+ // (Secondary supers are interfaces and very deeply nested subtypes.)
+ // This works in the same check above because of a tricky aliasing
+ // between the super_cache and the primary super display elements.
+ // (The 'super_check_addr' can address either, as the case requires.)
+ // Note that the cache is updated below if it does not help us find
+ // what we need immediately.
+ // So if it was a primary super, we can just fail immediately.
+ // Otherwise, it's the slow path for us (no success at this point).
+
+ if (super_check_offset.is_register()) {
+ local_jcc(Assembler::equal, *L_success);
+ cmpl(super_check_offset.as_register(), sc_offset);
+ if (L_failure == &L_fallthrough) {
+ local_jcc(Assembler::equal, *L_slow_path);
+ } else {
+ local_jcc(Assembler::notEqual, *L_failure);
+ final_jmp(*L_slow_path);
+ }
+ } else if (super_check_offset.as_constant() == sc_offset) {
+ // Need a slow path; fast failure is impossible.
+ if (L_slow_path == &L_fallthrough) {
+ local_jcc(Assembler::equal, *L_success);
+ } else {
+ local_jcc(Assembler::notEqual, *L_slow_path);
+ final_jmp(*L_success);
+ }
+ } else {
+ // No slow path; it's a fast decision.
+ if (L_failure == &L_fallthrough) {
+ local_jcc(Assembler::equal, *L_success);
+ } else {
+ local_jcc(Assembler::notEqual, *L_failure);
+ final_jmp(*L_success);
+ }
+ }
+
+ bind(L_fallthrough);
+
+#undef local_jcc
+#undef final_jmp
+}
+
+
+void MacroAssembler::check_klass_subtype_slow_path(Register sub_klass,
+ Register super_klass,
+ Register temp_reg,
+ Register temp2_reg,
+ Label* L_success,
+ Label* L_failure,
+ bool set_cond_codes) {
+ assert_different_registers(sub_klass, super_klass, temp_reg);
+ if (temp2_reg != noreg)
+ assert_different_registers(sub_klass, super_klass, temp_reg, temp2_reg);
+#define IS_A_TEMP(reg) ((reg) == temp_reg || (reg) == temp2_reg)
+
+ Label L_fallthrough;
+ int label_nulls = 0;
+ if (L_success == NULL) { L_success = &L_fallthrough; label_nulls++; }
+ if (L_failure == NULL) { L_failure = &L_fallthrough; label_nulls++; }
+ assert(label_nulls <= 1, "at most one NULL in the batch");
+
+ // a couple of useful fields in sub_klass:
+ int ss_offset = in_bytes(Klass::secondary_supers_offset());
+ int sc_offset = in_bytes(Klass::secondary_super_cache_offset());
+ Address secondary_supers_addr(sub_klass, ss_offset);
+ Address super_cache_addr( sub_klass, sc_offset);
+
+ // Do a linear scan of the secondary super-klass chain.
+ // This code is rarely used, so simplicity is a virtue here.
+ // The repne_scan instruction uses fixed registers, which we must spill.
+ // Don't worry too much about pre-existing connections with the input regs.
+
+ assert(sub_klass != rax, "killed reg"); // killed by mov(rax, super)
+ assert(sub_klass != rcx, "killed reg"); // killed by lea(rcx, &pst_counter)
+
+ // Get super_klass value into rax (even if it was in rdi or rcx).
+ bool pushed_rax = false, pushed_rcx = false, pushed_rdi = false;
+ if (super_klass != rax || UseCompressedOops) {
+ if (!IS_A_TEMP(rax)) { push(rax); pushed_rax = true; }
+ mov(rax, super_klass);
+ }
+ if (!IS_A_TEMP(rcx)) { push(rcx); pushed_rcx = true; }
+ if (!IS_A_TEMP(rdi)) { push(rdi); pushed_rdi = true; }
+
+#ifndef PRODUCT
+ int* pst_counter = &SharedRuntime::_partial_subtype_ctr;
+ ExternalAddress pst_counter_addr((address) pst_counter);
+ NOT_LP64( incrementl(pst_counter_addr) );
+ LP64_ONLY( lea(rcx, pst_counter_addr) );
+ LP64_ONLY( incrementl(Address(rcx, 0)) );
+#endif //PRODUCT
+
+ // We will consult the secondary-super array.
+ movptr(rdi, secondary_supers_addr);
+ // Load the array length. (Positive movl does right thing on LP64.)
+ movl(rcx, Address(rdi, Array::length_offset_in_bytes()));
+ // Skip to start of data.
+ addptr(rdi, Array::base_offset_in_bytes());
+
+ // Scan RCX words at [RDI] for an occurrence of RAX.
+ // Set NZ/Z based on last compare.
+ // Z flag value will not be set by 'repne' if RCX == 0 since 'repne' does
+ // not change flags (only scas instruction which is repeated sets flags).
+ // Set Z = 0 (not equal) before 'repne' to indicate that class was not found.
+
+ testptr(rax,rax); // Set Z = 0
+ repne_scan();
+
+ // Unspill the temp. registers:
+ if (pushed_rdi) pop(rdi);
+ if (pushed_rcx) pop(rcx);
+ if (pushed_rax) pop(rax);
+
+ if (set_cond_codes) {
+ // Special hack for the AD files: rdi is guaranteed non-zero.
+ assert(!pushed_rdi, "rdi must be left non-NULL");
+ // Also, the condition codes are properly set Z/NZ on succeed/failure.
+ }
+
+ if (L_failure == &L_fallthrough)
+ jccb(Assembler::notEqual, *L_failure);
+ else jcc(Assembler::notEqual, *L_failure);
+
+ // Success. Cache the super we found and proceed in triumph.
+ movptr(super_cache_addr, super_klass);
+
+ if (L_success != &L_fallthrough) {
+ jmp(*L_success);
+ }
+
+#undef IS_A_TEMP
+
+ bind(L_fallthrough);
+}
+
+
+void MacroAssembler::cmov32(Condition cc, Register dst, Address src) {
+ if (VM_Version::supports_cmov()) {
+ cmovl(cc, dst, src);
+ } else {
+ Label L;
+ jccb(negate_condition(cc), L);
+ movl(dst, src);
+ bind(L);
+ }
+}
+
+void MacroAssembler::cmov32(Condition cc, Register dst, Register src) {
+ if (VM_Version::supports_cmov()) {
+ cmovl(cc, dst, src);
+ } else {
+ Label L;
+ jccb(negate_condition(cc), L);
+ movl(dst, src);
+ bind(L);
+ }
+}
+
+void MacroAssembler::verify_oop(Register reg, const char* s) {
+ if (!VerifyOops) return;
+
+ // Pass register number to verify_oop_subroutine
+ char* b = new char[strlen(s) + 50];
+ sprintf(b, "verify_oop: %s: %s", reg->name(), s);
+ BLOCK_COMMENT("verify_oop {");
+#ifdef _LP64
+ push(rscratch1); // save r10, trashed by movptr()
+#endif
+ push(rax); // save rax,
+ push(reg); // pass register argument
+ ExternalAddress buffer((address) b);
+ // avoid using pushptr, as it modifies scratch registers
+ // and our contract is not to modify anything
+ movptr(rax, buffer.addr());
+ push(rax);
+ // call indirectly to solve generation ordering problem
+ movptr(rax, ExternalAddress(StubRoutines::verify_oop_subroutine_entry_address()));
+ call(rax);
+ // Caller pops the arguments (oop, message) and restores rax, r10
+ BLOCK_COMMENT("} verify_oop");
+}
+
+
+RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_addr,
+ Register tmp,
+ int offset) {
+ intptr_t value = *delayed_value_addr;
+ if (value != 0)
+ return RegisterOrConstant(value + offset);
+
+ // load indirectly to solve generation ordering problem
+ movptr(tmp, ExternalAddress((address) delayed_value_addr));
+
+#ifdef ASSERT
+ { Label L;
+ testptr(tmp, tmp);
+ if (WizardMode) {
+ jcc(Assembler::notZero, L);
+ char* buf = new char[40];
+ sprintf(buf, "DelayedValue="INTPTR_FORMAT, delayed_value_addr[1]);
+ STOP(buf);
+ } else {
+ jccb(Assembler::notZero, L);
+ hlt();
+ }
+ bind(L);
+ }
+#endif
+
+ if (offset != 0)
+ addptr(tmp, offset);
+
+ return RegisterOrConstant(tmp);
+}
+
+
+Address MacroAssembler::argument_address(RegisterOrConstant arg_slot,
+ int extra_slot_offset) {
+ // cf. TemplateTable::prepare_invoke(), if (load_receiver).
+ int stackElementSize = Interpreter::stackElementSize;
+ int offset = Interpreter::expr_offset_in_bytes(extra_slot_offset+0);
+#ifdef ASSERT
+ int offset1 = Interpreter::expr_offset_in_bytes(extra_slot_offset+1);
+ assert(offset1 - offset == stackElementSize, "correct arithmetic");
+#endif
+ Register scale_reg = noreg;
+ Address::ScaleFactor scale_factor = Address::no_scale;
+ if (arg_slot.is_constant()) {
+ offset += arg_slot.as_constant() * stackElementSize;
+ } else {
+ scale_reg = arg_slot.as_register();
+ scale_factor = Address::times(stackElementSize);
+ }
+ offset += wordSize; // return PC is on stack
+ return Address(rsp, scale_reg, scale_factor, offset);
+}
+
+
+void MacroAssembler::verify_oop_addr(Address addr, const char* s) {
+ if (!VerifyOops) return;
+
+ // Address adjust(addr.base(), addr.index(), addr.scale(), addr.disp() + BytesPerWord);
+ // Pass register number to verify_oop_subroutine
+ char* b = new char[strlen(s) + 50];
+ sprintf(b, "verify_oop_addr: %s", s);
+
+#ifdef _LP64
+ push(rscratch1); // save r10, trashed by movptr()
+#endif
+ push(rax); // save rax,
+ // addr may contain rsp so we will have to adjust it based on the push
+ // we just did (and on 64 bit we do two pushes)
+ // NOTE: 64bit seemed to have had a bug in that it did movq(addr, rax); which
+ // stores rax into addr which is backwards of what was intended.
+ if (addr.uses(rsp)) {
+ lea(rax, addr);
+ pushptr(Address(rax, LP64_ONLY(2 *) BytesPerWord));
+ } else {
+ pushptr(addr);
+ }
+
+ ExternalAddress buffer((address) b);
+ // pass msg argument
+ // avoid using pushptr, as it modifies scratch registers
+ // and our contract is not to modify anything
+ movptr(rax, buffer.addr());
+ push(rax);
+
+ // call indirectly to solve generation ordering problem
+ movptr(rax, ExternalAddress(StubRoutines::verify_oop_subroutine_entry_address()));
+ call(rax);
+ // Caller pops the arguments (addr, message) and restores rax, r10.
+}
+
+void MacroAssembler::verify_tlab() {
+#ifdef ASSERT
+ if (UseTLAB && VerifyOops) {
+ Label next, ok;
+ Register t1 = rsi;
+ Register thread_reg = NOT_LP64(rbx) LP64_ONLY(r15_thread);
+
+ push(t1);
+ NOT_LP64(push(thread_reg));
+ NOT_LP64(get_thread(thread_reg));
+
+ movptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_top_offset())));
+ cmpptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_start_offset())));
+ jcc(Assembler::aboveEqual, next);
+ STOP("assert(top >= start)");
+ should_not_reach_here();
+
+ bind(next);
+ movptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_end_offset())));
+ cmpptr(t1, Address(thread_reg, in_bytes(JavaThread::tlab_top_offset())));
+ jcc(Assembler::aboveEqual, ok);
+ STOP("assert(top <= end)");
+ should_not_reach_here();
+
+ bind(ok);
+ NOT_LP64(pop(thread_reg));
+ pop(t1);
+ }
+#endif
+}
+
+class ControlWord {
+ public:
+ int32_t _value;
+
+ int rounding_control() const { return (_value >> 10) & 3 ; }
+ int precision_control() const { return (_value >> 8) & 3 ; }
+ bool precision() const { return ((_value >> 5) & 1) != 0; }
+ bool underflow() const { return ((_value >> 4) & 1) != 0; }
+ bool overflow() const { return ((_value >> 3) & 1) != 0; }
+ bool zero_divide() const { return ((_value >> 2) & 1) != 0; }
+ bool denormalized() const { return ((_value >> 1) & 1) != 0; }
+ bool invalid() const { return ((_value >> 0) & 1) != 0; }
+
+ void print() const {
+ // rounding control
+ const char* rc;
+ switch (rounding_control()) {
+ case 0: rc = "round near"; break;
+ case 1: rc = "round down"; break;
+ case 2: rc = "round up "; break;
+ case 3: rc = "chop "; break;
+ };
+ // precision control
+ const char* pc;
+ switch (precision_control()) {
+ case 0: pc = "24 bits "; break;
+ case 1: pc = "reserved"; break;
+ case 2: pc = "53 bits "; break;
+ case 3: pc = "64 bits "; break;
+ };
+ // flags
+ char f[9];
+ f[0] = ' ';
+ f[1] = ' ';
+ f[2] = (precision ()) ? 'P' : 'p';
+ f[3] = (underflow ()) ? 'U' : 'u';
+ f[4] = (overflow ()) ? 'O' : 'o';
+ f[5] = (zero_divide ()) ? 'Z' : 'z';
+ f[6] = (denormalized()) ? 'D' : 'd';
+ f[7] = (invalid ()) ? 'I' : 'i';
+ f[8] = '\x0';
+ // output
+ printf("%04x masks = %s, %s, %s", _value & 0xFFFF, f, rc, pc);
+ }
+
+};
+
+class StatusWord {
+ public:
+ int32_t _value;
+
+ bool busy() const { return ((_value >> 15) & 1) != 0; }
+ bool C3() const { return ((_value >> 14) & 1) != 0; }
+ bool C2() const { return ((_value >> 10) & 1) != 0; }
+ bool C1() const { return ((_value >> 9) & 1) != 0; }
+ bool C0() const { return ((_value >> 8) & 1) != 0; }
+ int top() const { return (_value >> 11) & 7 ; }
+ bool error_status() const { return ((_value >> 7) & 1) != 0; }
+ bool stack_fault() const { return ((_value >> 6) & 1) != 0; }
+ bool precision() const { return ((_value >> 5) & 1) != 0; }
+ bool underflow() const { return ((_value >> 4) & 1) != 0; }
+ bool overflow() const { return ((_value >> 3) & 1) != 0; }
+ bool zero_divide() const { return ((_value >> 2) & 1) != 0; }
+ bool denormalized() const { return ((_value >> 1) & 1) != 0; }
+ bool invalid() const { return ((_value >> 0) & 1) != 0; }
+
+ void print() const {
+ // condition codes
+ char c[5];
+ c[0] = (C3()) ? '3' : '-';
+ c[1] = (C2()) ? '2' : '-';
+ c[2] = (C1()) ? '1' : '-';
+ c[3] = (C0()) ? '0' : '-';
+ c[4] = '\x0';
+ // flags
+ char f[9];
+ f[0] = (error_status()) ? 'E' : '-';
+ f[1] = (stack_fault ()) ? 'S' : '-';
+ f[2] = (precision ()) ? 'P' : '-';
+ f[3] = (underflow ()) ? 'U' : '-';
+ f[4] = (overflow ()) ? 'O' : '-';
+ f[5] = (zero_divide ()) ? 'Z' : '-';
+ f[6] = (denormalized()) ? 'D' : '-';
+ f[7] = (invalid ()) ? 'I' : '-';
+ f[8] = '\x0';
+ // output
+ printf("%04x flags = %s, cc = %s, top = %d", _value & 0xFFFF, f, c, top());
+ }
+
+};
+
+class TagWord {
+ public:
+ int32_t _value;
+
+ int tag_at(int i) const { return (_value >> (i*2)) & 3; }
+
+ void print() const {
+ printf("%04x", _value & 0xFFFF);
+ }
+
+};
+
+class FPU_Register {
+ public:
+ int32_t _m0;
+ int32_t _m1;
+ int16_t _ex;
+
+ bool is_indefinite() const {
+ return _ex == -1 && _m1 == (int32_t)0xC0000000 && _m0 == 0;
+ }
+
+ void print() const {
+ char sign = (_ex < 0) ? '-' : '+';
+ const char* kind = (_ex == 0x7FFF || _ex == (int16_t)-1) ? "NaN" : " ";
+ printf("%c%04hx.%08x%08x %s", sign, _ex, _m1, _m0, kind);
+ };
+
+};
+
+class FPU_State {
+ public:
+ enum {
+ register_size = 10,
+ number_of_registers = 8,
+ register_mask = 7
+ };
+
+ ControlWord _control_word;
+ StatusWord _status_word;
+ TagWord _tag_word;
+ int32_t _error_offset;
+ int32_t _error_selector;
+ int32_t _data_offset;
+ int32_t _data_selector;
+ int8_t _register[register_size * number_of_registers];
+
+ int tag_for_st(int i) const { return _tag_word.tag_at((_status_word.top() + i) & register_mask); }
+ FPU_Register* st(int i) const { return (FPU_Register*)&_register[register_size * i]; }
+
+ const char* tag_as_string(int tag) const {
+ switch (tag) {
+ case 0: return "valid";
+ case 1: return "zero";
+ case 2: return "special";
+ case 3: return "empty";
+ }
+ ShouldNotReachHere();
+ return NULL;
+ }
+
+ void print() const {
+ // print computation registers
+ { int t = _status_word.top();
+ for (int i = 0; i < number_of_registers; i++) {
+ int j = (i - t) & register_mask;
+ printf("%c r%d = ST%d = ", (j == 0 ? '*' : ' '), i, j);
+ st(j)->print();
+ printf(" %s\n", tag_as_string(_tag_word.tag_at(i)));
+ }
+ }
+ printf("\n");
+ // print control registers
+ printf("ctrl = "); _control_word.print(); printf("\n");
+ printf("stat = "); _status_word .print(); printf("\n");
+ printf("tags = "); _tag_word .print(); printf("\n");
+ }
+
+};
+
+class Flag_Register {
+ public:
+ int32_t _value;
+
+ bool overflow() const { return ((_value >> 11) & 1) != 0; }
+ bool direction() const { return ((_value >> 10) & 1) != 0; }
+ bool sign() const { return ((_value >> 7) & 1) != 0; }
+ bool zero() const { return ((_value >> 6) & 1) != 0; }
+ bool auxiliary_carry() const { return ((_value >> 4) & 1) != 0; }
+ bool parity() const { return ((_value >> 2) & 1) != 0; }
+ bool carry() const { return ((_value >> 0) & 1) != 0; }
+
+ void print() const {
+ // flags
+ char f[8];
+ f[0] = (overflow ()) ? 'O' : '-';
+ f[1] = (direction ()) ? 'D' : '-';
+ f[2] = (sign ()) ? 'S' : '-';
+ f[3] = (zero ()) ? 'Z' : '-';
+ f[4] = (auxiliary_carry()) ? 'A' : '-';
+ f[5] = (parity ()) ? 'P' : '-';
+ f[6] = (carry ()) ? 'C' : '-';
+ f[7] = '\x0';
+ // output
+ printf("%08x flags = %s", _value, f);
+ }
+
+};
+
+class IU_Register {
+ public:
+ int32_t _value;
+
+ void print() const {
+ printf("%08x %11d", _value, _value);
+ }
+
+};
+
+class IU_State {
+ public:
+ Flag_Register _eflags;
+ IU_Register _rdi;
+ IU_Register _rsi;
+ IU_Register _rbp;
+ IU_Register _rsp;
+ IU_Register _rbx;
+ IU_Register _rdx;
+ IU_Register _rcx;
+ IU_Register _rax;
+
+ void print() const {
+ // computation registers
+ printf("rax, = "); _rax.print(); printf("\n");
+ printf("rbx, = "); _rbx.print(); printf("\n");
+ printf("rcx = "); _rcx.print(); printf("\n");
+ printf("rdx = "); _rdx.print(); printf("\n");
+ printf("rdi = "); _rdi.print(); printf("\n");
+ printf("rsi = "); _rsi.print(); printf("\n");
+ printf("rbp, = "); _rbp.print(); printf("\n");
+ printf("rsp = "); _rsp.print(); printf("\n");
+ printf("\n");
+ // control registers
+ printf("flgs = "); _eflags.print(); printf("\n");
+ }
+};
+
+
+class CPU_State {
+ public:
+ FPU_State _fpu_state;
+ IU_State _iu_state;
+
+ void print() const {
+ printf("--------------------------------------------------\n");
+ _iu_state .print();
+ printf("\n");
+ _fpu_state.print();
+ printf("--------------------------------------------------\n");
+ }
+
+};
+
+
+static void _print_CPU_state(CPU_State* state) {
+ state->print();
+};
+
+
+void MacroAssembler::print_CPU_state() {
+ push_CPU_state();
+ push(rsp); // pass CPU state
+ call(RuntimeAddress(CAST_FROM_FN_PTR(address, _print_CPU_state)));
+ addptr(rsp, wordSize); // discard argument
+ pop_CPU_state();
+}
+
+
+static bool _verify_FPU(int stack_depth, char* s, CPU_State* state) {
+ static int counter = 0;
+ FPU_State* fs = &state->_fpu_state;
+ counter++;
+ // For leaf calls, only verify that the top few elements remain empty.
+ // We only need 1 empty at the top for C2 code.
+ if( stack_depth < 0 ) {
+ if( fs->tag_for_st(7) != 3 ) {
+ printf("FPR7 not empty\n");
+ state->print();
+ assert(false, "error");
+ return false;
+ }
+ return true; // All other stack states do not matter
+ }
+
+ assert((fs->_control_word._value & 0xffff) == StubRoutines::_fpu_cntrl_wrd_std,
+ "bad FPU control word");
+
+ // compute stack depth
+ int i = 0;
+ while (i < FPU_State::number_of_registers && fs->tag_for_st(i) < 3) i++;
+ int d = i;
+ while (i < FPU_State::number_of_registers && fs->tag_for_st(i) == 3) i++;
+ // verify findings
+ if (i != FPU_State::number_of_registers) {
+ // stack not contiguous
+ printf("%s: stack not contiguous at ST%d\n", s, i);
+ state->print();
+ assert(false, "error");
+ return false;
+ }
+ // check if computed stack depth corresponds to expected stack depth
+ if (stack_depth < 0) {
+ // expected stack depth is -stack_depth or less
+ if (d > -stack_depth) {
+ // too many elements on the stack
+ printf("%s: <= %d stack elements expected but found %d\n", s, -stack_depth, d);
+ state->print();
+ assert(false, "error");
+ return false;
+ }
+ } else {
+ // expected stack depth is stack_depth
+ if (d != stack_depth) {
+ // wrong stack depth
+ printf("%s: %d stack elements expected but found %d\n", s, stack_depth, d);
+ state->print();
+ assert(false, "error");
+ return false;
+ }
+ }
+ // everything is cool
+ return true;
+}
+
+
+void MacroAssembler::verify_FPU(int stack_depth, const char* s) {
+ if (!VerifyFPU) return;
+ push_CPU_state();
+ push(rsp); // pass CPU state
+ ExternalAddress msg((address) s);
+ // pass message string s
+ pushptr(msg.addr());
+ push(stack_depth); // pass stack depth
+ call(RuntimeAddress(CAST_FROM_FN_PTR(address, _verify_FPU)));
+ addptr(rsp, 3 * wordSize); // discard arguments
+ // check for error
+ { Label L;
+ testl(rax, rax);
+ jcc(Assembler::notZero, L);
+ int3(); // break if error condition
+ bind(L);
+ }
+ pop_CPU_state();
+}
+
+void MacroAssembler::load_klass(Register dst, Register src) {
+#ifdef _LP64
+ if (UseCompressedKlassPointers) {
+ movl(dst, Address(src, oopDesc::klass_offset_in_bytes()));
+ decode_klass_not_null(dst);
+ } else
+#endif
+ movptr(dst, Address(src, oopDesc::klass_offset_in_bytes()));
+}
+
+void MacroAssembler::load_prototype_header(Register dst, Register src) {
+#ifdef _LP64
+ if (UseCompressedKlassPointers) {
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ movl(dst, Address(src, oopDesc::klass_offset_in_bytes()));
+ if (Universe::narrow_klass_shift() != 0) {
+ assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
+ assert(LogKlassAlignmentInBytes == Address::times_8, "klass not aligned on 64bits?");
+ movq(dst, Address(r12_heapbase, dst, Address::times_8, Klass::prototype_header_offset()));
+ } else {
+ movq(dst, Address(dst, Klass::prototype_header_offset()));
+ }
+ } else
+#endif
+ {
+ movptr(dst, Address(src, oopDesc::klass_offset_in_bytes()));
+ movptr(dst, Address(dst, Klass::prototype_header_offset()));
+ }
+}
+
+void MacroAssembler::store_klass(Register dst, Register src) {
+#ifdef _LP64
+ if (UseCompressedKlassPointers) {
+ encode_klass_not_null(src);
+ movl(Address(dst, oopDesc::klass_offset_in_bytes()), src);
+ } else
+#endif
+ movptr(Address(dst, oopDesc::klass_offset_in_bytes()), src);
+}
+
+void MacroAssembler::load_heap_oop(Register dst, Address src) {
+#ifdef _LP64
+ // FIXME: Must change all places where we try to load the klass.
+ if (UseCompressedOops) {
+ movl(dst, src);
+ decode_heap_oop(dst);
+ } else
+#endif
+ movptr(dst, src);
+}
+
+// Doesn't do verfication, generates fixed size code
+void MacroAssembler::load_heap_oop_not_null(Register dst, Address src) {
+#ifdef _LP64
+ if (UseCompressedOops) {
+ movl(dst, src);
+ decode_heap_oop_not_null(dst);
+ } else
+#endif
+ movptr(dst, src);
+}
+
+void MacroAssembler::store_heap_oop(Address dst, Register src) {
+#ifdef _LP64
+ if (UseCompressedOops) {
+ assert(!dst.uses(src), "not enough registers");
+ encode_heap_oop(src);
+ movl(dst, src);
+ } else
+#endif
+ movptr(dst, src);
+}
+
+void MacroAssembler::cmp_heap_oop(Register src1, Address src2, Register tmp) {
+ assert_different_registers(src1, tmp);
+#ifdef _LP64
+ if (UseCompressedOops) {
+ bool did_push = false;
+ if (tmp == noreg) {
+ tmp = rax;
+ push(tmp);
+ did_push = true;
+ assert(!src2.uses(rsp), "can't push");
+ }
+ load_heap_oop(tmp, src2);
+ cmpptr(src1, tmp);
+ if (did_push) pop(tmp);
+ } else
+#endif
+ cmpptr(src1, src2);
+}
+
+// Used for storing NULLs.
+void MacroAssembler::store_heap_oop_null(Address dst) {
+#ifdef _LP64
+ if (UseCompressedOops) {
+ movl(dst, (int32_t)NULL_WORD);
+ } else {
+ movslq(dst, (int32_t)NULL_WORD);
+ }
+#else
+ movl(dst, (int32_t)NULL_WORD);
+#endif
+}
+
+#ifdef _LP64
+void MacroAssembler::store_klass_gap(Register dst, Register src) {
+ if (UseCompressedKlassPointers) {
+ // Store to klass gap in destination
+ movl(Address(dst, oopDesc::klass_gap_offset_in_bytes()), src);
+ }
+}
+
+#ifdef ASSERT
+void MacroAssembler::verify_heapbase(const char* msg) {
+ assert (UseCompressedOops || UseCompressedKlassPointers, "should be compressed");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ if (CheckCompressedOops) {
+ Label ok;
+ push(rscratch1); // cmpptr trashes rscratch1
+ cmpptr(r12_heapbase, ExternalAddress((address)Universe::narrow_ptrs_base_addr()));
+ jcc(Assembler::equal, ok);
+ STOP(msg);
+ bind(ok);
+ pop(rscratch1);
+ }
+}
+#endif
+
+// Algorithm must match oop.inline.hpp encode_heap_oop.
+void MacroAssembler::encode_heap_oop(Register r) {
+#ifdef ASSERT
+ verify_heapbase("MacroAssembler::encode_heap_oop: heap base corrupted?");
+#endif
+ verify_oop(r, "broken oop in encode_heap_oop");
+ if (Universe::narrow_oop_base() == NULL) {
+ if (Universe::narrow_oop_shift() != 0) {
+ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+ shrq(r, LogMinObjAlignmentInBytes);
+ }
+ return;
+ }
+ testq(r, r);
+ cmovq(Assembler::equal, r, r12_heapbase);
+ subq(r, r12_heapbase);
+ shrq(r, LogMinObjAlignmentInBytes);
+}
+
+void MacroAssembler::encode_heap_oop_not_null(Register r) {
+#ifdef ASSERT
+ verify_heapbase("MacroAssembler::encode_heap_oop_not_null: heap base corrupted?");
+ if (CheckCompressedOops) {
+ Label ok;
+ testq(r, r);
+ jcc(Assembler::notEqual, ok);
+ STOP("null oop passed to encode_heap_oop_not_null");
+ bind(ok);
+ }
+#endif
+ verify_oop(r, "broken oop in encode_heap_oop_not_null");
+ if (Universe::narrow_oop_base() != NULL) {
+ subq(r, r12_heapbase);
+ }
+ if (Universe::narrow_oop_shift() != 0) {
+ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+ shrq(r, LogMinObjAlignmentInBytes);
+ }
+}
+
+void MacroAssembler::encode_heap_oop_not_null(Register dst, Register src) {
+#ifdef ASSERT
+ verify_heapbase("MacroAssembler::encode_heap_oop_not_null2: heap base corrupted?");
+ if (CheckCompressedOops) {
+ Label ok;
+ testq(src, src);
+ jcc(Assembler::notEqual, ok);
+ STOP("null oop passed to encode_heap_oop_not_null2");
+ bind(ok);
+ }
+#endif
+ verify_oop(src, "broken oop in encode_heap_oop_not_null2");
+ if (dst != src) {
+ movq(dst, src);
+ }
+ if (Universe::narrow_oop_base() != NULL) {
+ subq(dst, r12_heapbase);
+ }
+ if (Universe::narrow_oop_shift() != 0) {
+ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+ shrq(dst, LogMinObjAlignmentInBytes);
+ }
+}
+
+void MacroAssembler::decode_heap_oop(Register r) {
+#ifdef ASSERT
+ verify_heapbase("MacroAssembler::decode_heap_oop: heap base corrupted?");
+#endif
+ if (Universe::narrow_oop_base() == NULL) {
+ if (Universe::narrow_oop_shift() != 0) {
+ assert (LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+ shlq(r, LogMinObjAlignmentInBytes);
+ }
+ } else {
+ Label done;
+ shlq(r, LogMinObjAlignmentInBytes);
+ jccb(Assembler::equal, done);
+ addq(r, r12_heapbase);
+ bind(done);
+ }
+ verify_oop(r, "broken oop in decode_heap_oop");
+}
+
+void MacroAssembler::decode_heap_oop_not_null(Register r) {
+ // Note: it will change flags
+ assert (UseCompressedOops, "should only be used for compressed headers");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ // Cannot assert, unverified entry point counts instructions (see .ad file)
+ // vtableStubs also counts instructions in pd_code_size_limit.
+ // Also do not verify_oop as this is called by verify_oop.
+ if (Universe::narrow_oop_shift() != 0) {
+ assert(LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+ shlq(r, LogMinObjAlignmentInBytes);
+ if (Universe::narrow_oop_base() != NULL) {
+ addq(r, r12_heapbase);
+ }
+ } else {
+ assert (Universe::narrow_oop_base() == NULL, "sanity");
+ }
+}
+
+void MacroAssembler::decode_heap_oop_not_null(Register dst, Register src) {
+ // Note: it will change flags
+ assert (UseCompressedOops, "should only be used for compressed headers");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ // Cannot assert, unverified entry point counts instructions (see .ad file)
+ // vtableStubs also counts instructions in pd_code_size_limit.
+ // Also do not verify_oop as this is called by verify_oop.
+ if (Universe::narrow_oop_shift() != 0) {
+ assert(LogMinObjAlignmentInBytes == Universe::narrow_oop_shift(), "decode alg wrong");
+ if (LogMinObjAlignmentInBytes == Address::times_8) {
+ leaq(dst, Address(r12_heapbase, src, Address::times_8, 0));
+ } else {
+ if (dst != src) {
+ movq(dst, src);
+ }
+ shlq(dst, LogMinObjAlignmentInBytes);
+ if (Universe::narrow_oop_base() != NULL) {
+ addq(dst, r12_heapbase);
+ }
+ }
+ } else {
+ assert (Universe::narrow_oop_base() == NULL, "sanity");
+ if (dst != src) {
+ movq(dst, src);
+ }
+ }
+}
+
+void MacroAssembler::encode_klass_not_null(Register r) {
+ assert(Metaspace::is_initialized(), "metaspace should be initialized");
+#ifdef ASSERT
+ verify_heapbase("MacroAssembler::encode_klass_not_null: heap base corrupted?");
+#endif
+ if (Universe::narrow_klass_base() != NULL) {
+ subq(r, r12_heapbase);
+ }
+ if (Universe::narrow_klass_shift() != 0) {
+ assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
+ shrq(r, LogKlassAlignmentInBytes);
+ }
+}
+
+void MacroAssembler::encode_klass_not_null(Register dst, Register src) {
+ assert(Metaspace::is_initialized(), "metaspace should be initialized");
+#ifdef ASSERT
+ verify_heapbase("MacroAssembler::encode_klass_not_null2: heap base corrupted?");
+#endif
+ if (dst != src) {
+ movq(dst, src);
+ }
+ if (Universe::narrow_klass_base() != NULL) {
+ subq(dst, r12_heapbase);
+ }
+ if (Universe::narrow_klass_shift() != 0) {
+ assert (LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
+ shrq(dst, LogKlassAlignmentInBytes);
+ }
+}
+
+void MacroAssembler::decode_klass_not_null(Register r) {
+ assert(Metaspace::is_initialized(), "metaspace should be initialized");
+ // Note: it will change flags
+ assert (UseCompressedKlassPointers, "should only be used for compressed headers");
+ // Cannot assert, unverified entry point counts instructions (see .ad file)
+ // vtableStubs also counts instructions in pd_code_size_limit.
+ // Also do not verify_oop as this is called by verify_oop.
+ if (Universe::narrow_klass_shift() != 0) {
+ assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
+ shlq(r, LogKlassAlignmentInBytes);
+ if (Universe::narrow_klass_base() != NULL) {
+ addq(r, r12_heapbase);
+ }
+ } else {
+ assert (Universe::narrow_klass_base() == NULL, "sanity");
+ }
+}
+
+void MacroAssembler::decode_klass_not_null(Register dst, Register src) {
+ assert(Metaspace::is_initialized(), "metaspace should be initialized");
+ // Note: it will change flags
+ assert (UseCompressedKlassPointers, "should only be used for compressed headers");
+ // Cannot assert, unverified entry point counts instructions (see .ad file)
+ // vtableStubs also counts instructions in pd_code_size_limit.
+ // Also do not verify_oop as this is called by verify_oop.
+ if (Universe::narrow_klass_shift() != 0) {
+ assert(LogKlassAlignmentInBytes == Universe::narrow_klass_shift(), "decode alg wrong");
+ assert(LogKlassAlignmentInBytes == Address::times_8, "klass not aligned on 64bits?");
+ leaq(dst, Address(r12_heapbase, src, Address::times_8, 0));
+ } else {
+ assert (Universe::narrow_klass_base() == NULL, "sanity");
+ if (dst != src) {
+ movq(dst, src);
+ }
+ }
+}
+
+void MacroAssembler::set_narrow_oop(Register dst, jobject obj) {
+ assert (UseCompressedOops, "should only be used for compressed headers");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
+ int oop_index = oop_recorder()->find_index(obj);
+ RelocationHolder rspec = oop_Relocation::spec(oop_index);
+ mov_narrow_oop(dst, oop_index, rspec);
+}
+
+void MacroAssembler::set_narrow_oop(Address dst, jobject obj) {
+ assert (UseCompressedOops, "should only be used for compressed headers");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
+ int oop_index = oop_recorder()->find_index(obj);
+ RelocationHolder rspec = oop_Relocation::spec(oop_index);
+ mov_narrow_oop(dst, oop_index, rspec);
+}
+
+void MacroAssembler::set_narrow_klass(Register dst, Klass* k) {
+ assert (UseCompressedKlassPointers, "should only be used for compressed headers");
+ assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
+ int klass_index = oop_recorder()->find_index(k);
+ RelocationHolder rspec = metadata_Relocation::spec(klass_index);
+ mov_narrow_oop(dst, oopDesc::encode_klass(k), rspec);
+}
+
+void MacroAssembler::set_narrow_klass(Address dst, Klass* k) {
+ assert (UseCompressedKlassPointers, "should only be used for compressed headers");
+ assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
+ int klass_index = oop_recorder()->find_index(k);
+ RelocationHolder rspec = metadata_Relocation::spec(klass_index);
+ mov_narrow_oop(dst, oopDesc::encode_klass(k), rspec);
+}
+
+void MacroAssembler::cmp_narrow_oop(Register dst, jobject obj) {
+ assert (UseCompressedOops, "should only be used for compressed headers");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
+ int oop_index = oop_recorder()->find_index(obj);
+ RelocationHolder rspec = oop_Relocation::spec(oop_index);
+ Assembler::cmp_narrow_oop(dst, oop_index, rspec);
+}
+
+void MacroAssembler::cmp_narrow_oop(Address dst, jobject obj) {
+ assert (UseCompressedOops, "should only be used for compressed headers");
+ assert (Universe::heap() != NULL, "java heap should be initialized");
+ assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
+ int oop_index = oop_recorder()->find_index(obj);
+ RelocationHolder rspec = oop_Relocation::spec(oop_index);
+ Assembler::cmp_narrow_oop(dst, oop_index, rspec);
+}
+
+void MacroAssembler::cmp_narrow_klass(Register dst, Klass* k) {
+ assert (UseCompressedKlassPointers, "should only be used for compressed headers");
+ assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
+ int klass_index = oop_recorder()->find_index(k);
+ RelocationHolder rspec = metadata_Relocation::spec(klass_index);
+ Assembler::cmp_narrow_oop(dst, oopDesc::encode_klass(k), rspec);
+}
+
+void MacroAssembler::cmp_narrow_klass(Address dst, Klass* k) {
+ assert (UseCompressedKlassPointers, "should only be used for compressed headers");
+ assert (oop_recorder() != NULL, "this assembler needs an OopRecorder");
+ int klass_index = oop_recorder()->find_index(k);
+ RelocationHolder rspec = metadata_Relocation::spec(klass_index);
+ Assembler::cmp_narrow_oop(dst, oopDesc::encode_klass(k), rspec);
+}
+
+void MacroAssembler::reinit_heapbase() {
+ if (UseCompressedOops || UseCompressedKlassPointers) {
+ movptr(r12_heapbase, ExternalAddress((address)Universe::narrow_ptrs_base_addr()));
+ }
+}
+#endif // _LP64
+
+
+// C2 compiled method's prolog code.
+void MacroAssembler::verified_entry(int framesize, bool stack_bang, bool fp_mode_24b) {
+
+ // WARNING: Initial instruction MUST be 5 bytes or longer so that
+ // NativeJump::patch_verified_entry will be able to patch out the entry
+ // code safely. The push to verify stack depth is ok at 5 bytes,
+ // the frame allocation can be either 3 or 6 bytes. So if we don't do
+ // stack bang then we must use the 6 byte frame allocation even if
+ // we have no frame. :-(
+
+ assert((framesize & (StackAlignmentInBytes-1)) == 0, "frame size not aligned");
+ // Remove word for return addr
+ framesize -= wordSize;
+
+ // Calls to C2R adapters often do not accept exceptional returns.
+ // We require that their callers must bang for them. But be careful, because
+ // some VM calls (such as call site linkage) can use several kilobytes of
+ // stack. But the stack safety zone should account for that.
+ // See bugs 4446381, 4468289, 4497237.
+ if (stack_bang) {
+ generate_stack_overflow_check(framesize);
+
+ // We always push rbp, so that on return to interpreter rbp, will be
+ // restored correctly and we can correct the stack.
+ push(rbp);
+ // Remove word for ebp
+ framesize -= wordSize;
+
+ // Create frame
+ if (framesize) {
+ subptr(rsp, framesize);
+ }
+ } else {
+ // Create frame (force generation of a 4 byte immediate value)
+ subptr_imm32(rsp, framesize);
+
+ // Save RBP register now.
+ framesize -= wordSize;
+ movptr(Address(rsp, framesize), rbp);
+ }
+
+ if (VerifyStackAtCalls) { // Majik cookie to verify stack depth
+ framesize -= wordSize;
+ movptr(Address(rsp, framesize), (int32_t)0xbadb100d);
+ }
+
+#ifndef _LP64
+ // If method sets FPU control word do it now
+ if (fp_mode_24b) {
+ fldcw(ExternalAddress(StubRoutines::addr_fpu_cntrl_wrd_24()));
+ }
+ if (UseSSE >= 2 && VerifyFPU) {
+ verify_FPU(0, "FPU stack must be clean on entry");
+ }
+#endif
+
+#ifdef ASSERT
+ if (VerifyStackAtCalls) {
+ Label L;
+ push(rax);
+ mov(rax, rsp);
+ andptr(rax, StackAlignmentInBytes-1);
+ cmpptr(rax, StackAlignmentInBytes-wordSize);
+ pop(rax);
+ jcc(Assembler::equal, L);
+ STOP("Stack is not properly aligned!");
+ bind(L);
+ }
+#endif
+
+}
+
+void MacroAssembler::clear_mem(Register base, Register cnt, Register tmp) {
+ // cnt - number of qwords (8-byte words).
+ // base - start address, qword aligned.
+ assert(base==rdi, "base register must be edi for rep stos");
+ assert(tmp==rax, "tmp register must be eax for rep stos");
+ assert(cnt==rcx, "cnt register must be ecx for rep stos");
+
+ xorptr(tmp, tmp);
+ if (UseFastStosb) {
+ shlptr(cnt,3); // convert to number of bytes
+ rep_stosb();
+ } else {
+ NOT_LP64(shlptr(cnt,1);) // convert to number of dwords for 32-bit VM
+ rep_stos();
+ }
+}
+
+// IndexOf for constant substrings with size >= 8 chars
+// which don't need to be loaded through stack.
+void MacroAssembler::string_indexofC8(Register str1, Register str2,
+ Register cnt1, Register cnt2,
+ int int_cnt2, Register result,
+ XMMRegister vec, Register tmp) {
+ ShortBranchVerifier sbv(this);
+ assert(UseSSE42Intrinsics, "SSE4.2 is required");
+
+ // This method uses pcmpestri inxtruction with bound registers
+ // inputs:
+ // xmm - substring
+ // rax - substring length (elements count)
+ // mem - scanned string
+ // rdx - string length (elements count)
+ // 0xd - mode: 1100 (substring search) + 01 (unsigned shorts)
+ // outputs:
+ // rcx - matched index in string
+ assert(cnt1 == rdx && cnt2 == rax && tmp == rcx, "pcmpestri");
+
+ Label RELOAD_SUBSTR, SCAN_TO_SUBSTR, SCAN_SUBSTR,
+ RET_FOUND, RET_NOT_FOUND, EXIT, FOUND_SUBSTR,
+ MATCH_SUBSTR_HEAD, RELOAD_STR, FOUND_CANDIDATE;
+
+ // Note, inline_string_indexOf() generates checks:
+ // if (substr.count > string.count) return -1;
+ // if (substr.count == 0) return 0;
+ assert(int_cnt2 >= 8, "this code isused only for cnt2 >= 8 chars");
+
+ // Load substring.
+ movdqu(vec, Address(str2, 0));
+ movl(cnt2, int_cnt2);
+ movptr(result, str1); // string addr
+
+ if (int_cnt2 > 8) {
+ jmpb(SCAN_TO_SUBSTR);
+
+ // Reload substr for rescan, this code
+ // is executed only for large substrings (> 8 chars)
+ bind(RELOAD_SUBSTR);
+ movdqu(vec, Address(str2, 0));
+ negptr(cnt2); // Jumped here with negative cnt2, convert to positive
+
+ bind(RELOAD_STR);
+ // We came here after the beginning of the substring was
+ // matched but the rest of it was not so we need to search
+ // again. Start from the next element after the previous match.
+
+ // cnt2 is number of substring reminding elements and
+ // cnt1 is number of string reminding elements when cmp failed.
+ // Restored cnt1 = cnt1 - cnt2 + int_cnt2
+ subl(cnt1, cnt2);
+ addl(cnt1, int_cnt2);
+ movl(cnt2, int_cnt2); // Now restore cnt2
+
+ decrementl(cnt1); // Shift to next element
+ cmpl(cnt1, cnt2);
+ jccb(Assembler::negative, RET_NOT_FOUND); // Left less then substring
+
+ addptr(result, 2);
+
+ } // (int_cnt2 > 8)
+
+ // Scan string for start of substr in 16-byte vectors
+ bind(SCAN_TO_SUBSTR);
+ pcmpestri(vec, Address(result, 0), 0x0d);
+ jccb(Assembler::below, FOUND_CANDIDATE); // CF == 1
+ subl(cnt1, 8);
+ jccb(Assembler::lessEqual, RET_NOT_FOUND); // Scanned full string
+ cmpl(cnt1, cnt2);
+ jccb(Assembler::negative, RET_NOT_FOUND); // Left less then substring
+ addptr(result, 16);
+ jmpb(SCAN_TO_SUBSTR);
+
+ // Found a potential substr
+ bind(FOUND_CANDIDATE);
+ // Matched whole vector if first element matched (tmp(rcx) == 0).
+ if (int_cnt2 == 8) {
+ jccb(Assembler::overflow, RET_FOUND); // OF == 1
+ } else { // int_cnt2 > 8
+ jccb(Assembler::overflow, FOUND_SUBSTR);
+ }
+ // After pcmpestri tmp(rcx) contains matched element index
+ // Compute start addr of substr
+ lea(result, Address(result, tmp, Address::times_2));
+
+ // Make sure string is still long enough
+ subl(cnt1, tmp);
+ cmpl(cnt1, cnt2);
+ if (int_cnt2 == 8) {
+ jccb(Assembler::greaterEqual, SCAN_TO_SUBSTR);
+ } else { // int_cnt2 > 8
+ jccb(Assembler::greaterEqual, MATCH_SUBSTR_HEAD);
+ }
+ // Left less then substring.
+
+ bind(RET_NOT_FOUND);
+ movl(result, -1);
+ jmpb(EXIT);
+
+ if (int_cnt2 > 8) {
+ // This code is optimized for the case when whole substring
+ // is matched if its head is matched.
+ bind(MATCH_SUBSTR_HEAD);
+ pcmpestri(vec, Address(result, 0), 0x0d);
+ // Reload only string if does not match
+ jccb(Assembler::noOverflow, RELOAD_STR); // OF == 0
+
+ Label CONT_SCAN_SUBSTR;
+ // Compare the rest of substring (> 8 chars).
+ bind(FOUND_SUBSTR);
+ // First 8 chars are already matched.
+ negptr(cnt2);
+ addptr(cnt2, 8);
+
+ bind(SCAN_SUBSTR);
+ subl(cnt1, 8);
+ cmpl(cnt2, -8); // Do not read beyond substring
+ jccb(Assembler::lessEqual, CONT_SCAN_SUBSTR);
+ // Back-up strings to avoid reading beyond substring:
+ // cnt1 = cnt1 - cnt2 + 8
+ addl(cnt1, cnt2); // cnt2 is negative
+ addl(cnt1, 8);
+ movl(cnt2, 8); negptr(cnt2);
+ bind(CONT_SCAN_SUBSTR);
+ if (int_cnt2 < (int)G) {
+ movdqu(vec, Address(str2, cnt2, Address::times_2, int_cnt2*2));
+ pcmpestri(vec, Address(result, cnt2, Address::times_2, int_cnt2*2), 0x0d);
+ } else {
+ // calculate index in register to avoid integer overflow (int_cnt2*2)
+ movl(tmp, int_cnt2);
+ addptr(tmp, cnt2);
+ movdqu(vec, Address(str2, tmp, Address::times_2, 0));
+ pcmpestri(vec, Address(result, tmp, Address::times_2, 0), 0x0d);
+ }
+ // Need to reload strings pointers if not matched whole vector
+ jcc(Assembler::noOverflow, RELOAD_SUBSTR); // OF == 0
+ addptr(cnt2, 8);
+ jcc(Assembler::negative, SCAN_SUBSTR);
+ // Fall through if found full substring
+
+ } // (int_cnt2 > 8)
+
+ bind(RET_FOUND);
+ // Found result if we matched full small substring.
+ // Compute substr offset
+ subptr(result, str1);
+ shrl(result, 1); // index
+ bind(EXIT);
+
+} // string_indexofC8
+
+// Small strings are loaded through stack if they cross page boundary.
+void MacroAssembler::string_indexof(Register str1, Register str2,
+ Register cnt1, Register cnt2,
+ int int_cnt2, Register result,
+ XMMRegister vec, Register tmp) {
+ ShortBranchVerifier sbv(this);
+ assert(UseSSE42Intrinsics, "SSE4.2 is required");
+ //
+ // int_cnt2 is length of small (< 8 chars) constant substring
+ // or (-1) for non constant substring in which case its length
+ // is in cnt2 register.
+ //
+ // Note, inline_string_indexOf() generates checks:
+ // if (substr.count > string.count) return -1;
+ // if (substr.count == 0) return 0;
+ //
+ assert(int_cnt2 == -1 || (0 < int_cnt2 && int_cnt2 < 8), "should be != 0");
+
+ // This method uses pcmpestri inxtruction with bound registers
+ // inputs:
+ // xmm - substring
+ // rax - substring length (elements count)
+ // mem - scanned string
+ // rdx - string length (elements count)
+ // 0xd - mode: 1100 (substring search) + 01 (unsigned shorts)
+ // outputs:
+ // rcx - matched index in string
+ assert(cnt1 == rdx && cnt2 == rax && tmp == rcx, "pcmpestri");
+
+ Label RELOAD_SUBSTR, SCAN_TO_SUBSTR, SCAN_SUBSTR, ADJUST_STR,
+ RET_FOUND, RET_NOT_FOUND, CLEANUP, FOUND_SUBSTR,
+ FOUND_CANDIDATE;
+
+ { //========================================================
+ // We don't know where these strings are located
+ // and we can't read beyond them. Load them through stack.
+ Label BIG_STRINGS, CHECK_STR, COPY_SUBSTR, COPY_STR;
+
+ movptr(tmp, rsp); // save old SP
+
+ if (int_cnt2 > 0) { // small (< 8 chars) constant substring
+ if (int_cnt2 == 1) { // One char
+ load_unsigned_short(result, Address(str2, 0));
+ movdl(vec, result); // move 32 bits
+ } else if (int_cnt2 == 2) { // Two chars
+ movdl(vec, Address(str2, 0)); // move 32 bits
+ } else if (int_cnt2 == 4) { // Four chars
+ movq(vec, Address(str2, 0)); // move 64 bits
+ } else { // cnt2 = { 3, 5, 6, 7 }
+ // Array header size is 12 bytes in 32-bit VM
+ // + 6 bytes for 3 chars == 18 bytes,
+ // enough space to load vec and shift.
+ assert(HeapWordSize*TypeArrayKlass::header_size() >= 12,"sanity");
+ movdqu(vec, Address(str2, (int_cnt2*2)-16));
+ psrldq(vec, 16-(int_cnt2*2));
+ }
+ } else { // not constant substring
+ cmpl(cnt2, 8);
+ jccb(Assembler::aboveEqual, BIG_STRINGS); // Both strings are big enough
+
+ // We can read beyond string if srt+16 does not cross page boundary
+ // since heaps are aligned and mapped by pages.
+ assert(os::vm_page_size() < (int)G, "default page should be small");
+ movl(result, str2); // We need only low 32 bits
+ andl(result, (os::vm_page_size()-1));
+ cmpl(result, (os::vm_page_size()-16));
+ jccb(Assembler::belowEqual, CHECK_STR);
+
+ // Move small strings to stack to allow load 16 bytes into vec.
+ subptr(rsp, 16);
+ int stk_offset = wordSize-2;
+ push(cnt2);
+
+ bind(COPY_SUBSTR);
+ load_unsigned_short(result, Address(str2, cnt2, Address::times_2, -2));
+ movw(Address(rsp, cnt2, Address::times_2, stk_offset), result);
+ decrement(cnt2);
+ jccb(Assembler::notZero, COPY_SUBSTR);
+
+ pop(cnt2);
+ movptr(str2, rsp); // New substring address
+ } // non constant
+
+ bind(CHECK_STR);
+ cmpl(cnt1, 8);
+ jccb(Assembler::aboveEqual, BIG_STRINGS);
+
+ // Check cross page boundary.
+ movl(result, str1); // We need only low 32 bits
+ andl(result, (os::vm_page_size()-1));
+ cmpl(result, (os::vm_page_size()-16));
+ jccb(Assembler::belowEqual, BIG_STRINGS);
+
+ subptr(rsp, 16);
+ int stk_offset = -2;
+ if (int_cnt2 < 0) { // not constant
+ push(cnt2);
+ stk_offset += wordSize;
+ }
+ movl(cnt2, cnt1);
+
+ bind(COPY_STR);
+ load_unsigned_short(result, Address(str1, cnt2, Address::times_2, -2));
+ movw(Address(rsp, cnt2, Address::times_2, stk_offset), result);
+ decrement(cnt2);
+ jccb(Assembler::notZero, COPY_STR);
+
+ if (int_cnt2 < 0) { // not constant
+ pop(cnt2);
+ }
+ movptr(str1, rsp); // New string address
+
+ bind(BIG_STRINGS);
+ // Load substring.
+ if (int_cnt2 < 0) { // -1
+ movdqu(vec, Address(str2, 0));
+ push(cnt2); // substr count
+ push(str2); // substr addr
+ push(str1); // string addr
+ } else {
+ // Small (< 8 chars) constant substrings are loaded already.
+ movl(cnt2, int_cnt2);
+ }
+ push(tmp); // original SP
+
+ } // Finished loading
+
+ //========================================================
+ // Start search
+ //
+
+ movptr(result, str1); // string addr
+
+ if (int_cnt2 < 0) { // Only for non constant substring
+ jmpb(SCAN_TO_SUBSTR);
+
+ // SP saved at sp+0
+ // String saved at sp+1*wordSize
+ // Substr saved at sp+2*wordSize
+ // Substr count saved at sp+3*wordSize
+
+ // Reload substr for rescan, this code
+ // is executed only for large substrings (> 8 chars)
+ bind(RELOAD_SUBSTR);
+ movptr(str2, Address(rsp, 2*wordSize));
+ movl(cnt2, Address(rsp, 3*wordSize));
+ movdqu(vec, Address(str2, 0));
+ // We came here after the beginning of the substring was
+ // matched but the rest of it was not so we need to search
+ // again. Start from the next element after the previous match.
+ subptr(str1, result); // Restore counter
+ shrl(str1, 1);
+ addl(cnt1, str1);
+ decrementl(cnt1); // Shift to next element
+ cmpl(cnt1, cnt2);
+ jccb(Assembler::negative, RET_NOT_FOUND); // Left less then substring
+
+ addptr(result, 2);
+ } // non constant
+
+ // Scan string for start of substr in 16-byte vectors
+ bind(SCAN_TO_SUBSTR);
+ assert(cnt1 == rdx && cnt2 == rax && tmp == rcx, "pcmpestri");
+ pcmpestri(vec, Address(result, 0), 0x0d);
+ jccb(Assembler::below, FOUND_CANDIDATE); // CF == 1
+ subl(cnt1, 8);
+ jccb(Assembler::lessEqual, RET_NOT_FOUND); // Scanned full string
+ cmpl(cnt1, cnt2);
+ jccb(Assembler::negative, RET_NOT_FOUND); // Left less then substring
+ addptr(result, 16);
+
+ bind(ADJUST_STR);
+ cmpl(cnt1, 8); // Do not read beyond string
+ jccb(Assembler::greaterEqual, SCAN_TO_SUBSTR);
+ // Back-up string to avoid reading beyond string.
+ lea(result, Address(result, cnt1, Address::times_2, -16));
+ movl(cnt1, 8);
+ jmpb(SCAN_TO_SUBSTR);
+
+ // Found a potential substr
+ bind(FOUND_CANDIDATE);
+ // After pcmpestri tmp(rcx) contains matched element index
+
+ // Make sure string is still long enough
+ subl(cnt1, tmp);
+ cmpl(cnt1, cnt2);
+ jccb(Assembler::greaterEqual, FOUND_SUBSTR);
+ // Left less then substring.
+
+ bind(RET_NOT_FOUND);
+ movl(result, -1);
+ jmpb(CLEANUP);
+
+ bind(FOUND_SUBSTR);
+ // Compute start addr of substr
+ lea(result, Address(result, tmp, Address::times_2));
+
+ if (int_cnt2 > 0) { // Constant substring
+ // Repeat search for small substring (< 8 chars)
+ // from new point without reloading substring.
+ // Have to check that we don't read beyond string.
+ cmpl(tmp, 8-int_cnt2);
+ jccb(Assembler::greater, ADJUST_STR);
+ // Fall through if matched whole substring.
+ } else { // non constant
+ assert(int_cnt2 == -1, "should be != 0");
+
+ addl(tmp, cnt2);
+ // Found result if we matched whole substring.
+ cmpl(tmp, 8);
+ jccb(Assembler::lessEqual, RET_FOUND);
+
+ // Repeat search for small substring (<= 8 chars)
+ // from new point 'str1' without reloading substring.
+ cmpl(cnt2, 8);
+ // Have to check that we don't read beyond string.
+ jccb(Assembler::lessEqual, ADJUST_STR);
+
+ Label CHECK_NEXT, CONT_SCAN_SUBSTR, RET_FOUND_LONG;
+ // Compare the rest of substring (> 8 chars).
+ movptr(str1, result);
+
+ cmpl(tmp, cnt2);
+ // First 8 chars are already matched.
+ jccb(Assembler::equal, CHECK_NEXT);
+
+ bind(SCAN_SUBSTR);
+ pcmpestri(vec, Address(str1, 0), 0x0d);
+ // Need to reload strings pointers if not matched whole vector
+ jcc(Assembler::noOverflow, RELOAD_SUBSTR); // OF == 0
+
+ bind(CHECK_NEXT);
+ subl(cnt2, 8);
+ jccb(Assembler::lessEqual, RET_FOUND_LONG); // Found full substring
+ addptr(str1, 16);
+ addptr(str2, 16);
+ subl(cnt1, 8);
+ cmpl(cnt2, 8); // Do not read beyond substring
+ jccb(Assembler::greaterEqual, CONT_SCAN_SUBSTR);
+ // Back-up strings to avoid reading beyond substring.
+ lea(str2, Address(str2, cnt2, Address::times_2, -16));
+ lea(str1, Address(str1, cnt2, Address::times_2, -16));
+ subl(cnt1, cnt2);
+ movl(cnt2, 8);
+ addl(cnt1, 8);
+ bind(CONT_SCAN_SUBSTR);
+ movdqu(vec, Address(str2, 0));
+ jmpb(SCAN_SUBSTR);
+
+ bind(RET_FOUND_LONG);
+ movptr(str1, Address(rsp, wordSize));
+ } // non constant
+
+ bind(RET_FOUND);
+ // Compute substr offset
+ subptr(result, str1);
+ shrl(result, 1); // index
+
+ bind(CLEANUP);
+ pop(rsp); // restore SP
+
+} // string_indexof
+
+// Compare strings.
+void MacroAssembler::string_compare(Register str1, Register str2,
+ Register cnt1, Register cnt2, Register result,
+ XMMRegister vec1) {
+ ShortBranchVerifier sbv(this);
+ Label LENGTH_DIFF_LABEL, POP_LABEL, DONE_LABEL, WHILE_HEAD_LABEL;
+
+ // Compute the minimum of the string lengths and the
+ // difference of the string lengths (stack).
+ // Do the conditional move stuff
+ movl(result, cnt1);
+ subl(cnt1, cnt2);
+ push(cnt1);
+ cmov32(Assembler::lessEqual, cnt2, result);
+
+ // Is the minimum length zero?
+ testl(cnt2, cnt2);
+ jcc(Assembler::zero, LENGTH_DIFF_LABEL);
+
+ // Compare first characters
+ load_unsigned_short(result, Address(str1, 0));
+ load_unsigned_short(cnt1, Address(str2, 0));
+ subl(result, cnt1);
+ jcc(Assembler::notZero, POP_LABEL);
+ cmpl(cnt2, 1);
+ jcc(Assembler::equal, LENGTH_DIFF_LABEL);
+
+ // Check if the strings start at the same location.
+ cmpptr(str1, str2);
+ jcc(Assembler::equal, LENGTH_DIFF_LABEL);
+
+ Address::ScaleFactor scale = Address::times_2;
+ int stride = 8;
+
+ if (UseAVX >= 2) {
+ Label COMPARE_WIDE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_WIDE_TAIL, COMPARE_SMALL_STR;
+ Label COMPARE_WIDE_VECTORS_LOOP, COMPARE_16_CHARS, COMPARE_INDEX_CHAR;
+ Label COMPARE_TAIL_LONG;
+ int pcmpmask = 0x19;
+
+ // Setup to compare 16-chars (32-bytes) vectors,
+ // start from first character again because it has aligned address.
+ int stride2 = 16;
+ int adr_stride = stride << scale;
+ int adr_stride2 = stride2 << scale;
+
+ assert(result == rax && cnt2 == rdx && cnt1 == rcx, "pcmpestri");
+ // rax and rdx are used by pcmpestri as elements counters
+ movl(result, cnt2);
+ andl(cnt2, ~(stride2-1)); // cnt2 holds the vector count
+ jcc(Assembler::zero, COMPARE_TAIL_LONG);
+
+ // fast path : compare first 2 8-char vectors.
+ bind(COMPARE_16_CHARS);
+ movdqu(vec1, Address(str1, 0));
+ pcmpestri(vec1, Address(str2, 0), pcmpmask);
+ jccb(Assembler::below, COMPARE_INDEX_CHAR);
+
+ movdqu(vec1, Address(str1, adr_stride));
+ pcmpestri(vec1, Address(str2, adr_stride), pcmpmask);
+ jccb(Assembler::aboveEqual, COMPARE_WIDE_VECTORS);
+ addl(cnt1, stride);
+
+ // Compare the characters at index in cnt1
+ bind(COMPARE_INDEX_CHAR); //cnt1 has the offset of the mismatching character
+ load_unsigned_short(result, Address(str1, cnt1, scale));
+ load_unsigned_short(cnt2, Address(str2, cnt1, scale));
+ subl(result, cnt2);
+ jmp(POP_LABEL);
+
+ // Setup the registers to start vector comparison loop
+ bind(COMPARE_WIDE_VECTORS);
+ lea(str1, Address(str1, result, scale));
+ lea(str2, Address(str2, result, scale));
+ subl(result, stride2);
+ subl(cnt2, stride2);
+ jccb(Assembler::zero, COMPARE_WIDE_TAIL);
+ negptr(result);
+
+ // In a loop, compare 16-chars (32-bytes) at once using (vpxor+vptest)
+ bind(COMPARE_WIDE_VECTORS_LOOP);
+ vmovdqu(vec1, Address(str1, result, scale));
+ vpxor(vec1, Address(str2, result, scale));
+ vptest(vec1, vec1);
+ jccb(Assembler::notZero, VECTOR_NOT_EQUAL);
+ addptr(result, stride2);
+ subl(cnt2, stride2);
+ jccb(Assembler::notZero, COMPARE_WIDE_VECTORS_LOOP);
+
+ // compare wide vectors tail
+ bind(COMPARE_WIDE_TAIL);
+ testptr(result, result);
+ jccb(Assembler::zero, LENGTH_DIFF_LABEL);
+
+ movl(result, stride2);
+ movl(cnt2, result);
+ negptr(result);
+ jmpb(COMPARE_WIDE_VECTORS_LOOP);
+
+ // Identifies the mismatching (higher or lower)16-bytes in the 32-byte vectors.
+ bind(VECTOR_NOT_EQUAL);
+ lea(str1, Address(str1, result, scale));
+ lea(str2, Address(str2, result, scale));
+ jmp(COMPARE_16_CHARS);
+
+ // Compare tail chars, length between 1 to 15 chars
+ bind(COMPARE_TAIL_LONG);
+ movl(cnt2, result);
+ cmpl(cnt2, stride);
+ jccb(Assembler::less, COMPARE_SMALL_STR);
+
+ movdqu(vec1, Address(str1, 0));
+ pcmpestri(vec1, Address(str2, 0), pcmpmask);
+ jcc(Assembler::below, COMPARE_INDEX_CHAR);
+ subptr(cnt2, stride);
+ jccb(Assembler::zero, LENGTH_DIFF_LABEL);
+ lea(str1, Address(str1, result, scale));
+ lea(str2, Address(str2, result, scale));
+ negptr(cnt2);
+ jmpb(WHILE_HEAD_LABEL);
+
+ bind(COMPARE_SMALL_STR);
+ } else if (UseSSE42Intrinsics) {
+ Label COMPARE_WIDE_VECTORS, VECTOR_NOT_EQUAL, COMPARE_TAIL;
+ int pcmpmask = 0x19;
+ // Setup to compare 8-char (16-byte) vectors,
+ // start from first character again because it has aligned address.
+ movl(result, cnt2);
+ andl(cnt2, ~(stride - 1)); // cnt2 holds the vector count
+ jccb(Assembler::zero, COMPARE_TAIL);
+
+ lea(str1, Address(str1, result, scale));
+ lea(str2, Address(str2, result, scale));
+ negptr(result);
+
+ // pcmpestri
+ // inputs:
+ // vec1- substring
+ // rax - negative string length (elements count)
+ // mem - scaned string
+ // rdx - string length (elements count)
+ // pcmpmask - cmp mode: 11000 (string compare with negated result)
+ // + 00 (unsigned bytes) or + 01 (unsigned shorts)
+ // outputs:
+ // rcx - first mismatched element index
+ assert(result == rax && cnt2 == rdx && cnt1 == rcx, "pcmpestri");
+
+ bind(COMPARE_WIDE_VECTORS);
+ movdqu(vec1, Address(str1, result, scale));
+ pcmpestri(vec1, Address(str2, result, scale), pcmpmask);
+ // After pcmpestri cnt1(rcx) contains mismatched element index
+
+ jccb(Assembler::below, VECTOR_NOT_EQUAL); // CF==1
+ addptr(result, stride);
+ subptr(cnt2, stride);
+ jccb(Assembler::notZero, COMPARE_WIDE_VECTORS);
+
+ // compare wide vectors tail
+ testptr(result, result);
+ jccb(Assembler::zero, LENGTH_DIFF_LABEL);
+
+ movl(cnt2, stride);
+ movl(result, stride);
+ negptr(result);
+ movdqu(vec1, Address(str1, result, scale));
+ pcmpestri(vec1, Address(str2, result, scale), pcmpmask);
+ jccb(Assembler::aboveEqual, LENGTH_DIFF_LABEL);
+
+ // Mismatched characters in the vectors
+ bind(VECTOR_NOT_EQUAL);
+ addptr(cnt1, result);
+ load_unsigned_short(result, Address(str1, cnt1, scale));
+ load_unsigned_short(cnt2, Address(str2, cnt1, scale));
+ subl(result, cnt2);
+ jmpb(POP_LABEL);
+
+ bind(COMPARE_TAIL); // limit is zero
+ movl(cnt2, result);
+ // Fallthru to tail compare
+ }
+ // Shift str2 and str1 to the end of the arrays, negate min
+ lea(str1, Address(str1, cnt2, scale));
+ lea(str2, Address(str2, cnt2, scale));
+ decrementl(cnt2); // first character was compared already
+ negptr(cnt2);
+
+ // Compare the rest of the elements
+ bind(WHILE_HEAD_LABEL);
+ load_unsigned_short(result, Address(str1, cnt2, scale, 0));
+ load_unsigned_short(cnt1, Address(str2, cnt2, scale, 0));
+ subl(result, cnt1);
+ jccb(Assembler::notZero, POP_LABEL);
+ increment(cnt2);
+ jccb(Assembler::notZero, WHILE_HEAD_LABEL);
+
+ // Strings are equal up to min length. Return the length difference.
+ bind(LENGTH_DIFF_LABEL);
+ pop(result);
+ jmpb(DONE_LABEL);
+
+ // Discard the stored length difference
+ bind(POP_LABEL);
+ pop(cnt1);
+
+ // That's it
+ bind(DONE_LABEL);
+}
+
+// Compare char[] arrays aligned to 4 bytes or substrings.
+void MacroAssembler::char_arrays_equals(bool is_array_equ, Register ary1, Register ary2,
+ Register limit, Register result, Register chr,
+ XMMRegister vec1, XMMRegister vec2) {
+ ShortBranchVerifier sbv(this);
+ Label TRUE_LABEL, FALSE_LABEL, DONE, COMPARE_VECTORS, COMPARE_CHAR;
+
+ int length_offset = arrayOopDesc::length_offset_in_bytes();
+ int base_offset = arrayOopDesc::base_offset_in_bytes(T_CHAR);
+
+ // Check the input args
+ cmpptr(ary1, ary2);
+ jcc(Assembler::equal, TRUE_LABEL);
+
+ if (is_array_equ) {
+ // Need additional checks for arrays_equals.
+ testptr(ary1, ary1);
+ jcc(Assembler::zero, FALSE_LABEL);
+ testptr(ary2, ary2);
+ jcc(Assembler::zero, FALSE_LABEL);
+
+ // Check the lengths
+ movl(limit, Address(ary1, length_offset));
+ cmpl(limit, Address(ary2, length_offset));
+ jcc(Assembler::notEqual, FALSE_LABEL);
+ }
+
+ // count == 0
+ testl(limit, limit);
+ jcc(Assembler::zero, TRUE_LABEL);
+
+ if (is_array_equ) {
+ // Load array address
+ lea(ary1, Address(ary1, base_offset));
+ lea(ary2, Address(ary2, base_offset));
+ }
+
+ shll(limit, 1); // byte count != 0
+ movl(result, limit); // copy
+
+ if (UseAVX >= 2) {
+ // With AVX2, use 32-byte vector compare
+ Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
+
+ // Compare 32-byte vectors
+ andl(result, 0x0000001e); // tail count (in bytes)
+ andl(limit, 0xffffffe0); // vector count (in bytes)
+ jccb(Assembler::zero, COMPARE_TAIL);
+
+ lea(ary1, Address(ary1, limit, Address::times_1));
+ lea(ary2, Address(ary2, limit, Address::times_1));
+ negptr(limit);
+
+ bind(COMPARE_WIDE_VECTORS);
+ vmovdqu(vec1, Address(ary1, limit, Address::times_1));
+ vmovdqu(vec2, Address(ary2, limit, Address::times_1));
+ vpxor(vec1, vec2);
+
+ vptest(vec1, vec1);
+ jccb(Assembler::notZero, FALSE_LABEL);
+ addptr(limit, 32);
+ jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
+
+ testl(result, result);
+ jccb(Assembler::zero, TRUE_LABEL);
+
+ vmovdqu(vec1, Address(ary1, result, Address::times_1, -32));
+ vmovdqu(vec2, Address(ary2, result, Address::times_1, -32));
+ vpxor(vec1, vec2);
+
+ vptest(vec1, vec1);
+ jccb(Assembler::notZero, FALSE_LABEL);
+ jmpb(TRUE_LABEL);
+
+ bind(COMPARE_TAIL); // limit is zero
+ movl(limit, result);
+ // Fallthru to tail compare
+ } else if (UseSSE42Intrinsics) {
+ // With SSE4.2, use double quad vector compare
+ Label COMPARE_WIDE_VECTORS, COMPARE_TAIL;
+
+ // Compare 16-byte vectors
+ andl(result, 0x0000000e); // tail count (in bytes)
+ andl(limit, 0xfffffff0); // vector count (in bytes)
+ jccb(Assembler::zero, COMPARE_TAIL);
+
+ lea(ary1, Address(ary1, limit, Address::times_1));
+ lea(ary2, Address(ary2, limit, Address::times_1));
+ negptr(limit);
+
+ bind(COMPARE_WIDE_VECTORS);
+ movdqu(vec1, Address(ary1, limit, Address::times_1));
+ movdqu(vec2, Address(ary2, limit, Address::times_1));
+ pxor(vec1, vec2);
+
+ ptest(vec1, vec1);
+ jccb(Assembler::notZero, FALSE_LABEL);
+ addptr(limit, 16);
+ jcc(Assembler::notZero, COMPARE_WIDE_VECTORS);
+
+ testl(result, result);
+ jccb(Assembler::zero, TRUE_LABEL);
+
+ movdqu(vec1, Address(ary1, result, Address::times_1, -16));
+ movdqu(vec2, Address(ary2, result, Address::times_1, -16));
+ pxor(vec1, vec2);
+
+ ptest(vec1, vec1);
+ jccb(Assembler::notZero, FALSE_LABEL);
+ jmpb(TRUE_LABEL);
+
+ bind(COMPARE_TAIL); // limit is zero
+ movl(limit, result);
+ // Fallthru to tail compare
+ }
+
+ // Compare 4-byte vectors
+ andl(limit, 0xfffffffc); // vector count (in bytes)
+ jccb(Assembler::zero, COMPARE_CHAR);
+
+ lea(ary1, Address(ary1, limit, Address::times_1));
+ lea(ary2, Address(ary2, limit, Address::times_1));
+ negptr(limit);
+
+ bind(COMPARE_VECTORS);
+ movl(chr, Address(ary1, limit, Address::times_1));
+ cmpl(chr, Address(ary2, limit, Address::times_1));
+ jccb(Assembler::notEqual, FALSE_LABEL);
+ addptr(limit, 4);
+ jcc(Assembler::notZero, COMPARE_VECTORS);
+
+ // Compare trailing char (final 2 bytes), if any
+ bind(COMPARE_CHAR);
+ testl(result, 0x2); // tail char
+ jccb(Assembler::zero, TRUE_LABEL);
+ load_unsigned_short(chr, Address(ary1, 0));
+ load_unsigned_short(limit, Address(ary2, 0));
+ cmpl(chr, limit);
+ jccb(Assembler::notEqual, FALSE_LABEL);
+
+ bind(TRUE_LABEL);
+ movl(result, 1); // return true
+ jmpb(DONE);
+
+ bind(FALSE_LABEL);
+ xorl(result, result); // return false
+
+ // That's it
+ bind(DONE);
+}
+
+void MacroAssembler::generate_fill(BasicType t, bool aligned,
+ Register to, Register value, Register count,
+ Register rtmp, XMMRegister xtmp) {
+ ShortBranchVerifier sbv(this);
+ assert_different_registers(to, value, count, rtmp);
+ Label L_exit, L_skip_align1, L_skip_align2, L_fill_byte;
+ Label L_fill_2_bytes, L_fill_4_bytes;
+
+ int shift = -1;
+ switch (t) {
+ case T_BYTE:
+ shift = 2;
+ break;
+ case T_SHORT:
+ shift = 1;
+ break;
+ case T_INT:
+ shift = 0;
+ break;
+ default: ShouldNotReachHere();
+ }
+
+ if (t == T_BYTE) {
+ andl(value, 0xff);
+ movl(rtmp, value);
+ shll(rtmp, 8);
+ orl(value, rtmp);
+ }
+ if (t == T_SHORT) {
+ andl(value, 0xffff);
+ }
+ if (t == T_BYTE || t == T_SHORT) {
+ movl(rtmp, value);
+ shll(rtmp, 16);
+ orl(value, rtmp);
+ }
+
+ cmpl(count, 2<= 2, "supported cpu only" );
+ Label L_fill_32_bytes_loop, L_check_fill_8_bytes, L_fill_8_bytes_loop, L_fill_8_bytes;
+ movdl(xtmp, value);
+ if (UseAVX >= 2 && UseUnalignedLoadStores) {
+ // Fill 64-byte chunks
+ Label L_fill_64_bytes_loop, L_check_fill_32_bytes;
+ vpbroadcastd(xtmp, xtmp);
+
+ subl(count, 16 << shift);
+ jcc(Assembler::less, L_check_fill_32_bytes);
+ align(16);
+
+ BIND(L_fill_64_bytes_loop);
+ vmovdqu(Address(to, 0), xtmp);
+ vmovdqu(Address(to, 32), xtmp);
+ addptr(to, 64);
+ subl(count, 16 << shift);
+ jcc(Assembler::greaterEqual, L_fill_64_bytes_loop);
+
+ BIND(L_check_fill_32_bytes);
+ addl(count, 8 << shift);
+ jccb(Assembler::less, L_check_fill_8_bytes);
+ vmovdqu(Address(to, 0), xtmp);
+ addptr(to, 32);
+ subl(count, 8 << shift);
+ } else {
+ // Fill 32-byte chunks
+ pshufd(xtmp, xtmp, 0);
+
+ subl(count, 8 << shift);
+ jcc(Assembler::less, L_check_fill_8_bytes);
+ align(16);
+
+ BIND(L_fill_32_bytes_loop);
+
+ if (UseUnalignedLoadStores) {
+ movdqu(Address(to, 0), xtmp);
+ movdqu(Address(to, 16), xtmp);
+ } else {
+ movq(Address(to, 0), xtmp);
+ movq(Address(to, 8), xtmp);
+ movq(Address(to, 16), xtmp);
+ movq(Address(to, 24), xtmp);
+ }
+
+ addptr(to, 32);
+ subl(count, 8 << shift);
+ jcc(Assembler::greaterEqual, L_fill_32_bytes_loop);
+ }
+ BIND(L_check_fill_8_bytes);
+ addl(count, 8 << shift);
+ jccb(Assembler::zero, L_exit);
+ jmpb(L_fill_8_bytes);
+
+ //
+ // length is too short, just fill qwords
+ //
+ BIND(L_fill_8_bytes_loop);
+ movq(Address(to, 0), xtmp);
+ addptr(to, 8);
+ BIND(L_fill_8_bytes);
+ subl(count, 1 << (shift + 1));
+ jcc(Assembler::greaterEqual, L_fill_8_bytes_loop);
+ }
+ }
+ // fill trailing 4 bytes
+ BIND(L_fill_4_bytes);
+ testl(count, 1<= 2) {
+ Label L_chars_8_check, L_copy_8_chars, L_copy_8_chars_exit;
+ Label L_chars_16_check, L_copy_16_chars, L_copy_16_chars_exit;
+
+ if (UseAVX >= 2) {
+ Label L_chars_32_check, L_copy_32_chars, L_copy_32_chars_exit;
+ movl(tmp5, 0xff00ff00); // create mask to test for Unicode chars in vector
+ movdl(tmp1Reg, tmp5);
+ vpbroadcastd(tmp1Reg, tmp1Reg);
+ jmpb(L_chars_32_check);
+
+ bind(L_copy_32_chars);
+ vmovdqu(tmp3Reg, Address(src, len, Address::times_2, -64));
+ vmovdqu(tmp4Reg, Address(src, len, Address::times_2, -32));
+ vpor(tmp2Reg, tmp3Reg, tmp4Reg, /* vector256 */ true);
+ vptest(tmp2Reg, tmp1Reg); // check for Unicode chars in vector
+ jccb(Assembler::notZero, L_copy_32_chars_exit);
+ vpackuswb(tmp3Reg, tmp3Reg, tmp4Reg, /* vector256 */ true);
+ vpermq(tmp4Reg, tmp3Reg, 0xD8, /* vector256 */ true);
+ vmovdqu(Address(dst, len, Address::times_1, -32), tmp4Reg);
+
+ bind(L_chars_32_check);
+ addptr(len, 32);
+ jccb(Assembler::lessEqual, L_copy_32_chars);
+
+ bind(L_copy_32_chars_exit);
+ subptr(len, 16);
+ jccb(Assembler::greater, L_copy_16_chars_exit);
+
+ } else if (UseSSE42Intrinsics) {
+ movl(tmp5, 0xff00ff00); // create mask to test for Unicode chars in vector
+ movdl(tmp1Reg, tmp5);
+ pshufd(tmp1Reg, tmp1Reg, 0);
+ jmpb(L_chars_16_check);
+ }
+
+ bind(L_copy_16_chars);
+ if (UseAVX >= 2) {
+ vmovdqu(tmp2Reg, Address(src, len, Address::times_2, -32));
+ vptest(tmp2Reg, tmp1Reg);
+ jccb(Assembler::notZero, L_copy_16_chars_exit);
+ vpackuswb(tmp2Reg, tmp2Reg, tmp1Reg, /* vector256 */ true);
+ vpermq(tmp3Reg, tmp2Reg, 0xD8, /* vector256 */ true);
+ } else {
+ if (UseAVX > 0) {
+ movdqu(tmp3Reg, Address(src, len, Address::times_2, -32));
+ movdqu(tmp4Reg, Address(src, len, Address::times_2, -16));
+ vpor(tmp2Reg, tmp3Reg, tmp4Reg, /* vector256 */ false);
+ } else {
+ movdqu(tmp3Reg, Address(src, len, Address::times_2, -32));
+ por(tmp2Reg, tmp3Reg);
+ movdqu(tmp4Reg, Address(src, len, Address::times_2, -16));
+ por(tmp2Reg, tmp4Reg);
+ }
+ ptest(tmp2Reg, tmp1Reg); // check for Unicode chars in vector
+ jccb(Assembler::notZero, L_copy_16_chars_exit);
+ packuswb(tmp3Reg, tmp4Reg);
+ }
+ movdqu(Address(dst, len, Address::times_1, -16), tmp3Reg);
+
+ bind(L_chars_16_check);
+ addptr(len, 16);
+ jccb(Assembler::lessEqual, L_copy_16_chars);
+
+ bind(L_copy_16_chars_exit);
+ subptr(len, 8);
+ jccb(Assembler::greater, L_copy_8_chars_exit);
+
+ bind(L_copy_8_chars);
+ movdqu(tmp3Reg, Address(src, len, Address::times_2, -16));
+ ptest(tmp3Reg, tmp1Reg);
+ jccb(Assembler::notZero, L_copy_8_chars_exit);
+ packuswb(tmp3Reg, tmp1Reg);
+ movq(Address(dst, len, Address::times_1, -8), tmp3Reg);
+ addptr(len, 8);
+ jccb(Assembler::lessEqual, L_copy_8_chars);
+
+ bind(L_copy_8_chars_exit);
+ subptr(len, 8);
+ jccb(Assembler::zero, L_done);
+ }
+
+ bind(L_copy_1_char);
+ load_unsigned_short(tmp5, Address(src, len, Address::times_2, 0));
+ testl(tmp5, 0xff00); // check if Unicode char
+ jccb(Assembler::notZero, L_copy_1_char_exit);
+ movb(Address(dst, len, Address::times_1, 0), tmp5);
+ addptr(len, 1);
+ jccb(Assembler::less, L_copy_1_char);
+
+ bind(L_copy_1_char_exit);
+ addptr(result, len); // len is negative count of not processed elements
+ bind(L_done);
+}
+
+#undef BIND
+#undef BLOCK_COMMENT
+
+
+Assembler::Condition MacroAssembler::negate_condition(Assembler::Condition cond) {
+ switch (cond) {
+ // Note some conditions are synonyms for others
+ case Assembler::zero: return Assembler::notZero;
+ case Assembler::notZero: return Assembler::zero;
+ case Assembler::less: return Assembler::greaterEqual;
+ case Assembler::lessEqual: return Assembler::greater;
+ case Assembler::greater: return Assembler::lessEqual;
+ case Assembler::greaterEqual: return Assembler::less;
+ case Assembler::below: return Assembler::aboveEqual;
+ case Assembler::belowEqual: return Assembler::above;
+ case Assembler::above: return Assembler::belowEqual;
+ case Assembler::aboveEqual: return Assembler::below;
+ case Assembler::overflow: return Assembler::noOverflow;
+ case Assembler::noOverflow: return Assembler::overflow;
+ case Assembler::negative: return Assembler::positive;
+ case Assembler::positive: return Assembler::negative;
+ case Assembler::parity: return Assembler::noParity;
+ case Assembler::noParity: return Assembler::parity;
+ }
+ ShouldNotReachHere(); return Assembler::overflow;
+}
+
+SkipIfEqual::SkipIfEqual(
+ MacroAssembler* masm, const bool* flag_addr, bool value) {
+ _masm = masm;
+ _masm->cmp8(ExternalAddress((address)flag_addr), value);
+ _masm->jcc(Assembler::equal, _label);
+}
+
+SkipIfEqual::~SkipIfEqual() {
+ _masm->bind(_label);
+}
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/macroAssembler_x86.hpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cpu/x86/vm/macroAssembler_x86.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -0,0 +1,1164 @@
+/*
+ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef CPU_X86_VM_MACROASSEMBLER_X86_HPP
+#define CPU_X86_VM_MACROASSEMBLER_X86_HPP
+
+#include "asm/assembler.hpp"
+
+
+// MacroAssembler extends Assembler by frequently used macros.
+//
+// Instructions for which a 'better' code sequence exists depending
+// on arguments should also go in here.
+
+class MacroAssembler: public Assembler {
+ friend class LIR_Assembler;
+ friend class Runtime1; // as_Address()
+
+ protected:
+
+ Address as_Address(AddressLiteral adr);
+ Address as_Address(ArrayAddress adr);
+
+ // Support for VM calls
+ //
+ // This is the base routine called by the different versions of call_VM_leaf. The interpreter
+ // may customize this version by overriding it for its purposes (e.g., to save/restore
+ // additional registers when doing a VM call).
+#ifdef CC_INTERP
+ // c++ interpreter never wants to use interp_masm version of call_VM
+ #define VIRTUAL
+#else
+ #define VIRTUAL virtual
+#endif
+
+ VIRTUAL void call_VM_leaf_base(
+ address entry_point, // the entry point
+ int number_of_arguments // the number of arguments to pop after the call
+ );
+
+ // This is the base routine called by the different versions of call_VM. The interpreter
+ // may customize this version by overriding it for its purposes (e.g., to save/restore
+ // additional registers when doing a VM call).
+ //
+ // If no java_thread register is specified (noreg) than rdi will be used instead. call_VM_base
+ // returns the register which contains the thread upon return. If a thread register has been
+ // specified, the return value will correspond to that register. If no last_java_sp is specified
+ // (noreg) than rsp will be used instead.
+ VIRTUAL void call_VM_base( // returns the register containing the thread upon return
+ Register oop_result, // where an oop-result ends up if any; use noreg otherwise
+ Register java_thread, // the thread if computed before ; use noreg otherwise
+ Register last_java_sp, // to set up last_Java_frame in stubs; use noreg otherwise
+ address entry_point, // the entry point
+ int number_of_arguments, // the number of arguments (w/o thread) to pop after the call
+ bool check_exceptions // whether to check for pending exceptions after return
+ );
+
+ // These routines should emit JVMTI PopFrame and ForceEarlyReturn handling code.
+ // The implementation is only non-empty for the InterpreterMacroAssembler,
+ // as only the interpreter handles PopFrame and ForceEarlyReturn requests.
+ virtual void check_and_handle_popframe(Register java_thread);
+ virtual void check_and_handle_earlyret(Register java_thread);
+
+ void call_VM_helper(Register oop_result, address entry_point, int number_of_arguments, bool check_exceptions = true);
+
+ // helpers for FPU flag access
+ // tmp is a temporary register, if none is available use noreg
+ void save_rax (Register tmp);
+ void restore_rax(Register tmp);
+
+ public:
+ MacroAssembler(CodeBuffer* code) : Assembler(code) {}
+
+ // Support for NULL-checks
+ //
+ // Generates code that causes a NULL OS exception if the content of reg is NULL.
+ // If the accessed location is M[reg + offset] and the offset is known, provide the
+ // offset. No explicit code generation is needed if the offset is within a certain
+ // range (0 <= offset <= page_size).
+
+ void null_check(Register reg, int offset = -1);
+ static bool needs_explicit_null_check(intptr_t offset);
+
+ // Required platform-specific helpers for Label::patch_instructions.
+ // They _shadow_ the declarations in AbstractAssembler, which are undefined.
+ void pd_patch_instruction(address branch, address target) {
+ unsigned char op = branch[0];
+ assert(op == 0xE8 /* call */ ||
+ op == 0xE9 /* jmp */ ||
+ op == 0xEB /* short jmp */ ||
+ (op & 0xF0) == 0x70 /* short jcc */ ||
+ op == 0x0F && (branch[1] & 0xF0) == 0x80 /* jcc */,
+ "Invalid opcode at patch point");
+
+ if (op == 0xEB || (op & 0xF0) == 0x70) {
+ // short offset operators (jmp and jcc)
+ char* disp = (char*) &branch[1];
+ int imm8 = target - (address) &disp[1];
+ guarantee(this->is8bit(imm8), "Short forward jump exceeds 8-bit offset");
+ *disp = imm8;
+ } else {
+ int* disp = (int*) &branch[(op == 0x0F)? 2: 1];
+ int imm32 = target - (address) &disp[1];
+ *disp = imm32;
+ }
+ }
+
+ // The following 4 methods return the offset of the appropriate move instruction
+
+ // Support for fast byte/short loading with zero extension (depending on particular CPU)
+ int load_unsigned_byte(Register dst, Address src);
+ int load_unsigned_short(Register dst, Address src);
+
+ // Support for fast byte/short loading with sign extension (depending on particular CPU)
+ int load_signed_byte(Register dst, Address src);
+ int load_signed_short(Register dst, Address src);
+
+ // Support for sign-extension (hi:lo = extend_sign(lo))
+ void extend_sign(Register hi, Register lo);
+
+ // Load and store values by size and signed-ness
+ void load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed, Register dst2 = noreg);
+ void store_sized_value(Address dst, Register src, size_t size_in_bytes, Register src2 = noreg);
+
+ // Support for inc/dec with optimal instruction selection depending on value
+
+ void increment(Register reg, int value = 1) { LP64_ONLY(incrementq(reg, value)) NOT_LP64(incrementl(reg, value)) ; }
+ void decrement(Register reg, int value = 1) { LP64_ONLY(decrementq(reg, value)) NOT_LP64(decrementl(reg, value)) ; }
+
+ void decrementl(Address dst, int value = 1);
+ void decrementl(Register reg, int value = 1);
+
+ void decrementq(Register reg, int value = 1);
+ void decrementq(Address dst, int value = 1);
+
+ void incrementl(Address dst, int value = 1);
+ void incrementl(Register reg, int value = 1);
+
+ void incrementq(Register reg, int value = 1);
+ void incrementq(Address dst, int value = 1);
+
+
+ // Support optimal SSE move instructions.
+ void movflt(XMMRegister dst, XMMRegister src) {
+ if (UseXmmRegToRegMoveAll) { movaps(dst, src); return; }
+ else { movss (dst, src); return; }
+ }
+ void movflt(XMMRegister dst, Address src) { movss(dst, src); }
+ void movflt(XMMRegister dst, AddressLiteral src);
+ void movflt(Address dst, XMMRegister src) { movss(dst, src); }
+
+ void movdbl(XMMRegister dst, XMMRegister src) {
+ if (UseXmmRegToRegMoveAll) { movapd(dst, src); return; }
+ else { movsd (dst, src); return; }
+ }
+
+ void movdbl(XMMRegister dst, AddressLiteral src);
+
+ void movdbl(XMMRegister dst, Address src) {
+ if (UseXmmLoadAndClearUpper) { movsd (dst, src); return; }
+ else { movlpd(dst, src); return; }
+ }
+ void movdbl(Address dst, XMMRegister src) { movsd(dst, src); }
+
+ void incrementl(AddressLiteral dst);
+ void incrementl(ArrayAddress dst);
+
+ // Alignment
+ void align(int modulus);
+
+ // A 5 byte nop that is safe for patching (see patch_verified_entry)
+ void fat_nop();
+
+ // Stack frame creation/removal
+ void enter();
+ void leave();
+
+ // Support for getting the JavaThread pointer (i.e.; a reference to thread-local information)
+ // The pointer will be loaded into the thread register.
+ void get_thread(Register thread);
+
+
+ // Support for VM calls
+ //
+ // It is imperative that all calls into the VM are handled via the call_VM macros.
+ // They make sure that the stack linkage is setup correctly. call_VM's correspond
+ // to ENTRY/ENTRY_X entry points while call_VM_leaf's correspond to LEAF entry points.
+
+
+ void call_VM(Register oop_result,
+ address entry_point,
+ bool check_exceptions = true);
+ void call_VM(Register oop_result,
+ address entry_point,
+ Register arg_1,
+ bool check_exceptions = true);
+ void call_VM(Register oop_result,
+ address entry_point,
+ Register arg_1, Register arg_2,
+ bool check_exceptions = true);
+ void call_VM(Register oop_result,
+ address entry_point,
+ Register arg_1, Register arg_2, Register arg_3,
+ bool check_exceptions = true);
+
+ // Overloadings with last_Java_sp
+ void call_VM(Register oop_result,
+ Register last_java_sp,
+ address entry_point,
+ int number_of_arguments = 0,
+ bool check_exceptions = true);
+ void call_VM(Register oop_result,
+ Register last_java_sp,
+ address entry_point,
+ Register arg_1, bool
+ check_exceptions = true);
+ void call_VM(Register oop_result,
+ Register last_java_sp,
+ address entry_point,
+ Register arg_1, Register arg_2,
+ bool check_exceptions = true);
+ void 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 get_vm_result (Register oop_result, Register thread);
+ void get_vm_result_2(Register metadata_result, Register thread);
+
+ // 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,
+ Register arg_1);
+ void call_VM_leaf(address entry_point,
+ Register arg_1, Register arg_2);
+ void call_VM_leaf(address entry_point,
+ Register arg_1, Register arg_2, Register arg_3);
+
+ // These always tightly bind to MacroAssembler::call_VM_leaf_base
+ // bypassing the virtual implementation
+ void super_call_VM_leaf(address entry_point);
+ void super_call_VM_leaf(address entry_point, Register arg_1);
+ void super_call_VM_leaf(address entry_point, Register arg_1, Register arg_2);
+ void super_call_VM_leaf(address entry_point, Register arg_1, Register arg_2, Register arg_3);
+ void super_call_VM_leaf(address entry_point, Register arg_1, Register arg_2, Register arg_3, Register arg_4);
+
+ // last Java Frame (fills frame anchor)
+ void set_last_Java_frame(Register thread,
+ Register last_java_sp,
+ Register last_java_fp,
+ address last_java_pc);
+
+ // thread in the default location (r15_thread on 64bit)
+ void set_last_Java_frame(Register last_java_sp,
+ Register last_java_fp,
+ address last_java_pc);
+
+ void reset_last_Java_frame(Register thread, bool clear_fp, bool clear_pc);
+
+ // thread in the default location (r15_thread on 64bit)
+ void reset_last_Java_frame(bool clear_fp, bool clear_pc);
+
+ // Stores
+ void store_check(Register obj); // store check for obj - register is destroyed afterwards
+ void store_check(Register obj, Address dst); // same as above, dst is exact store location (reg. is destroyed)
+
+#ifndef SERIALGC
+
+ void g1_write_barrier_pre(Register obj,
+ Register pre_val,
+ Register thread,
+ Register tmp,
+ bool tosca_live,
+ bool expand_call);
+
+ void g1_write_barrier_post(Register store_addr,
+ Register new_val,
+ Register thread,
+ Register tmp,
+ Register tmp2);
+
+#endif // SERIALGC
+
+ // split store_check(Register obj) to enhance instruction interleaving
+ void store_check_part_1(Register obj);
+ void store_check_part_2(Register obj);
+
+ // C 'boolean' to Java boolean: x == 0 ? 0 : 1
+ void c2bool(Register x);
+
+ // C++ bool manipulation
+
+ void movbool(Register dst, Address src);
+ void movbool(Address dst, bool boolconst);
+ void movbool(Address dst, Register src);
+ void testbool(Register dst);
+
+ // oop manipulations
+ void load_klass(Register dst, Register src);
+ void store_klass(Register dst, Register src);
+
+ void load_heap_oop(Register dst, Address src);
+ void load_heap_oop_not_null(Register dst, Address src);
+ void store_heap_oop(Address dst, Register src);
+ void cmp_heap_oop(Register src1, Address src2, Register tmp = noreg);
+
+ // Used for storing NULL. All other oop constants should be
+ // stored using routines that take a jobject.
+ void store_heap_oop_null(Address dst);
+
+ void load_prototype_header(Register dst, Register src);
+
+#ifdef _LP64
+ void store_klass_gap(Register dst, Register src);
+
+ // This dummy is to prevent a call to store_heap_oop from
+ // converting a zero (like NULL) into a Register by giving
+ // the compiler two choices it can't resolve
+
+ void store_heap_oop(Address dst, void* dummy);
+
+ void encode_heap_oop(Register r);
+ void decode_heap_oop(Register r);
+ void encode_heap_oop_not_null(Register r);
+ void decode_heap_oop_not_null(Register r);
+ void encode_heap_oop_not_null(Register dst, Register src);
+ void decode_heap_oop_not_null(Register dst, Register src);
+
+ void set_narrow_oop(Register dst, jobject obj);
+ void set_narrow_oop(Address dst, jobject obj);
+ void cmp_narrow_oop(Register dst, jobject obj);
+ void cmp_narrow_oop(Address dst, jobject obj);
+
+ void encode_klass_not_null(Register r);
+ void decode_klass_not_null(Register r);
+ void encode_klass_not_null(Register dst, Register src);
+ void decode_klass_not_null(Register dst, Register src);
+ void set_narrow_klass(Register dst, Klass* k);
+ void set_narrow_klass(Address dst, Klass* k);
+ void cmp_narrow_klass(Register dst, Klass* k);
+ void cmp_narrow_klass(Address dst, Klass* k);
+
+ // if heap base register is used - reinit it with the correct value
+ void reinit_heapbase();
+
+ DEBUG_ONLY(void verify_heapbase(const char* msg);)
+
+#endif // _LP64
+
+ // Int division/remainder for Java
+ // (as idivl, but checks for special case as described in JVM spec.)
+ // returns idivl instruction offset for implicit exception handling
+ int corrected_idivl(Register reg);
+
+ // Long division/remainder for Java
+ // (as idivq, but checks for special case as described in JVM spec.)
+ // returns idivq instruction offset for implicit exception handling
+ int corrected_idivq(Register reg);
+
+ void int3();
+
+ // Long operation macros for a 32bit cpu
+ // Long negation for Java
+ void lneg(Register hi, Register lo);
+
+ // Long multiplication for Java
+ // (destroys contents of eax, ebx, ecx and edx)
+ void lmul(int x_rsp_offset, int y_rsp_offset); // rdx:rax = x * y
+
+ // Long shifts for Java
+ // (semantics as described in JVM spec.)
+ void lshl(Register hi, Register lo); // hi:lo << (rcx & 0x3f)
+ void lshr(Register hi, Register lo, bool sign_extension = false); // hi:lo >> (rcx & 0x3f)
+
+ // Long compare for Java
+ // (semantics as described in JVM spec.)
+ void lcmp2int(Register x_hi, Register x_lo, Register y_hi, Register y_lo); // x_hi = lcmp(x, y)
+
+
+ // misc
+
+ // Sign extension
+ void sign_extend_short(Register reg);
+ void sign_extend_byte(Register reg);
+
+ // Division by power of 2, rounding towards 0
+ void division_with_shift(Register reg, int shift_value);
+
+ // Compares the top-most stack entries on the FPU stack and sets the eflags as follows:
+ //
+ // CF (corresponds to C0) if x < y
+ // PF (corresponds to C2) if unordered
+ // ZF (corresponds to C3) if x = y
+ //
+ // The arguments are in reversed order on the stack (i.e., top of stack is first argument).
+ // tmp is a temporary register, if none is available use noreg (only matters for non-P6 code)
+ void fcmp(Register tmp);
+ // Variant of the above which allows y to be further down the stack
+ // and which only pops x and y if specified. If pop_right is
+ // specified then pop_left must also be specified.
+ void fcmp(Register tmp, int index, bool pop_left, bool pop_right);
+
+ // Floating-point comparison for Java
+ // Compares the top-most stack entries on the FPU stack and stores the result in dst.
+ // The arguments are in reversed order on the stack (i.e., top of stack is first argument).
+ // (semantics as described in JVM spec.)
+ void fcmp2int(Register dst, bool unordered_is_less);
+ // Variant of the above which allows y to be further down the stack
+ // and which only pops x and y if specified. If pop_right is
+ // specified then pop_left must also be specified.
+ void fcmp2int(Register dst, bool unordered_is_less, int index, bool pop_left, bool pop_right);
+
+ // Floating-point remainder for Java (ST0 = ST0 fremr ST1, ST1 is empty afterwards)
+ // tmp is a temporary register, if none is available use noreg
+ void fremr(Register tmp);
+
+
+ // same as fcmp2int, but using SSE2
+ void cmpss2int(XMMRegister opr1, XMMRegister opr2, Register dst, bool unordered_is_less);
+ void cmpsd2int(XMMRegister opr1, XMMRegister opr2, Register dst, bool unordered_is_less);
+
+ // Inlined sin/cos generator for Java; must not use CPU instruction
+ // directly on Intel as it does not have high enough precision
+ // outside of the range [-pi/4, pi/4]. Extra argument indicate the
+ // number of FPU stack slots in use; all but the topmost will
+ // require saving if a slow case is necessary. Assumes argument is
+ // on FP TOS; result is on FP TOS. No cpu registers are changed by
+ // this code.
+ void trigfunc(char trig, int num_fpu_regs_in_use = 1);
+
+ // branch to L if FPU flag C2 is set/not set
+ // tmp is a temporary register, if none is available use noreg
+ void jC2 (Register tmp, Label& L);
+ void jnC2(Register tmp, Label& L);
+
+ // Pop ST (ffree & fincstp combined)
+ void fpop();
+
+ // pushes double TOS element of FPU stack on CPU stack; pops from FPU stack
+ void push_fTOS();
+
+ // pops double TOS element from CPU stack and pushes on FPU stack
+ void pop_fTOS();
+
+ void empty_FPU_stack();
+
+ void push_IU_state();
+ void pop_IU_state();
+
+ void push_FPU_state();
+ void pop_FPU_state();
+
+ void push_CPU_state();
+ void pop_CPU_state();
+
+ // Round up to a power of two
+ void round_to(Register reg, int modulus);
+
+ // Callee saved registers handling
+ void push_callee_saved_registers();
+ void pop_callee_saved_registers();
+
+ // allocation
+ void eden_allocate(
+ Register obj, // result: pointer to object after successful allocation
+ Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
+ int con_size_in_bytes, // object size in bytes if known at compile time
+ Register t1, // temp register
+ Label& slow_case // continuation point if fast allocation fails
+ );
+ void tlab_allocate(
+ Register obj, // result: pointer to object after successful allocation
+ Register var_size_in_bytes, // object size in bytes if unknown at compile time; invalid otherwise
+ int con_size_in_bytes, // object size in bytes if known at compile time
+ Register t1, // temp register
+ Register t2, // temp register
+ Label& slow_case // continuation point if fast allocation fails
+ );
+ Register tlab_refill(Label& retry_tlab, Label& try_eden, Label& slow_case); // returns TLS address
+ void incr_allocated_bytes(Register thread,
+ Register var_size_in_bytes, int con_size_in_bytes,
+ Register t1 = noreg);
+
+ // interface method calling
+ void lookup_interface_method(Register recv_klass,
+ Register intf_klass,
+ RegisterOrConstant itable_index,
+ Register method_result,
+ Register scan_temp,
+ Label& no_such_interface);
+
+ // virtual method calling
+ void lookup_virtual_method(Register recv_klass,
+ RegisterOrConstant vtable_index,
+ Register method_result);
+
+ // Test sub_klass against super_klass, with fast and slow paths.
+
+ // The fast path produces a tri-state answer: yes / no / maybe-slow.
+ // One of the three labels can be NULL, meaning take the fall-through.
+ // If super_check_offset is -1, the value is loaded up from super_klass.
+ // No registers are killed, except temp_reg.
+ void check_klass_subtype_fast_path(Register sub_klass,
+ Register super_klass,
+ Register temp_reg,
+ Label* L_success,
+ Label* L_failure,
+ Label* L_slow_path,
+ RegisterOrConstant super_check_offset = RegisterOrConstant(-1));
+
+ // The rest of the type check; must be wired to a corresponding fast path.
+ // It does not repeat the fast path logic, so don't use it standalone.
+ // The temp_reg and temp2_reg can be noreg, if no temps are available.
+ // Updates the sub's secondary super cache as necessary.
+ // If set_cond_codes, condition codes will be Z on success, NZ on failure.
+ void check_klass_subtype_slow_path(Register sub_klass,
+ Register super_klass,
+ Register temp_reg,
+ Register temp2_reg,
+ Label* L_success,
+ Label* L_failure,
+ bool set_cond_codes = false);
+
+ // Simplified, combined version, good for typical uses.
+ // Falls through on failure.
+ void check_klass_subtype(Register sub_klass,
+ Register super_klass,
+ Register temp_reg,
+ Label& L_success);
+
+ // method handles (JSR 292)
+ Address argument_address(RegisterOrConstant arg_slot, int extra_slot_offset = 0);
+
+ //----
+ void set_word_if_not_zero(Register reg); // sets reg to 1 if not zero, otherwise 0
+
+ // Debugging
+
+ // only if +VerifyOops
+ // TODO: Make these macros with file and line like sparc version!
+ void verify_oop(Register reg, const char* s = "broken oop");
+ void verify_oop_addr(Address addr, const char * s = "broken oop addr");
+
+ // TODO: verify method and klass metadata (compare against vptr?)
+ void _verify_method_ptr(Register reg, const char * msg, const char * file, int line) {}
+ void _verify_klass_ptr(Register reg, const char * msg, const char * file, int line){}
+
+#define verify_method_ptr(reg) _verify_method_ptr(reg, "broken method " #reg, __FILE__, __LINE__)
+#define verify_klass_ptr(reg) _verify_klass_ptr(reg, "broken klass " #reg, __FILE__, __LINE__)
+
+ // only if +VerifyFPU
+ void verify_FPU(int stack_depth, const char* s = "illegal FPU state");
+
+ // prints msg, dumps registers and stops execution
+ void stop(const char* msg);
+
+ // prints msg and continues
+ void warn(const char* msg);
+
+ // dumps registers and other state
+ void print_state();
+
+ static void debug32(int rdi, int rsi, int rbp, int rsp, int rbx, int rdx, int rcx, int rax, int eip, char* msg);
+ static void debug64(char* msg, int64_t pc, int64_t regs[]);
+ static void print_state32(int rdi, int rsi, int rbp, int rsp, int rbx, int rdx, int rcx, int rax, int eip);
+ static void print_state64(int64_t pc, int64_t regs[]);
+
+ void os_breakpoint();
+
+ void untested() { stop("untested"); }
+
+ void unimplemented(const char* what = "") { char* b = new char[1024]; jio_snprintf(b, 1024, "unimplemented: %s", what); stop(b); }
+
+ void should_not_reach_here() { stop("should not reach here"); }
+
+ void print_CPU_state();
+
+ // Stack overflow checking
+ void bang_stack_with_offset(int offset) {
+ // stack grows down, caller passes positive offset
+ assert(offset > 0, "must bang with negative offset");
+ movl(Address(rsp, (-offset)), rax);
+ }
+
+ // Writes to stack successive pages until offset reached to check for
+ // stack overflow + shadow pages. Also, clobbers tmp
+ void bang_stack_size(Register size, Register tmp);
+
+ virtual RegisterOrConstant delayed_value_impl(intptr_t* delayed_value_addr,
+ Register tmp,
+ int offset);
+
+ // Support for serializing memory accesses between threads
+ void serialize_memory(Register thread, Register tmp);
+
+ void verify_tlab();
+
+ // Biased locking support
+ // lock_reg and obj_reg must be loaded up with the appropriate values.
+ // swap_reg must be rax, and is killed.
+ // tmp_reg is optional. If it is supplied (i.e., != noreg) it will
+ // be killed; if not supplied, push/pop will be used internally to
+ // allocate a temporary (inefficient, avoid if possible).
+ // Optional slow case is for implementations (interpreter and C1) which branch to
+ // slow case directly. Leaves condition codes set for C2's Fast_Lock node.
+ // Returns offset of first potentially-faulting instruction for null
+ // check info (currently consumed only by C1). If
+ // swap_reg_contains_mark is true then returns -1 as it is assumed
+ // the calling code has already passed any potential faults.
+ int biased_locking_enter(Register lock_reg, Register obj_reg,
+ Register swap_reg, Register tmp_reg,
+ bool swap_reg_contains_mark,
+ Label& done, Label* slow_case = NULL,
+ BiasedLockingCounters* counters = NULL);
+ void biased_locking_exit (Register obj_reg, Register temp_reg, Label& done);
+
+
+ Condition negate_condition(Condition cond);
+
+ // Instructions that use AddressLiteral operands. These instruction can handle 32bit/64bit
+ // operands. In general the names are modified to avoid hiding the instruction in Assembler
+ // so that we don't need to implement all the varieties in the Assembler with trivial wrappers
+ // here in MacroAssembler. The major exception to this rule is call
+
+ // Arithmetics
+
+
+ void addptr(Address dst, int32_t src) { LP64_ONLY(addq(dst, src)) NOT_LP64(addl(dst, src)) ; }
+ void addptr(Address dst, Register src);
+
+ void addptr(Register dst, Address src) { LP64_ONLY(addq(dst, src)) NOT_LP64(addl(dst, src)); }
+ void addptr(Register dst, int32_t src);
+ void addptr(Register dst, Register src);
+ void addptr(Register dst, RegisterOrConstant src) {
+ if (src.is_constant()) addptr(dst, (int) src.as_constant());
+ else addptr(dst, src.as_register());
+ }
+
+ void andptr(Register dst, int32_t src);
+ void andptr(Register src1, Register src2) { LP64_ONLY(andq(src1, src2)) NOT_LP64(andl(src1, src2)) ; }
+
+ void cmp8(AddressLiteral src1, int imm);
+
+ // renamed to drag out the casting of address to int32_t/intptr_t
+ void cmp32(Register src1, int32_t imm);
+
+ void cmp32(AddressLiteral src1, int32_t imm);
+ // compare reg - mem, or reg - &mem
+ void cmp32(Register src1, AddressLiteral src2);
+
+ void cmp32(Register src1, Address src2);
+
+#ifndef _LP64
+ void cmpklass(Address dst, Metadata* obj);
+ void cmpklass(Register dst, Metadata* obj);
+ void cmpoop(Address dst, jobject obj);
+ void cmpoop(Register dst, jobject obj);
+#endif // _LP64
+
+ // NOTE src2 must be the lval. This is NOT an mem-mem compare
+ void cmpptr(Address src1, AddressLiteral src2);
+
+ void cmpptr(Register src1, AddressLiteral src2);
+
+ void cmpptr(Register src1, Register src2) { LP64_ONLY(cmpq(src1, src2)) NOT_LP64(cmpl(src1, src2)) ; }
+ void cmpptr(Register src1, Address src2) { LP64_ONLY(cmpq(src1, src2)) NOT_LP64(cmpl(src1, src2)) ; }
+ // void cmpptr(Address src1, Register src2) { LP64_ONLY(cmpq(src1, src2)) NOT_LP64(cmpl(src1, src2)) ; }
+
+ void cmpptr(Register src1, int32_t src2) { LP64_ONLY(cmpq(src1, src2)) NOT_LP64(cmpl(src1, src2)) ; }
+ void cmpptr(Address src1, int32_t src2) { LP64_ONLY(cmpq(src1, src2)) NOT_LP64(cmpl(src1, src2)) ; }
+
+ // cmp64 to avoild hiding cmpq
+ void cmp64(Register src1, AddressLiteral src);
+
+ void cmpxchgptr(Register reg, Address adr);
+
+ void locked_cmpxchgptr(Register reg, AddressLiteral adr);
+
+
+ void imulptr(Register dst, Register src) { LP64_ONLY(imulq(dst, src)) NOT_LP64(imull(dst, src)); }
+
+
+ void negptr(Register dst) { LP64_ONLY(negq(dst)) NOT_LP64(negl(dst)); }
+
+ void notptr(Register dst) { LP64_ONLY(notq(dst)) NOT_LP64(notl(dst)); }
+
+ void shlptr(Register dst, int32_t shift);
+ void shlptr(Register dst) { LP64_ONLY(shlq(dst)) NOT_LP64(shll(dst)); }
+
+ void shrptr(Register dst, int32_t shift);
+ void shrptr(Register dst) { LP64_ONLY(shrq(dst)) NOT_LP64(shrl(dst)); }
+
+ void sarptr(Register dst) { LP64_ONLY(sarq(dst)) NOT_LP64(sarl(dst)); }
+ void sarptr(Register dst, int32_t src) { LP64_ONLY(sarq(dst, src)) NOT_LP64(sarl(dst, src)); }
+
+ void subptr(Address dst, int32_t src) { LP64_ONLY(subq(dst, src)) NOT_LP64(subl(dst, src)); }
+
+ void subptr(Register dst, Address src) { LP64_ONLY(subq(dst, src)) NOT_LP64(subl(dst, src)); }
+ void subptr(Register dst, int32_t src);
+ // Force generation of a 4 byte immediate value even if it fits into 8bit
+ void subptr_imm32(Register dst, int32_t src);
+ void subptr(Register dst, Register src);
+ void subptr(Register dst, RegisterOrConstant src) {
+ if (src.is_constant()) subptr(dst, (int) src.as_constant());
+ else subptr(dst, src.as_register());
+ }
+
+ void sbbptr(Address dst, int32_t src) { LP64_ONLY(sbbq(dst, src)) NOT_LP64(sbbl(dst, src)); }
+ void sbbptr(Register dst, int32_t src) { LP64_ONLY(sbbq(dst, src)) NOT_LP64(sbbl(dst, src)); }
+
+ void xchgptr(Register src1, Register src2) { LP64_ONLY(xchgq(src1, src2)) NOT_LP64(xchgl(src1, src2)) ; }
+ void xchgptr(Register src1, Address src2) { LP64_ONLY(xchgq(src1, src2)) NOT_LP64(xchgl(src1, src2)) ; }
+
+ void xaddptr(Address src1, Register src2) { LP64_ONLY(xaddq(src1, src2)) NOT_LP64(xaddl(src1, src2)) ; }
+
+
+
+ // Helper functions for statistics gathering.
+ // Conditionally (atomically, on MPs) increments passed counter address, preserving condition codes.
+ void cond_inc32(Condition cond, AddressLiteral counter_addr);
+ // Unconditional atomic increment.
+ void atomic_incl(AddressLiteral counter_addr);
+
+ void lea(Register dst, AddressLiteral adr);
+ void lea(Address dst, AddressLiteral adr);
+ void lea(Register dst, Address adr) { Assembler::lea(dst, adr); }
+
+ void leal32(Register dst, Address src) { leal(dst, src); }
+
+ // Import other testl() methods from the parent class or else
+ // they will be hidden by the following overriding declaration.
+ using Assembler::testl;
+ void testl(Register dst, AddressLiteral src);
+
+ void orptr(Register dst, Address src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); }
+ void orptr(Register dst, Register src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); }
+ void orptr(Register dst, int32_t src) { LP64_ONLY(orq(dst, src)) NOT_LP64(orl(dst, src)); }
+
+ void testptr(Register src, int32_t imm32) { LP64_ONLY(testq(src, imm32)) NOT_LP64(testl(src, imm32)); }
+ void testptr(Register src1, Register src2);
+
+ void xorptr(Register dst, Register src) { LP64_ONLY(xorq(dst, src)) NOT_LP64(xorl(dst, src)); }
+ void xorptr(Register dst, Address src) { LP64_ONLY(xorq(dst, src)) NOT_LP64(xorl(dst, src)); }
+
+ // Calls
+
+ void call(Label& L, relocInfo::relocType rtype);
+ void call(Register entry);
+
+ // NOTE: this call tranfers to the effective address of entry NOT
+ // the address contained by entry. This is because this is more natural
+ // for jumps/calls.
+ void call(AddressLiteral entry);
+
+ // Emit the CompiledIC call idiom
+ void ic_call(address entry);
+
+ // Jumps
+
+ // NOTE: these jumps tranfer to the effective address of dst NOT
+ // the address contained by dst. This is because this is more natural
+ // for jumps/calls.
+ void jump(AddressLiteral dst);
+ void jump_cc(Condition cc, AddressLiteral dst);
+
+ // 32bit can do a case table jump in one instruction but we no longer allow the base
+ // to be installed in the Address class. This jump will tranfers to the address
+ // contained in the location described by entry (not the address of entry)
+ void jump(ArrayAddress entry);
+
+ // Floating
+
+ void andpd(XMMRegister dst, Address src) { Assembler::andpd(dst, src); }
+ void andpd(XMMRegister dst, AddressLiteral src);
+
+ void andps(XMMRegister dst, XMMRegister src) { Assembler::andps(dst, src); }
+ void andps(XMMRegister dst, Address src) { Assembler::andps(dst, src); }
+ void andps(XMMRegister dst, AddressLiteral src);
+
+ void comiss(XMMRegister dst, XMMRegister src) { Assembler::comiss(dst, src); }
+ void comiss(XMMRegister dst, Address src) { Assembler::comiss(dst, src); }
+ void comiss(XMMRegister dst, AddressLiteral src);
+
+ void comisd(XMMRegister dst, XMMRegister src) { Assembler::comisd(dst, src); }
+ void comisd(XMMRegister dst, Address src) { Assembler::comisd(dst, src); }
+ void comisd(XMMRegister dst, AddressLiteral src);
+
+ void fadd_s(Address src) { Assembler::fadd_s(src); }
+ void fadd_s(AddressLiteral src) { Assembler::fadd_s(as_Address(src)); }
+
+ void fldcw(Address src) { Assembler::fldcw(src); }
+ void fldcw(AddressLiteral src);
+
+ void fld_s(int index) { Assembler::fld_s(index); }
+ void fld_s(Address src) { Assembler::fld_s(src); }
+ void fld_s(AddressLiteral src);
+
+ void fld_d(Address src) { Assembler::fld_d(src); }
+ void fld_d(AddressLiteral src);
+
+ void fld_x(Address src) { Assembler::fld_x(src); }
+ void fld_x(AddressLiteral src);
+
+ void fmul_s(Address src) { Assembler::fmul_s(src); }
+ void fmul_s(AddressLiteral src) { Assembler::fmul_s(as_Address(src)); }
+
+ void ldmxcsr(Address src) { Assembler::ldmxcsr(src); }
+ void ldmxcsr(AddressLiteral src);
+
+ // compute pow(x,y) and exp(x) with x86 instructions. Don't cover
+ // all corner cases and may result in NaN and require fallback to a
+ // runtime call.
+ void fast_pow();
+ void fast_exp();
+ void increase_precision();
+ void restore_precision();
+
+ // computes exp(x). Fallback to runtime call included.
+ void exp_with_fallback(int num_fpu_regs_in_use) { pow_or_exp(true, num_fpu_regs_in_use); }
+ // computes pow(x,y). Fallback to runtime call included.
+ void pow_with_fallback(int num_fpu_regs_in_use) { pow_or_exp(false, num_fpu_regs_in_use); }
+
+private:
+
+ // call runtime as a fallback for trig functions and pow/exp.
+ void fp_runtime_fallback(address runtime_entry, int nb_args, int num_fpu_regs_in_use);
+
+ // computes 2^(Ylog2X); Ylog2X in ST(0)
+ void pow_exp_core_encoding();
+
+ // computes pow(x,y) or exp(x). Fallback to runtime call included.
+ void pow_or_exp(bool is_exp, int num_fpu_regs_in_use);
+
+ // these are private because users should be doing movflt/movdbl
+
+ void movss(Address dst, XMMRegister src) { Assembler::movss(dst, src); }
+ void movss(XMMRegister dst, XMMRegister src) { Assembler::movss(dst, src); }
+ void movss(XMMRegister dst, Address src) { Assembler::movss(dst, src); }
+ void movss(XMMRegister dst, AddressLiteral src);
+
+ void movlpd(XMMRegister dst, Address src) {Assembler::movlpd(dst, src); }
+ void movlpd(XMMRegister dst, AddressLiteral src);
+
+public:
+
+ void addsd(XMMRegister dst, XMMRegister src) { Assembler::addsd(dst, src); }
+ void addsd(XMMRegister dst, Address src) { Assembler::addsd(dst, src); }
+ void addsd(XMMRegister dst, AddressLiteral src);
+
+ void addss(XMMRegister dst, XMMRegister src) { Assembler::addss(dst, src); }
+ void addss(XMMRegister dst, Address src) { Assembler::addss(dst, src); }
+ void addss(XMMRegister dst, AddressLiteral src);
+
+ void divsd(XMMRegister dst, XMMRegister src) { Assembler::divsd(dst, src); }
+ void divsd(XMMRegister dst, Address src) { Assembler::divsd(dst, src); }
+ void divsd(XMMRegister dst, AddressLiteral src);
+
+ void divss(XMMRegister dst, XMMRegister src) { Assembler::divss(dst, src); }
+ void divss(XMMRegister dst, Address src) { Assembler::divss(dst, src); }
+ void divss(XMMRegister dst, AddressLiteral src);
+
+ // Move Unaligned Double Quadword
+ void movdqu(Address dst, XMMRegister src) { Assembler::movdqu(dst, src); }
+ void movdqu(XMMRegister dst, Address src) { Assembler::movdqu(dst, src); }
+ void movdqu(XMMRegister dst, XMMRegister src) { Assembler::movdqu(dst, src); }
+ void movdqu(XMMRegister dst, AddressLiteral src);
+
+ void movsd(XMMRegister dst, XMMRegister src) { Assembler::movsd(dst, src); }
+ void movsd(Address dst, XMMRegister src) { Assembler::movsd(dst, src); }
+ void movsd(XMMRegister dst, Address src) { Assembler::movsd(dst, src); }
+ void movsd(XMMRegister dst, AddressLiteral src);
+
+ void mulsd(XMMRegister dst, XMMRegister src) { Assembler::mulsd(dst, src); }
+ void mulsd(XMMRegister dst, Address src) { Assembler::mulsd(dst, src); }
+ void mulsd(XMMRegister dst, AddressLiteral src);
+
+ void mulss(XMMRegister dst, XMMRegister src) { Assembler::mulss(dst, src); }
+ void mulss(XMMRegister dst, Address src) { Assembler::mulss(dst, src); }
+ void mulss(XMMRegister dst, AddressLiteral src);
+
+ void sqrtsd(XMMRegister dst, XMMRegister src) { Assembler::sqrtsd(dst, src); }
+ void sqrtsd(XMMRegister dst, Address src) { Assembler::sqrtsd(dst, src); }
+ void sqrtsd(XMMRegister dst, AddressLiteral src);
+
+ void sqrtss(XMMRegister dst, XMMRegister src) { Assembler::sqrtss(dst, src); }
+ void sqrtss(XMMRegister dst, Address src) { Assembler::sqrtss(dst, src); }
+ void sqrtss(XMMRegister dst, AddressLiteral src);
+
+ void subsd(XMMRegister dst, XMMRegister src) { Assembler::subsd(dst, src); }
+ void subsd(XMMRegister dst, Address src) { Assembler::subsd(dst, src); }
+ void subsd(XMMRegister dst, AddressLiteral src);
+
+ void subss(XMMRegister dst, XMMRegister src) { Assembler::subss(dst, src); }
+ void subss(XMMRegister dst, Address src) { Assembler::subss(dst, src); }
+ void subss(XMMRegister dst, AddressLiteral src);
+
+ void ucomiss(XMMRegister dst, XMMRegister src) { Assembler::ucomiss(dst, src); }
+ void ucomiss(XMMRegister dst, Address src) { Assembler::ucomiss(dst, src); }
+ void ucomiss(XMMRegister dst, AddressLiteral src);
+
+ void ucomisd(XMMRegister dst, XMMRegister src) { Assembler::ucomisd(dst, src); }
+ void ucomisd(XMMRegister dst, Address src) { Assembler::ucomisd(dst, src); }
+ void ucomisd(XMMRegister dst, AddressLiteral src);
+
+ // Bitwise Logical XOR of Packed Double-Precision Floating-Point Values
+ void xorpd(XMMRegister dst, XMMRegister src) { Assembler::xorpd(dst, src); }
+ void xorpd(XMMRegister dst, Address src) { Assembler::xorpd(dst, src); }
+ void xorpd(XMMRegister dst, AddressLiteral src);
+
+ // Bitwise Logical XOR of Packed Single-Precision Floating-Point Values
+ void xorps(XMMRegister dst, XMMRegister src) { Assembler::xorps(dst, src); }
+ void xorps(XMMRegister dst, Address src) { Assembler::xorps(dst, src); }
+ void xorps(XMMRegister dst, AddressLiteral src);
+
+ // Shuffle Bytes
+ void pshufb(XMMRegister dst, XMMRegister src) { Assembler::pshufb(dst, src); }
+ void pshufb(XMMRegister dst, Address src) { Assembler::pshufb(dst, src); }
+ void pshufb(XMMRegister dst, AddressLiteral src);
+ // AVX 3-operands instructions
+
+ void vaddsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { Assembler::vaddsd(dst, nds, src); }
+ void vaddsd(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vaddsd(dst, nds, src); }
+ void vaddsd(XMMRegister dst, XMMRegister nds, AddressLiteral src);
+
+ void vaddss(XMMRegister dst, XMMRegister nds, XMMRegister src) { Assembler::vaddss(dst, nds, src); }
+ void vaddss(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vaddss(dst, nds, src); }
+ void vaddss(XMMRegister dst, XMMRegister nds, AddressLiteral src);
+
+ void vandpd(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { Assembler::vandpd(dst, nds, src, vector256); }
+ void vandpd(XMMRegister dst, XMMRegister nds, Address src, bool vector256) { Assembler::vandpd(dst, nds, src, vector256); }
+ void vandpd(XMMRegister dst, XMMRegister nds, AddressLiteral src, bool vector256);
+
+ void vandps(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { Assembler::vandps(dst, nds, src, vector256); }
+ void vandps(XMMRegister dst, XMMRegister nds, Address src, bool vector256) { Assembler::vandps(dst, nds, src, vector256); }
+ void vandps(XMMRegister dst, XMMRegister nds, AddressLiteral src, bool vector256);
+
+ void vdivsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { Assembler::vdivsd(dst, nds, src); }
+ void vdivsd(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vdivsd(dst, nds, src); }
+ void vdivsd(XMMRegister dst, XMMRegister nds, AddressLiteral src);
+
+ void vdivss(XMMRegister dst, XMMRegister nds, XMMRegister src) { Assembler::vdivss(dst, nds, src); }
+ void vdivss(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vdivss(dst, nds, src); }
+ void vdivss(XMMRegister dst, XMMRegister nds, AddressLiteral src);
+
+ void vmulsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { Assembler::vmulsd(dst, nds, src); }
+ void vmulsd(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vmulsd(dst, nds, src); }
+ void vmulsd(XMMRegister dst, XMMRegister nds, AddressLiteral src);
+
+ void vmulss(XMMRegister dst, XMMRegister nds, XMMRegister src) { Assembler::vmulss(dst, nds, src); }
+ void vmulss(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vmulss(dst, nds, src); }
+ void vmulss(XMMRegister dst, XMMRegister nds, AddressLiteral src);
+
+ void vsubsd(XMMRegister dst, XMMRegister nds, XMMRegister src) { Assembler::vsubsd(dst, nds, src); }
+ void vsubsd(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vsubsd(dst, nds, src); }
+ void vsubsd(XMMRegister dst, XMMRegister nds, AddressLiteral src);
+
+ void vsubss(XMMRegister dst, XMMRegister nds, XMMRegister src) { Assembler::vsubss(dst, nds, src); }
+ void vsubss(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vsubss(dst, nds, src); }
+ void vsubss(XMMRegister dst, XMMRegister nds, AddressLiteral src);
+
+ // AVX Vector instructions
+
+ void vxorpd(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { Assembler::vxorpd(dst, nds, src, vector256); }
+ void vxorpd(XMMRegister dst, XMMRegister nds, Address src, bool vector256) { Assembler::vxorpd(dst, nds, src, vector256); }
+ void vxorpd(XMMRegister dst, XMMRegister nds, AddressLiteral src, bool vector256);
+
+ void vxorps(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { Assembler::vxorps(dst, nds, src, vector256); }
+ void vxorps(XMMRegister dst, XMMRegister nds, Address src, bool vector256) { Assembler::vxorps(dst, nds, src, vector256); }
+ void vxorps(XMMRegister dst, XMMRegister nds, AddressLiteral src, bool vector256);
+
+ void vpxor(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) {
+ if (UseAVX > 1 || !vector256) // vpxor 256 bit is available only in AVX2
+ Assembler::vpxor(dst, nds, src, vector256);
+ else
+ Assembler::vxorpd(dst, nds, src, vector256);
+ }
+ void vpxor(XMMRegister dst, XMMRegister nds, Address src, bool vector256) {
+ if (UseAVX > 1 || !vector256) // vpxor 256 bit is available only in AVX2
+ Assembler::vpxor(dst, nds, src, vector256);
+ else
+ Assembler::vxorpd(dst, nds, src, vector256);
+ }
+
+ // Simple version for AVX2 256bit vectors
+ void vpxor(XMMRegister dst, XMMRegister src) { Assembler::vpxor(dst, dst, src, true); }
+ void vpxor(XMMRegister dst, Address src) { Assembler::vpxor(dst, dst, src, true); }
+
+ // Move packed integer values from low 128 bit to hign 128 bit in 256 bit vector.
+ void vinserti128h(XMMRegister dst, XMMRegister nds, XMMRegister src) {
+ if (UseAVX > 1) // vinserti128h is available only in AVX2
+ Assembler::vinserti128h(dst, nds, src);
+ else
+ Assembler::vinsertf128h(dst, nds, src);
+ }
+
+ // Data
+
+ void cmov32( Condition cc, Register dst, Address src);
+ void cmov32( Condition cc, Register dst, Register src);
+
+ void cmov( Condition cc, Register dst, Register src) { cmovptr(cc, dst, src); }
+
+ void cmovptr(Condition cc, Register dst, Address src) { LP64_ONLY(cmovq(cc, dst, src)) NOT_LP64(cmov32(cc, dst, src)); }
+ void cmovptr(Condition cc, Register dst, Register src) { LP64_ONLY(cmovq(cc, dst, src)) NOT_LP64(cmov32(cc, dst, src)); }
+
+ void movoop(Register dst, jobject obj);
+ void movoop(Address dst, jobject obj);
+
+ void mov_metadata(Register dst, Metadata* obj);
+ void mov_metadata(Address dst, Metadata* obj);
+
+ void movptr(ArrayAddress dst, Register src);
+ // can this do an lea?
+ void movptr(Register dst, ArrayAddress src);
+
+ void movptr(Register dst, Address src);
+
+ void movptr(Register dst, AddressLiteral src);
+
+ void movptr(Register dst, intptr_t src);
+ void movptr(Register dst, Register src);
+ void movptr(Address dst, intptr_t src);
+
+ void movptr(Address dst, Register src);
+
+ void movptr(Register dst, RegisterOrConstant src) {
+ if (src.is_constant()) movptr(dst, src.as_constant());
+ else movptr(dst, src.as_register());
+ }
+
+#ifdef _LP64
+ // Generally the next two are only used for moving NULL
+ // Although there are situations in initializing the mark word where
+ // they could be used. They are dangerous.
+
+ // They only exist on LP64 so that int32_t and intptr_t are not the same
+ // and we have ambiguous declarations.
+
+ void movptr(Address dst, int32_t imm32);
+ void movptr(Register dst, int32_t imm32);
+#endif // _LP64
+
+ // to avoid hiding movl
+ void mov32(AddressLiteral dst, Register src);
+ void mov32(Register dst, AddressLiteral src);
+
+ // to avoid hiding movb
+ void movbyte(ArrayAddress dst, int src);
+
+ // Import other mov() methods from the parent class or else
+ // they will be hidden by the following overriding declaration.
+ using Assembler::movdl;
+ using Assembler::movq;
+ void movdl(XMMRegister dst, AddressLiteral src);
+ void movq(XMMRegister dst, AddressLiteral src);
+
+ // Can push value or effective address
+ void pushptr(AddressLiteral src);
+
+ void pushptr(Address src) { LP64_ONLY(pushq(src)) NOT_LP64(pushl(src)); }
+ void popptr(Address src) { LP64_ONLY(popq(src)) NOT_LP64(popl(src)); }
+
+ void pushoop(jobject obj);
+ void pushklass(Metadata* obj);
+
+ // sign extend as need a l to ptr sized element
+ void movl2ptr(Register dst, Address src) { LP64_ONLY(movslq(dst, src)) NOT_LP64(movl(dst, src)); }
+ void movl2ptr(Register dst, Register src) { LP64_ONLY(movslq(dst, src)) NOT_LP64(if (dst != src) movl(dst, src)); }
+
+ // C2 compiled method's prolog code.
+ void verified_entry(int framesize, bool stack_bang, bool fp_mode_24b);
+
+ // clear memory of size 'cnt' qwords, starting at 'base'.
+ void clear_mem(Register base, Register cnt, Register rtmp);
+
+ // IndexOf strings.
+ // Small strings are loaded through stack if they cross page boundary.
+ void string_indexof(Register str1, Register str2,
+ Register cnt1, Register cnt2,
+ int int_cnt2, Register result,
+ XMMRegister vec, Register tmp);
+
+ // IndexOf for constant substrings with size >= 8 elements
+ // which don't need to be loaded through stack.
+ void string_indexofC8(Register str1, Register str2,
+ Register cnt1, Register cnt2,
+ int int_cnt2, Register result,
+ XMMRegister vec, Register tmp);
+
+ // Smallest code: we don't need to load through stack,
+ // check string tail.
+
+ // Compare strings.
+ void string_compare(Register str1, Register str2,
+ Register cnt1, Register cnt2, Register result,
+ XMMRegister vec1);
+
+ // Compare char[] arrays.
+ void char_arrays_equals(bool is_array_equ, Register ary1, Register ary2,
+ Register limit, Register result, Register chr,
+ XMMRegister vec1, XMMRegister vec2);
+
+ // Fill primitive arrays
+ void generate_fill(BasicType t, bool aligned,
+ Register to, Register value, Register count,
+ Register rtmp, XMMRegister xtmp);
+
+ void encode_iso_array(Register src, Register dst, Register len,
+ XMMRegister tmp1, XMMRegister tmp2, XMMRegister tmp3,
+ XMMRegister tmp4, Register tmp5, Register result);
+
+#undef VIRTUAL
+
+};
+
+/**
+ * class SkipIfEqual:
+ *
+ * Instantiating this class will result in assembly code being output that will
+ * jump around any code emitted between the creation of the instance and it's
+ * automatic destruction at the end of a scope block, depending on the value of
+ * the flag passed to the constructor, which will be checked at run-time.
+ */
+class SkipIfEqual {
+ private:
+ MacroAssembler* _masm;
+ Label _label;
+
+ public:
+ SkipIfEqual(MacroAssembler*, const bool* flag_addr, bool value);
+ ~SkipIfEqual();
+};
+
+#endif // CPU_X86_VM_MACROASSEMBLER_X86_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/metaspaceShared_x86_32.cpp
--- a/src/cpu/x86/vm/metaspaceShared_x86_32.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/metaspaceShared_x86_32.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,8 @@
*/
#include "precompiled.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/codeBuffer.hpp"
#include "memory/metaspaceShared.hpp"
// Generate the self-patching vtable method:
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/metaspaceShared_x86_64.cpp
--- a/src/cpu/x86/vm/metaspaceShared_x86_64.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/metaspaceShared_x86_64.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,8 @@
*/
#include "precompiled.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/codeBuffer.hpp"
#include "memory/metaspaceShared.hpp"
// Generate the self-patching vtable method:
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/methodHandles_x86.cpp
--- a/src/cpu/x86/vm/methodHandles_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/methodHandles_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "asm/macroAssembler.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "memory/allocation.inline.hpp"
@@ -168,8 +169,9 @@
if (VerifyMethodHandles && !for_compiler_entry) {
// make sure recv is already on stack
+ __ movptr(temp2, Address(method_temp, Method::const_offset()));
__ load_sized_value(temp2,
- Address(method_temp, Method::size_of_parameters_offset()),
+ Address(temp2, ConstMethod::size_of_parameters_offset()),
sizeof(u2), /*is_signed*/ false);
// assert(sizeof(u2) == sizeof(Method::_size_of_parameters), "");
Label L;
@@ -233,8 +235,9 @@
int ref_kind = signature_polymorphic_intrinsic_ref_kind(iid);
assert(ref_kind != 0 || iid == vmIntrinsics::_invokeBasic, "must be _invokeBasic or a linkTo intrinsic");
if (ref_kind == 0 || MethodHandles::ref_kind_has_receiver(ref_kind)) {
+ __ movptr(rdx_argp, Address(rbx_method, Method::const_offset()));
__ load_sized_value(rdx_argp,
- Address(rbx_method, Method::size_of_parameters_offset()),
+ Address(rdx_argp, ConstMethod::size_of_parameters_offset()),
sizeof(u2), /*is_signed*/ false);
// assert(sizeof(u2) == sizeof(Method::_size_of_parameters), "");
rdx_first_arg_addr = __ argument_address(rdx_argp, -1);
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/nativeInst_x86.cpp
--- a/src/cpu/x86/vm/nativeInst_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/nativeInst_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
#include "memory/resourceArea.hpp"
#include "nativeInst_x86.hpp"
#include "oops/oop.inline.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/relocInfo_x86.cpp
--- a/src/cpu/x86/vm/relocInfo_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/relocInfo_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.inline.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
#include "code/relocInfo.hpp"
#include "nativeInst_x86.hpp"
#include "oops/oop.inline.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/runtime_x86_32.cpp
--- a/src/cpu/x86/vm/runtime_x86_32.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/runtime_x86_32.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -24,12 +24,11 @@
#include "precompiled.hpp"
#ifdef COMPILER2
-#include "asm/assembler.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/vmreg.hpp"
#include "interpreter/interpreter.hpp"
-#include "nativeInst_x86.hpp"
#include "opto/runtime.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/sharedRuntime.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/runtime_x86_64.cpp
--- a/src/cpu/x86/vm/runtime_x86_64.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/runtime_x86_64.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -24,12 +24,11 @@
#include "precompiled.hpp"
#ifdef COMPILER2
-#include "asm/assembler.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/vmreg.hpp"
#include "interpreter/interpreter.hpp"
-#include "nativeInst_x86.hpp"
#include "opto/runtime.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/sharedRuntime.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/sharedRuntime_x86_32.cpp
--- a/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/sharedRuntime_x86_32.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "code/debugInfoRec.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
@@ -1936,7 +1936,7 @@
if (method->is_static() && !is_critical_native) {
// load opp into a register
- __ movoop(oop_handle_reg, JNIHandles::make_local(Klass::cast(method->method_holder())->java_mirror()));
+ __ movoop(oop_handle_reg, JNIHandles::make_local(method->method_holder()->java_mirror()));
// Now handlize the static class mirror it's known not-null.
__ movptr(Address(rsp, klass_offset), oop_handle_reg);
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/sharedRuntime_x86_64.cpp
--- a/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/sharedRuntime_x86_64.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "code/debugInfoRec.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
@@ -2179,7 +2179,7 @@
if (method->is_static() && !is_critical_native) {
// load oop into a register
- __ movoop(oop_handle_reg, JNIHandles::make_local(Klass::cast(method->method_holder())->java_mirror()));
+ __ movoop(oop_handle_reg, JNIHandles::make_local(method->method_holder()->java_mirror()));
// Now handlize the static class mirror it's known not-null.
__ movptr(Address(rsp, klass_offset), oop_handle_reg);
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/stubGenerator_x86_32.cpp
--- a/src/cpu/x86/vm/stubGenerator_x86_32.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/stubGenerator_x86_32.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "nativeInst_x86.hpp"
#include "oops/instanceOop.hpp"
@@ -37,19 +37,8 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubCodeGenerator.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
#include "utilities/top.hpp"
-#ifdef TARGET_OS_FAMILY_linux
-# include "thread_linux.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_solaris
-# include "thread_solaris.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_windows
-# include "thread_windows.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_bsd
-# include "thread_bsd.inline.hpp"
-#endif
#ifdef COMPILER2
#include "opto/runtime.hpp"
#endif
@@ -807,16 +796,22 @@
__ align(OptoLoopAlignment);
__ BIND(L_copy_64_bytes_loop);
- if(UseUnalignedLoadStores) {
- __ movdqu(xmm0, Address(from, 0));
- __ movdqu(Address(from, to_from, Address::times_1, 0), xmm0);
- __ movdqu(xmm1, Address(from, 16));
- __ movdqu(Address(from, to_from, Address::times_1, 16), xmm1);
- __ movdqu(xmm2, Address(from, 32));
- __ movdqu(Address(from, to_from, Address::times_1, 32), xmm2);
- __ movdqu(xmm3, Address(from, 48));
- __ movdqu(Address(from, to_from, Address::times_1, 48), xmm3);
-
+ if (UseUnalignedLoadStores) {
+ if (UseAVX >= 2) {
+ __ vmovdqu(xmm0, Address(from, 0));
+ __ vmovdqu(Address(from, to_from, Address::times_1, 0), xmm0);
+ __ vmovdqu(xmm1, Address(from, 32));
+ __ vmovdqu(Address(from, to_from, Address::times_1, 32), xmm1);
+ } else {
+ __ movdqu(xmm0, Address(from, 0));
+ __ movdqu(Address(from, to_from, Address::times_1, 0), xmm0);
+ __ movdqu(xmm1, Address(from, 16));
+ __ movdqu(Address(from, to_from, Address::times_1, 16), xmm1);
+ __ movdqu(xmm2, Address(from, 32));
+ __ movdqu(Address(from, to_from, Address::times_1, 32), xmm2);
+ __ movdqu(xmm3, Address(from, 48));
+ __ movdqu(Address(from, to_from, Address::times_1, 48), xmm3);
+ }
} else {
__ movq(xmm0, Address(from, 0));
__ movq(Address(from, to_from, Address::times_1, 0), xmm0);
@@ -2137,6 +2132,581 @@
}
}
+ // AES intrinsic stubs
+ enum {AESBlockSize = 16};
+
+ address generate_key_shuffle_mask() {
+ __ align(16);
+ StubCodeMark mark(this, "StubRoutines", "key_shuffle_mask");
+ address start = __ pc();
+ __ emit_data(0x00010203, relocInfo::none, 0 );
+ __ emit_data(0x04050607, relocInfo::none, 0 );
+ __ emit_data(0x08090a0b, relocInfo::none, 0 );
+ __ emit_data(0x0c0d0e0f, relocInfo::none, 0 );
+ return start;
+ }
+
+ // Utility routine for loading a 128-bit key word in little endian format
+ // can optionally specify that the shuffle mask is already in an xmmregister
+ void load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask=NULL) {
+ __ movdqu(xmmdst, Address(key, offset));
+ if (xmm_shuf_mask != NULL) {
+ __ pshufb(xmmdst, xmm_shuf_mask);
+ } else {
+ __ pshufb(xmmdst, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()));
+ }
+ }
+
+ // aesenc using specified key+offset
+ // can optionally specify that the shuffle mask is already in an xmmregister
+ void aes_enc_key(XMMRegister xmmdst, XMMRegister xmmtmp, Register key, int offset, XMMRegister xmm_shuf_mask=NULL) {
+ load_key(xmmtmp, key, offset, xmm_shuf_mask);
+ __ aesenc(xmmdst, xmmtmp);
+ }
+
+ // aesdec using specified key+offset
+ // can optionally specify that the shuffle mask is already in an xmmregister
+ void aes_dec_key(XMMRegister xmmdst, XMMRegister xmmtmp, Register key, int offset, XMMRegister xmm_shuf_mask=NULL) {
+ load_key(xmmtmp, key, offset, xmm_shuf_mask);
+ __ aesdec(xmmdst, xmmtmp);
+ }
+
+
+ // Arguments:
+ //
+ // Inputs:
+ // c_rarg0 - source byte array address
+ // c_rarg1 - destination byte array address
+ // c_rarg2 - K (key) in little endian int array
+ //
+ address generate_aescrypt_encryptBlock() {
+ assert(UseAES, "need AES instructions and misaligned SSE support");
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "aescrypt_encryptBlock");
+ Label L_doLast;
+ address start = __ pc();
+
+ const Register from = rdx; // source array address
+ const Register to = rdx; // destination array address
+ const Register key = rcx; // key array address
+ const Register keylen = rax;
+ const Address from_param(rbp, 8+0);
+ const Address to_param (rbp, 8+4);
+ const Address key_param (rbp, 8+8);
+
+ const XMMRegister xmm_result = xmm0;
+ const XMMRegister xmm_key_shuf_mask = xmm1;
+ const XMMRegister xmm_temp1 = xmm2;
+ const XMMRegister xmm_temp2 = xmm3;
+ const XMMRegister xmm_temp3 = xmm4;
+ const XMMRegister xmm_temp4 = xmm5;
+
+ __ enter(); // required for proper stackwalking of RuntimeStub frame
+ __ movptr(from, from_param);
+ __ movptr(key, key_param);
+
+ // keylen could be only {11, 13, 15} * 4 = {44, 52, 60}
+ __ movl(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
+
+ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()));
+ __ movdqu(xmm_result, Address(from, 0)); // get 16 bytes of input
+ __ movptr(to, to_param);
+
+ // For encryption, the java expanded key ordering is just what we need
+
+ load_key(xmm_temp1, key, 0x00, xmm_key_shuf_mask);
+ __ pxor(xmm_result, xmm_temp1);
+
+ load_key(xmm_temp1, key, 0x10, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0x20, xmm_key_shuf_mask);
+ load_key(xmm_temp3, key, 0x30, xmm_key_shuf_mask);
+ load_key(xmm_temp4, key, 0x40, xmm_key_shuf_mask);
+
+ __ aesenc(xmm_result, xmm_temp1);
+ __ aesenc(xmm_result, xmm_temp2);
+ __ aesenc(xmm_result, xmm_temp3);
+ __ aesenc(xmm_result, xmm_temp4);
+
+ load_key(xmm_temp1, key, 0x50, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0x60, xmm_key_shuf_mask);
+ load_key(xmm_temp3, key, 0x70, xmm_key_shuf_mask);
+ load_key(xmm_temp4, key, 0x80, xmm_key_shuf_mask);
+
+ __ aesenc(xmm_result, xmm_temp1);
+ __ aesenc(xmm_result, xmm_temp2);
+ __ aesenc(xmm_result, xmm_temp3);
+ __ aesenc(xmm_result, xmm_temp4);
+
+ load_key(xmm_temp1, key, 0x90, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0xa0, xmm_key_shuf_mask);
+
+ __ cmpl(keylen, 44);
+ __ jccb(Assembler::equal, L_doLast);
+
+ __ aesenc(xmm_result, xmm_temp1);
+ __ aesenc(xmm_result, xmm_temp2);
+
+ load_key(xmm_temp1, key, 0xb0, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0xc0, xmm_key_shuf_mask);
+
+ __ cmpl(keylen, 52);
+ __ jccb(Assembler::equal, L_doLast);
+
+ __ aesenc(xmm_result, xmm_temp1);
+ __ aesenc(xmm_result, xmm_temp2);
+
+ load_key(xmm_temp1, key, 0xd0, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0xe0, xmm_key_shuf_mask);
+
+ __ BIND(L_doLast);
+ __ aesenc(xmm_result, xmm_temp1);
+ __ aesenclast(xmm_result, xmm_temp2);
+ __ movdqu(Address(to, 0), xmm_result); // store the result
+ __ xorptr(rax, rax); // return 0
+ __ leave(); // required for proper stackwalking of RuntimeStub frame
+ __ ret(0);
+
+ return start;
+ }
+
+
+ // Arguments:
+ //
+ // Inputs:
+ // c_rarg0 - source byte array address
+ // c_rarg1 - destination byte array address
+ // c_rarg2 - K (key) in little endian int array
+ //
+ address generate_aescrypt_decryptBlock() {
+ assert(UseAES, "need AES instructions and misaligned SSE support");
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "aescrypt_decryptBlock");
+ Label L_doLast;
+ address start = __ pc();
+
+ const Register from = rdx; // source array address
+ const Register to = rdx; // destination array address
+ const Register key = rcx; // key array address
+ const Register keylen = rax;
+ const Address from_param(rbp, 8+0);
+ const Address to_param (rbp, 8+4);
+ const Address key_param (rbp, 8+8);
+
+ const XMMRegister xmm_result = xmm0;
+ const XMMRegister xmm_key_shuf_mask = xmm1;
+ const XMMRegister xmm_temp1 = xmm2;
+ const XMMRegister xmm_temp2 = xmm3;
+ const XMMRegister xmm_temp3 = xmm4;
+ const XMMRegister xmm_temp4 = xmm5;
+
+ __ enter(); // required for proper stackwalking of RuntimeStub frame
+ __ movptr(from, from_param);
+ __ movptr(key, key_param);
+
+ // keylen could be only {11, 13, 15} * 4 = {44, 52, 60}
+ __ movl(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
+
+ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()));
+ __ movdqu(xmm_result, Address(from, 0));
+ __ movptr(to, to_param);
+
+ // for decryption java expanded key ordering is rotated one position from what we want
+ // so we start from 0x10 here and hit 0x00 last
+ // we don't know if the key is aligned, hence not using load-execute form
+ load_key(xmm_temp1, key, 0x10, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0x20, xmm_key_shuf_mask);
+ load_key(xmm_temp3, key, 0x30, xmm_key_shuf_mask);
+ load_key(xmm_temp4, key, 0x40, xmm_key_shuf_mask);
+
+ __ pxor (xmm_result, xmm_temp1);
+ __ aesdec(xmm_result, xmm_temp2);
+ __ aesdec(xmm_result, xmm_temp3);
+ __ aesdec(xmm_result, xmm_temp4);
+
+ load_key(xmm_temp1, key, 0x50, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0x60, xmm_key_shuf_mask);
+ load_key(xmm_temp3, key, 0x70, xmm_key_shuf_mask);
+ load_key(xmm_temp4, key, 0x80, xmm_key_shuf_mask);
+
+ __ aesdec(xmm_result, xmm_temp1);
+ __ aesdec(xmm_result, xmm_temp2);
+ __ aesdec(xmm_result, xmm_temp3);
+ __ aesdec(xmm_result, xmm_temp4);
+
+ load_key(xmm_temp1, key, 0x90, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0xa0, xmm_key_shuf_mask);
+ load_key(xmm_temp3, key, 0x00, xmm_key_shuf_mask);
+
+ __ cmpl(keylen, 44);
+ __ jccb(Assembler::equal, L_doLast);
+
+ __ aesdec(xmm_result, xmm_temp1);
+ __ aesdec(xmm_result, xmm_temp2);
+
+ load_key(xmm_temp1, key, 0xb0, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0xc0, xmm_key_shuf_mask);
+
+ __ cmpl(keylen, 52);
+ __ jccb(Assembler::equal, L_doLast);
+
+ __ aesdec(xmm_result, xmm_temp1);
+ __ aesdec(xmm_result, xmm_temp2);
+
+ load_key(xmm_temp1, key, 0xd0, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0xe0, xmm_key_shuf_mask);
+
+ __ BIND(L_doLast);
+ __ aesdec(xmm_result, xmm_temp1);
+ __ aesdec(xmm_result, xmm_temp2);
+
+ // for decryption the aesdeclast operation is always on key+0x00
+ __ aesdeclast(xmm_result, xmm_temp3);
+ __ movdqu(Address(to, 0), xmm_result); // store the result
+ __ xorptr(rax, rax); // return 0
+ __ leave(); // required for proper stackwalking of RuntimeStub frame
+ __ ret(0);
+
+ return start;
+ }
+
+ void handleSOERegisters(bool saving) {
+ const int saveFrameSizeInBytes = 4 * wordSize;
+ const Address saved_rbx (rbp, -3 * wordSize);
+ const Address saved_rsi (rbp, -2 * wordSize);
+ const Address saved_rdi (rbp, -1 * wordSize);
+
+ if (saving) {
+ __ subptr(rsp, saveFrameSizeInBytes);
+ __ movptr(saved_rsi, rsi);
+ __ movptr(saved_rdi, rdi);
+ __ movptr(saved_rbx, rbx);
+ } else {
+ // restoring
+ __ movptr(rsi, saved_rsi);
+ __ movptr(rdi, saved_rdi);
+ __ movptr(rbx, saved_rbx);
+ }
+ }
+
+ // Arguments:
+ //
+ // Inputs:
+ // c_rarg0 - source byte array address
+ // c_rarg1 - destination byte array address
+ // c_rarg2 - K (key) in little endian int array
+ // c_rarg3 - r vector byte array address
+ // c_rarg4 - input length
+ //
+ address generate_cipherBlockChaining_encryptAESCrypt() {
+ assert(UseAES, "need AES instructions and misaligned SSE support");
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_encryptAESCrypt");
+ address start = __ pc();
+
+ Label L_exit, L_key_192_256, L_key_256, L_loopTop_128, L_loopTop_192, L_loopTop_256;
+ const Register from = rsi; // source array address
+ const Register to = rdx; // destination array address
+ const Register key = rcx; // key array address
+ const Register rvec = rdi; // r byte array initialized from initvector array address
+ // and left with the results of the last encryption block
+ const Register len_reg = rbx; // src len (must be multiple of blocksize 16)
+ const Register pos = rax;
+
+ // xmm register assignments for the loops below
+ const XMMRegister xmm_result = xmm0;
+ const XMMRegister xmm_temp = xmm1;
+ // first 6 keys preloaded into xmm2-xmm7
+ const int XMM_REG_NUM_KEY_FIRST = 2;
+ const int XMM_REG_NUM_KEY_LAST = 7;
+ const XMMRegister xmm_key0 = as_XMMRegister(XMM_REG_NUM_KEY_FIRST);
+
+ __ enter(); // required for proper stackwalking of RuntimeStub frame
+ handleSOERegisters(true /*saving*/);
+
+ // load registers from incoming parameters
+ const Address from_param(rbp, 8+0);
+ const Address to_param (rbp, 8+4);
+ const Address key_param (rbp, 8+8);
+ const Address rvec_param (rbp, 8+12);
+ const Address len_param (rbp, 8+16);
+ __ movptr(from , from_param);
+ __ movptr(to , to_param);
+ __ movptr(key , key_param);
+ __ movptr(rvec , rvec_param);
+ __ movptr(len_reg , len_param);
+
+ const XMMRegister xmm_key_shuf_mask = xmm_temp; // used temporarily to swap key bytes up front
+ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()));
+ // load up xmm regs 2 thru 7 with keys 0-5
+ for (int rnum = XMM_REG_NUM_KEY_FIRST, offset = 0x00; rnum <= XMM_REG_NUM_KEY_LAST; rnum++) {
+ load_key(as_XMMRegister(rnum), key, offset, xmm_key_shuf_mask);
+ offset += 0x10;
+ }
+
+ __ movdqu(xmm_result, Address(rvec, 0x00)); // initialize xmm_result with r vec
+
+ // now split to different paths depending on the keylen (len in ints of AESCrypt.KLE array (52=192, or 60=256))
+ __ movl(rax, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
+ __ cmpl(rax, 44);
+ __ jcc(Assembler::notEqual, L_key_192_256);
+
+ // 128 bit code follows here
+ __ movl(pos, 0);
+ __ align(OptoLoopAlignment);
+ __ BIND(L_loopTop_128);
+ __ movdqu(xmm_temp, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of input
+ __ pxor (xmm_result, xmm_temp); // xor with the current r vector
+
+ __ pxor (xmm_result, xmm_key0); // do the aes rounds
+ for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++) {
+ __ aesenc(xmm_result, as_XMMRegister(rnum));
+ }
+ for (int key_offset = 0x60; key_offset <= 0x90; key_offset += 0x10) {
+ aes_enc_key(xmm_result, xmm_temp, key, key_offset);
+ }
+ load_key(xmm_temp, key, 0xa0);
+ __ aesenclast(xmm_result, xmm_temp);
+
+ __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output
+ // no need to store r to memory until we exit
+ __ addptr(pos, AESBlockSize);
+ __ subptr(len_reg, AESBlockSize);
+ __ jcc(Assembler::notEqual, L_loopTop_128);
+
+ __ BIND(L_exit);
+ __ movdqu(Address(rvec, 0), xmm_result); // final value of r stored in rvec of CipherBlockChaining object
+
+ handleSOERegisters(false /*restoring*/);
+ __ movl(rax, 0); // return 0 (why?)
+ __ leave(); // required for proper stackwalking of RuntimeStub frame
+ __ ret(0);
+
+ __ BIND(L_key_192_256);
+ // here rax = len in ints of AESCrypt.KLE array (52=192, or 60=256)
+ __ cmpl(rax, 52);
+ __ jcc(Assembler::notEqual, L_key_256);
+
+ // 192-bit code follows here (could be changed to use more xmm registers)
+ __ movl(pos, 0);
+ __ align(OptoLoopAlignment);
+ __ BIND(L_loopTop_192);
+ __ movdqu(xmm_temp, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of input
+ __ pxor (xmm_result, xmm_temp); // xor with the current r vector
+
+ __ pxor (xmm_result, xmm_key0); // do the aes rounds
+ for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++) {
+ __ aesenc(xmm_result, as_XMMRegister(rnum));
+ }
+ for (int key_offset = 0x60; key_offset <= 0xb0; key_offset += 0x10) {
+ aes_enc_key(xmm_result, xmm_temp, key, key_offset);
+ }
+ load_key(xmm_temp, key, 0xc0);
+ __ aesenclast(xmm_result, xmm_temp);
+
+ __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output
+ // no need to store r to memory until we exit
+ __ addptr(pos, AESBlockSize);
+ __ subptr(len_reg, AESBlockSize);
+ __ jcc(Assembler::notEqual, L_loopTop_192);
+ __ jmp(L_exit);
+
+ __ BIND(L_key_256);
+ // 256-bit code follows here (could be changed to use more xmm registers)
+ __ movl(pos, 0);
+ __ align(OptoLoopAlignment);
+ __ BIND(L_loopTop_256);
+ __ movdqu(xmm_temp, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of input
+ __ pxor (xmm_result, xmm_temp); // xor with the current r vector
+
+ __ pxor (xmm_result, xmm_key0); // do the aes rounds
+ for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++) {
+ __ aesenc(xmm_result, as_XMMRegister(rnum));
+ }
+ for (int key_offset = 0x60; key_offset <= 0xd0; key_offset += 0x10) {
+ aes_enc_key(xmm_result, xmm_temp, key, key_offset);
+ }
+ load_key(xmm_temp, key, 0xe0);
+ __ aesenclast(xmm_result, xmm_temp);
+
+ __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output
+ // no need to store r to memory until we exit
+ __ addptr(pos, AESBlockSize);
+ __ subptr(len_reg, AESBlockSize);
+ __ jcc(Assembler::notEqual, L_loopTop_256);
+ __ jmp(L_exit);
+
+ return start;
+ }
+
+
+ // CBC AES Decryption.
+ // In 32-bit stub, because of lack of registers we do not try to parallelize 4 blocks at a time.
+ //
+ // Arguments:
+ //
+ // Inputs:
+ // c_rarg0 - source byte array address
+ // c_rarg1 - destination byte array address
+ // c_rarg2 - K (key) in little endian int array
+ // c_rarg3 - r vector byte array address
+ // c_rarg4 - input length
+ //
+
+ address generate_cipherBlockChaining_decryptAESCrypt() {
+ assert(UseAES, "need AES instructions and misaligned SSE support");
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_decryptAESCrypt");
+ address start = __ pc();
+
+ Label L_exit, L_key_192_256, L_key_256;
+ Label L_singleBlock_loopTop_128;
+ Label L_singleBlock_loopTop_192, L_singleBlock_loopTop_256;
+ const Register from = rsi; // source array address
+ const Register to = rdx; // destination array address
+ const Register key = rcx; // key array address
+ const Register rvec = rdi; // r byte array initialized from initvector array address
+ // and left with the results of the last encryption block
+ const Register len_reg = rbx; // src len (must be multiple of blocksize 16)
+ const Register pos = rax;
+
+ // xmm register assignments for the loops below
+ const XMMRegister xmm_result = xmm0;
+ const XMMRegister xmm_temp = xmm1;
+ // first 6 keys preloaded into xmm2-xmm7
+ const int XMM_REG_NUM_KEY_FIRST = 2;
+ const int XMM_REG_NUM_KEY_LAST = 7;
+ const int FIRST_NON_REG_KEY_offset = 0x70;
+ const XMMRegister xmm_key_first = as_XMMRegister(XMM_REG_NUM_KEY_FIRST);
+
+ __ enter(); // required for proper stackwalking of RuntimeStub frame
+ handleSOERegisters(true /*saving*/);
+
+ // load registers from incoming parameters
+ const Address from_param(rbp, 8+0);
+ const Address to_param (rbp, 8+4);
+ const Address key_param (rbp, 8+8);
+ const Address rvec_param (rbp, 8+12);
+ const Address len_param (rbp, 8+16);
+ __ movptr(from , from_param);
+ __ movptr(to , to_param);
+ __ movptr(key , key_param);
+ __ movptr(rvec , rvec_param);
+ __ movptr(len_reg , len_param);
+
+ // the java expanded key ordering is rotated one position from what we want
+ // so we start from 0x10 here and hit 0x00 last
+ const XMMRegister xmm_key_shuf_mask = xmm1; // used temporarily to swap key bytes up front
+ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()));
+ // load up xmm regs 2 thru 6 with first 5 keys
+ for (int rnum = XMM_REG_NUM_KEY_FIRST, offset = 0x10; rnum <= XMM_REG_NUM_KEY_LAST; rnum++) {
+ load_key(as_XMMRegister(rnum), key, offset, xmm_key_shuf_mask);
+ offset += 0x10;
+ }
+
+ // inside here, use the rvec register to point to previous block cipher
+ // with which we xor at the end of each newly decrypted block
+ const Register prev_block_cipher_ptr = rvec;
+
+ // now split to different paths depending on the keylen (len in ints of AESCrypt.KLE array (52=192, or 60=256))
+ __ movl(rax, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
+ __ cmpl(rax, 44);
+ __ jcc(Assembler::notEqual, L_key_192_256);
+
+
+ // 128-bit code follows here, parallelized
+ __ movl(pos, 0);
+ __ align(OptoLoopAlignment);
+ __ BIND(L_singleBlock_loopTop_128);
+ __ cmpptr(len_reg, 0); // any blocks left??
+ __ jcc(Assembler::equal, L_exit);
+ __ movdqu(xmm_result, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of cipher input
+ __ pxor (xmm_result, xmm_key_first); // do the aes dec rounds
+ for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++) {
+ __ aesdec(xmm_result, as_XMMRegister(rnum));
+ }
+ for (int key_offset = FIRST_NON_REG_KEY_offset; key_offset <= 0xa0; key_offset += 0x10) { // 128-bit runs up to key offset a0
+ aes_dec_key(xmm_result, xmm_temp, key, key_offset);
+ }
+ load_key(xmm_temp, key, 0x00); // final key is stored in java expanded array at offset 0
+ __ aesdeclast(xmm_result, xmm_temp);
+ __ movdqu(xmm_temp, Address(prev_block_cipher_ptr, 0x00));
+ __ pxor (xmm_result, xmm_temp); // xor with the current r vector
+ __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output
+ // no need to store r to memory until we exit
+ __ lea(prev_block_cipher_ptr, Address(from, pos, Address::times_1, 0)); // set up new ptr
+ __ addptr(pos, AESBlockSize);
+ __ subptr(len_reg, AESBlockSize);
+ __ jmp(L_singleBlock_loopTop_128);
+
+
+ __ BIND(L_exit);
+ __ movdqu(xmm_temp, Address(prev_block_cipher_ptr, 0x00));
+ __ movptr(rvec , rvec_param); // restore this since used in loop
+ __ movdqu(Address(rvec, 0), xmm_temp); // final value of r stored in rvec of CipherBlockChaining object
+ handleSOERegisters(false /*restoring*/);
+ __ movl(rax, 0); // return 0 (why?)
+ __ leave(); // required for proper stackwalking of RuntimeStub frame
+ __ ret(0);
+
+
+ __ BIND(L_key_192_256);
+ // here rax = len in ints of AESCrypt.KLE array (52=192, or 60=256)
+ __ cmpl(rax, 52);
+ __ jcc(Assembler::notEqual, L_key_256);
+
+ // 192-bit code follows here (could be optimized to use parallelism)
+ __ movl(pos, 0);
+ __ align(OptoLoopAlignment);
+ __ BIND(L_singleBlock_loopTop_192);
+ __ movdqu(xmm_result, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of cipher input
+ __ pxor (xmm_result, xmm_key_first); // do the aes dec rounds
+ for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++) {
+ __ aesdec(xmm_result, as_XMMRegister(rnum));
+ }
+ for (int key_offset = FIRST_NON_REG_KEY_offset; key_offset <= 0xc0; key_offset += 0x10) { // 192-bit runs up to key offset c0
+ aes_dec_key(xmm_result, xmm_temp, key, key_offset);
+ }
+ load_key(xmm_temp, key, 0x00); // final key is stored in java expanded array at offset 0
+ __ aesdeclast(xmm_result, xmm_temp);
+ __ movdqu(xmm_temp, Address(prev_block_cipher_ptr, 0x00));
+ __ pxor (xmm_result, xmm_temp); // xor with the current r vector
+ __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output
+ // no need to store r to memory until we exit
+ __ lea(prev_block_cipher_ptr, Address(from, pos, Address::times_1, 0)); // set up new ptr
+ __ addptr(pos, AESBlockSize);
+ __ subptr(len_reg, AESBlockSize);
+ __ jcc(Assembler::notEqual,L_singleBlock_loopTop_192);
+ __ jmp(L_exit);
+
+ __ BIND(L_key_256);
+ // 256-bit code follows here (could be optimized to use parallelism)
+ __ movl(pos, 0);
+ __ align(OptoLoopAlignment);
+ __ BIND(L_singleBlock_loopTop_256);
+ __ movdqu(xmm_result, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of cipher input
+ __ pxor (xmm_result, xmm_key_first); // do the aes dec rounds
+ for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST; rnum++) {
+ __ aesdec(xmm_result, as_XMMRegister(rnum));
+ }
+ for (int key_offset = FIRST_NON_REG_KEY_offset; key_offset <= 0xe0; key_offset += 0x10) { // 256-bit runs up to key offset e0
+ aes_dec_key(xmm_result, xmm_temp, key, key_offset);
+ }
+ load_key(xmm_temp, key, 0x00); // final key is stored in java expanded array at offset 0
+ __ aesdeclast(xmm_result, xmm_temp);
+ __ movdqu(xmm_temp, Address(prev_block_cipher_ptr, 0x00));
+ __ pxor (xmm_result, xmm_temp); // xor with the current r vector
+ __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output
+ // no need to store r to memory until we exit
+ __ lea(prev_block_cipher_ptr, Address(from, pos, Address::times_1, 0)); // set up new ptr
+ __ addptr(pos, AESBlockSize);
+ __ subptr(len_reg, AESBlockSize);
+ __ jcc(Assembler::notEqual,L_singleBlock_loopTop_256);
+ __ jmp(L_exit);
+
+ return start;
+ }
+
+
public:
// Information about frame layout at time of blocking runtime call.
// Note that we only have to preserve callee-saved registers since
@@ -2332,6 +2902,16 @@
generate_arraycopy_stubs();
generate_math_stubs();
+
+ // don't bother generating these AES intrinsic stubs unless global flag is set
+ if (UseAESIntrinsics) {
+ StubRoutines::x86::_key_shuffle_mask_addr = generate_key_shuffle_mask(); // might be needed by the others
+
+ StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock();
+ StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock();
+ StubRoutines::_cipherBlockChaining_encryptAESCrypt = generate_cipherBlockChaining_encryptAESCrypt();
+ StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt();
+ }
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/stubGenerator_x86_64.cpp
--- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "nativeInst_x86.hpp"
#include "oops/instanceOop.hpp"
@@ -37,19 +37,8 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubCodeGenerator.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
#include "utilities/top.hpp"
-#ifdef TARGET_OS_FAMILY_linux
-# include "thread_linux.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_solaris
-# include "thread_solaris.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_windows
-# include "thread_windows.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_bsd
-# include "thread_bsd.inline.hpp"
-#endif
#ifdef COMPILER2
#include "opto/runtime.hpp"
#endif
@@ -1297,23 +1286,54 @@
// end_to - destination array end address
// qword_count - 64-bits element count, negative
// to - scratch
- // L_copy_32_bytes - entry label
+ // L_copy_bytes - entry label
// L_copy_8_bytes - exit label
//
- void copy_32_bytes_forward(Register end_from, Register end_to,
+ void copy_bytes_forward(Register end_from, Register end_to,
Register qword_count, Register to,
- Label& L_copy_32_bytes, Label& L_copy_8_bytes) {
+ Label& L_copy_bytes, Label& L_copy_8_bytes) {
DEBUG_ONLY(__ stop("enter at entry label, not here"));
Label L_loop;
__ align(OptoLoopAlignment);
- __ BIND(L_loop);
- if(UseUnalignedLoadStores) {
- __ movdqu(xmm0, Address(end_from, qword_count, Address::times_8, -24));
- __ movdqu(Address(end_to, qword_count, Address::times_8, -24), xmm0);
- __ movdqu(xmm1, Address(end_from, qword_count, Address::times_8, - 8));
- __ movdqu(Address(end_to, qword_count, Address::times_8, - 8), xmm1);
-
+ if (UseUnalignedLoadStores) {
+ Label L_end;
+ // Copy 64-bytes per iteration
+ __ BIND(L_loop);
+ if (UseAVX >= 2) {
+ __ vmovdqu(xmm0, Address(end_from, qword_count, Address::times_8, -56));
+ __ vmovdqu(Address(end_to, qword_count, Address::times_8, -56), xmm0);
+ __ vmovdqu(xmm1, Address(end_from, qword_count, Address::times_8, -24));
+ __ vmovdqu(Address(end_to, qword_count, Address::times_8, -24), xmm1);
+ } else {
+ __ movdqu(xmm0, Address(end_from, qword_count, Address::times_8, -56));
+ __ movdqu(Address(end_to, qword_count, Address::times_8, -56), xmm0);
+ __ movdqu(xmm1, Address(end_from, qword_count, Address::times_8, -40));
+ __ movdqu(Address(end_to, qword_count, Address::times_8, -40), xmm1);
+ __ movdqu(xmm2, Address(end_from, qword_count, Address::times_8, -24));
+ __ movdqu(Address(end_to, qword_count, Address::times_8, -24), xmm2);
+ __ movdqu(xmm3, Address(end_from, qword_count, Address::times_8, - 8));
+ __ movdqu(Address(end_to, qword_count, Address::times_8, - 8), xmm3);
+ }
+ __ BIND(L_copy_bytes);
+ __ addptr(qword_count, 8);
+ __ jcc(Assembler::lessEqual, L_loop);
+ __ subptr(qword_count, 4); // sub(8) and add(4)
+ __ jccb(Assembler::greater, L_end);
+ // Copy trailing 32 bytes
+ if (UseAVX >= 2) {
+ __ vmovdqu(xmm0, Address(end_from, qword_count, Address::times_8, -24));
+ __ vmovdqu(Address(end_to, qword_count, Address::times_8, -24), xmm0);
+ } else {
+ __ movdqu(xmm0, Address(end_from, qword_count, Address::times_8, -24));
+ __ movdqu(Address(end_to, qword_count, Address::times_8, -24), xmm0);
+ __ movdqu(xmm1, Address(end_from, qword_count, Address::times_8, - 8));
+ __ movdqu(Address(end_to, qword_count, Address::times_8, - 8), xmm1);
+ }
+ __ addptr(qword_count, 4);
+ __ BIND(L_end);
} else {
+ // Copy 32-bytes per iteration
+ __ BIND(L_loop);
__ movq(to, Address(end_from, qword_count, Address::times_8, -24));
__ movq(Address(end_to, qword_count, Address::times_8, -24), to);
__ movq(to, Address(end_from, qword_count, Address::times_8, -16));
@@ -1322,15 +1342,15 @@
__ movq(Address(end_to, qword_count, Address::times_8, - 8), to);
__ movq(to, Address(end_from, qword_count, Address::times_8, - 0));
__ movq(Address(end_to, qword_count, Address::times_8, - 0), to);
+
+ __ BIND(L_copy_bytes);
+ __ addptr(qword_count, 4);
+ __ jcc(Assembler::lessEqual, L_loop);
}
- __ BIND(L_copy_32_bytes);
- __ addptr(qword_count, 4);
- __ jcc(Assembler::lessEqual, L_loop);
__ subptr(qword_count, 4);
__ jcc(Assembler::less, L_copy_8_bytes); // Copy trailing qwords
}
-
// Copy big chunks backward
//
// Inputs:
@@ -1338,23 +1358,55 @@
// dest - destination array address
// qword_count - 64-bits element count
// to - scratch
- // L_copy_32_bytes - entry label
+ // L_copy_bytes - entry label
// L_copy_8_bytes - exit label
//
- void copy_32_bytes_backward(Register from, Register dest,
+ void copy_bytes_backward(Register from, Register dest,
Register qword_count, Register to,
- Label& L_copy_32_bytes, Label& L_copy_8_bytes) {
+ Label& L_copy_bytes, Label& L_copy_8_bytes) {
DEBUG_ONLY(__ stop("enter at entry label, not here"));
Label L_loop;
__ align(OptoLoopAlignment);
- __ BIND(L_loop);
- if(UseUnalignedLoadStores) {
- __ movdqu(xmm0, Address(from, qword_count, Address::times_8, 16));
- __ movdqu(Address(dest, qword_count, Address::times_8, 16), xmm0);
- __ movdqu(xmm1, Address(from, qword_count, Address::times_8, 0));
- __ movdqu(Address(dest, qword_count, Address::times_8, 0), xmm1);
-
+ if (UseUnalignedLoadStores) {
+ Label L_end;
+ // Copy 64-bytes per iteration
+ __ BIND(L_loop);
+ if (UseAVX >= 2) {
+ __ vmovdqu(xmm0, Address(from, qword_count, Address::times_8, 32));
+ __ vmovdqu(Address(dest, qword_count, Address::times_8, 32), xmm0);
+ __ vmovdqu(xmm1, Address(from, qword_count, Address::times_8, 0));
+ __ vmovdqu(Address(dest, qword_count, Address::times_8, 0), xmm1);
+ } else {
+ __ movdqu(xmm0, Address(from, qword_count, Address::times_8, 48));
+ __ movdqu(Address(dest, qword_count, Address::times_8, 48), xmm0);
+ __ movdqu(xmm1, Address(from, qword_count, Address::times_8, 32));
+ __ movdqu(Address(dest, qword_count, Address::times_8, 32), xmm1);
+ __ movdqu(xmm2, Address(from, qword_count, Address::times_8, 16));
+ __ movdqu(Address(dest, qword_count, Address::times_8, 16), xmm2);
+ __ movdqu(xmm3, Address(from, qword_count, Address::times_8, 0));
+ __ movdqu(Address(dest, qword_count, Address::times_8, 0), xmm3);
+ }
+ __ BIND(L_copy_bytes);
+ __ subptr(qword_count, 8);
+ __ jcc(Assembler::greaterEqual, L_loop);
+
+ __ addptr(qword_count, 4); // add(8) and sub(4)
+ __ jccb(Assembler::less, L_end);
+ // Copy trailing 32 bytes
+ if (UseAVX >= 2) {
+ __ vmovdqu(xmm0, Address(from, qword_count, Address::times_8, 0));
+ __ vmovdqu(Address(dest, qword_count, Address::times_8, 0), xmm0);
+ } else {
+ __ movdqu(xmm0, Address(from, qword_count, Address::times_8, 16));
+ __ movdqu(Address(dest, qword_count, Address::times_8, 16), xmm0);
+ __ movdqu(xmm1, Address(from, qword_count, Address::times_8, 0));
+ __ movdqu(Address(dest, qword_count, Address::times_8, 0), xmm1);
+ }
+ __ subptr(qword_count, 4);
+ __ BIND(L_end);
} else {
+ // Copy 32-bytes per iteration
+ __ BIND(L_loop);
__ movq(to, Address(from, qword_count, Address::times_8, 24));
__ movq(Address(dest, qword_count, Address::times_8, 24), to);
__ movq(to, Address(from, qword_count, Address::times_8, 16));
@@ -1363,10 +1415,11 @@
__ movq(Address(dest, qword_count, Address::times_8, 8), to);
__ movq(to, Address(from, qword_count, Address::times_8, 0));
__ movq(Address(dest, qword_count, Address::times_8, 0), to);
+
+ __ BIND(L_copy_bytes);
+ __ subptr(qword_count, 4);
+ __ jcc(Assembler::greaterEqual, L_loop);
}
- __ BIND(L_copy_32_bytes);
- __ subptr(qword_count, 4);
- __ jcc(Assembler::greaterEqual, L_loop);
__ addptr(qword_count, 4);
__ jcc(Assembler::greater, L_copy_8_bytes); // Copy trailing qwords
}
@@ -1396,7 +1449,7 @@
StubCodeMark mark(this, "StubRoutines", name);
address start = __ pc();
- Label L_copy_32_bytes, L_copy_8_bytes, L_copy_4_bytes, L_copy_2_bytes;
+ Label L_copy_bytes, L_copy_8_bytes, L_copy_4_bytes, L_copy_2_bytes;
Label L_copy_byte, L_exit;
const Register from = rdi; // source array address
const Register to = rsi; // destination array address
@@ -1428,7 +1481,7 @@
__ lea(end_from, Address(from, qword_count, Address::times_8, -8));
__ lea(end_to, Address(to, qword_count, Address::times_8, -8));
__ negptr(qword_count); // make the count negative
- __ jmp(L_copy_32_bytes);
+ __ jmp(L_copy_bytes);
// Copy trailing qwords
__ BIND(L_copy_8_bytes);
@@ -1471,8 +1524,8 @@
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
- // Copy in 32-bytes chunks
- copy_32_bytes_forward(end_from, end_to, qword_count, rax, L_copy_32_bytes, L_copy_8_bytes);
+ // Copy in multi-bytes chunks
+ copy_bytes_forward(end_from, end_to, qword_count, rax, L_copy_bytes, L_copy_8_bytes);
__ jmp(L_copy_4_bytes);
return start;
@@ -1499,7 +1552,7 @@
StubCodeMark mark(this, "StubRoutines", name);
address start = __ pc();
- Label L_copy_32_bytes, L_copy_8_bytes, L_copy_4_bytes, L_copy_2_bytes;
+ Label L_copy_bytes, L_copy_8_bytes, L_copy_4_bytes, L_copy_2_bytes;
const Register from = rdi; // source array address
const Register to = rsi; // destination array address
const Register count = rdx; // elements count
@@ -1542,10 +1595,10 @@
// Check for and copy trailing dword
__ BIND(L_copy_4_bytes);
__ testl(byte_count, 4);
- __ jcc(Assembler::zero, L_copy_32_bytes);
+ __ jcc(Assembler::zero, L_copy_bytes);
__ movl(rax, Address(from, qword_count, Address::times_8));
__ movl(Address(to, qword_count, Address::times_8), rax);
- __ jmp(L_copy_32_bytes);
+ __ jmp(L_copy_bytes);
// Copy trailing qwords
__ BIND(L_copy_8_bytes);
@@ -1560,8 +1613,8 @@
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
- // Copy in 32-bytes chunks
- copy_32_bytes_backward(from, to, qword_count, rax, L_copy_32_bytes, L_copy_8_bytes);
+ // Copy in multi-bytes chunks
+ copy_bytes_backward(from, to, qword_count, rax, L_copy_bytes, L_copy_8_bytes);
restore_arg_regs();
inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr); // Update counter after rscratch1 is free
@@ -1596,7 +1649,7 @@
StubCodeMark mark(this, "StubRoutines", name);
address start = __ pc();
- Label L_copy_32_bytes, L_copy_8_bytes, L_copy_4_bytes,L_copy_2_bytes,L_exit;
+ Label L_copy_bytes, L_copy_8_bytes, L_copy_4_bytes,L_copy_2_bytes,L_exit;
const Register from = rdi; // source array address
const Register to = rsi; // destination array address
const Register count = rdx; // elements count
@@ -1627,7 +1680,7 @@
__ lea(end_from, Address(from, qword_count, Address::times_8, -8));
__ lea(end_to, Address(to, qword_count, Address::times_8, -8));
__ negptr(qword_count);
- __ jmp(L_copy_32_bytes);
+ __ jmp(L_copy_bytes);
// Copy trailing qwords
__ BIND(L_copy_8_bytes);
@@ -1663,8 +1716,8 @@
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
- // Copy in 32-bytes chunks
- copy_32_bytes_forward(end_from, end_to, qword_count, rax, L_copy_32_bytes, L_copy_8_bytes);
+ // Copy in multi-bytes chunks
+ copy_bytes_forward(end_from, end_to, qword_count, rax, L_copy_bytes, L_copy_8_bytes);
__ jmp(L_copy_4_bytes);
return start;
@@ -1711,7 +1764,7 @@
StubCodeMark mark(this, "StubRoutines", name);
address start = __ pc();
- Label L_copy_32_bytes, L_copy_8_bytes, L_copy_4_bytes;
+ Label L_copy_bytes, L_copy_8_bytes, L_copy_4_bytes;
const Register from = rdi; // source array address
const Register to = rsi; // destination array address
const Register count = rdx; // elements count
@@ -1746,10 +1799,10 @@
// Check for and copy trailing dword
__ BIND(L_copy_4_bytes);
__ testl(word_count, 2);
- __ jcc(Assembler::zero, L_copy_32_bytes);
+ __ jcc(Assembler::zero, L_copy_bytes);
__ movl(rax, Address(from, qword_count, Address::times_8));
__ movl(Address(to, qword_count, Address::times_8), rax);
- __ jmp(L_copy_32_bytes);
+ __ jmp(L_copy_bytes);
// Copy trailing qwords
__ BIND(L_copy_8_bytes);
@@ -1764,8 +1817,8 @@
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
- // Copy in 32-bytes chunks
- copy_32_bytes_backward(from, to, qword_count, rax, L_copy_32_bytes, L_copy_8_bytes);
+ // Copy in multi-bytes chunks
+ copy_bytes_backward(from, to, qword_count, rax, L_copy_bytes, L_copy_8_bytes);
restore_arg_regs();
inc_counter_np(SharedRuntime::_jshort_array_copy_ctr); // Update counter after rscratch1 is free
@@ -1801,7 +1854,7 @@
StubCodeMark mark(this, "StubRoutines", name);
address start = __ pc();
- Label L_copy_32_bytes, L_copy_8_bytes, L_copy_4_bytes, L_exit;
+ Label L_copy_bytes, L_copy_8_bytes, L_copy_4_bytes, L_exit;
const Register from = rdi; // source array address
const Register to = rsi; // destination array address
const Register count = rdx; // elements count
@@ -1837,7 +1890,7 @@
__ lea(end_from, Address(from, qword_count, Address::times_8, -8));
__ lea(end_to, Address(to, qword_count, Address::times_8, -8));
__ negptr(qword_count);
- __ jmp(L_copy_32_bytes);
+ __ jmp(L_copy_bytes);
// Copy trailing qwords
__ BIND(L_copy_8_bytes);
@@ -1864,8 +1917,8 @@
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
- // Copy 32-bytes chunks
- copy_32_bytes_forward(end_from, end_to, qword_count, rax, L_copy_32_bytes, L_copy_8_bytes);
+ // Copy in multi-bytes chunks
+ copy_bytes_forward(end_from, end_to, qword_count, rax, L_copy_bytes, L_copy_8_bytes);
__ jmp(L_copy_4_bytes);
return start;
@@ -1893,7 +1946,7 @@
StubCodeMark mark(this, "StubRoutines", name);
address start = __ pc();
- Label L_copy_32_bytes, L_copy_8_bytes, L_copy_2_bytes, L_exit;
+ Label L_copy_bytes, L_copy_8_bytes, L_copy_2_bytes, L_exit;
const Register from = rdi; // source array address
const Register to = rsi; // destination array address
const Register count = rdx; // elements count
@@ -1927,10 +1980,10 @@
// Check for and copy trailing dword
__ testl(dword_count, 1);
- __ jcc(Assembler::zero, L_copy_32_bytes);
+ __ jcc(Assembler::zero, L_copy_bytes);
__ movl(rax, Address(from, dword_count, Address::times_4, -4));
__ movl(Address(to, dword_count, Address::times_4, -4), rax);
- __ jmp(L_copy_32_bytes);
+ __ jmp(L_copy_bytes);
// Copy trailing qwords
__ BIND(L_copy_8_bytes);
@@ -1948,8 +2001,8 @@
__ leave(); // required for proper stackwalking of RuntimeStub frame
__ ret(0);
- // Copy in 32-bytes chunks
- copy_32_bytes_backward(from, to, qword_count, rax, L_copy_32_bytes, L_copy_8_bytes);
+ // Copy in multi-bytes chunks
+ copy_bytes_backward(from, to, qword_count, rax, L_copy_bytes, L_copy_8_bytes);
__ bind(L_exit);
if (is_oop) {
@@ -1987,7 +2040,7 @@
StubCodeMark mark(this, "StubRoutines", name);
address start = __ pc();
- Label L_copy_32_bytes, L_copy_8_bytes, L_exit;
+ Label L_copy_bytes, L_copy_8_bytes, L_exit;
const Register from = rdi; // source array address
const Register to = rsi; // destination array address
const Register qword_count = rdx; // elements count
@@ -2019,7 +2072,7 @@
__ lea(end_from, Address(from, qword_count, Address::times_8, -8));
__ lea(end_to, Address(to, qword_count, Address::times_8, -8));
__ negptr(qword_count);
- __ jmp(L_copy_32_bytes);
+ __ jmp(L_copy_bytes);
// Copy trailing qwords
__ BIND(L_copy_8_bytes);
@@ -2038,8 +2091,8 @@
__ ret(0);
}
- // Copy 64-byte chunks
- copy_32_bytes_forward(end_from, end_to, qword_count, rax, L_copy_32_bytes, L_copy_8_bytes);
+ // Copy in multi-bytes chunks
+ copy_bytes_forward(end_from, end_to, qword_count, rax, L_copy_bytes, L_copy_8_bytes);
if (is_oop) {
__ BIND(L_exit);
@@ -2076,7 +2129,7 @@
StubCodeMark mark(this, "StubRoutines", name);
address start = __ pc();
- Label L_copy_32_bytes, L_copy_8_bytes, L_exit;
+ Label L_copy_bytes, L_copy_8_bytes, L_exit;
const Register from = rdi; // source array address
const Register to = rsi; // destination array address
const Register qword_count = rdx; // elements count
@@ -2102,7 +2155,7 @@
gen_write_ref_array_pre_barrier(to, saved_count, dest_uninitialized);
}
- __ jmp(L_copy_32_bytes);
+ __ jmp(L_copy_bytes);
// Copy trailing qwords
__ BIND(L_copy_8_bytes);
@@ -2121,8 +2174,8 @@
__ ret(0);
}
- // Copy in 32-bytes chunks
- copy_32_bytes_backward(from, to, qword_count, rax, L_copy_32_bytes, L_copy_8_bytes);
+ // Copy in multi-bytes chunks
+ copy_bytes_backward(from, to, qword_count, rax, L_copy_bytes, L_copy_8_bytes);
if (is_oop) {
__ BIND(L_exit);
@@ -2941,6 +2994,596 @@
}
}
+ // AES intrinsic stubs
+ enum {AESBlockSize = 16};
+
+ address generate_key_shuffle_mask() {
+ __ align(16);
+ StubCodeMark mark(this, "StubRoutines", "key_shuffle_mask");
+ address start = __ pc();
+ __ emit_data64( 0x0405060700010203, relocInfo::none );
+ __ emit_data64( 0x0c0d0e0f08090a0b, relocInfo::none );
+ return start;
+ }
+
+ // Utility routine for loading a 128-bit key word in little endian format
+ // can optionally specify that the shuffle mask is already in an xmmregister
+ void load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask=NULL) {
+ __ movdqu(xmmdst, Address(key, offset));
+ if (xmm_shuf_mask != NULL) {
+ __ pshufb(xmmdst, xmm_shuf_mask);
+ } else {
+ __ pshufb(xmmdst, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()));
+ }
+ }
+
+ // Arguments:
+ //
+ // Inputs:
+ // c_rarg0 - source byte array address
+ // c_rarg1 - destination byte array address
+ // c_rarg2 - K (key) in little endian int array
+ //
+ address generate_aescrypt_encryptBlock() {
+ assert(UseAES, "need AES instructions and misaligned SSE support");
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "aescrypt_encryptBlock");
+ Label L_doLast;
+ address start = __ pc();
+
+ const Register from = c_rarg0; // source array address
+ const Register to = c_rarg1; // destination array address
+ const Register key = c_rarg2; // key array address
+ const Register keylen = rax;
+
+ const XMMRegister xmm_result = xmm0;
+ const XMMRegister xmm_key_shuf_mask = xmm1;
+ // On win64 xmm6-xmm15 must be preserved so don't use them.
+ const XMMRegister xmm_temp1 = xmm2;
+ const XMMRegister xmm_temp2 = xmm3;
+ const XMMRegister xmm_temp3 = xmm4;
+ const XMMRegister xmm_temp4 = xmm5;
+
+ __ enter(); // required for proper stackwalking of RuntimeStub frame
+
+ // keylen could be only {11, 13, 15} * 4 = {44, 52, 60}
+ __ movl(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
+
+ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()));
+ __ movdqu(xmm_result, Address(from, 0)); // get 16 bytes of input
+
+ // For encryption, the java expanded key ordering is just what we need
+ // we don't know if the key is aligned, hence not using load-execute form
+
+ load_key(xmm_temp1, key, 0x00, xmm_key_shuf_mask);
+ __ pxor(xmm_result, xmm_temp1);
+
+ load_key(xmm_temp1, key, 0x10, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0x20, xmm_key_shuf_mask);
+ load_key(xmm_temp3, key, 0x30, xmm_key_shuf_mask);
+ load_key(xmm_temp4, key, 0x40, xmm_key_shuf_mask);
+
+ __ aesenc(xmm_result, xmm_temp1);
+ __ aesenc(xmm_result, xmm_temp2);
+ __ aesenc(xmm_result, xmm_temp3);
+ __ aesenc(xmm_result, xmm_temp4);
+
+ load_key(xmm_temp1, key, 0x50, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0x60, xmm_key_shuf_mask);
+ load_key(xmm_temp3, key, 0x70, xmm_key_shuf_mask);
+ load_key(xmm_temp4, key, 0x80, xmm_key_shuf_mask);
+
+ __ aesenc(xmm_result, xmm_temp1);
+ __ aesenc(xmm_result, xmm_temp2);
+ __ aesenc(xmm_result, xmm_temp3);
+ __ aesenc(xmm_result, xmm_temp4);
+
+ load_key(xmm_temp1, key, 0x90, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0xa0, xmm_key_shuf_mask);
+
+ __ cmpl(keylen, 44);
+ __ jccb(Assembler::equal, L_doLast);
+
+ __ aesenc(xmm_result, xmm_temp1);
+ __ aesenc(xmm_result, xmm_temp2);
+
+ load_key(xmm_temp1, key, 0xb0, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0xc0, xmm_key_shuf_mask);
+
+ __ cmpl(keylen, 52);
+ __ jccb(Assembler::equal, L_doLast);
+
+ __ aesenc(xmm_result, xmm_temp1);
+ __ aesenc(xmm_result, xmm_temp2);
+
+ load_key(xmm_temp1, key, 0xd0, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0xe0, xmm_key_shuf_mask);
+
+ __ BIND(L_doLast);
+ __ aesenc(xmm_result, xmm_temp1);
+ __ aesenclast(xmm_result, xmm_temp2);
+ __ movdqu(Address(to, 0), xmm_result); // store the result
+ __ xorptr(rax, rax); // return 0
+ __ leave(); // required for proper stackwalking of RuntimeStub frame
+ __ ret(0);
+
+ return start;
+ }
+
+
+ // Arguments:
+ //
+ // Inputs:
+ // c_rarg0 - source byte array address
+ // c_rarg1 - destination byte array address
+ // c_rarg2 - K (key) in little endian int array
+ //
+ address generate_aescrypt_decryptBlock() {
+ assert(UseAES, "need AES instructions and misaligned SSE support");
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "aescrypt_decryptBlock");
+ Label L_doLast;
+ address start = __ pc();
+
+ const Register from = c_rarg0; // source array address
+ const Register to = c_rarg1; // destination array address
+ const Register key = c_rarg2; // key array address
+ const Register keylen = rax;
+
+ const XMMRegister xmm_result = xmm0;
+ const XMMRegister xmm_key_shuf_mask = xmm1;
+ // On win64 xmm6-xmm15 must be preserved so don't use them.
+ const XMMRegister xmm_temp1 = xmm2;
+ const XMMRegister xmm_temp2 = xmm3;
+ const XMMRegister xmm_temp3 = xmm4;
+ const XMMRegister xmm_temp4 = xmm5;
+
+ __ enter(); // required for proper stackwalking of RuntimeStub frame
+
+ // keylen could be only {11, 13, 15} * 4 = {44, 52, 60}
+ __ movl(keylen, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
+
+ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()));
+ __ movdqu(xmm_result, Address(from, 0));
+
+ // for decryption java expanded key ordering is rotated one position from what we want
+ // so we start from 0x10 here and hit 0x00 last
+ // we don't know if the key is aligned, hence not using load-execute form
+ load_key(xmm_temp1, key, 0x10, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0x20, xmm_key_shuf_mask);
+ load_key(xmm_temp3, key, 0x30, xmm_key_shuf_mask);
+ load_key(xmm_temp4, key, 0x40, xmm_key_shuf_mask);
+
+ __ pxor (xmm_result, xmm_temp1);
+ __ aesdec(xmm_result, xmm_temp2);
+ __ aesdec(xmm_result, xmm_temp3);
+ __ aesdec(xmm_result, xmm_temp4);
+
+ load_key(xmm_temp1, key, 0x50, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0x60, xmm_key_shuf_mask);
+ load_key(xmm_temp3, key, 0x70, xmm_key_shuf_mask);
+ load_key(xmm_temp4, key, 0x80, xmm_key_shuf_mask);
+
+ __ aesdec(xmm_result, xmm_temp1);
+ __ aesdec(xmm_result, xmm_temp2);
+ __ aesdec(xmm_result, xmm_temp3);
+ __ aesdec(xmm_result, xmm_temp4);
+
+ load_key(xmm_temp1, key, 0x90, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0xa0, xmm_key_shuf_mask);
+ load_key(xmm_temp3, key, 0x00, xmm_key_shuf_mask);
+
+ __ cmpl(keylen, 44);
+ __ jccb(Assembler::equal, L_doLast);
+
+ __ aesdec(xmm_result, xmm_temp1);
+ __ aesdec(xmm_result, xmm_temp2);
+
+ load_key(xmm_temp1, key, 0xb0, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0xc0, xmm_key_shuf_mask);
+
+ __ cmpl(keylen, 52);
+ __ jccb(Assembler::equal, L_doLast);
+
+ __ aesdec(xmm_result, xmm_temp1);
+ __ aesdec(xmm_result, xmm_temp2);
+
+ load_key(xmm_temp1, key, 0xd0, xmm_key_shuf_mask);
+ load_key(xmm_temp2, key, 0xe0, xmm_key_shuf_mask);
+
+ __ BIND(L_doLast);
+ __ aesdec(xmm_result, xmm_temp1);
+ __ aesdec(xmm_result, xmm_temp2);
+
+ // for decryption the aesdeclast operation is always on key+0x00
+ __ aesdeclast(xmm_result, xmm_temp3);
+ __ movdqu(Address(to, 0), xmm_result); // store the result
+ __ xorptr(rax, rax); // return 0
+ __ leave(); // required for proper stackwalking of RuntimeStub frame
+ __ ret(0);
+
+ return start;
+ }
+
+
+ // Arguments:
+ //
+ // Inputs:
+ // c_rarg0 - source byte array address
+ // c_rarg1 - destination byte array address
+ // c_rarg2 - K (key) in little endian int array
+ // c_rarg3 - r vector byte array address
+ // c_rarg4 - input length
+ //
+ address generate_cipherBlockChaining_encryptAESCrypt() {
+ assert(UseAES, "need AES instructions and misaligned SSE support");
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_encryptAESCrypt");
+ address start = __ pc();
+
+ Label L_exit, L_key_192_256, L_key_256, L_loopTop_128, L_loopTop_192, L_loopTop_256;
+ const Register from = c_rarg0; // source array address
+ const Register to = c_rarg1; // destination array address
+ const Register key = c_rarg2; // key array address
+ const Register rvec = c_rarg3; // r byte array initialized from initvector array address
+ // and left with the results of the last encryption block
+#ifndef _WIN64
+ const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16)
+#else
+ const Address len_mem(rsp, 6 * wordSize); // length is on stack on Win64
+ const Register len_reg = r10; // pick the first volatile windows register
+#endif
+ const Register pos = rax;
+
+ // xmm register assignments for the loops below
+ const XMMRegister xmm_result = xmm0;
+ const XMMRegister xmm_temp = xmm1;
+ // keys 0-10 preloaded into xmm2-xmm12
+ const int XMM_REG_NUM_KEY_FIRST = 2;
+ const int XMM_REG_NUM_KEY_LAST = 15;
+ const XMMRegister xmm_key0 = as_XMMRegister(XMM_REG_NUM_KEY_FIRST);
+ const XMMRegister xmm_key10 = as_XMMRegister(XMM_REG_NUM_KEY_FIRST+10);
+ const XMMRegister xmm_key11 = as_XMMRegister(XMM_REG_NUM_KEY_FIRST+11);
+ const XMMRegister xmm_key12 = as_XMMRegister(XMM_REG_NUM_KEY_FIRST+12);
+ const XMMRegister xmm_key13 = as_XMMRegister(XMM_REG_NUM_KEY_FIRST+13);
+
+ __ enter(); // required for proper stackwalking of RuntimeStub frame
+
+#ifdef _WIN64
+ // on win64, fill len_reg from stack position
+ __ movl(len_reg, len_mem);
+ // save the xmm registers which must be preserved 6-15
+ __ subptr(rsp, -rsp_after_call_off * wordSize);
+ for (int i = 6; i <= XMM_REG_NUM_KEY_LAST; i++) {
+ __ movdqu(xmm_save(i), as_XMMRegister(i));
+ }
+#endif
+
+ const XMMRegister xmm_key_shuf_mask = xmm_temp; // used temporarily to swap key bytes up front
+ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()));
+ // load up xmm regs xmm2 thru xmm12 with key 0x00 - 0xa0
+ for (int rnum = XMM_REG_NUM_KEY_FIRST, offset = 0x00; rnum <= XMM_REG_NUM_KEY_FIRST+10; rnum++) {
+ load_key(as_XMMRegister(rnum), key, offset, xmm_key_shuf_mask);
+ offset += 0x10;
+ }
+ __ movdqu(xmm_result, Address(rvec, 0x00)); // initialize xmm_result with r vec
+
+ // now split to different paths depending on the keylen (len in ints of AESCrypt.KLE array (52=192, or 60=256))
+ __ movl(rax, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
+ __ cmpl(rax, 44);
+ __ jcc(Assembler::notEqual, L_key_192_256);
+
+ // 128 bit code follows here
+ __ movptr(pos, 0);
+ __ align(OptoLoopAlignment);
+
+ __ BIND(L_loopTop_128);
+ __ movdqu(xmm_temp, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of input
+ __ pxor (xmm_result, xmm_temp); // xor with the current r vector
+ __ pxor (xmm_result, xmm_key0); // do the aes rounds
+ for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_FIRST + 9; rnum++) {
+ __ aesenc(xmm_result, as_XMMRegister(rnum));
+ }
+ __ aesenclast(xmm_result, xmm_key10);
+ __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output
+ // no need to store r to memory until we exit
+ __ addptr(pos, AESBlockSize);
+ __ subptr(len_reg, AESBlockSize);
+ __ jcc(Assembler::notEqual, L_loopTop_128);
+
+ __ BIND(L_exit);
+ __ movdqu(Address(rvec, 0), xmm_result); // final value of r stored in rvec of CipherBlockChaining object
+
+#ifdef _WIN64
+ // restore xmm regs belonging to calling function
+ for (int i = 6; i <= XMM_REG_NUM_KEY_LAST; i++) {
+ __ movdqu(as_XMMRegister(i), xmm_save(i));
+ }
+#endif
+ __ movl(rax, 0); // return 0 (why?)
+ __ leave(); // required for proper stackwalking of RuntimeStub frame
+ __ ret(0);
+
+ __ BIND(L_key_192_256);
+ // here rax = len in ints of AESCrypt.KLE array (52=192, or 60=256)
+ load_key(xmm_key11, key, 0xb0, xmm_key_shuf_mask);
+ load_key(xmm_key12, key, 0xc0, xmm_key_shuf_mask);
+ __ cmpl(rax, 52);
+ __ jcc(Assembler::notEqual, L_key_256);
+
+ // 192-bit code follows here (could be changed to use more xmm registers)
+ __ movptr(pos, 0);
+ __ align(OptoLoopAlignment);
+
+ __ BIND(L_loopTop_192);
+ __ movdqu(xmm_temp, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of input
+ __ pxor (xmm_result, xmm_temp); // xor with the current r vector
+ __ pxor (xmm_result, xmm_key0); // do the aes rounds
+ for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_FIRST + 11; rnum++) {
+ __ aesenc(xmm_result, as_XMMRegister(rnum));
+ }
+ __ aesenclast(xmm_result, xmm_key12);
+ __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output
+ // no need to store r to memory until we exit
+ __ addptr(pos, AESBlockSize);
+ __ subptr(len_reg, AESBlockSize);
+ __ jcc(Assembler::notEqual, L_loopTop_192);
+ __ jmp(L_exit);
+
+ __ BIND(L_key_256);
+ // 256-bit code follows here (could be changed to use more xmm registers)
+ load_key(xmm_key13, key, 0xd0, xmm_key_shuf_mask);
+ __ movptr(pos, 0);
+ __ align(OptoLoopAlignment);
+
+ __ BIND(L_loopTop_256);
+ __ movdqu(xmm_temp, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of input
+ __ pxor (xmm_result, xmm_temp); // xor with the current r vector
+ __ pxor (xmm_result, xmm_key0); // do the aes rounds
+ for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_FIRST + 13; rnum++) {
+ __ aesenc(xmm_result, as_XMMRegister(rnum));
+ }
+ load_key(xmm_temp, key, 0xe0);
+ __ aesenclast(xmm_result, xmm_temp);
+ __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output
+ // no need to store r to memory until we exit
+ __ addptr(pos, AESBlockSize);
+ __ subptr(len_reg, AESBlockSize);
+ __ jcc(Assembler::notEqual, L_loopTop_256);
+ __ jmp(L_exit);
+
+ return start;
+ }
+
+
+
+ // This is a version of CBC/AES Decrypt which does 4 blocks in a loop at a time
+ // to hide instruction latency
+ //
+ // Arguments:
+ //
+ // Inputs:
+ // c_rarg0 - source byte array address
+ // c_rarg1 - destination byte array address
+ // c_rarg2 - K (key) in little endian int array
+ // c_rarg3 - r vector byte array address
+ // c_rarg4 - input length
+ //
+
+ address generate_cipherBlockChaining_decryptAESCrypt_Parallel() {
+ assert(UseAES, "need AES instructions and misaligned SSE support");
+ __ align(CodeEntryAlignment);
+ StubCodeMark mark(this, "StubRoutines", "cipherBlockChaining_decryptAESCrypt");
+ address start = __ pc();
+
+ Label L_exit, L_key_192_256, L_key_256;
+ Label L_singleBlock_loopTop_128, L_multiBlock_loopTop_128;
+ Label L_singleBlock_loopTop_192, L_singleBlock_loopTop_256;
+ const Register from = c_rarg0; // source array address
+ const Register to = c_rarg1; // destination array address
+ const Register key = c_rarg2; // key array address
+ const Register rvec = c_rarg3; // r byte array initialized from initvector array address
+ // and left with the results of the last encryption block
+#ifndef _WIN64
+ const Register len_reg = c_rarg4; // src len (must be multiple of blocksize 16)
+#else
+ const Address len_mem(rsp, 6 * wordSize); // length is on stack on Win64
+ const Register len_reg = r10; // pick the first volatile windows register
+#endif
+ const Register pos = rax;
+
+ // keys 0-10 preloaded into xmm2-xmm12
+ const int XMM_REG_NUM_KEY_FIRST = 5;
+ const int XMM_REG_NUM_KEY_LAST = 15;
+ const XMMRegister xmm_key_first = as_XMMRegister(XMM_REG_NUM_KEY_FIRST);
+ const XMMRegister xmm_key_last = as_XMMRegister(XMM_REG_NUM_KEY_LAST);
+
+ __ enter(); // required for proper stackwalking of RuntimeStub frame
+
+#ifdef _WIN64
+ // on win64, fill len_reg from stack position
+ __ movl(len_reg, len_mem);
+ // save the xmm registers which must be preserved 6-15
+ __ subptr(rsp, -rsp_after_call_off * wordSize);
+ for (int i = 6; i <= XMM_REG_NUM_KEY_LAST; i++) {
+ __ movdqu(xmm_save(i), as_XMMRegister(i));
+ }
+#endif
+ // the java expanded key ordering is rotated one position from what we want
+ // so we start from 0x10 here and hit 0x00 last
+ const XMMRegister xmm_key_shuf_mask = xmm1; // used temporarily to swap key bytes up front
+ __ movdqu(xmm_key_shuf_mask, ExternalAddress(StubRoutines::x86::key_shuffle_mask_addr()));
+ // load up xmm regs 5 thru 15 with key 0x10 - 0xa0 - 0x00
+ for (int rnum = XMM_REG_NUM_KEY_FIRST, offset = 0x10; rnum < XMM_REG_NUM_KEY_LAST; rnum++) {
+ load_key(as_XMMRegister(rnum), key, offset, xmm_key_shuf_mask);
+ offset += 0x10;
+ }
+ load_key(xmm_key_last, key, 0x00, xmm_key_shuf_mask);
+
+ const XMMRegister xmm_prev_block_cipher = xmm1; // holds cipher of previous block
+
+ // registers holding the four results in the parallelized loop
+ const XMMRegister xmm_result0 = xmm0;
+ const XMMRegister xmm_result1 = xmm2;
+ const XMMRegister xmm_result2 = xmm3;
+ const XMMRegister xmm_result3 = xmm4;
+
+ __ movdqu(xmm_prev_block_cipher, Address(rvec, 0x00)); // initialize with initial rvec
+
+ // now split to different paths depending on the keylen (len in ints of AESCrypt.KLE array (52=192, or 60=256))
+ __ movl(rax, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT)));
+ __ cmpl(rax, 44);
+ __ jcc(Assembler::notEqual, L_key_192_256);
+
+
+ // 128-bit code follows here, parallelized
+ __ movptr(pos, 0);
+ __ align(OptoLoopAlignment);
+ __ BIND(L_multiBlock_loopTop_128);
+ __ cmpptr(len_reg, 4*AESBlockSize); // see if at least 4 blocks left
+ __ jcc(Assembler::less, L_singleBlock_loopTop_128);
+
+ __ movdqu(xmm_result0, Address(from, pos, Address::times_1, 0*AESBlockSize)); // get next 4 blocks into xmmresult registers
+ __ movdqu(xmm_result1, Address(from, pos, Address::times_1, 1*AESBlockSize));
+ __ movdqu(xmm_result2, Address(from, pos, Address::times_1, 2*AESBlockSize));
+ __ movdqu(xmm_result3, Address(from, pos, Address::times_1, 3*AESBlockSize));
+
+#define DoFour(opc, src_reg) \
+ __ opc(xmm_result0, src_reg); \
+ __ opc(xmm_result1, src_reg); \
+ __ opc(xmm_result2, src_reg); \
+ __ opc(xmm_result3, src_reg);
+
+ DoFour(pxor, xmm_key_first);
+ for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST - 1; rnum++) {
+ DoFour(aesdec, as_XMMRegister(rnum));
+ }
+ DoFour(aesdeclast, xmm_key_last);
+ // for each result, xor with the r vector of previous cipher block
+ __ pxor(xmm_result0, xmm_prev_block_cipher);
+ __ movdqu(xmm_prev_block_cipher, Address(from, pos, Address::times_1, 0*AESBlockSize));
+ __ pxor(xmm_result1, xmm_prev_block_cipher);
+ __ movdqu(xmm_prev_block_cipher, Address(from, pos, Address::times_1, 1*AESBlockSize));
+ __ pxor(xmm_result2, xmm_prev_block_cipher);
+ __ movdqu(xmm_prev_block_cipher, Address(from, pos, Address::times_1, 2*AESBlockSize));
+ __ pxor(xmm_result3, xmm_prev_block_cipher);
+ __ movdqu(xmm_prev_block_cipher, Address(from, pos, Address::times_1, 3*AESBlockSize)); // this will carry over to next set of blocks
+
+ __ movdqu(Address(to, pos, Address::times_1, 0*AESBlockSize), xmm_result0); // store 4 results into the next 64 bytes of output
+ __ movdqu(Address(to, pos, Address::times_1, 1*AESBlockSize), xmm_result1);
+ __ movdqu(Address(to, pos, Address::times_1, 2*AESBlockSize), xmm_result2);
+ __ movdqu(Address(to, pos, Address::times_1, 3*AESBlockSize), xmm_result3);
+
+ __ addptr(pos, 4*AESBlockSize);
+ __ subptr(len_reg, 4*AESBlockSize);
+ __ jmp(L_multiBlock_loopTop_128);
+
+ // registers used in the non-parallelized loops
+ // xmm register assignments for the loops below
+ const XMMRegister xmm_result = xmm0;
+ const XMMRegister xmm_prev_block_cipher_save = xmm2;
+ const XMMRegister xmm_key11 = xmm3;
+ const XMMRegister xmm_key12 = xmm4;
+ const XMMRegister xmm_temp = xmm4;
+
+ __ align(OptoLoopAlignment);
+ __ BIND(L_singleBlock_loopTop_128);
+ __ cmpptr(len_reg, 0); // any blocks left??
+ __ jcc(Assembler::equal, L_exit);
+ __ movdqu(xmm_result, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of cipher input
+ __ movdqa(xmm_prev_block_cipher_save, xmm_result); // save for next r vector
+ __ pxor (xmm_result, xmm_key_first); // do the aes dec rounds
+ for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST - 1; rnum++) {
+ __ aesdec(xmm_result, as_XMMRegister(rnum));
+ }
+ __ aesdeclast(xmm_result, xmm_key_last);
+ __ pxor (xmm_result, xmm_prev_block_cipher); // xor with the current r vector
+ __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output
+ // no need to store r to memory until we exit
+ __ movdqa(xmm_prev_block_cipher, xmm_prev_block_cipher_save); // set up next r vector with cipher input from this block
+
+ __ addptr(pos, AESBlockSize);
+ __ subptr(len_reg, AESBlockSize);
+ __ jmp(L_singleBlock_loopTop_128);
+
+
+ __ BIND(L_exit);
+ __ movdqu(Address(rvec, 0), xmm_prev_block_cipher); // final value of r stored in rvec of CipherBlockChaining object
+#ifdef _WIN64
+ // restore regs belonging to calling function
+ for (int i = 6; i <= XMM_REG_NUM_KEY_LAST; i++) {
+ __ movdqu(as_XMMRegister(i), xmm_save(i));
+ }
+#endif
+ __ movl(rax, 0); // return 0 (why?)
+ __ leave(); // required for proper stackwalking of RuntimeStub frame
+ __ ret(0);
+
+
+ __ BIND(L_key_192_256);
+ // here rax = len in ints of AESCrypt.KLE array (52=192, or 60=256)
+ load_key(xmm_key11, key, 0xb0);
+ __ cmpl(rax, 52);
+ __ jcc(Assembler::notEqual, L_key_256);
+
+ // 192-bit code follows here (could be optimized to use parallelism)
+ load_key(xmm_key12, key, 0xc0); // 192-bit key goes up to c0
+ __ movptr(pos, 0);
+ __ align(OptoLoopAlignment);
+
+ __ BIND(L_singleBlock_loopTop_192);
+ __ movdqu(xmm_result, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of cipher input
+ __ movdqa(xmm_prev_block_cipher_save, xmm_result); // save for next r vector
+ __ pxor (xmm_result, xmm_key_first); // do the aes dec rounds
+ for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST - 1; rnum++) {
+ __ aesdec(xmm_result, as_XMMRegister(rnum));
+ }
+ __ aesdec(xmm_result, xmm_key11);
+ __ aesdec(xmm_result, xmm_key12);
+ __ aesdeclast(xmm_result, xmm_key_last); // xmm15 always came from key+0
+ __ pxor (xmm_result, xmm_prev_block_cipher); // xor with the current r vector
+ __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output
+ // no need to store r to memory until we exit
+ __ movdqa(xmm_prev_block_cipher, xmm_prev_block_cipher_save); // set up next r vector with cipher input from this block
+ __ addptr(pos, AESBlockSize);
+ __ subptr(len_reg, AESBlockSize);
+ __ jcc(Assembler::notEqual,L_singleBlock_loopTop_192);
+ __ jmp(L_exit);
+
+ __ BIND(L_key_256);
+ // 256-bit code follows here (could be optimized to use parallelism)
+ __ movptr(pos, 0);
+ __ align(OptoLoopAlignment);
+
+ __ BIND(L_singleBlock_loopTop_256);
+ __ movdqu(xmm_result, Address(from, pos, Address::times_1, 0)); // get next 16 bytes of cipher input
+ __ movdqa(xmm_prev_block_cipher_save, xmm_result); // save for next r vector
+ __ pxor (xmm_result, xmm_key_first); // do the aes dec rounds
+ for (int rnum = XMM_REG_NUM_KEY_FIRST + 1; rnum <= XMM_REG_NUM_KEY_LAST - 1; rnum++) {
+ __ aesdec(xmm_result, as_XMMRegister(rnum));
+ }
+ __ aesdec(xmm_result, xmm_key11);
+ load_key(xmm_temp, key, 0xc0);
+ __ aesdec(xmm_result, xmm_temp);
+ load_key(xmm_temp, key, 0xd0);
+ __ aesdec(xmm_result, xmm_temp);
+ load_key(xmm_temp, key, 0xe0); // 256-bit key goes up to e0
+ __ aesdec(xmm_result, xmm_temp);
+ __ aesdeclast(xmm_result, xmm_key_last); // xmm15 came from key+0
+ __ pxor (xmm_result, xmm_prev_block_cipher); // xor with the current r vector
+ __ movdqu(Address(to, pos, Address::times_1, 0), xmm_result); // store into the next 16 bytes of output
+ // no need to store r to memory until we exit
+ __ movdqa(xmm_prev_block_cipher, xmm_prev_block_cipher_save); // set up next r vector with cipher input from this block
+ __ addptr(pos, AESBlockSize);
+ __ subptr(len_reg, AESBlockSize);
+ __ jcc(Assembler::notEqual,L_singleBlock_loopTop_256);
+ __ jmp(L_exit);
+
+ return start;
+ }
+
+
+
#undef __
#define __ masm->
@@ -3135,6 +3778,16 @@
generate_arraycopy_stubs();
generate_math_stubs();
+
+ // don't bother generating these AES intrinsic stubs unless global flag is set
+ if (UseAESIntrinsics) {
+ StubRoutines::x86::_key_shuffle_mask_addr = generate_key_shuffle_mask(); // needed by the others
+
+ StubRoutines::_aescrypt_encryptBlock = generate_aescrypt_encryptBlock();
+ StubRoutines::_aescrypt_decryptBlock = generate_aescrypt_decryptBlock();
+ StubRoutines::_cipherBlockChaining_encryptAESCrypt = generate_cipherBlockChaining_encryptAESCrypt();
+ StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt_Parallel();
+ }
}
public:
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/stubRoutines_x86_32.cpp
--- a/src/cpu/x86/vm/stubRoutines_x86_32.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/stubRoutines_x86_32.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -26,21 +26,11 @@
#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/stubRoutines.hpp"
-#ifdef TARGET_OS_FAMILY_linux
-# include "thread_linux.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_solaris
-# include "thread_solaris.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_windows
-# include "thread_windows.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_bsd
-# include "thread_bsd.inline.hpp"
-#endif
+#include "runtime/thread.inline.hpp"
// Implementation of the platform-specific part of StubRoutines - for
// a description of how to extend it, see the stubRoutines.hpp file.
address StubRoutines::x86::_verify_mxcsr_entry = NULL;
address StubRoutines::x86::_verify_fpu_cntrl_wrd_entry = NULL;
+address StubRoutines::x86::_key_shuffle_mask_addr = NULL;
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/stubRoutines_x86_32.hpp
--- a/src/cpu/x86/vm/stubRoutines_x86_32.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/stubRoutines_x86_32.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -41,10 +41,14 @@
private:
static address _verify_mxcsr_entry;
static address _verify_fpu_cntrl_wrd_entry;
+ // shuffle mask for fixing up 128-bit words consisting of big-endian 32-bit integers
+ static address _key_shuffle_mask_addr;
public:
static address verify_mxcsr_entry() { return _verify_mxcsr_entry; }
static address verify_fpu_cntrl_wrd_entry() { return _verify_fpu_cntrl_wrd_entry; }
+ static address key_shuffle_mask_addr() { return _key_shuffle_mask_addr; }
+
};
static bool returns_to_call_stub(address return_pc) { return return_pc == _call_stub_return_address; }
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/stubRoutines_x86_64.cpp
--- a/src/cpu/x86/vm/stubRoutines_x86_64.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/stubRoutines_x86_64.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -26,18 +26,7 @@
#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/stubRoutines.hpp"
-#ifdef TARGET_OS_FAMILY_linux
-# include "thread_linux.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_solaris
-# include "thread_solaris.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_windows
-# include "thread_windows.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_bsd
-# include "thread_bsd.inline.hpp"
-#endif
+#include "runtime/thread.inline.hpp"
// Implementation of the platform-specific part of StubRoutines - for
// a description of how to extend it, see the stubRoutines.hpp file.
@@ -56,3 +45,4 @@
address StubRoutines::x86::_double_sign_mask = NULL;
address StubRoutines::x86::_double_sign_flip = NULL;
address StubRoutines::x86::_mxcsr_std = NULL;
+address StubRoutines::x86::_key_shuffle_mask_addr = NULL;
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/stubRoutines_x86_64.hpp
--- a/src/cpu/x86/vm/stubRoutines_x86_64.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/stubRoutines_x86_64.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -54,6 +54,8 @@
static address _double_sign_mask;
static address _double_sign_flip;
static address _mxcsr_std;
+ // shuffle mask for fixing up 128-bit words consisting of big-endian 32-bit integers
+ static address _key_shuffle_mask_addr;
public:
@@ -116,6 +118,9 @@
{
return _mxcsr_std;
}
+
+ static address key_shuffle_mask_addr() { return _key_shuffle_mask_addr; }
+
};
#endif // CPU_X86_VM_STUBROUTINES_X86_64_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/templateInterpreter_x86_32.cpp
--- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
+#include "asm/macroAssembler.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterGenerator.hpp"
@@ -424,8 +424,6 @@
// C++ interpreter only
// rsi - previous interpreter state pointer
- const Address size_of_parameters(rbx, Method::size_of_parameters_offset());
-
// InterpreterRuntime::frequency_counter_overflow takes one argument
// indicating if the counter overflow occurs at a backwards branch (non-NULL bcp).
// The call returns the address of the verified entry point for the method or NULL
@@ -868,12 +866,13 @@
// rsi: previous interpreter state (C++ interpreter) must preserve
address entry_point = __ pc();
-
- const Address size_of_parameters(rbx, Method::size_of_parameters_offset());
+ const Address constMethod (rbx, Method::const_offset());
const Address invocation_counter(rbx, Method::invocation_counter_offset() + InvocationCounter::counter_offset());
const Address access_flags (rbx, Method::access_flags_offset());
+ const Address size_of_parameters(rcx, ConstMethod::size_of_parameters_offset());
// get parameter size (always needed)
+ __ movptr(rcx, constMethod);
__ load_unsigned_short(rcx, size_of_parameters);
// native calls don't need the stack size check since they have no expression stack
@@ -988,7 +987,9 @@
// allocate space for parameters
__ get_method(method);
- __ load_unsigned_short(t, Address(method, Method::size_of_parameters_offset()));
+ __ movptr(t, Address(method, Method::const_offset()));
+ __ load_unsigned_short(t, Address(t, ConstMethod::size_of_parameters_offset()));
+
__ shlptr(t, Interpreter::logStackElementSize);
__ addptr(t, 2*wordSize); // allocate two more slots for JNIEnv and possible mirror
__ subptr(rsp, t);
@@ -1297,13 +1298,14 @@
// rsi: sender sp
address entry_point = __ pc();
-
- const Address size_of_parameters(rbx, Method::size_of_parameters_offset());
- const Address size_of_locals (rbx, Method::size_of_locals_offset());
+ const Address constMethod (rbx, Method::const_offset());
const Address invocation_counter(rbx, Method::invocation_counter_offset() + InvocationCounter::counter_offset());
const Address access_flags (rbx, Method::access_flags_offset());
+ const Address size_of_parameters(rdx, ConstMethod::size_of_parameters_offset());
+ const Address size_of_locals (rdx, ConstMethod::size_of_locals_offset());
// get parameter size (always needed)
+ __ movptr(rdx, constMethod);
__ load_unsigned_short(rcx, size_of_parameters);
// rbx,: Method*
@@ -1734,7 +1736,8 @@
// Compute size of arguments for saving when returning to deoptimized caller
__ get_method(rax);
- __ load_unsigned_short(rax, Address(rax, in_bytes(Method::size_of_parameters_offset())));
+ __ movptr(rax, Address(rax, Method::const_offset()));
+ __ load_unsigned_short(rax, Address(rax, ConstMethod::size_of_parameters_offset()));
__ shlptr(rax, Interpreter::logStackElementSize);
__ restore_locals();
__ subptr(rdi, rax);
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/templateInterpreter_x86_64.cpp
--- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
+#include "asm/macroAssembler.hpp"
#include "interpreter/bytecodeHistogram.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterGenerator.hpp"
@@ -369,9 +369,6 @@
// Everything as it was on entry
// rdx is not restored. Doesn't appear to really be set.
- const Address size_of_parameters(rbx,
- Method::size_of_parameters_offset());
-
// InterpreterRuntime::frequency_counter_overflow takes two
// arguments, the first (thread) is passed by call_VM, the second
// indicates if the counter overflow occurs at a backwards branch
@@ -844,14 +841,17 @@
address entry_point = __ pc();
- const Address size_of_parameters(rbx, Method::
- size_of_parameters_offset());
+ const Address constMethod (rbx, Method::const_offset());
const Address invocation_counter(rbx, Method::
invocation_counter_offset() +
InvocationCounter::counter_offset());
const Address access_flags (rbx, Method::access_flags_offset());
+ const Address size_of_parameters(rcx, ConstMethod::
+ size_of_parameters_offset());
+
// get parameter size (always needed)
+ __ movptr(rcx, constMethod);
__ load_unsigned_short(rcx, size_of_parameters);
// native calls don't need the stack size check since they have no
@@ -967,9 +967,8 @@
// allocate space for parameters
__ get_method(method);
- __ load_unsigned_short(t,
- Address(method,
- Method::size_of_parameters_offset()));
+ __ movptr(t, Address(method, Method::const_offset()));
+ __ load_unsigned_short(t, Address(t, ConstMethod::size_of_parameters_offset()));
__ shll(t, Interpreter::logStackElementSize);
__ subptr(rsp, t);
@@ -1302,15 +1301,18 @@
// r13: sender sp
address entry_point = __ pc();
- const Address size_of_parameters(rbx,
- Method::size_of_parameters_offset());
- const Address size_of_locals(rbx, Method::size_of_locals_offset());
+ const Address constMethod(rbx, Method::const_offset());
const Address invocation_counter(rbx,
Method::invocation_counter_offset() +
InvocationCounter::counter_offset());
const Address access_flags(rbx, Method::access_flags_offset());
+ const Address size_of_parameters(rdx,
+ ConstMethod::size_of_parameters_offset());
+ const Address size_of_locals(rdx, ConstMethod::size_of_locals_offset());
+
// get parameter size (always needed)
+ __ movptr(rdx, constMethod);
__ load_unsigned_short(rcx, size_of_parameters);
// rbx: Method*
@@ -1752,7 +1754,8 @@
// Compute size of arguments for saving when returning to
// deoptimized caller
__ get_method(rax);
- __ load_unsigned_short(rax, Address(rax, in_bytes(Method::
+ __ movptr(rax, Address(rax, Method::const_offset()));
+ __ load_unsigned_short(rax, Address(rax, in_bytes(ConstMethod::
size_of_parameters_offset())));
__ shll(rax, Interpreter::logStackElementSize);
__ restore_locals(); // XXX do we need this?
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/templateTable_x86_32.cpp
--- a/src/cpu/x86/vm/templateTable_x86_32.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/templateTable_x86_32.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
+#include "asm/macroAssembler.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "interpreter/templateTable.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/templateTable_x86_64.cpp
--- a/src/cpu/x86/vm/templateTable_x86_64.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/templateTable_x86_64.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "asm/macroAssembler.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "interpreter/templateTable.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/vmStructs_x86.hpp
--- a/src/cpu/x86/vm/vmStructs_x86.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/vmStructs_x86.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -29,7 +29,7 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \
+#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
\
/******************************/ \
/* JavaCallWrapper */ \
@@ -37,31 +37,14 @@
/******************************/ \
/* JavaFrameAnchor */ \
/******************************/ \
- volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*) \
- \
+ volatile_nonstatic_field(JavaFrameAnchor, _last_Java_fp, intptr_t*)
- /* NOTE that we do not use the last_entry() macro here; it is used */
- /* in vmStructs__.hpp's VM_STRUCTS_OS_CPU macro (and must */
- /* be present there) */
-#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \
-
- /* NOTE that we do not use the last_entry() macro here; it is used */
- /* in vmStructs__.hpp's VM_TYPES_OS_CPU macro (and must */
- /* be present there) */
-
-
-#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
+#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
- /* NOTE that we do not use the last_entry() macro here; it is used */
- /* in vmStructs__.hpp's VM_INT_CONSTANTS_OS_CPU macro (and must */
- /* be present there) */
+#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
-#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
-
- /* NOTE that we do not use the last_entry() macro here; it is used */
- /* in vmStructs__.hpp's VM_LONG_CONSTANTS_OS_CPU macro (and must */
- /* be present there) */
+#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
#endif // CPU_X86_VM_VMSTRUCTS_X86_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/vm_version_x86.cpp
--- a/src/cpu/x86/vm/vm_version_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/vm_version_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,8 @@
*/
#include "precompiled.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/java.hpp"
#include "runtime/stubCodeGenerator.hpp"
@@ -419,13 +420,16 @@
if (UseAVX < 1)
_cpuFeatures &= ~CPU_AVX;
+ if (!UseAES && !FLAG_IS_DEFAULT(UseAES))
+ _cpuFeatures &= ~CPU_AES;
+
if (logical_processors_per_package() == 1) {
// HT processor could be installed on a system which doesn't support HT.
_cpuFeatures &= ~CPU_HT;
}
char buf[256];
- jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
cores_per_cpu(), threads_per_core(),
cpu_family(), _model, _stepping,
(supports_cmov() ? ", cmov" : ""),
@@ -441,6 +445,8 @@
(supports_popcnt() ? ", popcnt" : ""),
(supports_avx() ? ", avx" : ""),
(supports_avx2() ? ", avx2" : ""),
+ (supports_aes() ? ", aes" : ""),
+ (supports_erms() ? ", erms" : ""),
(supports_mmx_ext() ? ", mmxext" : ""),
(supports_3dnow_prefetch() ? ", 3dnowpref" : ""),
(supports_lzcnt() ? ", lzcnt": ""),
@@ -472,6 +478,29 @@
if (!supports_avx ()) // Drop to 0 if no AVX support
UseAVX = 0;
+ // Use AES instructions if available.
+ if (supports_aes()) {
+ if (FLAG_IS_DEFAULT(UseAES)) {
+ UseAES = true;
+ }
+ } else if (UseAES) {
+ if (!FLAG_IS_DEFAULT(UseAES))
+ warning("AES instructions not available on this CPU");
+ FLAG_SET_DEFAULT(UseAES, false);
+ }
+
+ // The AES intrinsic stubs require AES instruction support (of course)
+ // but also require sse3 mode for instructions it use.
+ if (UseAES && (UseSSE > 2)) {
+ if (FLAG_IS_DEFAULT(UseAESIntrinsics)) {
+ UseAESIntrinsics = true;
+ }
+ } else if (UseAESIntrinsics) {
+ if (!FLAG_IS_DEFAULT(UseAESIntrinsics))
+ warning("AES intrinsics not available on this CPU");
+ FLAG_SET_DEFAULT(UseAESIntrinsics, false);
+ }
+
#ifdef COMPILER2
if (UseFPUForSpilling) {
if (UseSSE < 2) {
@@ -632,6 +661,14 @@
}
}
}
+#if defined(COMPILER2) && defined(_ALLBSD_SOURCE)
+ if (MaxVectorSize > 16) {
+ // Limit vectors size to 16 bytes on BSD until it fixes
+ // restoring upper 128bit of YMM registers on return
+ // from signal handler.
+ FLAG_SET_DEFAULT(MaxVectorSize, 16);
+ }
+#endif // COMPILER2
// Use population count instruction if available.
if (supports_popcnt()) {
@@ -643,6 +680,16 @@
FLAG_SET_DEFAULT(UsePopCountInstruction, false);
}
+ // Use fast-string operations if available.
+ if (supports_erms()) {
+ if (FLAG_IS_DEFAULT(UseFastStosb)) {
+ UseFastStosb = true;
+ }
+ } else if (UseFastStosb) {
+ warning("fast-string operations are not available on this CPU");
+ FLAG_SET_DEFAULT(UseFastStosb, false);
+ }
+
#ifdef COMPILER2
if (FLAG_IS_DEFAULT(AlignVector)) {
// Modern processors allow misaligned memory operations for vectors.
@@ -706,6 +753,10 @@
PrefetchFieldsAhead = prefetch_fields_ahead();
#endif
+ if (FLAG_IS_DEFAULT(ContendedPaddingWidth) &&
+ (cache_line_size > ContendedPaddingWidth))
+ ContendedPaddingWidth = cache_line_size;
+
#ifndef PRODUCT
if (PrintMiscellaneous && Verbose) {
tty->print_cr("Logical CPUs per core: %u",
@@ -714,6 +765,9 @@
if (UseAVX > 0) {
tty->print(" UseAVX=%d",UseAVX);
}
+ if (UseAES) {
+ tty->print(" UseAES=1");
+ }
tty->cr();
tty->print("Allocation");
if (AllocatePrefetchStyle <= 0 || UseSSE == 0 && !supports_3dnow_prefetch()) {
@@ -749,6 +803,9 @@
if (PrefetchFieldsAhead > 0) {
tty->print_cr("PrefetchFieldsAhead %d", PrefetchFieldsAhead);
}
+ if (ContendedPaddingWidth > 0) {
+ tty->print_cr("ContendedPaddingWidth %d", ContendedPaddingWidth);
+ }
}
#endif // !PRODUCT
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/vm_version_x86.hpp
--- a/src/cpu/x86/vm/vm_version_x86.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/vm_version_x86.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -78,7 +78,9 @@
sse4_2 : 1,
: 2,
popcnt : 1,
- : 3,
+ : 1,
+ aes : 1,
+ : 1,
osxsave : 1,
avx : 1,
: 3;
@@ -202,7 +204,8 @@
avx2 : 1,
: 2,
bmi2 : 1,
- : 23;
+ erms : 1,
+ : 22;
} bits;
};
@@ -244,7 +247,9 @@
CPU_TSC = (1 << 15),
CPU_TSCINV = (1 << 16),
CPU_AVX = (1 << 17),
- CPU_AVX2 = (1 << 18)
+ CPU_AVX2 = (1 << 18),
+ CPU_AES = (1 << 19),
+ CPU_ERMS = (1 << 20) // enhanced 'rep movsb/stosb' instructions
} cpuFeatureFlags;
enum {
@@ -420,6 +425,10 @@
result |= CPU_TSC;
if (_cpuid_info.ext_cpuid7_edx.bits.tsc_invariance != 0)
result |= CPU_TSCINV;
+ if (_cpuid_info.std_cpuid1_ecx.bits.aes != 0)
+ result |= CPU_AES;
+ if (_cpuid_info.sef_cpuid7_ebx.bits.erms != 0)
+ result |= CPU_ERMS;
// AMD features.
if (is_amd()) {
@@ -484,7 +493,7 @@
return (_cpuid_info.std_max_function >= 0xB) &&
// eax[4:0] | ebx[0:15] == 0 indicates invalid topology level.
// Some cpus have max cpuid >= 0xB but do not support processor topology.
- ((_cpuid_info.tpl_cpuidB0_eax & 0x1f | _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus) != 0);
+ (((_cpuid_info.tpl_cpuidB0_eax & 0x1f) | _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus) != 0);
}
static uint cores_per_cpu() {
@@ -544,6 +553,8 @@
static bool supports_avx() { return (_cpuFeatures & CPU_AVX) != 0; }
static bool supports_avx2() { return (_cpuFeatures & CPU_AVX2) != 0; }
static bool supports_tsc() { return (_cpuFeatures & CPU_TSC) != 0; }
+ static bool supports_aes() { return (_cpuFeatures & CPU_AES) != 0; }
+ static bool supports_erms() { return (_cpuFeatures & CPU_ERMS) != 0; }
// Intel features
static bool is_intel_family_core() { return is_intel() &&
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/vtableStubs_x86_32.cpp
--- a/src/cpu/x86/vm/vtableStubs_x86_32.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/vtableStubs_x86_32.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
#include "code/vtableStubs.hpp"
#include "interp_masm_x86_32.hpp"
#include "memory/resourceArea.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/vtableStubs_x86_64.cpp
--- a/src/cpu/x86/vm/vtableStubs_x86_64.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/vtableStubs_x86_64.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
#include "code/vtableStubs.hpp"
#include "interp_masm_x86_64.hpp"
#include "memory/resourceArea.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/x86.ad
--- a/src/cpu/x86/vm/x86.ad Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/x86.ad Sun Feb 03 22:43:57 2013 +0100
@@ -4102,9 +4102,158 @@
// ----------------------- LogicalRightShift -----------------------------------
-// Shorts/Chars vector logical right shift produces incorrect Java result
+// Shorts vector logical right shift produces incorrect Java result
// for negative data because java code convert short value into int with
-// sign extension before a shift.
+// sign extension before a shift. But char vectors are fine since chars are
+// unsigned values.
+
+instruct vsrl2S(vecS dst, vecS shift) %{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (URShiftVS dst shift));
+ format %{ "psrlw $dst,$shift\t! logical right shift packed2S" %}
+ ins_encode %{
+ __ psrlw($dst$$XMMRegister, $shift$$XMMRegister);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vsrl2S_imm(vecS dst, immI8 shift) %{
+ predicate(n->as_Vector()->length() == 2);
+ match(Set dst (URShiftVS dst shift));
+ format %{ "psrlw $dst,$shift\t! logical right shift packed2S" %}
+ ins_encode %{
+ __ psrlw($dst$$XMMRegister, (int)$shift$$constant);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vsrl2S_reg(vecS dst, vecS src, vecS shift) %{
+ predicate(UseAVX > 0 && n->as_Vector()->length() == 2);
+ match(Set dst (URShiftVS src shift));
+ format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed2S" %}
+ ins_encode %{
+ bool vector256 = false;
+ __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector256);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vsrl2S_reg_imm(vecS dst, vecS src, immI8 shift) %{
+ predicate(UseAVX > 0 && n->as_Vector()->length() == 2);
+ match(Set dst (URShiftVS src shift));
+ format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed2S" %}
+ ins_encode %{
+ bool vector256 = false;
+ __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector256);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vsrl4S(vecD dst, vecS shift) %{
+ predicate(n->as_Vector()->length() == 4);
+ match(Set dst (URShiftVS dst shift));
+ format %{ "psrlw $dst,$shift\t! logical right shift packed4S" %}
+ ins_encode %{
+ __ psrlw($dst$$XMMRegister, $shift$$XMMRegister);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vsrl4S_imm(vecD dst, immI8 shift) %{
+ predicate(n->as_Vector()->length() == 4);
+ match(Set dst (URShiftVS dst shift));
+ format %{ "psrlw $dst,$shift\t! logical right shift packed4S" %}
+ ins_encode %{
+ __ psrlw($dst$$XMMRegister, (int)$shift$$constant);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vsrl4S_reg(vecD dst, vecD src, vecS shift) %{
+ predicate(UseAVX > 0 && n->as_Vector()->length() == 4);
+ match(Set dst (URShiftVS src shift));
+ format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed4S" %}
+ ins_encode %{
+ bool vector256 = false;
+ __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector256);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vsrl4S_reg_imm(vecD dst, vecD src, immI8 shift) %{
+ predicate(UseAVX > 0 && n->as_Vector()->length() == 4);
+ match(Set dst (URShiftVS src shift));
+ format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed4S" %}
+ ins_encode %{
+ bool vector256 = false;
+ __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector256);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vsrl8S(vecX dst, vecS shift) %{
+ predicate(n->as_Vector()->length() == 8);
+ match(Set dst (URShiftVS dst shift));
+ format %{ "psrlw $dst,$shift\t! logical right shift packed8S" %}
+ ins_encode %{
+ __ psrlw($dst$$XMMRegister, $shift$$XMMRegister);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vsrl8S_imm(vecX dst, immI8 shift) %{
+ predicate(n->as_Vector()->length() == 8);
+ match(Set dst (URShiftVS dst shift));
+ format %{ "psrlw $dst,$shift\t! logical right shift packed8S" %}
+ ins_encode %{
+ __ psrlw($dst$$XMMRegister, (int)$shift$$constant);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vsrl8S_reg(vecX dst, vecX src, vecS shift) %{
+ predicate(UseAVX > 0 && n->as_Vector()->length() == 8);
+ match(Set dst (URShiftVS src shift));
+ format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed8S" %}
+ ins_encode %{
+ bool vector256 = false;
+ __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector256);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vsrl8S_reg_imm(vecX dst, vecX src, immI8 shift) %{
+ predicate(UseAVX > 0 && n->as_Vector()->length() == 8);
+ match(Set dst (URShiftVS src shift));
+ format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed8S" %}
+ ins_encode %{
+ bool vector256 = false;
+ __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector256);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vsrl16S_reg(vecY dst, vecY src, vecS shift) %{
+ predicate(UseAVX > 1 && n->as_Vector()->length() == 16);
+ match(Set dst (URShiftVS src shift));
+ format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed16S" %}
+ ins_encode %{
+ bool vector256 = true;
+ __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, $shift$$XMMRegister, vector256);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct vsrl16S_reg_imm(vecY dst, vecY src, immI8 shift) %{
+ predicate(UseAVX > 1 && n->as_Vector()->length() == 16);
+ match(Set dst (URShiftVS src shift));
+ format %{ "vpsrlw $dst,$src,$shift\t! logical right shift packed16S" %}
+ ins_encode %{
+ bool vector256 = true;
+ __ vpsrlw($dst$$XMMRegister, $src$$XMMRegister, (int)$shift$$constant, vector256);
+ %}
+ ins_pipe( pipe_slow );
+%}
// Integers vector logical right shift
instruct vsrl2I(vecD dst, vecS shift) %{
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/x86_32.ad
--- a/src/cpu/x86/vm/x86_32.ad Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/x86_32.ad Sun Feb 03 22:43:57 2013 +0100
@@ -11572,15 +11572,28 @@
// =======================================================================
// fast clearing of an array
instruct rep_stos(eCXRegI cnt, eDIRegP base, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
+ predicate(!UseFastStosb);
match(Set dummy (ClearArray cnt base));
effect(USE_KILL cnt, USE_KILL base, KILL zero, KILL cr);
- format %{ "SHL ECX,1\t# Convert doublewords to words\n\t"
- "XOR EAX,EAX\n\t"
+ format %{ "XOR EAX,EAX\t# ClearArray:\n\t"
+ "SHL ECX,1\t# Convert doublewords to words\n\t"
"REP STOS\t# store EAX into [EDI++] while ECX--" %}
- opcode(0,0x4);
- ins_encode( Opcode(0xD1), RegOpc(ECX),
- OpcRegReg(0x33,EAX,EAX),
- Opcode(0xF3), Opcode(0xAB) );
+ ins_encode %{
+ __ clear_mem($base$$Register, $cnt$$Register, $zero$$Register);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+instruct rep_fast_stosb(eCXRegI cnt, eDIRegP base, eAXRegI zero, Universe dummy, eFlagsReg cr) %{
+ predicate(UseFastStosb);
+ match(Set dummy (ClearArray cnt base));
+ effect(USE_KILL cnt, USE_KILL base, KILL zero, KILL cr);
+ format %{ "XOR EAX,EAX\t# ClearArray:\n\t"
+ "SHL ECX,3\t# Convert doublewords to bytes\n\t"
+ "REP STOSB\t# store EAX into [EDI++] while ECX--" %}
+ ins_encode %{
+ __ clear_mem($base$$Register, $cnt$$Register, $zero$$Register);
+ %}
ins_pipe( pipe_slow );
%}
@@ -11674,6 +11687,23 @@
ins_pipe( pipe_slow );
%}
+// encode char[] to byte[] in ISO_8859_1
+instruct encode_iso_array(eSIRegP src, eDIRegP dst, eDXRegI len,
+ regD tmp1, regD tmp2, regD tmp3, regD tmp4,
+ eCXRegI tmp5, eAXRegI result, eFlagsReg cr) %{
+ match(Set result (EncodeISOArray src (Binary dst len)));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr);
+
+ format %{ "Encode array $src,$dst,$len -> $result // KILL ECX, EDX, $tmp1, $tmp2, $tmp3, $tmp4, ESI, EDI " %}
+ ins_encode %{
+ __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register,
+ $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister,
+ $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+
//----------Control Flow Instructions------------------------------------------
// Signed compare Instructions
instruct compI_eReg(eFlagsReg cr, rRegI op1, rRegI op2) %{
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/x86/vm/x86_64.ad
--- a/src/cpu/x86/vm/x86_64.ad Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/x86/vm/x86_64.ad Sun Feb 03 22:43:57 2013 +0100
@@ -10374,16 +10374,33 @@
instruct rep_stos(rcx_RegL cnt, rdi_RegP base, rax_RegI zero, Universe dummy,
rFlagsReg cr)
%{
+ predicate(!UseFastStosb);
match(Set dummy (ClearArray cnt base));
effect(USE_KILL cnt, USE_KILL base, KILL zero, KILL cr);
- format %{ "xorl rax, rax\t# ClearArray:\n\t"
- "rep stosq\t# Store rax to *rdi++ while rcx--" %}
- ins_encode(opc_reg_reg(0x33, RAX, RAX), // xorl %eax, %eax
- Opcode(0xF3), Opcode(0x48), Opcode(0xAB)); // rep REX_W stos
+ format %{ "xorq rax, rax\t# ClearArray:\n\t"
+ "rep stosq\t# Store rax to *rdi++ while rcx--" %}
+ ins_encode %{
+ __ clear_mem($base$$Register, $cnt$$Register, $zero$$Register);
+ %}
ins_pipe(pipe_slow);
%}
+instruct rep_fast_stosb(rcx_RegL cnt, rdi_RegP base, rax_RegI zero, Universe dummy,
+ rFlagsReg cr)
+%{
+ predicate(UseFastStosb);
+ match(Set dummy (ClearArray cnt base));
+ effect(USE_KILL cnt, USE_KILL base, KILL zero, KILL cr);
+ format %{ "xorq rax, rax\t# ClearArray:\n\t"
+ "shlq rcx,3\t# Convert doublewords to bytes\n\t"
+ "rep stosb\t# Store rax to *rdi++ while rcx--" %}
+ ins_encode %{
+ __ clear_mem($base$$Register, $cnt$$Register, $zero$$Register);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
instruct string_compare(rdi_RegP str1, rcx_RegI cnt1, rsi_RegP str2, rdx_RegI cnt2,
rax_RegI result, regD tmp1, rFlagsReg cr)
%{
@@ -10478,6 +10495,23 @@
ins_pipe( pipe_slow );
%}
+// encode char[] to byte[] in ISO_8859_1
+instruct encode_iso_array(rsi_RegP src, rdi_RegP dst, rdx_RegI len,
+ regD tmp1, regD tmp2, regD tmp3, regD tmp4,
+ rcx_RegI tmp5, rax_RegI result, rFlagsReg cr) %{
+ match(Set result (EncodeISOArray src (Binary dst len)));
+ effect(TEMP tmp1, TEMP tmp2, TEMP tmp3, TEMP tmp4, USE_KILL src, USE_KILL dst, USE_KILL len, KILL tmp5, KILL cr);
+
+ format %{ "Encode array $src,$dst,$len -> $result // KILL RCX, RDX, $tmp1, $tmp2, $tmp3, $tmp4, RSI, RDI " %}
+ ins_encode %{
+ __ encode_iso_array($src$$Register, $dst$$Register, $len$$Register,
+ $tmp1$$XMMRegister, $tmp2$$XMMRegister, $tmp3$$XMMRegister,
+ $tmp4$$XMMRegister, $tmp5$$Register, $result$$Register);
+ %}
+ ins_pipe( pipe_slow );
+%}
+
+
//----------Control Flow Instructions------------------------------------------
// Signed compare Instructions
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/assembler_zero.cpp
--- a/src/cpu/zero/vm/assembler_zero.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/assembler_zero.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -46,19 +46,19 @@
return 0;
}
+#ifdef ASSERT
+bool AbstractAssembler::pd_check_instruction_mark() {
+ ShouldNotCallThis();
+}
+#endif
+
void Assembler::pd_patch_instruction(address branch, address target) {
ShouldNotCallThis();
}
-#ifndef PRODUCT
-void Assembler::pd_print_patched_instruction(address branch) {
- ShouldNotCallThis();
-}
-#endif // PRODUCT
-
void MacroAssembler::align(int modulus) {
while (offset() % modulus != 0)
- emit_byte(AbstractAssembler::code_fill_byte());
+ emit_int8(AbstractAssembler::code_fill_byte());
}
void MacroAssembler::bang_stack_with_offset(int offset) {
@@ -66,8 +66,7 @@
}
void MacroAssembler::advance(int bytes) {
- _code_pos += bytes;
- sync();
+ code_section()->set_end(code_section()->end() + bytes);
}
RegisterOrConstant MacroAssembler::delayed_value_impl(
@@ -80,6 +79,11 @@
emit_address((address) obj);
}
+void MacroAssembler::store_Metadata(Metadata* md) {
+ code_section()->relocate(pc(), metadata_Relocation::spec_for_immediate());
+ emit_address((address) md);
+}
+
static void should_not_call() {
report_should_not_call(__FILE__, __LINE__);
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/assembler_zero.hpp
--- a/src/cpu/zero/vm/assembler_zero.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/assembler_zero.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -37,9 +37,6 @@
public:
void pd_patch_instruction(address branch, address target);
-#ifndef PRODUCT
- static void pd_print_patched_instruction(address branch);
-#endif // PRODUCT
};
class MacroAssembler : public Assembler {
@@ -55,14 +52,9 @@
public:
void advance(int bytes);
void store_oop(jobject obj);
+ void store_Metadata(Metadata* obj);
};
-#ifdef ASSERT
-inline bool AbstractAssembler::pd_check_instruction_mark() {
- ShouldNotCallThis();
-}
-#endif
-
address ShouldNotCallThisStub();
address ShouldNotCallThisEntry();
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/cppInterpreterGenerator_zero.hpp
--- a/src/cpu/zero/vm/cppInterpreterGenerator_zero.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/cppInterpreterGenerator_zero.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -31,12 +31,17 @@
return _masm;
}
- protected:
- address generate_entry(address entry_point) {
- ZeroEntry *entry = (ZeroEntry *) assembler()->pc();
- assembler()->advance(sizeof(ZeroEntry));
+ public:
+ static address generate_entry_impl(MacroAssembler* masm, address entry_point) {
+ ZeroEntry *entry = (ZeroEntry *) masm->pc();
+ masm->advance(sizeof(ZeroEntry));
entry->set_entry_point(entry_point);
return (address) entry;
}
+ protected:
+ address generate_entry(address entry_point) {
+ return generate_entry_impl(assembler(), entry_point);
+ }
+
#endif // CPU_ZERO_VM_CPPINTERPRETERGENERATOR_ZERO_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/cppInterpreter_zero.cpp
--- a/src/cpu/zero/vm/cppInterpreter_zero.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/cppInterpreter_zero.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -180,25 +180,6 @@
method, istate->osr_entry(), istate->osr_buf(), THREAD);
return;
}
- else if (istate->msg() == BytecodeInterpreter::call_method_handle) {
- oop method_handle = istate->callee();
-
- // Trim back the stack to put the parameters at the top
- stack->set_sp(istate->stack() + 1);
-
- // Make the call
- process_method_handle(method_handle, THREAD);
- fixup_after_potential_safepoint();
-
- // Convert the result
- istate->set_stack(stack->sp() - 1);
-
- // Restore the stack
- stack->set_sp(istate->stack_limit() + 1);
-
- // Resume the interpreter
- istate->set_msg(BytecodeInterpreter::method_resume);
- }
else {
ShouldNotReachHere();
}
@@ -535,35 +516,35 @@
if (entry->is_volatile()) {
switch (entry->flag_state()) {
case ctos:
- SET_LOCALS_INT(object->char_field_acquire(entry->f2()), 0);
+ SET_LOCALS_INT(object->char_field_acquire(entry->f2_as_index()), 0);
break;
case btos:
- SET_LOCALS_INT(object->byte_field_acquire(entry->f2()), 0);
+ SET_LOCALS_INT(object->byte_field_acquire(entry->f2_as_index()), 0);
break;
case stos:
- SET_LOCALS_INT(object->short_field_acquire(entry->f2()), 0);
+ SET_LOCALS_INT(object->short_field_acquire(entry->f2_as_index()), 0);
break;
case itos:
- SET_LOCALS_INT(object->int_field_acquire(entry->f2()), 0);
+ SET_LOCALS_INT(object->int_field_acquire(entry->f2_as_index()), 0);
break;
case ltos:
- SET_LOCALS_LONG(object->long_field_acquire(entry->f2()), 0);
+ SET_LOCALS_LONG(object->long_field_acquire(entry->f2_as_index()), 0);
break;
case ftos:
- SET_LOCALS_FLOAT(object->float_field_acquire(entry->f2()), 0);
+ SET_LOCALS_FLOAT(object->float_field_acquire(entry->f2_as_index()), 0);
break;
case dtos:
- SET_LOCALS_DOUBLE(object->double_field_acquire(entry->f2()), 0);
+ SET_LOCALS_DOUBLE(object->double_field_acquire(entry->f2_as_index()), 0);
break;
case atos:
- SET_LOCALS_OBJECT(object->obj_field_acquire(entry->f2()), 0);
+ SET_LOCALS_OBJECT(object->obj_field_acquire(entry->f2_as_index()), 0);
break;
default:
@@ -573,35 +554,35 @@
else {
switch (entry->flag_state()) {
case ctos:
- SET_LOCALS_INT(object->char_field(entry->f2()), 0);
+ SET_LOCALS_INT(object->char_field(entry->f2_as_index()), 0);
break;
case btos:
- SET_LOCALS_INT(object->byte_field(entry->f2()), 0);
+ SET_LOCALS_INT(object->byte_field(entry->f2_as_index()), 0);
break;
case stos:
- SET_LOCALS_INT(object->short_field(entry->f2()), 0);
+ SET_LOCALS_INT(object->short_field(entry->f2_as_index()), 0);
break;
case itos:
- SET_LOCALS_INT(object->int_field(entry->f2()), 0);
+ SET_LOCALS_INT(object->int_field(entry->f2_as_index()), 0);
break;
case ltos:
- SET_LOCALS_LONG(object->long_field(entry->f2()), 0);
+ SET_LOCALS_LONG(object->long_field(entry->f2_as_index()), 0);
break;
case ftos:
- SET_LOCALS_FLOAT(object->float_field(entry->f2()), 0);
+ SET_LOCALS_FLOAT(object->float_field(entry->f2_as_index()), 0);
break;
case dtos:
- SET_LOCALS_DOUBLE(object->double_field(entry->f2()), 0);
+ SET_LOCALS_DOUBLE(object->double_field(entry->f2_as_index()), 0);
break;
case atos:
- SET_LOCALS_OBJECT(object->obj_field(entry->f2()), 0);
+ SET_LOCALS_OBJECT(object->obj_field(entry->f2_as_index()), 0);
break;
default:
@@ -629,516 +610,6 @@
return 0;
}
-int CppInterpreter::method_handle_entry(Method* method,
- intptr_t UNUSED, TRAPS) {
- JavaThread *thread = (JavaThread *) THREAD;
- ZeroStack *stack = thread->zero_stack();
- int argument_slots = method->size_of_parameters();
- int result_slots = type2size[result_type_of(method)];
- intptr_t *vmslots = stack->sp();
- intptr_t *unwind_sp = vmslots + argument_slots;
-
- // Find the MethodType
- address p = (address) method;
- for (jint* pc = method->method_type_offsets_chain(); (*pc) != -1; pc++) {
- p = *(address*)(p + (*pc));
- }
- oop method_type = (oop) p;
-
- // The MethodHandle is in the slot after the arguments
- int num_vmslots = argument_slots - 1;
- oop method_handle = VMSLOTS_OBJECT(num_vmslots);
-
- // InvokeGeneric requires some extra shuffling
- oop mhtype = java_lang_invoke_MethodHandle::type(method_handle);
- bool is_exact = mhtype == method_type;
- if (!is_exact) {
- if (true || // FIXME
- method->intrinsic_id() == vmIntrinsics::_invokeExact) {
- CALL_VM_NOCHECK_NOFIX(
- SharedRuntime::throw_WrongMethodTypeException(
- thread, method_type, mhtype));
- // NB all oops trashed!
- assert(HAS_PENDING_EXCEPTION, "should do");
- stack->set_sp(unwind_sp);
- return 0;
- }
- assert(method->intrinsic_id() == vmIntrinsics::_invokeGeneric, "should be");
-
- // Load up an adapter from the calling type
- // NB the x86 code for this (in methodHandles_x86.cpp, search for
- // "genericInvoker") is really really odd. I'm hoping it's trying
- // to accomodate odd VM/class library combinations I can ignore.
- oop adapter = NULL; //FIXME: load the adapter from the CP cache
- IF (adapter == NULL) {
- CALL_VM_NOCHECK_NOFIX(
- SharedRuntime::throw_WrongMethodTypeException(
- thread, method_type, mhtype));
- // NB all oops trashed!
- assert(HAS_PENDING_EXCEPTION, "should do");
- stack->set_sp(unwind_sp);
- return 0;
- }
-
- // Adapters are shared among form-families of method-type. The
- // type being called is passed as a trusted first argument so that
- // the adapter knows the actual types of its arguments and return
- // values.
- insert_vmslots(num_vmslots + 1, 1, THREAD);
- if (HAS_PENDING_EXCEPTION) {
- // NB all oops trashed!
- stack->set_sp(unwind_sp);
- return 0;
- }
-
- vmslots = stack->sp();
- num_vmslots++;
- SET_VMSLOTS_OBJECT(method_type, num_vmslots);
-
- method_handle = adapter;
- }
-
- // Start processing
- process_method_handle(method_handle, THREAD);
- if (HAS_PENDING_EXCEPTION)
- result_slots = 0;
-
- // If this is an invokeExact then the eventual callee will not
- // have unwound the method handle argument so we have to do it.
- // If a result is being returned the it will be above the method
- // handle argument we're unwinding.
- if (is_exact) {
- intptr_t result[2];
- for (int i = 0; i < result_slots; i++)
- result[i] = stack->pop();
- stack->pop();
- for (int i = result_slots - 1; i >= 0; i--)
- stack->push(result[i]);
- }
-
- // Check
- assert(stack->sp() == unwind_sp - result_slots, "should be");
-
- // No deoptimized frames on the stack
- return 0;
-}
-
-void CppInterpreter::process_method_handle(oop method_handle, TRAPS) {
- JavaThread *thread = (JavaThread *) THREAD;
- ZeroStack *stack = thread->zero_stack();
- intptr_t *vmslots = stack->sp();
-
- bool direct_to_method = false;
- BasicType src_rtype = T_ILLEGAL;
- BasicType dst_rtype = T_ILLEGAL;
-
- MethodHandleEntry *entry =
- java_lang_invoke_MethodHandle::vmentry(method_handle);
- MethodHandles::EntryKind entry_kind =
- (MethodHandles::EntryKind) (((intptr_t) entry) & 0xffffffff);
-
- Method* method = NULL;
- switch (entry_kind) {
- case MethodHandles::_invokestatic_mh:
- direct_to_method = true;
- break;
-
- case MethodHandles::_invokespecial_mh:
- case MethodHandles::_invokevirtual_mh:
- case MethodHandles::_invokeinterface_mh:
- {
- oop receiver =
- VMSLOTS_OBJECT(
- java_lang_invoke_MethodHandle::vmslots(method_handle) - 1);
- if (receiver == NULL) {
- stack->set_sp(calculate_unwind_sp(stack, method_handle));
- CALL_VM_NOCHECK_NOFIX(
- throw_exception(
- thread, vmSymbols::java_lang_NullPointerException()));
- // NB all oops trashed!
- assert(HAS_PENDING_EXCEPTION, "should do");
- return;
- }
- if (entry_kind != MethodHandles::_invokespecial_mh) {
- intptr_t index = java_lang_invoke_DirectMethodHandle::vmindex(method_handle);
- InstanceKlass* rcvrKlass =
- (InstanceKlass *) receiver->klass();
- if (entry_kind == MethodHandles::_invokevirtual_mh) {
- method = (Method*) rcvrKlass->start_of_vtable()[index];
- }
- else {
- oop iclass = java_lang_invoke_MethodHandle::next_target(method_handle);
- itableOffsetEntry* ki =
- (itableOffsetEntry *) rcvrKlass->start_of_itable();
- int i, length = rcvrKlass->itable_length();
- for (i = 0; i < length; i++, ki++ ) {
- if (ki->interface_klass() == iclass)
- break;
- }
- if (i == length) {
- stack->set_sp(calculate_unwind_sp(stack, method_handle));
- CALL_VM_NOCHECK_NOFIX(
- throw_exception(
- thread, vmSymbols::java_lang_IncompatibleClassChangeError()));
- // NB all oops trashed!
- assert(HAS_PENDING_EXCEPTION, "should do");
- return;
- }
- itableMethodEntry* im = ki->first_method_entry(receiver->klass());
- method = im[index].method();
- if (method == NULL) {
- stack->set_sp(calculate_unwind_sp(stack, method_handle));
- CALL_VM_NOCHECK_NOFIX(
- throw_exception(
- thread, vmSymbols::java_lang_AbstractMethodError()));
- // NB all oops trashed!
- assert(HAS_PENDING_EXCEPTION, "should do");
- return;
- }
- }
- }
- }
- direct_to_method = true;
- break;
-
- case MethodHandles::_bound_ref_direct_mh:
- case MethodHandles::_bound_int_direct_mh:
- case MethodHandles::_bound_long_direct_mh:
- direct_to_method = true;
- // fall through
- case MethodHandles::_bound_ref_mh:
- case MethodHandles::_bound_int_mh:
- case MethodHandles::_bound_long_mh:
- {
- BasicType arg_type = T_ILLEGAL;
- int arg_mask = -1;
- int arg_slots = -1;
- MethodHandles::get_ek_bound_mh_info(
- entry_kind, arg_type, arg_mask, arg_slots);
- int arg_slot =
- java_lang_invoke_BoundMethodHandle::vmargslot(method_handle);
-
- // Create the new slot(s)
- intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle);
- insert_vmslots(arg_slot, arg_slots, THREAD);
- if (HAS_PENDING_EXCEPTION) {
- // all oops trashed
- stack->set_sp(unwind_sp);
- return;
- }
- vmslots = stack->sp();
-
- // Store bound argument into new stack slot
- oop arg = java_lang_invoke_BoundMethodHandle::argument(method_handle);
- if (arg_type == T_OBJECT) {
- assert(arg_slots == 1, "should be");
- SET_VMSLOTS_OBJECT(arg, arg_slot);
- }
- else {
- jvalue arg_value;
- arg_type = java_lang_boxing_object::get_value(arg, &arg_value);
- switch (arg_type) {
- case T_BOOLEAN:
- SET_VMSLOTS_INT(arg_value.z, arg_slot);
- break;
- case T_CHAR:
- SET_VMSLOTS_INT(arg_value.c, arg_slot);
- break;
- case T_BYTE:
- SET_VMSLOTS_INT(arg_value.b, arg_slot);
- break;
- case T_SHORT:
- SET_VMSLOTS_INT(arg_value.s, arg_slot);
- break;
- case T_INT:
- SET_VMSLOTS_INT(arg_value.i, arg_slot);
- break;
- case T_FLOAT:
- SET_VMSLOTS_FLOAT(arg_value.f, arg_slot);
- break;
- case T_LONG:
- SET_VMSLOTS_LONG(arg_value.j, arg_slot + 1);
- break;
- case T_DOUBLE:
- SET_VMSLOTS_DOUBLE(arg_value.d, arg_slot + 1);
- break;
- default:
- tty->print_cr("unhandled type %s", type2name(arg_type));
- ShouldNotReachHere();
- }
- }
- }
- break;
-
- case MethodHandles::_adapter_retype_only:
- case MethodHandles::_adapter_retype_raw:
- src_rtype = result_type_of_handle(
- java_lang_invoke_MethodHandle::next_target(method_handle));
- dst_rtype = result_type_of_handle(method_handle);
- break;
-
- case MethodHandles::_adapter_check_cast:
- {
- int arg_slot =
- java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
- oop arg = VMSLOTS_OBJECT(arg_slot);
- if (arg != NULL) {
- Klass* objKlassOop = arg->klass();
- Klass* klassOf = java_lang_Class::as_Klass(
- java_lang_invoke_AdapterMethodHandle::argument(method_handle));
-
- if (objKlassOop != klassOf &&
- !objKlassOop->is_subtype_of(klassOf)) {
- ResourceMark rm(THREAD);
- const char* objName = Klass::cast(objKlassOop)->external_name();
- const char* klassName = Klass::cast(klassOf)->external_name();
- char* message = SharedRuntime::generate_class_cast_message(
- objName, klassName);
-
- stack->set_sp(calculate_unwind_sp(stack, method_handle));
- CALL_VM_NOCHECK_NOFIX(
- throw_exception(
- thread, vmSymbols::java_lang_ClassCastException(), message));
- // NB all oops trashed!
- assert(HAS_PENDING_EXCEPTION, "should do");
- return;
- }
- }
- }
- break;
-
- case MethodHandles::_adapter_dup_args:
- {
- int arg_slot =
- java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
- int conv =
- java_lang_invoke_AdapterMethodHandle::conversion(method_handle);
- int num_slots = -MethodHandles::adapter_conversion_stack_move(conv);
- assert(num_slots > 0, "should be");
-
- // Create the new slot(s)
- intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle);
- stack->overflow_check(num_slots, THREAD);
- if (HAS_PENDING_EXCEPTION) {
- // all oops trashed
- stack->set_sp(unwind_sp);
- return;
- }
-
- // Duplicate the arguments
- for (int i = num_slots - 1; i >= 0; i--)
- stack->push(*VMSLOTS_SLOT(arg_slot + i));
-
- vmslots = stack->sp(); // unused, but let the compiler figure that out
- }
- break;
-
- case MethodHandles::_adapter_drop_args:
- {
- int arg_slot =
- java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
- int conv =
- java_lang_invoke_AdapterMethodHandle::conversion(method_handle);
- int num_slots = MethodHandles::adapter_conversion_stack_move(conv);
- assert(num_slots > 0, "should be");
-
- remove_vmslots(arg_slot, num_slots, THREAD); // doesn't trap
- vmslots = stack->sp(); // unused, but let the compiler figure that out
- }
- break;
-
- case MethodHandles::_adapter_opt_swap_1:
- case MethodHandles::_adapter_opt_swap_2:
- case MethodHandles::_adapter_opt_rot_1_up:
- case MethodHandles::_adapter_opt_rot_1_down:
- case MethodHandles::_adapter_opt_rot_2_up:
- case MethodHandles::_adapter_opt_rot_2_down:
- {
- int arg1 =
- java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
- int conv =
- java_lang_invoke_AdapterMethodHandle::conversion(method_handle);
- int arg2 = MethodHandles::adapter_conversion_vminfo(conv);
-
- int swap_bytes = 0, rotate = 0;
- MethodHandles::get_ek_adapter_opt_swap_rot_info(
- entry_kind, swap_bytes, rotate);
- int swap_slots = swap_bytes >> LogBytesPerWord;
-
- intptr_t tmp;
- switch (rotate) {
- case 0: // swap
- for (int i = 0; i < swap_slots; i++) {
- tmp = *VMSLOTS_SLOT(arg1 + i);
- SET_VMSLOTS_SLOT(VMSLOTS_SLOT(arg2 + i), arg1 + i);
- SET_VMSLOTS_SLOT(&tmp, arg2 + i);
- }
- break;
-
- case 1: // up
- assert(arg1 - swap_slots > arg2, "should be");
-
- tmp = *VMSLOTS_SLOT(arg1);
- for (int i = arg1 - swap_slots; i >= arg2; i--)
- SET_VMSLOTS_SLOT(VMSLOTS_SLOT(i), i + swap_slots);
- SET_VMSLOTS_SLOT(&tmp, arg2);
-
- break;
-
- case -1: // down
- assert(arg2 - swap_slots > arg1, "should be");
-
- tmp = *VMSLOTS_SLOT(arg1);
- for (int i = arg1 + swap_slots; i <= arg2; i++)
- SET_VMSLOTS_SLOT(VMSLOTS_SLOT(i), i - swap_slots);
- SET_VMSLOTS_SLOT(&tmp, arg2);
- break;
-
- default:
- ShouldNotReachHere();
- }
- }
- break;
-
- case MethodHandles::_adapter_opt_i2l:
- {
- int arg_slot =
- java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
- int arg = VMSLOTS_INT(arg_slot);
- intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle);
- insert_vmslots(arg_slot, 1, THREAD);
- if (HAS_PENDING_EXCEPTION) {
- // all oops trashed
- stack->set_sp(unwind_sp);
- return;
- }
- vmslots = stack->sp();
- arg_slot++;
- SET_VMSLOTS_LONG(arg, arg_slot);
- }
- break;
-
- case MethodHandles::_adapter_opt_unboxi:
- case MethodHandles::_adapter_opt_unboxl:
- {
- int arg_slot =
- java_lang_invoke_AdapterMethodHandle::vmargslot(method_handle);
- oop arg = VMSLOTS_OBJECT(arg_slot);
- jvalue arg_value;
- if (arg == NULL) {
- // queue a nullpointer exception for the caller
- stack->set_sp(calculate_unwind_sp(stack, method_handle));
- CALL_VM_NOCHECK_NOFIX(
- throw_exception(
- thread, vmSymbols::java_lang_NullPointerException()));
- // NB all oops trashed!
- assert(HAS_PENDING_EXCEPTION, "should do");
- return;
- }
- BasicType arg_type = java_lang_boxing_object::get_value(arg, &arg_value);
- if (arg_type == T_LONG || arg_type == T_DOUBLE) {
- intptr_t *unwind_sp = calculate_unwind_sp(stack, method_handle);
- insert_vmslots(arg_slot, 1, THREAD);
- if (HAS_PENDING_EXCEPTION) {
- // all oops trashed
- stack->set_sp(unwind_sp);
- return;
- }
- vmslots = stack->sp();
- arg_slot++;
- }
- switch (arg_type) {
- case T_BOOLEAN:
- SET_VMSLOTS_INT(arg_value.z, arg_slot);
- break;
- case T_CHAR:
- SET_VMSLOTS_INT(arg_value.c, arg_slot);
- break;
- case T_BYTE:
- SET_VMSLOTS_INT(arg_value.b, arg_slot);
- break;
- case T_SHORT:
- SET_VMSLOTS_INT(arg_value.s, arg_slot);
- break;
- case T_INT:
- SET_VMSLOTS_INT(arg_value.i, arg_slot);
- break;
- case T_FLOAT:
- SET_VMSLOTS_FLOAT(arg_value.f, arg_slot);
- break;
- case T_LONG:
- SET_VMSLOTS_LONG(arg_value.j, arg_slot);
- break;
- case T_DOUBLE:
- SET_VMSLOTS_DOUBLE(arg_value.d, arg_slot);
- break;
- default:
- tty->print_cr("unhandled type %s", type2name(arg_type));
- ShouldNotReachHere();
- }
- }
- break;
-
- default:
- tty->print_cr("unhandled entry_kind %s",
- MethodHandles::entry_name(entry_kind));
- ShouldNotReachHere();
- }
-
- // Continue along the chain
- if (direct_to_method) {
- if (method == NULL) {
- method =
- (Method*) java_lang_invoke_MethodHandle::vmtarget(method_handle);
- }
- address entry_point = method->from_interpreted_entry();
- Interpreter::invoke_method(method, entry_point, THREAD);
- }
- else {
- process_method_handle(
- java_lang_invoke_MethodHandle::next_target(method_handle), THREAD);
- }
- // NB all oops now trashed
-
- // Adapt the result type, if necessary
- if (src_rtype != dst_rtype && !HAS_PENDING_EXCEPTION) {
- switch (dst_rtype) {
- case T_VOID:
- for (int i = 0; i < type2size[src_rtype]; i++)
- stack->pop();
- return;
-
- case T_INT:
- switch (src_rtype) {
- case T_VOID:
- stack->overflow_check(1, CHECK);
- stack->push(0);
- return;
-
- case T_BOOLEAN:
- case T_CHAR:
- case T_BYTE:
- case T_SHORT:
- return;
- }
- // INT results sometimes need narrowing
- case T_BOOLEAN:
- case T_CHAR:
- case T_BYTE:
- case T_SHORT:
- switch (src_rtype) {
- case T_INT:
- return;
- }
- }
-
- tty->print_cr("unhandled conversion:");
- tty->print_cr("src_rtype = %s", type2name(src_rtype));
- tty->print_cr("dst_rtype = %s", type2name(dst_rtype));
- ShouldNotReachHere();
- }
-}
-
// The new slots will be inserted before slot insert_before.
// Slots < insert_before will have the same slot number after the insert.
// Slots >= insert_before will become old_slot + num_slots.
@@ -1380,10 +851,6 @@
entry_point = ((InterpreterGenerator*) this)->generate_abstract_entry();
break;
- case Interpreter::method_handle:
- entry_point = ((InterpreterGenerator*) this)->generate_method_handle_entry();
- break;
-
case Interpreter::java_lang_math_sin:
case Interpreter::java_lang_math_cos:
case Interpreter::java_lang_math_tan:
@@ -1391,6 +858,8 @@
case Interpreter::java_lang_math_log:
case Interpreter::java_lang_math_log10:
case Interpreter::java_lang_math_sqrt:
+ case Interpreter::java_lang_math_pow:
+ case Interpreter::java_lang_math_exp:
entry_point = ((InterpreterGenerator*) this)->generate_math_entry(kind);
break;
@@ -1546,11 +1015,7 @@
// Helper for figuring out if frames are interpreter frames
bool CppInterpreter::contains(address pc) {
-#ifdef PRODUCT
- ShouldNotCallThis();
-#else
return false; // make frame::print_value_on work
-#endif // !PRODUCT
}
// Result handlers and convertors
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/cppInterpreter_zero.hpp
--- a/src/cpu/zero/vm/cppInterpreter_zero.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/cppInterpreter_zero.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -36,7 +36,6 @@
static int native_entry(Method* method, intptr_t UNUSED, TRAPS);
static int accessor_entry(Method* method, intptr_t UNUSED, TRAPS);
static int empty_entry(Method* method, intptr_t UNUSED, TRAPS);
- static int method_handle_entry(Method* method, intptr_t UNUSED, TRAPS);
public:
// Main loop of normal_entry
@@ -44,7 +43,6 @@
private:
// Helpers for method_handle_entry
- static void process_method_handle(oop method_handle, TRAPS);
static void insert_vmslots(int insert_before, int num_slots, TRAPS);
static void remove_vmslots(int first_slot, int num_slots, TRAPS);
static BasicType result_type_of_handle(oop method_handle);
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/frame_zero.cpp
--- a/src/cpu/zero/vm/frame_zero.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/frame_zero.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -98,10 +98,20 @@
#endif // CC_INTERP
void frame::patch_pc(Thread* thread, address pc) {
- // We borrow this call to set the thread pointer in the interpreter
- // state; the hook to set up deoptimized frames isn't supplied it.
- assert(pc == NULL, "should be");
- get_interpreterState()->set_thread((JavaThread *) thread);
+
+ if (pc != NULL) {
+ _cb = CodeCache::find_blob(pc);
+ SharkFrame* sharkframe = zeroframe()->as_shark_frame();
+ sharkframe->set_pc(pc);
+ _pc = pc;
+ _deopt_state = is_deoptimized;
+
+ } else {
+ // We borrow this call to set the thread pointer in the interpreter
+ // state; the hook to set up deoptimized frames isn't supplied it.
+ assert(pc == NULL, "should be");
+ get_interpreterState()->set_thread((JavaThread *) thread);
+ }
}
bool frame::safe_for_sender(JavaThread *thread) {
@@ -351,7 +361,7 @@
switch (offset) {
case pc_off:
strncpy(fieldbuf, "pc", buflen);
- if (method()->is_oop()) {
+ if (method()->is_method()) {
nmethod *code = method()->code();
if (code && code->pc_desc_at(pc())) {
SimpleScopeDesc ssd(code, pc());
@@ -367,7 +377,7 @@
case method_off:
strncpy(fieldbuf, "method", buflen);
- if (method()->is_oop()) {
+ if (method()->is_method()) {
method()->name_and_sig_as_C_string(valuebuf, buflen);
}
return;
@@ -378,7 +388,7 @@
}
// Variable part
- if (method()->is_oop()) {
+ if (method()->is_method()) {
identify_vp_word(frame_index, addr_of_word(offset),
addr_of_word(header_words + 1),
unextended_sp() + method()->max_stack(),
@@ -430,4 +440,3 @@
// unused... but returns fp() to minimize changes introduced by 7087445
return fp();
}
-
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/frame_zero.inline.hpp
--- a/src/cpu/zero/vm/frame_zero.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/frame_zero.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -36,6 +36,8 @@
_deopt_state = unknown;
}
+inline address frame::sender_pc() const { ShouldNotCallThis(); }
+
inline frame::frame(ZeroFrame* zf, intptr_t* sp) {
_zeroframe = zf;
_sp = sp;
@@ -43,27 +45,36 @@
case ZeroFrame::ENTRY_FRAME:
_pc = StubRoutines::call_stub_return_pc();
_cb = NULL;
+ _deopt_state = not_deoptimized;
break;
case ZeroFrame::INTERPRETER_FRAME:
_pc = NULL;
_cb = NULL;
+ _deopt_state = not_deoptimized;
break;
- case ZeroFrame::SHARK_FRAME:
+ case ZeroFrame::SHARK_FRAME: {
_pc = zero_sharkframe()->pc();
_cb = CodeCache::find_blob_unsafe(pc());
+ address original_pc = nmethod::get_deopt_original_pc(this);
+ if (original_pc != NULL) {
+ _pc = original_pc;
+ _deopt_state = is_deoptimized;
+ } else {
+ _deopt_state = not_deoptimized;
+ }
break;
-
+ }
case ZeroFrame::FAKE_STUB_FRAME:
_pc = NULL;
_cb = NULL;
+ _deopt_state = not_deoptimized;
break;
default:
ShouldNotReachHere();
}
- _deopt_state = not_deoptimized;
}
// Accessors
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/globals_zero.hpp
--- a/src/cpu/zero/vm/globals_zero.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/globals_zero.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -52,11 +52,7 @@
define_pd_global(bool, RewriteBytecodes, true);
define_pd_global(bool, RewriteFrequentPairs, true);
-#ifdef _ALLBSD_SOURCE
define_pd_global(bool, UseMembar, true);
-#else
-define_pd_global(bool, UseMembar, false);
-#endif
// GC Ergo Flags
define_pd_global(intx, CMSYoungGenPerWorker, 16*M); // default max size of CMS young gen, per GC worker thread
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/icBuffer_zero.cpp
--- a/src/cpu/zero/vm/icBuffer_zero.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/icBuffer_zero.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -40,7 +40,7 @@
}
void InlineCacheBuffer::assemble_ic_buffer_code(address code_begin,
- Metadata* cached_oop,
+ void* cached_oop,
address entry_point) {
// NB ic_stub_code_size() must return the size of the code we generate
ShouldNotCallThis();
@@ -51,7 +51,6 @@
ShouldNotCallThis();
}
-Metadata* InlineCacheBuffer::ic_buffer_cached_oop(address code_begin) {
- // NB ic_stub_code_size() must return the size of the code we generate
+void* InlineCacheBuffer::ic_buffer_cached_value(address code_begin) {
ShouldNotCallThis();
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/interp_masm_zero.cpp
--- a/src/cpu/zero/vm/interp_masm_zero.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/interp_masm_zero.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -37,11 +37,6 @@
#include "runtime/basicLock.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/sharedRuntime.hpp"
-#ifdef TARGET_OS_FAMILY_linux
-# include "thread_linux.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_bsd
-# include "thread_bsd.inline.hpp"
-#endif
+#include "runtime/thread.inline.hpp"
// This file is intentionally empty
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/methodHandles_zero.cpp
--- a/src/cpu/zero/vm/methodHandles_zero.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/methodHandles_zero.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -24,26 +24,159 @@
*/
#include "precompiled.hpp"
+#include "interpreter/interpreterGenerator.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/allocation.inline.hpp"
#include "prims/methodHandles.hpp"
-int MethodHandles::adapter_conversion_ops_supported_mask() {
- return ((1<zero_stack();
+ InterpreterFrame *frame = thread->top_zero_frame()->as_interpreter_frame();
+ interpreterState istate = frame->interpreter_state();
+
+ // Trim back the stack to put the parameters at the top
+ stack->set_sp(istate->stack() + 1);
+
+ Interpreter::invoke_method(method, method->from_interpreted_entry(), THREAD);
+
+ // Convert the result
+ istate->set_stack(stack->sp() - 1);
+
+}
+
+oop MethodHandles::popFromStack(TRAPS) {
+
+ JavaThread *thread = (JavaThread *) THREAD;
+ InterpreterFrame *frame = thread->top_zero_frame()->as_interpreter_frame();
+ interpreterState istate = frame->interpreter_state();
+ intptr_t* topOfStack = istate->stack();
+
+ oop top = STACK_OBJECT(-1);
+ MORE_STACK(-1);
+ istate->set_stack(topOfStack);
+
+ return top;
+
+}
+
+int MethodHandles::method_handle_entry_invokeBasic(Method* method, intptr_t UNUSED, TRAPS) {
+
+ JavaThread *thread = (JavaThread *) THREAD;
+ InterpreterFrame *frame = thread->top_zero_frame()->as_interpreter_frame();
+ interpreterState istate = frame->interpreter_state();
+ intptr_t* topOfStack = istate->stack();
+
+ // 'this' is a MethodHandle. We resolve the target method by accessing this.form.vmentry.vmtarget.
+ int numArgs = method->size_of_parameters();
+ oop lform1 = java_lang_invoke_MethodHandle::form(STACK_OBJECT(-numArgs)); // this.form
+ oop vmEntry1 = java_lang_invoke_LambdaForm::vmentry(lform1);
+ Method* vmtarget = (Method*) java_lang_invoke_MemberName::vmtarget(vmEntry1);
+
+ invoke_target(vmtarget, THREAD);
+
+ // No deoptimized frames on the stack
+ return 0;
+}
+
+int MethodHandles::method_handle_entry_linkToStaticOrSpecial(Method* method, intptr_t UNUSED, TRAPS) {
+
+ // Pop appendix argument from stack. This is a MemberName which we resolve to the
+ // target method.
+ oop vmentry = popFromStack(THREAD);
+
+ Method* vmtarget = (Method*) java_lang_invoke_MemberName::vmtarget(vmentry);
+
+ invoke_target(vmtarget, THREAD);
+
+ return 0;
}
-void MethodHandles::generate_method_handle_stub(MacroAssembler* masm,
- MethodHandles::EntryKind ek) {
- init_entry(ek, (MethodHandleEntry *) ek);
+int MethodHandles::method_handle_entry_linkToInterface(Method* method, intptr_t UNUSED, TRAPS) {
+ JavaThread *thread = (JavaThread *) THREAD;
+ InterpreterFrame *frame = thread->top_zero_frame()->as_interpreter_frame();
+ interpreterState istate = frame->interpreter_state();
+
+ // Pop appendix argument from stack. This is a MemberName which we resolve to the
+ // target method.
+ oop vmentry = popFromStack(THREAD);
+ intptr_t* topOfStack = istate->stack();
+
+ // Resolve target method by looking up in the receiver object's itable.
+ Klass* clazz = java_lang_Class::as_Klass(java_lang_invoke_MemberName::clazz(vmentry));
+ intptr_t vmindex = java_lang_invoke_MemberName::vmindex(vmentry);
+ Method* target = (Method*) java_lang_invoke_MemberName::vmtarget(vmentry);
+
+ int numArgs = target->size_of_parameters();
+ oop recv = STACK_OBJECT(-numArgs);
+
+ InstanceKlass* klass_part = InstanceKlass::cast(recv->klass());
+ itableOffsetEntry* ki = (itableOffsetEntry*) klass_part->start_of_itable();
+ int i;
+ for ( i = 0 ; i < klass_part->itable_length() ; i++, ki++ ) {
+ if (ki->interface_klass() == clazz) break;
+ }
+
+ itableMethodEntry* im = ki->first_method_entry(recv->klass());
+ Method* vmtarget = im[vmindex].method();
+
+ invoke_target(vmtarget, THREAD);
+
+ return 0;
}
+
+int MethodHandles::method_handle_entry_linkToVirtual(Method* method, intptr_t UNUSED, TRAPS) {
+ JavaThread *thread = (JavaThread *) THREAD;
+
+ InterpreterFrame *frame = thread->top_zero_frame()->as_interpreter_frame();
+ interpreterState istate = frame->interpreter_state();
+
+ // Pop appendix argument from stack. This is a MemberName which we resolve to the
+ // target method.
+ oop vmentry = popFromStack(THREAD);
+ intptr_t* topOfStack = istate->stack();
+
+ // Resolve target method by looking up in the receiver object's vtable.
+ intptr_t vmindex = java_lang_invoke_MemberName::vmindex(vmentry);
+ Method* target = (Method*) java_lang_invoke_MemberName::vmtarget(vmentry);
+ int numArgs = target->size_of_parameters();
+ oop recv = STACK_OBJECT(-numArgs);
+ Klass* clazz = recv->klass();
+ Klass* klass_part = InstanceKlass::cast(clazz);
+ klassVtable* vtable = klass_part->vtable();
+ Method* vmtarget = vtable->method_at(vmindex);
+
+ invoke_target(vmtarget, THREAD);
+
+ return 0;
+}
+
+int MethodHandles::method_handle_entry_invalid(Method* method, intptr_t UNUSED, TRAPS) {
+ ShouldNotReachHere();
+ return 0;
+}
+
+address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* masm,
+ vmIntrinsics::ID iid) {
+ switch (iid) {
+ case vmIntrinsics::_invokeGeneric:
+ case vmIntrinsics::_compiledLambdaForm:
+ // Perhaps surprisingly, the symbolic references visible to Java are not directly used.
+ // They are linked to Java-generated adapters via MethodHandleNatives.linkMethod.
+ // They all allow an appendix argument.
+ return InterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_invalid);
+ case vmIntrinsics::_invokeBasic:
+ return InterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_invokeBasic);
+ case vmIntrinsics::_linkToStatic:
+ case vmIntrinsics::_linkToSpecial:
+ return InterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_linkToStaticOrSpecial);
+ case vmIntrinsics::_linkToInterface:
+ return InterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_linkToInterface);
+ case vmIntrinsics::_linkToVirtual:
+ return InterpreterGenerator::generate_entry_impl(masm, (address) MethodHandles::method_handle_entry_linkToVirtual);
+ default:
+ ShouldNotReachHere();
+ return NULL;
+ }
+}
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/methodHandles_zero.hpp
--- a/src/cpu/zero/vm/methodHandles_zero.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/methodHandles_zero.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -26,6 +26,14 @@
// Adapters
enum /* platform_dependent_constants */ {
- adapter_code_size = 0
+ adapter_code_size = sizeof(ZeroEntry) * (Interpreter::method_handle_invoke_LAST - Interpreter::method_handle_invoke_FIRST + 1)
};
+private:
+ static oop popFromStack(TRAPS);
+ static void invoke_target(Method* method, TRAPS);
+ static int method_handle_entry_invokeBasic(Method* method, intptr_t UNUSED, TRAPS);
+ static int method_handle_entry_linkToStaticOrSpecial(Method* method, intptr_t UNUSED, TRAPS);
+ static int method_handle_entry_linkToVirtual(Method* method, intptr_t UNUSED, TRAPS);
+ static int method_handle_entry_linkToInterface(Method* method, intptr_t UNUSED, TRAPS);
+ static int method_handle_entry_invalid(Method* method, intptr_t UNUSED, TRAPS);
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/register_zero.hpp
--- a/src/cpu/zero/vm/register_zero.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/register_zero.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -114,5 +114,8 @@
};
CONSTANT_REGISTER_DECLARATION(Register, noreg, (-1));
+#ifndef DONT_USE_REGISTER_DEFINES
+#define noreg ((Register)(noreg_RegisterEnumValue))
+#endif
#endif // CPU_ZERO_VM_REGISTER_ZERO_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/relocInfo_zero.cpp
--- a/src/cpu/zero/vm/relocInfo_zero.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/relocInfo_zero.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -77,3 +77,7 @@
CodeBuffer* dst) {
ShouldNotCallThis();
}
+
+void metadata_Relocation::pd_fix_value(address x) {
+ ShouldNotCallThis();
+}
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/sharedRuntime_zero.cpp
--- a/src/cpu/zero/vm/sharedRuntime_zero.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/sharedRuntime_zero.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -35,6 +35,7 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/vframeArray.hpp"
#include "vmreg_zero.inline.hpp"
+
#ifdef COMPILER1
#include "c1/c1_Runtime1.hpp"
#endif
@@ -47,6 +48,12 @@
#endif
+
+static address zero_null_code_stub() {
+ address start = ShouldNotCallThisStub();
+ return start;
+}
+
int SharedRuntime::java_calling_convention(const BasicType *sig_bt,
VMRegPair *regs,
int total_args_passed,
@@ -63,16 +70,14 @@
AdapterFingerPrint *fingerprint) {
return AdapterHandlerLibrary::new_entry(
fingerprint,
- ShouldNotCallThisStub(),
- ShouldNotCallThisStub(),
- ShouldNotCallThisStub());
+ CAST_FROM_FN_PTR(address,zero_null_code_stub),
+ CAST_FROM_FN_PTR(address,zero_null_code_stub),
+ CAST_FROM_FN_PTR(address,zero_null_code_stub));
}
nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
methodHandle method,
int compile_id,
- int total_args_passed,
- int max_arg,
BasicType *sig_bt,
VMRegPair *regs,
BasicType ret_type) {
@@ -96,19 +101,20 @@
ShouldNotCallThis();
}
+JRT_LEAF(void, zero_stub())
+ ShouldNotCallThis();
+JRT_END
+
static RuntimeStub* generate_empty_runtime_stub(const char* name) {
- CodeBuffer buffer(name, 0, 0);
- return RuntimeStub::new_runtime_stub(name, &buffer, 0, 0, NULL, false);
+ return CAST_FROM_FN_PTR(RuntimeStub*,zero_stub);
}
static SafepointBlob* generate_empty_safepoint_blob() {
- CodeBuffer buffer("handler_blob", 0, 0);
- return SafepointBlob::create(&buffer, NULL, 0);
+ return CAST_FROM_FN_PTR(SafepointBlob*,zero_stub);
}
static DeoptimizationBlob* generate_empty_deopt_blob() {
- CodeBuffer buffer("handler_blob", 0, 0);
- return DeoptimizationBlob::create(&buffer, NULL, 0, 0, 0, 0);
+ return CAST_FROM_FN_PTR(DeoptimizationBlob*,zero_stub);
}
@@ -116,7 +122,7 @@
_deopt_blob = generate_empty_deopt_blob();
}
-SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, bool cause_return) {
+SafepointBlob* SharedRuntime::generate_handler_blob(address call_ptr, int poll_type) {
return generate_empty_safepoint_blob();
}
@@ -124,6 +130,7 @@
return generate_empty_runtime_stub("resolve_blob");
}
+
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
VMRegPair *regs,
int total_args_passed) {
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/sharkFrame_zero.hpp
--- a/src/cpu/zero/vm/sharkFrame_zero.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/sharkFrame_zero.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -68,6 +68,10 @@
return (address) value_of_word(pc_off);
}
+ void set_pc(address pc) const {
+ *((address*) addr_of_word(pc_off)) = pc;
+ }
+
intptr_t* unextended_sp() const {
return (intptr_t *) value_of_word(unextended_sp_off);
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/stubGenerator_zero.cpp
--- a/src/cpu/zero/vm/stubGenerator_zero.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/stubGenerator_zero.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -38,14 +38,9 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubCodeGenerator.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
#include "stack_zero.inline.hpp"
#include "utilities/top.hpp"
-#ifdef TARGET_OS_FAMILY_linux
-# include "thread_linux.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_bsd
-# include "thread_bsd.inline.hpp"
-#endif
#ifdef COMPILER2
#include "opto/runtime.hpp"
#endif
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/stubRoutines_zero.cpp
--- a/src/cpu/zero/vm/stubRoutines_zero.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/stubRoutines_zero.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -27,9 +27,4 @@
#include "runtime/deoptimization.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/stubRoutines.hpp"
-#ifdef TARGET_OS_FAMILY_linux
-# include "thread_linux.inline.hpp"
-#endif
-#ifdef TARGET_OS_FAMILY_bsd
-# include "thread_bsd.inline.hpp"
-#endif
+#include "runtime/thread.inline.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/cpu/zero/vm/vmStructs_zero.hpp
--- a/src/cpu/zero/vm/vmStructs_zero.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/cpu/zero/vm/vmStructs_zero.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -30,28 +30,12 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \
-
- /* NOTE that we do not use the last_entry() macro here; it is used */
- /* in vmStructs__.hpp's VM_STRUCTS_OS_CPU macro (and must */
- /* be present there) */
+#define VM_STRUCTS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \
-
- /* NOTE that we do not use the last_entry() macro here; it is used */
- /* in vmStructs__.hpp's VM_TYPES_OS_CPU macro (and must */
- /* be present there) */
+#define VM_TYPES_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
-#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
-
- /* NOTE that we do not use the last_entry() macro here; it is used */
- /* in vmStructs__.hpp's VM_INT_CONSTANTS_OS_CPU macro (and must */
- /* be present there) */
+#define VM_INT_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
-#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
-
- /* NOTE that we do not use the last_entry() macro here; it is used */
- /* in vmStructs__.hpp's VM_LONG_CONSTANTS_OS_CPU macro (and must */
- /* be present there) */
+#define VM_LONG_CONSTANTS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
#endif // CPU_ZERO_VM_VMSTRUCTS_ZERO_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/bsd/vm/attachListener_bsd.cpp
--- a/src/os/bsd/vm/attachListener_bsd.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/bsd/vm/attachListener_bsd.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -342,7 +342,6 @@
// get the credentials of the peer and check the effective uid/guid
// - check with jeff on this.
-#ifdef _ALLBSD_SOURCE
uid_t puid;
gid_t pgid;
if (::getpeereid(s, &puid, &pgid) != 0) {
@@ -350,17 +349,6 @@
RESTARTABLE(::close(s), res);
continue;
}
-#else
- struct ucred cred_info;
- socklen_t optlen = sizeof(cred_info);
- if (::getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void*)&cred_info, &optlen) == -1) {
- int res;
- RESTARTABLE(::close(s), res);
- continue;
- }
- uid_t puid = cred_info.uid;
- gid_t pgid = cred_info.gid;
-#endif
uid_t euid = geteuid();
gid_t egid = getegid();
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/bsd/vm/mutex_bsd.cpp
--- a/src/os/bsd/vm/mutex_bsd.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/bsd/vm/mutex_bsd.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -26,7 +26,7 @@
#include "mutex_bsd.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/mutex.hpp"
-#include "thread_bsd.inline.hpp"
+#include "runtime/thread.inline.hpp"
#include "utilities/events.hpp"
// put OS-includes here
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/bsd/vm/mutex_bsd.inline.hpp
--- a/src/os/bsd/vm/mutex_bsd.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/bsd/vm/mutex_bsd.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -27,7 +27,7 @@
#include "os_bsd.inline.hpp"
#include "runtime/interfaceSupport.hpp"
-#include "thread_bsd.inline.hpp"
+#include "runtime/thread.inline.hpp"
// Reconciliation History
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/bsd/vm/osThread_bsd.cpp
--- a/src/os/bsd/vm/osThread_bsd.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/bsd/vm/osThread_bsd.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,29 +23,10 @@
*/
// no precompiled headers
-#include "runtime/atomic.hpp"
-#include "runtime/handles.inline.hpp"
#include "runtime/mutexLocker.hpp"
-#include "runtime/os.hpp"
#include "runtime/osThread.hpp"
-#include "runtime/safepoint.hpp"
-#include "runtime/vmThread.hpp"
-#ifdef TARGET_ARCH_x86
-# include "assembler_x86.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_sparc
-# include "assembler_sparc.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_zero
-# include "assembler_zero.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_arm
-# include "assembler_arm.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_ppc
-# include "assembler_ppc.inline.hpp"
-#endif
+#include
void OSThread::pd_initialize() {
assert(this != NULL, "check");
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/bsd/vm/osThread_bsd.hpp
--- a/src/os/bsd/vm/osThread_bsd.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/bsd/vm/osThread_bsd.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -39,18 +39,12 @@
private:
-#ifdef _ALLBSD_SOURCE
-
#ifdef __APPLE__
typedef thread_t thread_id_t;
#else
typedef pthread_t thread_id_t;
#endif
-#else
- typedef pid_t thread_id_t;
-#endif
-
// _pthread_id is the pthread id, which is used by library calls
// (e.g. pthread_kill).
pthread_t _pthread_id;
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/bsd/vm/os_bsd.cpp
--- a/src/os/bsd/vm/os_bsd.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/bsd/vm/os_bsd.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "compiler/compileBroker.hpp"
+#include "compiler/disassembler.hpp"
#include "interpreter/interpreter.hpp"
#include "jvm_bsd.h"
#include "memory/allocation.inline.hpp"
@@ -52,36 +53,16 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/statSampler.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/threadCritical.hpp"
#include "runtime/timer.hpp"
#include "services/attachListener.hpp"
#include "services/runtimeService.hpp"
-#include "thread_bsd.inline.hpp"
#include "utilities/decoder.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/events.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/vmError.hpp"
-#ifdef TARGET_ARCH_x86
-# include "assembler_x86.inline.hpp"
-# include "nativeInst_x86.hpp"
-#endif
-#ifdef TARGET_ARCH_sparc
-# include "assembler_sparc.inline.hpp"
-# include "nativeInst_sparc.hpp"
-#endif
-#ifdef TARGET_ARCH_zero
-# include "assembler_zero.inline.hpp"
-# include "nativeInst_zero.hpp"
-#endif
-#ifdef TARGET_ARCH_arm
-# include "assembler_arm.inline.hpp"
-# include "nativeInst_arm.hpp"
-#endif
-#ifdef TARGET_ARCH_ppc
-# include "assembler_ppc.inline.hpp"
-# include "nativeInst_ppc.hpp"
-#endif
// put OS-includes here
# include
@@ -108,14 +89,8 @@
# include
# include
# include
-#ifdef _ALLBSD_SOURCE
# include
# include
-#else
-# include
-# include
-# include
-#endif
# include
# include
#ifndef __APPLE__
@@ -150,25 +125,10 @@
// global variables
julong os::Bsd::_physical_memory = 0;
-#ifndef _ALLBSD_SOURCE
-address os::Bsd::_initial_thread_stack_bottom = NULL;
-uintptr_t os::Bsd::_initial_thread_stack_size = 0;
-#endif
int (*os::Bsd::_clock_gettime)(clockid_t, struct timespec *) = NULL;
-#ifndef _ALLBSD_SOURCE
-int (*os::Bsd::_pthread_getcpuclockid)(pthread_t, clockid_t *) = NULL;
-Mutex* os::Bsd::_createThread_lock = NULL;
-#endif
pthread_t os::Bsd::_main_thread;
int os::Bsd::_page_size = -1;
-#ifndef _ALLBSD_SOURCE
-bool os::Bsd::_is_floating_stack = false;
-bool os::Bsd::_is_NPTL = false;
-bool os::Bsd::_supports_fast_thread_cpu_time = false;
-const char * os::Bsd::_glibc_version = NULL;
-const char * os::Bsd::_libpthread_version = NULL;
-#endif
static jlong initial_time_count=0;
@@ -176,7 +136,7 @@
// For diagnostics to print a message once. see run_periodic_checks
static sigset_t check_signal_done;
-static bool check_signals = true;;
+static bool check_signals = true;
static pid_t _initial_pid = 0;
@@ -198,16 +158,8 @@
}
julong os::Bsd::available_memory() {
-#ifdef _ALLBSD_SOURCE
// XXXBSD: this is just a stopgap implementation
return physical_memory() >> 2;
-#else
- // values in struct sysinfo are "unsigned long"
- struct sysinfo si;
- sysinfo(&si);
-
- return (julong)si.freeram * si.mem_unit;
-#endif
}
julong os::physical_memory() {
@@ -255,22 +207,6 @@
}
-#ifndef _ALLBSD_SOURCE
-#ifndef SYS_gettid
-// i386: 224, ia64: 1105, amd64: 186, sparc 143
-#ifdef __ia64__
-#define SYS_gettid 1105
-#elif __i386__
-#define SYS_gettid 224
-#elif __amd64__
-#define SYS_gettid 186
-#elif __sparc__
-#define SYS_gettid 143
-#else
-#error define gettid for the arch
-#endif
-#endif
-#endif
// Cpu architecture string
#if defined(ZERO)
@@ -302,63 +238,37 @@
#define COMPILER_VARIANT "client"
#endif
-#ifndef _ALLBSD_SOURCE
-// pid_t gettid()
-//
-// Returns the kernel thread id of the currently running thread. Kernel
-// thread id is used to access /proc.
-//
-// (Note that getpid() on BsdThreads returns kernel thread id too; but
-// on NPTL, it returns the same pid for all threads, as required by POSIX.)
-//
-pid_t os::Bsd::gettid() {
- int rslt = syscall(SYS_gettid);
- if (rslt == -1) {
- // old kernel, no NPTL support
- return getpid();
- } else {
- return (pid_t)rslt;
- }
-}
-
-// Most versions of bsd have a bug where the number of processors are
-// determined by looking at the /proc file system. In a chroot environment,
-// the system call returns 1. This causes the VM to act as if it is
-// a single processor and elide locking (see is_MP() call).
-static bool unsafe_chroot_detected = false;
-static const char *unstable_chroot_error = "/proc file system not found.\n"
- "Java may be unstable running multithreaded in a chroot "
- "environment on Bsd when /proc filesystem is not mounted.";
-#endif
-
-#ifdef _ALLBSD_SOURCE
+
void os::Bsd::initialize_system_info() {
int mib[2];
size_t len;
int cpu_val;
- u_long mem_val;
+ julong mem_val;
/* get processors count via hw.ncpus sysctl */
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
len = sizeof(cpu_val);
if (sysctl(mib, 2, &cpu_val, &len, NULL, 0) != -1 && cpu_val >= 1) {
+ assert(len == sizeof(cpu_val), "unexpected data size");
set_processor_count(cpu_val);
}
else {
set_processor_count(1); // fallback
}
- /* get physical memory via hw.usermem sysctl (hw.usermem is used
- * instead of hw.physmem because we need size of allocatable memory
+ /* get physical memory via hw.memsize sysctl (hw.memsize is used
+ * since it returns a 64 bit value)
*/
mib[0] = CTL_HW;
- mib[1] = HW_USERMEM;
+ mib[1] = HW_MEMSIZE;
len = sizeof(mem_val);
- if (sysctl(mib, 2, &mem_val, &len, NULL, 0) != -1)
+ if (sysctl(mib, 2, &mem_val, &len, NULL, 0) != -1) {
+ assert(len == sizeof(mem_val), "unexpected data size");
_physical_memory = mem_val;
- else
+ } else {
_physical_memory = 256*1024*1024; // fallback (XXXBSD?)
+ }
#ifdef __OpenBSD__
{
@@ -370,24 +280,6 @@
}
#endif
}
-#else
-void os::Bsd::initialize_system_info() {
- set_processor_count(sysconf(_SC_NPROCESSORS_CONF));
- if (processor_count() == 1) {
- pid_t pid = os::Bsd::gettid();
- char fname[32];
- jio_snprintf(fname, sizeof(fname), "/proc/%d", pid);
- FILE *fp = fopen(fname, "r");
- if (fp == NULL) {
- unsafe_chroot_detected = true;
- } else {
- fclose(fp);
- }
- }
- _physical_memory = (julong)sysconf(_SC_PHYS_PAGES) * (julong)sysconf(_SC_PAGESIZE);
- assert(processor_count() > 0, "bsd error");
-}
-#endif
#ifdef __APPLE__
static const char *get_home() {
@@ -409,12 +301,12 @@
// The next steps are taken in the product version:
//
- // Obtain the JAVA_HOME value from the location of libjvm[_g].so.
+ // Obtain the JAVA_HOME value from the location of libjvm.so.
// This library should be located at:
- // /jre/lib//{client|server}/libjvm[_g].so.
+ // /jre/lib//{client|server}/libjvm.so.
//
// If "/jre/lib/" appears at the right place in the path, then we
- // assume libjvm[_g].so is installed in a JDK and we use this path.
+ // assume libjvm.so is installed in a JDK and we use this path.
//
// Otherwise exit with message: "Could not create the Java virtual machine."
//
@@ -424,9 +316,9 @@
// instead of exit check for $JAVA_HOME environment variable.
//
// If it is defined and we are able to locate $JAVA_HOME/jre/lib/,
- // then we append a fake suffix "hotspot/libjvm[_g].so" to this path so
- // it looks like libjvm[_g].so is installed there
- // /jre/lib//hotspot/libjvm[_g].so.
+ // then we append a fake suffix "hotspot/libjvm.so" to this path so
+ // it looks like libjvm.so is installed there
+ // /jre/lib//hotspot/libjvm.so.
//
// Otherwise exit.
//
@@ -744,171 +636,6 @@
}
}
-#ifndef _ALLBSD_SOURCE
-//////////////////////////////////////////////////////////////////////////////
-// detecting pthread library
-
-void os::Bsd::libpthread_init() {
- // Save glibc and pthread version strings. Note that _CS_GNU_LIBC_VERSION
- // and _CS_GNU_LIBPTHREAD_VERSION are supported in glibc >= 2.3.2. Use a
- // generic name for earlier versions.
- // Define macros here so we can build HotSpot on old systems.
-# ifndef _CS_GNU_LIBC_VERSION
-# define _CS_GNU_LIBC_VERSION 2
-# endif
-# ifndef _CS_GNU_LIBPTHREAD_VERSION
-# define _CS_GNU_LIBPTHREAD_VERSION 3
-# endif
-
- size_t n = confstr(_CS_GNU_LIBC_VERSION, NULL, 0);
- if (n > 0) {
- char *str = (char *)malloc(n);
- confstr(_CS_GNU_LIBC_VERSION, str, n);
- os::Bsd::set_glibc_version(str);
- } else {
- // _CS_GNU_LIBC_VERSION is not supported, try gnu_get_libc_version()
- static char _gnu_libc_version[32];
- jio_snprintf(_gnu_libc_version, sizeof(_gnu_libc_version),
- "glibc %s %s", gnu_get_libc_version(), gnu_get_libc_release());
- os::Bsd::set_glibc_version(_gnu_libc_version);
- }
-
- n = confstr(_CS_GNU_LIBPTHREAD_VERSION, NULL, 0);
- if (n > 0) {
- char *str = (char *)malloc(n);
- confstr(_CS_GNU_LIBPTHREAD_VERSION, str, n);
- // Vanilla RH-9 (glibc 2.3.2) has a bug that confstr() always tells
- // us "NPTL-0.29" even we are running with BsdThreads. Check if this
- // is the case. BsdThreads has a hard limit on max number of threads.
- // So sysconf(_SC_THREAD_THREADS_MAX) will return a positive value.
- // On the other hand, NPTL does not have such a limit, sysconf()
- // will return -1 and errno is not changed. Check if it is really NPTL.
- if (strcmp(os::Bsd::glibc_version(), "glibc 2.3.2") == 0 &&
- strstr(str, "NPTL") &&
- sysconf(_SC_THREAD_THREADS_MAX) > 0) {
- free(str);
- os::Bsd::set_libpthread_version("bsdthreads");
- } else {
- os::Bsd::set_libpthread_version(str);
- }
- } else {
- // glibc before 2.3.2 only has BsdThreads.
- os::Bsd::set_libpthread_version("bsdthreads");
- }
-
- if (strstr(libpthread_version(), "NPTL")) {
- os::Bsd::set_is_NPTL();
- } else {
- os::Bsd::set_is_BsdThreads();
- }
-
- // BsdThreads have two flavors: floating-stack mode, which allows variable
- // stack size; and fixed-stack mode. NPTL is always floating-stack.
- if (os::Bsd::is_NPTL() || os::Bsd::supports_variable_stack_size()) {
- os::Bsd::set_is_floating_stack();
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// thread stack
-
-// Force Bsd kernel to expand current thread stack. If "bottom" is close
-// to the stack guard, caller should block all signals.
-//
-// MAP_GROWSDOWN:
-// A special mmap() flag that is used to implement thread stacks. It tells
-// kernel that the memory region should extend downwards when needed. This
-// allows early versions of BsdThreads to only mmap the first few pages
-// when creating a new thread. Bsd kernel will automatically expand thread
-// stack as needed (on page faults).
-//
-// However, because the memory region of a MAP_GROWSDOWN stack can grow on
-// demand, if a page fault happens outside an already mapped MAP_GROWSDOWN
-// region, it's hard to tell if the fault is due to a legitimate stack
-// access or because of reading/writing non-exist memory (e.g. buffer
-// overrun). As a rule, if the fault happens below current stack pointer,
-// Bsd kernel does not expand stack, instead a SIGSEGV is sent to the
-// application (see Bsd kernel fault.c).
-//
-// This Bsd feature can cause SIGSEGV when VM bangs thread stack for
-// stack overflow detection.
-//
-// Newer version of BsdThreads (since glibc-2.2, or, RH-7.x) and NPTL do
-// not use this flag. However, the stack of initial thread is not created
-// by pthread, it is still MAP_GROWSDOWN. Also it's possible (though
-// unlikely) that user code can create a thread with MAP_GROWSDOWN stack
-// and then attach the thread to JVM.
-//
-// To get around the problem and allow stack banging on Bsd, we need to
-// manually expand thread stack after receiving the SIGSEGV.
-//
-// There are two ways to expand thread stack to address "bottom", we used
-// both of them in JVM before 1.5:
-// 1. adjust stack pointer first so that it is below "bottom", and then
-// touch "bottom"
-// 2. mmap() the page in question
-//
-// Now alternate signal stack is gone, it's harder to use 2. For instance,
-// if current sp is already near the lower end of page 101, and we need to
-// call mmap() to map page 100, it is possible that part of the mmap() frame
-// will be placed in page 100. When page 100 is mapped, it is zero-filled.
-// That will destroy the mmap() frame and cause VM to crash.
-//
-// The following code works by adjusting sp first, then accessing the "bottom"
-// page to force a page fault. Bsd kernel will then automatically expand the
-// stack mapping.
-//
-// _expand_stack_to() assumes its frame size is less than page size, which
-// should always be true if the function is not inlined.
-
-#if __GNUC__ < 3 // gcc 2.x does not support noinline attribute
-#define NOINLINE
-#else
-#define NOINLINE __attribute__ ((noinline))
-#endif
-
-static void _expand_stack_to(address bottom) NOINLINE;
-
-static void _expand_stack_to(address bottom) {
- address sp;
- size_t size;
- volatile char *p;
-
- // Adjust bottom to point to the largest address within the same page, it
- // gives us a one-page buffer if alloca() allocates slightly more memory.
- bottom = (address)align_size_down((uintptr_t)bottom, os::Bsd::page_size());
- bottom += os::Bsd::page_size() - 1;
-
- // sp might be slightly above current stack pointer; if that's the case, we
- // will alloca() a little more space than necessary, which is OK. Don't use
- // os::current_stack_pointer(), as its result can be slightly below current
- // stack pointer, causing us to not alloca enough to reach "bottom".
- sp = (address)&sp;
-
- if (sp > bottom) {
- size = sp - bottom;
- p = (volatile char *)alloca(size);
- assert(p != NULL && p <= (volatile char *)bottom, "alloca problem?");
- p[0] = '\0';
- }
-}
-
-bool os::Bsd::manually_expand_stack(JavaThread * t, address addr) {
- assert(t!=NULL, "just checking");
- assert(t->osthread()->expanding_stack(), "expand should be set");
- assert(t->stack_base() != NULL, "stack_base was not initialized");
-
- if (addr < t->stack_base() && addr >= t->stack_yellow_zone_base()) {
- sigset_t mask_all, old_sigset;
- sigfillset(&mask_all);
- pthread_sigmask(SIG_SETMASK, &mask_all, &old_sigset);
- _expand_stack_to(addr);
- pthread_sigmask(SIG_SETMASK, &old_sigset, NULL);
- return true;
- }
- return false;
-}
-#endif
//////////////////////////////////////////////////////////////////////////////
// create new thread
@@ -917,43 +644,7 @@
// check if it's safe to start a new thread
static bool _thread_safety_check(Thread* thread) {
-#ifdef _ALLBSD_SOURCE
- return true;
-#else
- if (os::Bsd::is_BsdThreads() && !os::Bsd::is_floating_stack()) {
- // Fixed stack BsdThreads (SuSE Bsd/x86, and some versions of Redhat)
- // Heap is mmap'ed at lower end of memory space. Thread stacks are
- // allocated (MAP_FIXED) from high address space. Every thread stack
- // occupies a fixed size slot (usually 2Mbytes, but user can change
- // it to other values if they rebuild BsdThreads).
- //
- // Problem with MAP_FIXED is that mmap() can still succeed even part of
- // the memory region has already been mmap'ed. That means if we have too
- // many threads and/or very large heap, eventually thread stack will
- // collide with heap.
- //
- // Here we try to prevent heap/stack collision by comparing current
- // stack bottom with the highest address that has been mmap'ed by JVM
- // plus a safety margin for memory maps created by native code.
- //
- // This feature can be disabled by setting ThreadSafetyMargin to 0
- //
- if (ThreadSafetyMargin > 0) {
- address stack_bottom = os::current_stack_base() - os::current_stack_size();
-
- // not safe if our stack extends below the safety margin
- return stack_bottom - ThreadSafetyMargin >= highest_vm_reserved_address();
- } else {
- return true;
- }
- } else {
- // Floating stack BsdThreads or NPTL:
- // Unlike fixed stack BsdThreads, thread stacks are not MAP_FIXED. When
- // there's not enough space left, pthread_create() will fail. If we come
- // here, that means enough space has been reserved for stack.
- return true;
- }
-#endif
+ return true;
}
#ifdef __APPLE__
@@ -991,7 +682,6 @@
return NULL;
}
-#ifdef _ALLBSD_SOURCE
#ifdef __APPLE__
// thread_id is mach thread on macos
osthread->set_thread_id(::mach_thread_self());
@@ -999,17 +689,6 @@
// thread_id is pthread_id on BSD
osthread->set_thread_id(::pthread_self());
#endif
-#else
- // thread_id is kernel thread id (similar to Solaris LWP id)
- osthread->set_thread_id(os::Bsd::gettid());
-
- if (UseNUMA) {
- int lgrp_id = os::numa_get_group_id();
- if (lgrp_id != -1) {
- thread->set_lgrp_id(lgrp_id);
- }
- }
-#endif
// initialize signal mask for this thread
os::Bsd::hotspot_sigmask(thread);
@@ -1099,23 +778,9 @@
// let pthread_create() pick the default value.
}
-#ifndef _ALLBSD_SOURCE
- // glibc guard page
- pthread_attr_setguardsize(&attr, os::Bsd::default_guard_size(thr_type));
-#endif
-
ThreadState state;
{
-
-#ifndef _ALLBSD_SOURCE
- // Serialize thread creation if we are running with fixed stack BsdThreads
- bool lock = os::Bsd::is_BsdThreads() && !os::Bsd::is_floating_stack();
- if (lock) {
- os::Bsd::createThread_lock()->lock_without_safepoint_check();
- }
-#endif
-
pthread_t tid;
int ret = pthread_create(&tid, &attr, (void* (*)(void*)) java_start, thread);
@@ -1128,9 +793,6 @@
// Need to clean up stuff we've allocated so far
thread->set_osthread(NULL);
delete osthread;
-#ifndef _ALLBSD_SOURCE
- if (lock) os::Bsd::createThread_lock()->unlock();
-#endif
return false;
}
@@ -1146,11 +808,6 @@
}
}
-#ifndef _ALLBSD_SOURCE
- if (lock) {
- os::Bsd::createThread_lock()->unlock();
- }
-#endif
}
// Aborted due to thread limit being reached
@@ -1188,15 +845,11 @@
}
// Store pthread info into the OSThread
-#ifdef _ALLBSD_SOURCE
#ifdef __APPLE__
osthread->set_thread_id(::mach_thread_self());
#else
osthread->set_thread_id(::pthread_self());
#endif
-#else
- osthread->set_thread_id(os::Bsd::gettid());
-#endif
osthread->set_pthread_id(::pthread_self());
// initialize floating point control register
@@ -1207,35 +860,6 @@
thread->set_osthread(osthread);
-#ifndef _ALLBSD_SOURCE
- if (UseNUMA) {
- int lgrp_id = os::numa_get_group_id();
- if (lgrp_id != -1) {
- thread->set_lgrp_id(lgrp_id);
- }
- }
-
- if (os::Bsd::is_initial_thread()) {
- // If current thread is initial thread, its stack is mapped on demand,
- // see notes about MAP_GROWSDOWN. Here we try to force kernel to map
- // the entire stack region to avoid SEGV in stack banging.
- // It is also useful to get around the heap-stack-gap problem on SuSE
- // kernel (see 4821821 for details). We first expand stack to the top
- // of yellow zone, then enable stack yellow zone (order is significant,
- // enabling yellow zone first will crash JVM on SuSE Bsd), so there
- // is no gap between the last two virtual memory regions.
-
- JavaThread *jt = (JavaThread *)thread;
- address addr = jt->stack_yellow_zone_base();
- assert(addr != NULL, "initialization problem?");
- assert(jt->stack_available(addr) > 0, "stack guard should not be enabled");
-
- osthread->set_expanding_stack();
- os::Bsd::manually_expand_stack(jt, addr);
- osthread->clear_expanding_stack();
- }
-#endif
-
// initialize signal mask for this thread
// and save the caller's signal mask
os::Bsd::hotspot_sigmask(thread);
@@ -1290,247 +914,6 @@
return ThreadLocalStorage::thread();
}
-//////////////////////////////////////////////////////////////////////////////
-// initial thread
-
-#ifndef _ALLBSD_SOURCE
-// Check if current thread is the initial thread, similar to Solaris thr_main.
-bool os::Bsd::is_initial_thread(void) {
- char dummy;
- // If called before init complete, thread stack bottom will be null.
- // Can be called if fatal error occurs before initialization.
- if (initial_thread_stack_bottom() == NULL) return false;
- assert(initial_thread_stack_bottom() != NULL &&
- initial_thread_stack_size() != 0,
- "os::init did not locate initial thread's stack region");
- if ((address)&dummy >= initial_thread_stack_bottom() &&
- (address)&dummy < initial_thread_stack_bottom() + initial_thread_stack_size())
- return true;
- else return false;
-}
-
-// Find the virtual memory area that contains addr
-static bool find_vma(address addr, address* vma_low, address* vma_high) {
- FILE *fp = fopen("/proc/self/maps", "r");
- if (fp) {
- address low, high;
- while (!feof(fp)) {
- if (fscanf(fp, "%p-%p", &low, &high) == 2) {
- if (low <= addr && addr < high) {
- if (vma_low) *vma_low = low;
- if (vma_high) *vma_high = high;
- fclose (fp);
- return true;
- }
- }
- for (;;) {
- int ch = fgetc(fp);
- if (ch == EOF || ch == (int)'\n') break;
- }
- }
- fclose(fp);
- }
- return false;
-}
-
-// Locate initial thread stack. This special handling of initial thread stack
-// is needed because pthread_getattr_np() on most (all?) Bsd distros returns
-// bogus value for initial thread.
-void os::Bsd::capture_initial_stack(size_t max_size) {
- // stack size is the easy part, get it from RLIMIT_STACK
- size_t stack_size;
- struct rlimit rlim;
- getrlimit(RLIMIT_STACK, &rlim);
- stack_size = rlim.rlim_cur;
-
- // 6308388: a bug in ld.so will relocate its own .data section to the
- // lower end of primordial stack; reduce ulimit -s value a little bit
- // so we won't install guard page on ld.so's data section.
- stack_size -= 2 * page_size();
-
- // 4441425: avoid crash with "unlimited" stack size on SuSE 7.1 or Redhat
- // 7.1, in both cases we will get 2G in return value.
- // 4466587: glibc 2.2.x compiled w/o "--enable-kernel=2.4.0" (RH 7.0,
- // SuSE 7.2, Debian) can not handle alternate signal stack correctly
- // for initial thread if its stack size exceeds 6M. Cap it at 2M,
- // in case other parts in glibc still assumes 2M max stack size.
- // FIXME: alt signal stack is gone, maybe we can relax this constraint?
-#ifndef IA64
- if (stack_size > 2 * K * K) stack_size = 2 * K * K;
-#else
- // Problem still exists RH7.2 (IA64 anyway) but 2MB is a little small
- if (stack_size > 4 * K * K) stack_size = 4 * K * K;
-#endif
-
- // Try to figure out where the stack base (top) is. This is harder.
- //
- // When an application is started, glibc saves the initial stack pointer in
- // a global variable "__libc_stack_end", which is then used by system
- // libraries. __libc_stack_end should be pretty close to stack top. The
- // variable is available since the very early days. However, because it is
- // a private interface, it could disappear in the future.
- //
- // Bsd kernel saves start_stack information in /proc//stat. Similar
- // to __libc_stack_end, it is very close to stack top, but isn't the real
- // stack top. Note that /proc may not exist if VM is running as a chroot
- // program, so reading /proc//stat could fail. Also the contents of
- // /proc//stat could change in the future (though unlikely).
- //
- // We try __libc_stack_end first. If that doesn't work, look for
- // /proc//stat. If neither of them works, we use current stack pointer
- // as a hint, which should work well in most cases.
-
- uintptr_t stack_start;
-
- // try __libc_stack_end first
- uintptr_t *p = (uintptr_t *)dlsym(RTLD_DEFAULT, "__libc_stack_end");
- if (p && *p) {
- stack_start = *p;
- } else {
- // see if we can get the start_stack field from /proc/self/stat
- FILE *fp;
- int pid;
- char state;
- int ppid;
- int pgrp;
- int session;
- int nr;
- int tpgrp;
- unsigned long flags;
- unsigned long minflt;
- unsigned long cminflt;
- unsigned long majflt;
- unsigned long cmajflt;
- unsigned long utime;
- unsigned long stime;
- long cutime;
- long cstime;
- long prio;
- long nice;
- long junk;
- long it_real;
- uintptr_t start;
- uintptr_t vsize;
- intptr_t rss;
- uintptr_t rsslim;
- uintptr_t scodes;
- uintptr_t ecode;
- int i;
-
- // Figure what the primordial thread stack base is. Code is inspired
- // by email from Hans Boehm. /proc/self/stat begins with current pid,
- // followed by command name surrounded by parentheses, state, etc.
- char stat[2048];
- int statlen;
-
- fp = fopen("/proc/self/stat", "r");
- if (fp) {
- statlen = fread(stat, 1, 2047, fp);
- stat[statlen] = '\0';
- fclose(fp);
-
- // Skip pid and the command string. Note that we could be dealing with
- // weird command names, e.g. user could decide to rename java launcher
- // to "java 1.4.2 :)", then the stat file would look like
- // 1234 (java 1.4.2 :)) R ... ...
- // We don't really need to know the command string, just find the last
- // occurrence of ")" and then start parsing from there. See bug 4726580.
- char * s = strrchr(stat, ')');
-
- i = 0;
- if (s) {
- // Skip blank chars
- do s++; while (isspace(*s));
-
-#define _UFM UINTX_FORMAT
-#define _DFM INTX_FORMAT
-
- /* 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 */
- /* 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 */
- i = sscanf(s, "%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld " _UFM _UFM _DFM _UFM _UFM _UFM _UFM,
- &state, /* 3 %c */
- &ppid, /* 4 %d */
- &pgrp, /* 5 %d */
- &session, /* 6 %d */
- &nr, /* 7 %d */
- &tpgrp, /* 8 %d */
- &flags, /* 9 %lu */
- &minflt, /* 10 %lu */
- &cminflt, /* 11 %lu */
- &majflt, /* 12 %lu */
- &cmajflt, /* 13 %lu */
- &utime, /* 14 %lu */
- &stime, /* 15 %lu */
- &cutime, /* 16 %ld */
- &cstime, /* 17 %ld */
- &prio, /* 18 %ld */
- &nice, /* 19 %ld */
- &junk, /* 20 %ld */
- &it_real, /* 21 %ld */
- &start, /* 22 UINTX_FORMAT */
- &vsize, /* 23 UINTX_FORMAT */
- &rss, /* 24 INTX_FORMAT */
- &rsslim, /* 25 UINTX_FORMAT */
- &scodes, /* 26 UINTX_FORMAT */
- &ecode, /* 27 UINTX_FORMAT */
- &stack_start); /* 28 UINTX_FORMAT */
- }
-
-#undef _UFM
-#undef _DFM
-
- if (i != 28 - 2) {
- assert(false, "Bad conversion from /proc/self/stat");
- // product mode - assume we are the initial thread, good luck in the
- // embedded case.
- warning("Can't detect initial thread stack location - bad conversion");
- stack_start = (uintptr_t) &rlim;
- }
- } else {
- // For some reason we can't open /proc/self/stat (for example, running on
- // FreeBSD with a Bsd emulator, or inside chroot), this should work for
- // most cases, so don't abort:
- warning("Can't detect initial thread stack location - no /proc/self/stat");
- stack_start = (uintptr_t) &rlim;
- }
- }
-
- // Now we have a pointer (stack_start) very close to the stack top, the
- // next thing to do is to figure out the exact location of stack top. We
- // can find out the virtual memory area that contains stack_start by
- // reading /proc/self/maps, it should be the last vma in /proc/self/maps,
- // and its upper limit is the real stack top. (again, this would fail if
- // running inside chroot, because /proc may not exist.)
-
- uintptr_t stack_top;
- address low, high;
- if (find_vma((address)stack_start, &low, &high)) {
- // success, "high" is the true stack top. (ignore "low", because initial
- // thread stack grows on demand, its real bottom is high - RLIMIT_STACK.)
- stack_top = (uintptr_t)high;
- } else {
- // failed, likely because /proc/self/maps does not exist
- warning("Can't detect initial thread stack location - find_vma failed");
- // best effort: stack_start is normally within a few pages below the real
- // stack top, use it as stack top, and reduce stack size so we won't put
- // guard page outside stack.
- stack_top = stack_start;
- stack_size -= 16 * page_size();
- }
-
- // stack_top could be partially down the page so align it
- stack_top = align_size_up(stack_top, page_size());
-
- if (max_size && stack_size > max_size) {
- _initial_thread_stack_size = max_size;
- } else {
- _initial_thread_stack_size = stack_size;
- }
-
- _initial_thread_stack_size = align_size_down(_initial_thread_stack_size, page_size());
- _initial_thread_stack_bottom = (address)stack_top - _initial_thread_stack_size;
-}
-#endif
////////////////////////////////////////////////////////////////////////////////
// time support
@@ -1576,7 +959,7 @@
void os::Bsd::clock_init() {
// XXXDARWIN: Investigate replacement monotonic clock
}
-#elif defined(_ALLBSD_SOURCE)
+#else
void os::Bsd::clock_init() {
struct timespec res;
struct timespec tp;
@@ -1586,86 +969,8 @@
_clock_gettime = ::clock_gettime;
}
}
-#else
-void os::Bsd::clock_init() {
- // we do dlopen's in this particular order due to bug in bsd
- // dynamical loader (see 6348968) leading to crash on exit
- void* handle = dlopen("librt.so.1", RTLD_LAZY);
- if (handle == NULL) {
- handle = dlopen("librt.so", RTLD_LAZY);
- }
-
- if (handle) {
- int (*clock_getres_func)(clockid_t, struct timespec*) =
- (int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_getres");
- int (*clock_gettime_func)(clockid_t, struct timespec*) =
- (int(*)(clockid_t, struct timespec*))dlsym(handle, "clock_gettime");
- if (clock_getres_func && clock_gettime_func) {
- // See if monotonic clock is supported by the kernel. Note that some
- // early implementations simply return kernel jiffies (updated every
- // 1/100 or 1/1000 second). It would be bad to use such a low res clock
- // for nano time (though the monotonic property is still nice to have).
- // It's fixed in newer kernels, however clock_getres() still returns
- // 1/HZ. We check if clock_getres() works, but will ignore its reported
- // resolution for now. Hopefully as people move to new kernels, this
- // won't be a problem.
- struct timespec res;
- struct timespec tp;
- if (clock_getres_func (CLOCK_MONOTONIC, &res) == 0 &&
- clock_gettime_func(CLOCK_MONOTONIC, &tp) == 0) {
- // yes, monotonic clock is supported
- _clock_gettime = clock_gettime_func;
- } else {
- // close librt if there is no monotonic clock
- dlclose(handle);
- }
- }
- }
-}
#endif
-#ifndef _ALLBSD_SOURCE
-#ifndef SYS_clock_getres
-
-#if defined(IA32) || defined(AMD64)
-#define SYS_clock_getres IA32_ONLY(266) AMD64_ONLY(229)
-#define sys_clock_getres(x,y) ::syscall(SYS_clock_getres, x, y)
-#else
-#warning "SYS_clock_getres not defined for this platform, disabling fast_thread_cpu_time"
-#define sys_clock_getres(x,y) -1
-#endif
-
-#else
-#define sys_clock_getres(x,y) ::syscall(SYS_clock_getres, x, y)
-#endif
-
-void os::Bsd::fast_thread_clock_init() {
- if (!UseBsdPosixThreadCPUClocks) {
- return;
- }
- clockid_t clockid;
- struct timespec tp;
- int (*pthread_getcpuclockid_func)(pthread_t, clockid_t *) =
- (int(*)(pthread_t, clockid_t *)) dlsym(RTLD_DEFAULT, "pthread_getcpuclockid");
-
- // Switch to using fast clocks for thread cpu time if
- // the sys_clock_getres() returns 0 error code.
- // Note, that some kernels may support the current thread
- // clock (CLOCK_THREAD_CPUTIME_ID) but not the clocks
- // returned by the pthread_getcpuclockid().
- // If the fast Posix clocks are supported then the sys_clock_getres()
- // must return at least tp.tv_sec == 0 which means a resolution
- // better than 1 sec. This is extra check for reliability.
-
- if(pthread_getcpuclockid_func &&
- pthread_getcpuclockid_func(_main_thread, &clockid) == 0 &&
- sys_clock_getres(clockid, &tp) == 0 && tp.tv_sec == 0) {
-
- _supports_fast_thread_cpu_time = true;
- _pthread_getcpuclockid = pthread_getcpuclockid_func;
- }
-}
-#endif
jlong os::javaTimeNanos() {
if (Bsd::supports_monotonic_clock()) {
@@ -1877,19 +1182,20 @@
return os::stat(filename, &statbuf) == 0;
}
-void os::dll_build_name(char* buffer, size_t buflen,
+bool os::dll_build_name(char* buffer, size_t buflen,
const char* pname, const char* fname) {
+ bool retval = false;
// Copied from libhpi
const size_t pnamelen = pname ? strlen(pname) : 0;
- // Quietly truncate on buffer overflow. Should be an error.
+ // Return error on buffer overflow.
if (pnamelen + strlen(fname) + strlen(JNI_LIB_PREFIX) + strlen(JNI_LIB_SUFFIX) + 2 > buflen) {
- *buffer = '\0';
- return;
+ return retval;
}
if (pnamelen == 0) {
snprintf(buffer, buflen, JNI_LIB_PREFIX "%s" JNI_LIB_SUFFIX, fname);
+ retval = true;
} else if (strchr(pname, *os::path_separator()) != NULL) {
int n;
char** pelements = split_path(pname, &n);
@@ -1901,6 +1207,7 @@
snprintf(buffer, buflen, "%s/" JNI_LIB_PREFIX "%s" JNI_LIB_SUFFIX,
pelements[i], fname);
if (file_exists(buffer)) {
+ retval = true;
break;
}
}
@@ -1915,14 +1222,16 @@
}
} else {
snprintf(buffer, buflen, "%s/" JNI_LIB_PREFIX "%s" JNI_LIB_SUFFIX, pname, fname);
+ retval = true;
}
+ return retval;
}
const char* os::get_current_directory(char *buf, int buflen) {
return getcwd(buf, buflen);
}
-// check if addr is inside libjvm[_g].so
+// check if addr is inside libjvm.so
bool os::address_is_in_vm(address addr) {
static address libjvm_base_addr;
Dl_info dlinfo;
@@ -1978,7 +1287,6 @@
return false;
}
-#ifdef _ALLBSD_SOURCE
// ported from solaris version
bool os::dll_address_to_library_name(address addr, char* buf,
int buflen, int* offset) {
@@ -1994,86 +1302,10 @@
return false;
}
}
-#else
-struct _address_to_library_name {
- address addr; // input : memory address
- size_t buflen; // size of fname
- char* fname; // output: library name
- address base; // library base addr
-};
-
-static int address_to_library_name_callback(struct dl_phdr_info *info,
- size_t size, void *data) {
- int i;
- bool found = false;
- address libbase = NULL;
- struct _address_to_library_name * d = (struct _address_to_library_name *)data;
-
- // iterate through all loadable segments
- for (i = 0; i < info->dlpi_phnum; i++) {
- address segbase = (address)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
- if (info->dlpi_phdr[i].p_type == PT_LOAD) {
- // base address of a library is the lowest address of its loaded
- // segments.
- if (libbase == NULL || libbase > segbase) {
- libbase = segbase;
- }
- // see if 'addr' is within current segment
- if (segbase <= d->addr &&
- d->addr < segbase + info->dlpi_phdr[i].p_memsz) {
- found = true;
- }
- }
- }
-
- // dlpi_name is NULL or empty if the ELF file is executable, return 0
- // so dll_address_to_library_name() can fall through to use dladdr() which
- // can figure out executable name from argv[0].
- if (found && info->dlpi_name && info->dlpi_name[0]) {
- d->base = libbase;
- if (d->fname) {
- jio_snprintf(d->fname, d->buflen, "%s", info->dlpi_name);
- }
- return 1;
- }
- return 0;
-}
-
-bool os::dll_address_to_library_name(address addr, char* buf,
- int buflen, int* offset) {
- Dl_info dlinfo;
- struct _address_to_library_name data;
-
- // There is a bug in old glibc dladdr() implementation that it could resolve
- // to wrong library name if the .so file has a base address != NULL. Here
- // we iterate through the program headers of all loaded libraries to find
- // out which library 'addr' really belongs to. This workaround can be
- // removed once the minimum requirement for glibc is moved to 2.3.x.
- data.addr = addr;
- data.fname = buf;
- data.buflen = buflen;
- data.base = NULL;
- int rslt = dl_iterate_phdr(address_to_library_name_callback, (void *)&data);
-
- if (rslt) {
- // buf already contains library name
- if (offset) *offset = addr - data.base;
- return true;
- } else if (dladdr((void*)addr, &dlinfo)){
- if (buf) jio_snprintf(buf, buflen, "%s", dlinfo.dli_fname);
- if (offset) *offset = addr - (address)dlinfo.dli_fbase;
- return true;
- } else {
- if (buf) buf[0] = '\0';
- if (offset) *offset = -1;
- return false;
- }
-}
-#endif
-
- // Loads .dll/.so and
- // in case of error it checks if .dll/.so was built for the
- // same architecture as Hotspot is running on
+
+// Loads .dll/.so and
+// in case of error it checks if .dll/.so was built for the
+// same architecture as Hotspot is running on
#ifdef __APPLE__
void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
@@ -2292,7 +1524,6 @@
void os::print_dll_info(outputStream *st) {
st->print_cr("Dynamic libraries:");
-#ifdef _ALLBSD_SOURCE
#ifdef RTLD_DI_LINKMAP
Dl_info dli;
void *handle;
@@ -2336,16 +1567,6 @@
#else
st->print_cr("Error: Cannot print dynamic libraries.");
#endif
-#else
- char fname[32];
- pid_t pid = os::Bsd::gettid();
-
- jio_snprintf(fname, sizeof(fname), "/proc/%d/maps", pid);
-
- if (!_print_ascii_file(fname, st)) {
- st->print("Can not get library information for pid = %d\n", pid);
- }
-#endif
}
void os::print_os_info_brief(outputStream* st) {
@@ -2374,22 +1595,10 @@
st->print("Memory:");
st->print(" %dk page", os::vm_page_size()>>10);
-#ifndef _ALLBSD_SOURCE
- // values in struct sysinfo are "unsigned long"
- struct sysinfo si;
- sysinfo(&si);
-#endif
-
st->print(", physical " UINT64_FORMAT "k",
os::physical_memory() >> 10);
st->print("(" UINT64_FORMAT "k free)",
os::available_memory() >> 10);
-#ifndef _ALLBSD_SOURCE
- st->print(", swap " UINT64_FORMAT "k",
- ((jlong)si.totalswap * si.mem_unit) >> 10);
- st->print("(" UINT64_FORMAT "k free)",
- ((jlong)si.freeswap * si.mem_unit) >> 10);
-#endif
st->cr();
// meminfo
@@ -2483,7 +1692,7 @@
static char saved_jvm_path[MAXPATHLEN] = {0};
-// Find the full path to the current module, libjvm or libjvm_g
+// Find the full path to the current module, libjvm
void os::jvm_path(char *buf, jint buflen) {
// Error checking.
if (buflen < MAXPATHLEN) {
@@ -2526,10 +1735,9 @@
char* jrelib_p;
int len;
- // Check the current module name "libjvm" or "libjvm_g".
+ // Check the current module name "libjvm"
p = strrchr(buf, '/');
assert(strstr(p, "/libjvm") == p, "invalid library name");
- p = strstr(p, "_g") ? "_g" : "";
rp = realpath(java_home_var, buf);
if (rp == NULL)
@@ -2558,11 +1766,9 @@
// to complete the path to JVM being overridden. Otherwise fallback
// to the path to the current library.
if (0 == access(buf, F_OK)) {
- // Use current module name "libjvm[_g]" instead of
- // "libjvm"debug_only("_g")"" since for fastdebug version
- // we should have "libjvm" but debug_only("_g") adds "_g"!
+ // Use current module name "libjvm"
len = strlen(buf);
- snprintf(buf + len, buflen-len, "/libjvm%s%s", p, JNI_LIB_SUFFIX);
+ snprintf(buf + len, buflen-len, "/libjvm%s", JNI_LIB_SUFFIX);
} else {
// Fall back to path of current library
rp = realpath(dli_fname, buf);
@@ -2786,42 +1992,13 @@
#endif
}
-#ifndef _ALLBSD_SOURCE
-// Define MAP_HUGETLB here so we can build HotSpot on old systems.
-#ifndef MAP_HUGETLB
-#define MAP_HUGETLB 0x40000
-#endif
-
-// Define MADV_HUGEPAGE here so we can build HotSpot on old systems.
-#ifndef MADV_HUGEPAGE
-#define MADV_HUGEPAGE 14
-#endif
-#endif
bool os::pd_commit_memory(char* addr, size_t size, size_t alignment_hint,
bool exec) {
-#ifndef _ALLBSD_SOURCE
- if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) {
- int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
- uintptr_t res =
- (uintptr_t) ::mmap(addr, size, prot,
- MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS|MAP_HUGETLB,
- -1, 0);
- return res != (uintptr_t) MAP_FAILED;
- }
-#endif
-
return commit_memory(addr, size, exec);
}
void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) {
-#ifndef _ALLBSD_SOURCE
- if (UseHugeTLBFS && alignment_hint > (size_t)vm_page_size()) {
- // We don't check the return value: madvise(MADV_HUGEPAGE) may not
- // be supported or the memory may already be backed by huge pages.
- ::madvise(addr, bytes, MADV_HUGEPAGE);
- }
-#endif
}
void os::pd_free_memory(char *addr, size_t bytes, size_t alignment_hint) {
@@ -2860,111 +2037,6 @@
return end;
}
-#ifndef _ALLBSD_SOURCE
-// Something to do with the numa-aware allocator needs these symbols
-extern "C" JNIEXPORT void numa_warn(int number, char *where, ...) { }
-extern "C" JNIEXPORT void numa_error(char *where) { }
-extern "C" JNIEXPORT int fork1() { return fork(); }
-
-
-// If we are running with libnuma version > 2, then we should
-// be trying to use symbols with versions 1.1
-// If we are running with earlier version, which did not have symbol versions,
-// we should use the base version.
-void* os::Bsd::libnuma_dlsym(void* handle, const char *name) {
- void *f = dlvsym(handle, name, "libnuma_1.1");
- if (f == NULL) {
- f = dlsym(handle, name);
- }
- return f;
-}
-
-bool os::Bsd::libnuma_init() {
- // sched_getcpu() should be in libc.
- set_sched_getcpu(CAST_TO_FN_PTR(sched_getcpu_func_t,
- dlsym(RTLD_DEFAULT, "sched_getcpu")));
-
- if (sched_getcpu() != -1) { // Does it work?
- void *handle = dlopen("libnuma.so.1", RTLD_LAZY);
- if (handle != NULL) {
- set_numa_node_to_cpus(CAST_TO_FN_PTR(numa_node_to_cpus_func_t,
- libnuma_dlsym(handle, "numa_node_to_cpus")));
- set_numa_max_node(CAST_TO_FN_PTR(numa_max_node_func_t,
- libnuma_dlsym(handle, "numa_max_node")));
- set_numa_available(CAST_TO_FN_PTR(numa_available_func_t,
- libnuma_dlsym(handle, "numa_available")));
- set_numa_tonode_memory(CAST_TO_FN_PTR(numa_tonode_memory_func_t,
- libnuma_dlsym(handle, "numa_tonode_memory")));
- set_numa_interleave_memory(CAST_TO_FN_PTR(numa_interleave_memory_func_t,
- libnuma_dlsym(handle, "numa_interleave_memory")));
-
-
- if (numa_available() != -1) {
- set_numa_all_nodes((unsigned long*)libnuma_dlsym(handle, "numa_all_nodes"));
- // Create a cpu -> node mapping
- _cpu_to_node = new (ResourceObj::C_HEAP) GrowableArray(0, true);
- rebuild_cpu_to_node_map();
- return true;
- }
- }
- }
- return false;
-}
-
-// rebuild_cpu_to_node_map() constructs a table mapping cpud id to node id.
-// The table is later used in get_node_by_cpu().
-void os::Bsd::rebuild_cpu_to_node_map() {
- const size_t NCPUS = 32768; // Since the buffer size computation is very obscure
- // in libnuma (possible values are starting from 16,
- // and continuing up with every other power of 2, but less
- // than the maximum number of CPUs supported by kernel), and
- // is a subject to change (in libnuma version 2 the requirements
- // are more reasonable) we'll just hardcode the number they use
- // in the library.
- const size_t BitsPerCLong = sizeof(long) * CHAR_BIT;
-
- size_t cpu_num = os::active_processor_count();
- size_t cpu_map_size = NCPUS / BitsPerCLong;
- size_t cpu_map_valid_size =
- MIN2((cpu_num + BitsPerCLong - 1) / BitsPerCLong, cpu_map_size);
-
- cpu_to_node()->clear();
- cpu_to_node()->at_grow(cpu_num - 1);
- size_t node_num = numa_get_groups_num();
-
- unsigned long *cpu_map = NEW_C_HEAP_ARRAY(unsigned long, cpu_map_size);
- for (size_t i = 0; i < node_num; i++) {
- if (numa_node_to_cpus(i, cpu_map, cpu_map_size * sizeof(unsigned long)) != -1) {
- for (size_t j = 0; j < cpu_map_valid_size; j++) {
- if (cpu_map[j] != 0) {
- for (size_t k = 0; k < BitsPerCLong; k++) {
- if (cpu_map[j] & (1UL << k)) {
- cpu_to_node()->at_put(j * BitsPerCLong + k, i);
- }
- }
- }
- }
- }
- }
- FREE_C_HEAP_ARRAY(unsigned long, cpu_map);
-}
-
-int os::Bsd::get_node_by_cpu(int cpu_id) {
- if (cpu_to_node() != NULL && cpu_id >= 0 && cpu_id < cpu_to_node()->length()) {
- return cpu_to_node()->at(cpu_id);
- }
- return -1;
-}
-
-GrowableArray* os::Bsd::_cpu_to_node;
-os::Bsd::sched_getcpu_func_t os::Bsd::_sched_getcpu;
-os::Bsd::numa_node_to_cpus_func_t os::Bsd::_numa_node_to_cpus;
-os::Bsd::numa_max_node_func_t os::Bsd::_numa_max_node;
-os::Bsd::numa_available_func_t os::Bsd::_numa_available;
-os::Bsd::numa_tonode_memory_func_t os::Bsd::_numa_tonode_memory;
-os::Bsd::numa_interleave_memory_func_t os::Bsd::_numa_interleave_memory;
-unsigned long* os::Bsd::_numa_all_nodes;
-#endif
bool os::pd_uncommit_memory(char* addr, size_t size) {
#ifdef __OpenBSD__
@@ -3084,42 +2156,7 @@
}
bool os::Bsd::hugetlbfs_sanity_check(bool warn, size_t page_size) {
- bool result = false;
-#ifndef _ALLBSD_SOURCE
- void *p = mmap (NULL, page_size, PROT_READ|PROT_WRITE,
- MAP_ANONYMOUS|MAP_PRIVATE|MAP_HUGETLB,
- -1, 0);
-
- if (p != (void *) -1) {
- // We don't know if this really is a huge page or not.
- FILE *fp = fopen("/proc/self/maps", "r");
- if (fp) {
- while (!feof(fp)) {
- char chars[257];
- long x = 0;
- if (fgets(chars, sizeof(chars), fp)) {
- if (sscanf(chars, "%lx-%*x", &x) == 1
- && x == (long)p) {
- if (strstr (chars, "hugepage")) {
- result = true;
- break;
- }
- }
- }
- }
- fclose(fp);
- }
- munmap (p, page_size);
- if (result)
- return true;
- }
-
- if (warn) {
- warning("HugeTLBFS is not supported by the operating system.");
- }
-#endif
-
- return result;
+ return false;
}
/*
@@ -3164,92 +2201,8 @@
static size_t _large_page_size = 0;
void os::large_page_init() {
-#ifndef _ALLBSD_SOURCE
- if (!UseLargePages) {
- UseHugeTLBFS = false;
- UseSHM = false;
- return;
- }
-
- if (FLAG_IS_DEFAULT(UseHugeTLBFS) && FLAG_IS_DEFAULT(UseSHM)) {
- // If UseLargePages is specified on the command line try both methods,
- // if it's default, then try only HugeTLBFS.
- if (FLAG_IS_DEFAULT(UseLargePages)) {
- UseHugeTLBFS = true;
- } else {
- UseHugeTLBFS = UseSHM = true;
- }
- }
-
- if (LargePageSizeInBytes) {
- _large_page_size = LargePageSizeInBytes;
- } else {
- // large_page_size on Bsd is used to round up heap size. x86 uses either
- // 2M or 4M page, depending on whether PAE (Physical Address Extensions)
- // mode is enabled. AMD64/EM64T uses 2M page in 64bit mode. IA64 can use
- // page as large as 256M.
- //
- // Here we try to figure out page size by parsing /proc/meminfo and looking
- // for a line with the following format:
- // Hugepagesize: 2048 kB
- //
- // If we can't determine the value (e.g. /proc is not mounted, or the text
- // format has been changed), we'll use the largest page size supported by
- // the processor.
-
-#ifndef ZERO
- _large_page_size = IA32_ONLY(4 * M) AMD64_ONLY(2 * M) IA64_ONLY(256 * M) SPARC_ONLY(4 * M)
- ARM_ONLY(2 * M) PPC_ONLY(4 * M);
-#endif // ZERO
-
- FILE *fp = fopen("/proc/meminfo", "r");
- if (fp) {
- while (!feof(fp)) {
- int x = 0;
- char buf[16];
- if (fscanf(fp, "Hugepagesize: %d", &x) == 1) {
- if (x && fgets(buf, sizeof(buf), fp) && strcmp(buf, " kB\n") == 0) {
- _large_page_size = x * K;
- break;
- }
- } else {
- // skip to next line
- for (;;) {
- int ch = fgetc(fp);
- if (ch == EOF || ch == (int)'\n') break;
- }
- }
- }
- fclose(fp);
- }
- }
-
- // print a warning if any large page related flag is specified on command line
- bool warn_on_failure = !FLAG_IS_DEFAULT(UseHugeTLBFS);
-
- const size_t default_page_size = (size_t)Bsd::page_size();
- if (_large_page_size > default_page_size) {
- _page_sizes[0] = _large_page_size;
- _page_sizes[1] = default_page_size;
- _page_sizes[2] = 0;
- }
- UseHugeTLBFS = UseHugeTLBFS &&
- Bsd::hugetlbfs_sanity_check(warn_on_failure, _large_page_size);
-
- if (UseHugeTLBFS)
- UseSHM = false;
-
- UseLargePages = UseHugeTLBFS || UseSHM;
-
- set_coredump_filter();
-#endif
}
-#ifndef _ALLBSD_SOURCE
-#ifndef SHM_HUGETLB
-#define SHM_HUGETLB 04000
-#endif
-#endif
char* os::reserve_memory_special(size_t bytes, char* req_addr, bool exec) {
// "exec" is passed in but not used. Creating the shared image for
@@ -3267,11 +2220,7 @@
// Create a large shared memory region to attach to based on size.
// Currently, size is the total size of the heap
-#ifndef _ALLBSD_SOURCE
- int shmid = shmget(key, bytes, SHM_HUGETLB|IPC_CREAT|SHM_R|SHM_W);
-#else
int shmid = shmget(key, bytes, IPC_CREAT|SHM_R|SHM_W);
-#endif
if (shmid == -1) {
// Possible reasons for shmget failure:
// 1. shmmax is too small for Java heap.
@@ -3558,7 +2507,7 @@
// this reason, the code should not be used as default (ThreadPriorityPolicy=0).
// It is only used when ThreadPriorityPolicy=1 and requires root privilege.
-#if defined(_ALLBSD_SOURCE) && !defined(__APPLE__)
+#if !defined(__APPLE__)
int os::java_to_os_priority[CriticalPriority + 1] = {
19, // 0 Entry should never be used
@@ -3578,7 +2527,7 @@
31 // 11 CriticalPriority
};
-#elif defined(__APPLE__)
+#else
/* Using Mach high-level priority assignments */
int os::java_to_os_priority[CriticalPriority + 1] = {
0, // 0 Entry should never be used (MINPRI_USER)
@@ -3599,26 +2548,6 @@
36 // 11 CriticalPriority
};
-#else
-int os::java_to_os_priority[CriticalPriority + 1] = {
- 19, // 0 Entry should never be used
-
- 4, // 1 MinPriority
- 3, // 2
- 2, // 3
-
- 1, // 4
- 0, // 5 NormPriority
- -1, // 6
-
- -2, // 7
- -3, // 8
- -4, // 9 NearMaxPriority
-
- -5, // 10 MaxPriority
-
- -5 // 11 CriticalPriority
-};
#endif
static int prio_init() {
@@ -4179,22 +3108,6 @@
}
}
-#ifndef _ALLBSD_SOURCE
-// This is the fastest way to get thread cpu time on Bsd.
-// Returns cpu time (user+sys) for any thread, not only for current.
-// POSIX compliant clocks are implemented in the kernels 2.6.16+.
-// It might work on 2.6.10+ with a special kernel/glibc patch.
-// For reference, please, see IEEE Std 1003.1-2004:
-// http://www.unix.org/single_unix_specification
-
-jlong os::Bsd::fast_thread_cpu_time(clockid_t clockid) {
- struct timespec tp;
- int rc = os::Bsd::clock_gettime(clockid, &tp);
- assert(rc == 0, "clock_gettime is expected to return 0 code");
-
- return (tp.tv_sec * NANOSECS_PER_SEC) + tp.tv_nsec;
-}
-#endif
/////
// glibc on Bsd platform uses non-documented flag
@@ -4458,10 +3371,6 @@
// this is called _after_ the global arguments have been parsed
jint os::init_2(void)
{
-#ifndef _ALLBSD_SOURCE
- Bsd::fast_thread_clock_init();
-#endif
-
// Allocate a single page and mark it as readable for safepoint polling
address polling_page = (address) ::mmap(NULL, Bsd::page_size(), PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
guarantee( polling_page != MAP_FAILED, "os::init_2: failed to allocate polling page" );
@@ -4518,48 +3427,6 @@
JavaThread::set_stack_size_at_create(round_to(threadStackSizeInBytes,
vm_page_size()));
-#ifndef _ALLBSD_SOURCE
- Bsd::capture_initial_stack(JavaThread::stack_size_at_create());
-
- Bsd::libpthread_init();
- if (PrintMiscellaneous && (Verbose || WizardMode)) {
- tty->print_cr("[HotSpot is running with %s, %s(%s)]\n",
- Bsd::glibc_version(), Bsd::libpthread_version(),
- Bsd::is_floating_stack() ? "floating stack" : "fixed stack");
- }
-
- if (UseNUMA) {
- if (!Bsd::libnuma_init()) {
- UseNUMA = false;
- } else {
- if ((Bsd::numa_max_node() < 1)) {
- // There's only one node(they start from 0), disable NUMA.
- UseNUMA = false;
- }
- }
- // With SHM large pages we cannot uncommit a page, so there's not way
- // we can make the adaptive lgrp chunk resizing work. If the user specified
- // both UseNUMA and UseLargePages (or UseSHM) on the command line - warn and
- // disable adaptive resizing.
- if (UseNUMA && UseLargePages && UseSHM) {
- if (!FLAG_IS_DEFAULT(UseNUMA)) {
- if (FLAG_IS_DEFAULT(UseLargePages) && FLAG_IS_DEFAULT(UseSHM)) {
- UseLargePages = false;
- } else {
- warning("UseNUMA is not fully compatible with SHM large pages, disabling adaptive resizing");
- UseAdaptiveSizePolicy = false;
- UseAdaptiveNUMAChunkSizing = false;
- }
- } else {
- UseNUMA = false;
- }
- }
- if (!UseNUMA && ForceNUMA) {
- UseNUMA = true;
- }
- }
-#endif
-
if (MaxFDLimit) {
// set the number of file descriptors to max. print out error
// if getrlimit/setrlimit fails but continue regardless.
@@ -4586,11 +3453,6 @@
}
}
-#ifndef _ALLBSD_SOURCE
- // Initialize lock used to serialize thread creation (see os::create_thread)
- Bsd::set_createThread_lock(new Mutex(Mutex::leaf, "createThread_lock", false));
-#endif
-
// at-exit methods are called in the reverse order of their registration.
// atexit functions are called on return from main or as a result of a
// call to exit(3C). There can be only 32 of these functions registered
@@ -4641,15 +3503,7 @@
};
int os::active_processor_count() {
-#ifdef _ALLBSD_SOURCE
return _processor_count;
-#else
- // Bsd doesn't yet have a (official) notion of processor sets,
- // so just return the number of online processors.
- int online_cpus = ::sysconf(_SC_NPROCESSORS_ONLN);
- assert(online_cpus > 0 && online_cpus <= processor_count(), "sanity check");
- return online_cpus;
-#endif
}
void os::set_native_thread_name(const char *name) {
@@ -4703,25 +3557,7 @@
int os::Bsd::safe_cond_timedwait(pthread_cond_t *_cond, pthread_mutex_t *_mutex, const struct timespec *_abstime)
{
-#ifdef _ALLBSD_SOURCE
return pthread_cond_timedwait(_cond, _mutex, _abstime);
-#else
- if (is_NPTL()) {
- return pthread_cond_timedwait(_cond, _mutex, _abstime);
- } else {
-#ifndef IA64
- // 6292965: BsdThreads pthread_cond_timedwait() resets FPU control
- // word back to default 64bit precision if condvar is signaled. Java
- // wants 53bit precision. Save and restore current value.
- int fpu = get_fpu_control_word();
-#endif // IA64
- int status = pthread_cond_timedwait(_cond, _mutex, _abstime);
-#ifndef IA64
- set_fpu_control_word(fpu);
-#endif // IA64
- return status;
- }
-#endif
}
////////////////////////////////////////////////////////////////////////////////
@@ -5041,20 +3877,6 @@
return munmap(addr, bytes) == 0;
}
-#ifndef _ALLBSD_SOURCE
-static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time);
-
-static clockid_t thread_cpu_clockid(Thread* thread) {
- pthread_t tid = thread->osthread()->pthread_id();
- clockid_t clockid;
-
- // Get thread clockid
- int rc = os::Bsd::pthread_getcpuclockid(tid, &clockid);
- assert(rc == 0, "pthread_getcpuclockid is expected to return 0 code");
- return clockid;
-}
-#endif
-
// current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool)
// are used by JVM M&M and JVMTI to get user+sys or user CPU time
// of a thread.
@@ -5065,36 +3887,15 @@
jlong os::current_thread_cpu_time() {
#ifdef __APPLE__
return os::thread_cpu_time(Thread::current(), true /* user + sys */);
-#elif !defined(_ALLBSD_SOURCE)
- if (os::Bsd::supports_fast_thread_cpu_time()) {
- return os::Bsd::fast_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID);
- } else {
- // return user + sys since the cost is the same
- return slow_thread_cpu_time(Thread::current(), true /* user + sys */);
- }
#endif
}
jlong os::thread_cpu_time(Thread* thread) {
-#ifndef _ALLBSD_SOURCE
- // consistent with what current_thread_cpu_time() returns
- if (os::Bsd::supports_fast_thread_cpu_time()) {
- return os::Bsd::fast_thread_cpu_time(thread_cpu_clockid(thread));
- } else {
- return slow_thread_cpu_time(thread, true /* user + sys */);
- }
-#endif
}
jlong os::current_thread_cpu_time(bool user_sys_cpu_time) {
#ifdef __APPLE__
return os::thread_cpu_time(Thread::current(), user_sys_cpu_time);
-#elif !defined(_ALLBSD_SOURCE)
- if (user_sys_cpu_time && os::Bsd::supports_fast_thread_cpu_time()) {
- return os::Bsd::fast_thread_cpu_time(CLOCK_THREAD_CPUTIME_ID);
- } else {
- return slow_thread_cpu_time(Thread::current(), user_sys_cpu_time);
- }
#endif
}
@@ -5118,106 +3919,9 @@
} else {
return ((jlong)tinfo.user_time.seconds * 1000000000) + ((jlong)tinfo.user_time.microseconds * (jlong)1000);
}
-#elif !defined(_ALLBSD_SOURCE)
- if (user_sys_cpu_time && os::Bsd::supports_fast_thread_cpu_time()) {
- return os::Bsd::fast_thread_cpu_time(thread_cpu_clockid(thread));
- } else {
- return slow_thread_cpu_time(thread, user_sys_cpu_time);
- }
#endif
}
-#ifndef _ALLBSD_SOURCE
-//
-// -1 on error.
-//
-
-static jlong slow_thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
- static bool proc_pid_cpu_avail = true;
- static bool proc_task_unchecked = true;
- static const char *proc_stat_path = "/proc/%d/stat";
- pid_t tid = thread->osthread()->thread_id();
- int i;
- char *s;
- char stat[2048];
- int statlen;
- char proc_name[64];
- int count;
- long sys_time, user_time;
- char string[64];
- char cdummy;
- int idummy;
- long ldummy;
- FILE *fp;
-
- // We first try accessing /proc//cpu since this is faster to
- // process. If this file is not present (bsd kernels 2.5 and above)
- // then we open /proc//stat.
- if ( proc_pid_cpu_avail ) {
- sprintf(proc_name, "/proc/%d/cpu", tid);
- fp = fopen(proc_name, "r");
- if ( fp != NULL ) {
- count = fscanf( fp, "%s %lu %lu\n", string, &user_time, &sys_time);
- fclose(fp);
- if ( count != 3 ) return -1;
-
- if (user_sys_cpu_time) {
- return ((jlong)sys_time + (jlong)user_time) * (1000000000 / clock_tics_per_sec);
- } else {
- return (jlong)user_time * (1000000000 / clock_tics_per_sec);
- }
- }
- else proc_pid_cpu_avail = false;
- }
-
- // The /proc//stat aggregates per-process usage on
- // new Bsd kernels 2.6+ where NPTL is supported.
- // The /proc/self/task//stat still has the per-thread usage.
- // See bug 6328462.
- // There can be no directory /proc/self/task on kernels 2.4 with NPTL
- // and possibly in some other cases, so we check its availability.
- if (proc_task_unchecked && os::Bsd::is_NPTL()) {
- // This is executed only once
- proc_task_unchecked = false;
- fp = fopen("/proc/self/task", "r");
- if (fp != NULL) {
- proc_stat_path = "/proc/self/task/%d/stat";
- fclose(fp);
- }
- }
-
- sprintf(proc_name, proc_stat_path, tid);
- fp = fopen(proc_name, "r");
- if ( fp == NULL ) return -1;
- statlen = fread(stat, 1, 2047, fp);
- stat[statlen] = '\0';
- fclose(fp);
-
- // Skip pid and the command string. Note that we could be dealing with
- // weird command names, e.g. user could decide to rename java launcher
- // to "java 1.4.2 :)", then the stat file would look like
- // 1234 (java 1.4.2 :)) R ... ...
- // We don't really need to know the command string, just find the last
- // occurrence of ")" and then start parsing from there. See bug 4726580.
- s = strrchr(stat, ')');
- i = 0;
- if (s == NULL ) return -1;
-
- // Skip blank chars
- do s++; while (isspace(*s));
-
- count = sscanf(s,"%c %d %d %d %d %d %lu %lu %lu %lu %lu %lu %lu",
- &cdummy, &idummy, &idummy, &idummy, &idummy, &idummy,
- &ldummy, &ldummy, &ldummy, &ldummy, &ldummy,
- &user_time, &sys_time);
- if ( count != 13 ) return -1;
- if (user_sys_cpu_time) {
- return ((jlong)sys_time + (jlong)user_time) * (1000000000 / clock_tics_per_sec);
- } else {
- return (jlong)user_time * (1000000000 / clock_tics_per_sec);
- }
-}
-#endif
void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
info_ptr->max_value = ALL_64_BITS; // will not wrap in less than 64 bits
@@ -5236,10 +3940,8 @@
bool os::is_thread_cpu_time_supported() {
#ifdef __APPLE__
return true;
-#elif defined(_ALLBSD_SOURCE)
+#else
return false;
-#else
- return true;
#endif
}
@@ -5392,11 +4094,12 @@
}
-- _nParked ;
- // In theory we could move the ST of 0 into _Event past the unlock(),
- // but then we'd need a MEMBAR after the ST.
_Event = 0 ;
status = pthread_mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
+ // Paranoia to ensure our locked and lock-free paths interact
+ // correctly with each other.
+ OrderAccess::fence();
}
guarantee (_Event >= 0, "invariant") ;
}
@@ -5459,40 +4162,44 @@
status = pthread_mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
assert (_nParked == 0, "invariant") ;
+ // Paranoia to ensure our locked and lock-free paths interact
+ // correctly with each other.
+ OrderAccess::fence();
return ret;
}
void os::PlatformEvent::unpark() {
- int v, AnyWaiters ;
- for (;;) {
- v = _Event ;
- if (v > 0) {
- // The LD of _Event could have reordered or be satisfied
- // by a read-aside from this processor's write buffer.
- // To avoid problems execute a barrier and then
- // ratify the value.
- OrderAccess::fence() ;
- if (_Event == v) return ;
- continue ;
- }
- if (Atomic::cmpxchg (v+1, &_Event, v) == v) break ;
+ // Transitions for _Event:
+ // 0 :=> 1
+ // 1 :=> 1
+ // -1 :=> either 0 or 1; must signal target thread
+ // That is, we can safely transition _Event from -1 to either
+ // 0 or 1. Forcing 1 is slightly more efficient for back-to-back
+ // unpark() calls.
+ // See also: "Semaphores in Plan 9" by Mullender & Cox
+ //
+ // Note: Forcing a transition from "-1" to "1" on an unpark() means
+ // that it will take two back-to-back park() calls for the owning
+ // thread to block. This has the benefit of forcing a spurious return
+ // from the first park() call after an unpark() call which will help
+ // shake out uses of park() and unpark() without condition variables.
+
+ if (Atomic::xchg(1, &_Event) >= 0) return;
+
+ // Wait for the thread associated with the event to vacate
+ int status = pthread_mutex_lock(_mutex);
+ assert_status(status == 0, status, "mutex_lock");
+ int AnyWaiters = _nParked;
+ assert(AnyWaiters == 0 || AnyWaiters == 1, "invariant");
+ if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) {
+ AnyWaiters = 0;
+ pthread_cond_signal(_cond);
}
- if (v < 0) {
- // Wait for the thread associated with the event to vacate
- int status = pthread_mutex_lock(_mutex);
- assert_status(status == 0, status, "mutex_lock");
- AnyWaiters = _nParked ;
- assert (AnyWaiters == 0 || AnyWaiters == 1, "invariant") ;
- if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) {
- AnyWaiters = 0 ;
- pthread_cond_signal (_cond);
- }
- status = pthread_mutex_unlock(_mutex);
- assert_status(status == 0, status, "mutex_unlock");
- if (AnyWaiters != 0) {
- status = pthread_cond_signal(_cond);
- assert_status(status == 0, status, "cond_signal");
- }
+ status = pthread_mutex_unlock(_mutex);
+ assert_status(status == 0, status, "mutex_unlock");
+ if (AnyWaiters != 0) {
+ status = pthread_cond_signal(_cond);
+ assert_status(status == 0, status, "cond_signal");
}
// Note that we signal() _after dropping the lock for "immortal" Events.
@@ -5578,13 +4285,14 @@
}
void Parker::park(bool isAbsolute, jlong time) {
+ // Ideally we'd do something useful while spinning, such
+ // as calling unpackTime().
+
// Optional fast-path check:
// Return immediately if a permit is available.
- if (_counter > 0) {
- _counter = 0 ;
- OrderAccess::fence();
- return ;
- }
+ // We depend on Atomic::xchg() having full barrier semantics
+ // since we are doing a lock-free update to _counter.
+ if (Atomic::xchg(0, &_counter) > 0) return;
Thread* thread = Thread::current();
assert(thread->is_Java_thread(), "Must be JavaThread");
@@ -5625,6 +4333,8 @@
_counter = 0;
status = pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant") ;
+ // Paranoia to ensure our locked and lock-free paths interact
+ // correctly with each other and Java-level accesses.
OrderAccess::fence();
return;
}
@@ -5661,12 +4371,14 @@
_counter = 0 ;
status = pthread_mutex_unlock(_mutex) ;
assert_status(status == 0, status, "invariant") ;
+ // Paranoia to ensure our locked and lock-free paths interact
+ // correctly with each other and Java-level accesses.
+ OrderAccess::fence();
+
// If externally suspended while waiting, re-suspend
if (jt->handle_special_suspend_equivalent_condition()) {
jt->java_suspend_self();
}
-
- OrderAccess::fence();
}
void Parker::unpark() {
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/bsd/vm/os_bsd.hpp
--- a/src/os/bsd/vm/os_bsd.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/bsd/vm/os_bsd.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -56,19 +56,6 @@
static int sigflags[MAXSIGNUM];
static int (*_clock_gettime)(clockid_t, struct timespec *);
-#ifndef _ALLBSD_SOURCE
- static int (*_pthread_getcpuclockid)(pthread_t, clockid_t *);
-
- static address _initial_thread_stack_bottom;
- static uintptr_t _initial_thread_stack_size;
-
- static const char *_glibc_version;
- static const char *_libpthread_version;
-
- static bool _is_floating_stack;
- static bool _is_NPTL;
- static bool _supports_fast_thread_cpu_time;
-#endif
static GrowableArray* _cpu_to_node;
@@ -76,28 +63,14 @@
static julong _physical_memory;
static pthread_t _main_thread;
-#ifndef _ALLBSD_SOURCE
- static Mutex* _createThread_lock;
-#endif
static int _page_size;
static julong available_memory();
static julong physical_memory() { return _physical_memory; }
static void initialize_system_info();
-#ifndef _ALLBSD_SOURCE
- static void set_glibc_version(const char *s) { _glibc_version = s; }
- static void set_libpthread_version(const char *s) { _libpthread_version = s; }
-#endif
-
static bool supports_variable_stack_size();
-#ifndef _ALLBSD_SOURCE
- static void set_is_NPTL() { _is_NPTL = true; }
- static void set_is_BsdThreads() { _is_NPTL = false; }
- static void set_is_floating_stack() { _is_floating_stack = true; }
-#endif
-
static void rebuild_cpu_to_node_map();
static GrowableArray* cpu_to_node() { return _cpu_to_node; }
@@ -106,25 +79,10 @@
public:
static void init_thread_fpu_state();
-#ifndef _ALLBSD_SOURCE
- static int get_fpu_control_word();
- static void set_fpu_control_word(int fpu_control);
-#endif
static pthread_t main_thread(void) { return _main_thread; }
-#ifndef _ALLBSD_SOURCE
- // returns kernel thread id (similar to LWP id on Solaris), which can be
- // used to access /proc
- static pid_t gettid();
- static void set_createThread_lock(Mutex* lk) { _createThread_lock = lk; }
- static Mutex* createThread_lock(void) { return _createThread_lock; }
-#endif
static void hotspot_sigmask(Thread* thread);
-#ifndef _ALLBSD_SOURCE
- static address initial_thread_stack_bottom(void) { return _initial_thread_stack_bottom; }
- static uintptr_t initial_thread_stack_size(void) { return _initial_thread_stack_size; }
-#endif
static bool is_initial_thread(void);
static int page_size(void) { return _page_size; }
@@ -161,23 +119,6 @@
static struct sigaction *get_chained_signal_action(int sig);
static bool chained_handler(int sig, siginfo_t* siginfo, void* context);
-#ifndef _ALLBSD_SOURCE
- // GNU libc and libpthread version strings
- static const char *glibc_version() { return _glibc_version; }
- static const char *libpthread_version() { return _libpthread_version; }
-
- // NPTL or BsdThreads?
- static bool is_BsdThreads() { return !_is_NPTL; }
- static bool is_NPTL() { return _is_NPTL; }
-
- // NPTL is always floating stack. BsdThreads could be using floating
- // stack or fixed stack.
- static bool is_floating_stack() { return _is_floating_stack; }
-
- static void libpthread_init();
- static bool libnuma_init();
- static void* libnuma_dlsym(void* handle, const char* name);
-#endif
// Minimum stack size a thread can be created with (allowing
// the VM to completely create the thread and enter user code)
static size_t min_stack_allowed;
@@ -186,22 +127,9 @@
static size_t default_stack_size(os::ThreadType thr_type);
static size_t default_guard_size(os::ThreadType thr_type);
-#ifndef _ALLBSD_SOURCE
- static void capture_initial_stack(size_t max_size);
-
- // Stack overflow handling
- static bool manually_expand_stack(JavaThread * t, address addr);
- static int max_register_window_saves_before_flushing();
-#endif
-
// Real-time clock functions
static void clock_init(void);
-#ifndef _ALLBSD_SOURCE
- // fast POSIX clocks support
- static void fast_thread_clock_init(void);
-#endif
-
static inline bool supports_monotonic_clock() {
return _clock_gettime != NULL;
}
@@ -210,18 +138,6 @@
return _clock_gettime ? _clock_gettime(clock_id, tp) : -1;
}
-#ifndef _ALLBSD_SOURCE
- static int pthread_getcpuclockid(pthread_t tid, clockid_t *clock_id) {
- return _pthread_getcpuclockid ? _pthread_getcpuclockid(tid, clock_id) : -1;
- }
-
- static bool supports_fast_thread_cpu_time() {
- return _supports_fast_thread_cpu_time;
- }
-
- static jlong fast_thread_cpu_time(clockid_t clockid);
-#endif
-
// Stack repair handling
// none present
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/bsd/vm/os_bsd.inline.hpp
--- a/src/os/bsd/vm/os_bsd.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/bsd/vm/os_bsd.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,13 +26,13 @@
#define OS_BSD_VM_OS_BSD_INLINE_HPP
#include "runtime/atomic.hpp"
+#include "runtime/atomic.inline.hpp"
#include "runtime/os.hpp"
+
#ifdef TARGET_OS_ARCH_bsd_x86
-# include "atomic_bsd_x86.inline.hpp"
# include "orderAccess_bsd_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_bsd_zero
-# include "atomic_bsd_zero.inline.hpp"
# include "orderAccess_bsd_zero.inline.hpp"
#endif
@@ -59,14 +59,6 @@
return ":";
}
-inline const char* os::jlong_format_specifier() {
- return "%lld";
-}
-
-inline const char* os::julong_format_specifier() {
- return "%llu";
-}
-
// File names are case-sensitive on windows only
inline int os::file_name_strcmp(const char* s1, const char* s2) {
return strcmp(s1, s2);
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/bsd/vm/perfMemory_bsd.cpp
--- a/src/os/bsd/vm/perfMemory_bsd.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/bsd/vm/perfMemory_bsd.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -30,6 +30,7 @@
#include "os_bsd.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/perfMemory.hpp"
+#include "services/memTracker.hpp"
#include "utilities/exceptions.hpp"
// put OS-includes here
@@ -753,6 +754,10 @@
// clear the shared memory region
(void)::memset((void*) mapAddress, 0, size);
+ // it does not go through os api, the operation has to record from here
+ MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC);
+ MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal);
+
return mapAddress;
}
@@ -912,6 +917,10 @@
"Could not map PerfMemory");
}
+ // it does not go through os api, the operation has to record from here
+ MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC);
+ MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal);
+
*addr = mapAddress;
*sizep = size;
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/bsd/vm/threadCritical_bsd.cpp
--- a/src/os/bsd/vm/threadCritical_bsd.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/bsd/vm/threadCritical_bsd.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/threadCritical.hpp"
-#include "thread_bsd.inline.hpp"
// put OS-includes here
# include
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/bsd/vm/thread_bsd.inline.hpp
--- a/src/os/bsd/vm/thread_bsd.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/bsd/vm/thread_bsd.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,6 +25,10 @@
#ifndef OS_BSD_VM_THREAD_BSD_INLINE_HPP
#define OS_BSD_VM_THREAD_BSD_INLINE_HPP
+#ifndef SHARE_VM_RUNTIME_THREAD_INLINE_HPP_SCOPE
+#error "This file should only be included from thread.inline.hpp"
+#endif
+
#include "runtime/atomic.hpp"
#include "runtime/prefetch.hpp"
#include "runtime/thread.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/linux/vm/mutex_linux.cpp
--- a/src/os/linux/vm/mutex_linux.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/linux/vm/mutex_linux.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -26,7 +26,7 @@
#include "mutex_linux.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/mutex.hpp"
-#include "thread_linux.inline.hpp"
+#include "runtime/thread.inline.hpp"
#include "utilities/events.hpp"
// put OS-includes here
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/linux/vm/mutex_linux.inline.hpp
--- a/src/os/linux/vm/mutex_linux.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/linux/vm/mutex_linux.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -27,7 +27,7 @@
#include "os_linux.inline.hpp"
#include "runtime/interfaceSupport.hpp"
-#include "thread_linux.inline.hpp"
+#include "runtime/thread.inline.hpp"
// Reconciliation History
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/linux/vm/osThread_linux.cpp
--- a/src/os/linux/vm/osThread_linux.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/linux/vm/osThread_linux.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,29 +23,10 @@
*/
// no precompiled headers
-#include "runtime/atomic.hpp"
-#include "runtime/handles.inline.hpp"
-#include "runtime/mutexLocker.hpp"
-#include "runtime/os.hpp"
+#include "runtime/mutex.hpp"
#include "runtime/osThread.hpp"
-#include "runtime/safepoint.hpp"
-#include "runtime/vmThread.hpp"
-#ifdef TARGET_ARCH_x86
-# include "assembler_x86.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_sparc
-# include "assembler_sparc.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_zero
-# include "assembler_zero.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_arm
-# include "assembler_arm.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_ppc
-# include "assembler_ppc.inline.hpp"
-#endif
+#include
void OSThread::pd_initialize() {
assert(this != NULL, "check");
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/linux/vm/os_linux.cpp
--- a/src/os/linux/vm/os_linux.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/linux/vm/os_linux.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "compiler/compileBroker.hpp"
+#include "compiler/disassembler.hpp"
#include "interpreter/interpreter.hpp"
#include "jvm_linux.h"
#include "memory/allocation.inline.hpp"
@@ -52,36 +53,16 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/statSampler.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/threadCritical.hpp"
#include "runtime/timer.hpp"
#include "services/attachListener.hpp"
#include "services/runtimeService.hpp"
-#include "thread_linux.inline.hpp"
#include "utilities/decoder.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/events.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/vmError.hpp"
-#ifdef TARGET_ARCH_x86
-# include "assembler_x86.inline.hpp"
-# include "nativeInst_x86.hpp"
-#endif
-#ifdef TARGET_ARCH_sparc
-# include "assembler_sparc.inline.hpp"
-# include "nativeInst_sparc.hpp"
-#endif
-#ifdef TARGET_ARCH_zero
-# include "assembler_zero.inline.hpp"
-# include "nativeInst_zero.hpp"
-#endif
-#ifdef TARGET_ARCH_arm
-# include "assembler_arm.inline.hpp"
-# include "nativeInst_arm.hpp"
-#endif
-#ifdef TARGET_ARCH_ppc
-# include "assembler_ppc.inline.hpp"
-# include "nativeInst_ppc.hpp"
-#endif
// put OS-includes here
# include
@@ -340,12 +321,12 @@
// The next steps are taken in the product version:
//
- // Obtain the JAVA_HOME value from the location of libjvm[_g].so.
+ // Obtain the JAVA_HOME value from the location of libjvm.so.
// This library should be located at:
- // /jre/lib//{client|server}/libjvm[_g].so.
+ // /jre/lib//{client|server}/libjvm.so.
//
// If "/jre/lib/" appears at the right place in the path, then we
- // assume libjvm[_g].so is installed in a JDK and we use this path.
+ // assume libjvm.so is installed in a JDK and we use this path.
//
// Otherwise exit with message: "Could not create the Java virtual machine."
//
@@ -355,9 +336,9 @@
// instead of exit check for $JAVA_HOME environment variable.
//
// If it is defined and we are able to locate $JAVA_HOME/jre/lib/,
- // then we append a fake suffix "hotspot/libjvm[_g].so" to this path so
- // it looks like libjvm[_g].so is installed there
- // /jre/lib//hotspot/libjvm[_g].so.
+ // then we append a fake suffix "hotspot/libjvm.so" to this path so
+ // it looks like libjvm.so is installed there
+ // /jre/lib//hotspot/libjvm.so.
//
// Otherwise exit.
//
@@ -1650,19 +1631,20 @@
return os::stat(filename, &statbuf) == 0;
}
-void os::dll_build_name(char* buffer, size_t buflen,
+bool os::dll_build_name(char* buffer, size_t buflen,
const char* pname, const char* fname) {
+ bool retval = false;
// Copied from libhpi
const size_t pnamelen = pname ? strlen(pname) : 0;
- // Quietly truncate on buffer overflow. Should be an error.
+ // Return error on buffer overflow.
if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
- *buffer = '\0';
- return;
+ return retval;
}
if (pnamelen == 0) {
snprintf(buffer, buflen, "lib%s.so", fname);
+ retval = true;
} else if (strchr(pname, *os::path_separator()) != NULL) {
int n;
char** pelements = split_path(pname, &n);
@@ -1673,6 +1655,7 @@
}
snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
if (file_exists(buffer)) {
+ retval = true;
break;
}
}
@@ -1687,14 +1670,16 @@
}
} else {
snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
- }
+ retval = true;
+ }
+ return retval;
}
const char* os::get_current_directory(char *buf, int buflen) {
return getcwd(buf, buflen);
}
-// check if addr is inside libjvm[_g].so
+// check if addr is inside libjvm.so
bool os::address_is_in_vm(address addr) {
static address libjvm_base_addr;
Dl_info dlinfo;
@@ -2195,7 +2180,7 @@
static char saved_jvm_path[MAXPATHLEN] = {0};
-// Find the full path to the current module, libjvm.so or libjvm_g.so
+// Find the full path to the current module, libjvm.so
void os::jvm_path(char *buf, jint buflen) {
// Error checking.
if (buflen < MAXPATHLEN) {
@@ -2238,10 +2223,9 @@
char* jrelib_p;
int len;
- // Check the current module name "libjvm.so" or "libjvm_g.so".
+ // Check the current module name "libjvm.so".
p = strrchr(buf, '/');
assert(strstr(p, "/libjvm") == p, "invalid library name");
- p = strstr(p, "_g") ? "_g" : "";
rp = realpath(java_home_var, buf);
if (rp == NULL)
@@ -2257,11 +2241,9 @@
}
if (0 == access(buf, F_OK)) {
- // Use current module name "libjvm[_g].so" instead of
- // "libjvm"debug_only("_g")".so" since for fastdebug version
- // we should have "libjvm.so" but debug_only("_g") adds "_g"!
+ // Use current module name "libjvm.so"
len = strlen(buf);
- snprintf(buf + len, buflen-len, "/hotspot/libjvm%s.so", p);
+ snprintf(buf + len, buflen-len, "/hotspot/libjvm.so");
} else {
// Go back to path of .so
rp = realpath(dli_fname, buf);
@@ -5019,11 +5001,12 @@
}
-- _nParked ;
- // In theory we could move the ST of 0 into _Event past the unlock(),
- // but then we'd need a MEMBAR after the ST.
_Event = 0 ;
status = pthread_mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
+ // Paranoia to ensure our locked and lock-free paths interact
+ // correctly with each other.
+ OrderAccess::fence();
}
guarantee (_Event >= 0, "invariant") ;
}
@@ -5086,40 +5069,44 @@
status = pthread_mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
assert (_nParked == 0, "invariant") ;
+ // Paranoia to ensure our locked and lock-free paths interact
+ // correctly with each other.
+ OrderAccess::fence();
return ret;
}
void os::PlatformEvent::unpark() {
- int v, AnyWaiters ;
- for (;;) {
- v = _Event ;
- if (v > 0) {
- // The LD of _Event could have reordered or be satisfied
- // by a read-aside from this processor's write buffer.
- // To avoid problems execute a barrier and then
- // ratify the value.
- OrderAccess::fence() ;
- if (_Event == v) return ;
- continue ;
- }
- if (Atomic::cmpxchg (v+1, &_Event, v) == v) break ;
- }
- if (v < 0) {
- // Wait for the thread associated with the event to vacate
- int status = pthread_mutex_lock(_mutex);
- assert_status(status == 0, status, "mutex_lock");
- AnyWaiters = _nParked ;
- assert (AnyWaiters == 0 || AnyWaiters == 1, "invariant") ;
- if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) {
- AnyWaiters = 0 ;
- pthread_cond_signal (_cond);
- }
- status = pthread_mutex_unlock(_mutex);
- assert_status(status == 0, status, "mutex_unlock");
- if (AnyWaiters != 0) {
- status = pthread_cond_signal(_cond);
- assert_status(status == 0, status, "cond_signal");
- }
+ // Transitions for _Event:
+ // 0 :=> 1
+ // 1 :=> 1
+ // -1 :=> either 0 or 1; must signal target thread
+ // That is, we can safely transition _Event from -1 to either
+ // 0 or 1. Forcing 1 is slightly more efficient for back-to-back
+ // unpark() calls.
+ // See also: "Semaphores in Plan 9" by Mullender & Cox
+ //
+ // Note: Forcing a transition from "-1" to "1" on an unpark() means
+ // that it will take two back-to-back park() calls for the owning
+ // thread to block. This has the benefit of forcing a spurious return
+ // from the first park() call after an unpark() call which will help
+ // shake out uses of park() and unpark() without condition variables.
+
+ if (Atomic::xchg(1, &_Event) >= 0) return;
+
+ // Wait for the thread associated with the event to vacate
+ int status = pthread_mutex_lock(_mutex);
+ assert_status(status == 0, status, "mutex_lock");
+ int AnyWaiters = _nParked;
+ assert(AnyWaiters == 0 || AnyWaiters == 1, "invariant");
+ if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) {
+ AnyWaiters = 0;
+ pthread_cond_signal(_cond);
+ }
+ status = pthread_mutex_unlock(_mutex);
+ assert_status(status == 0, status, "mutex_unlock");
+ if (AnyWaiters != 0) {
+ status = pthread_cond_signal(_cond);
+ assert_status(status == 0, status, "cond_signal");
}
// Note that we signal() _after dropping the lock for "immortal" Events.
@@ -5205,13 +5192,14 @@
}
void Parker::park(bool isAbsolute, jlong time) {
+ // Ideally we'd do something useful while spinning, such
+ // as calling unpackTime().
+
// Optional fast-path check:
// Return immediately if a permit is available.
- if (_counter > 0) {
- _counter = 0 ;
- OrderAccess::fence();
- return ;
- }
+ // We depend on Atomic::xchg() having full barrier semantics
+ // since we are doing a lock-free update to _counter.
+ if (Atomic::xchg(0, &_counter) > 0) return;
Thread* thread = Thread::current();
assert(thread->is_Java_thread(), "Must be JavaThread");
@@ -5252,6 +5240,8 @@
_counter = 0;
status = pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant") ;
+ // Paranoia to ensure our locked and lock-free paths interact
+ // correctly with each other and Java-level accesses.
OrderAccess::fence();
return;
}
@@ -5288,12 +5278,14 @@
_counter = 0 ;
status = pthread_mutex_unlock(_mutex) ;
assert_status(status == 0, status, "invariant") ;
+ // Paranoia to ensure our locked and lock-free paths interact
+ // correctly with each other and Java-level accesses.
+ OrderAccess::fence();
+
// If externally suspended while waiting, re-suspend
if (jt->handle_special_suspend_equivalent_condition()) {
jt->java_suspend_self();
}
-
- OrderAccess::fence();
}
void Parker::unpark() {
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/linux/vm/os_linux.inline.hpp
--- a/src/os/linux/vm/os_linux.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/linux/vm/os_linux.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,25 +26,22 @@
#define OS_LINUX_VM_OS_LINUX_INLINE_HPP
#include "runtime/atomic.hpp"
+#include "runtime/atomic.inline.hpp"
#include "runtime/os.hpp"
+
#ifdef TARGET_OS_ARCH_linux_x86
-# include "atomic_linux_x86.inline.hpp"
# include "orderAccess_linux_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_sparc
-# include "atomic_linux_sparc.inline.hpp"
# include "orderAccess_linux_sparc.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_zero
-# include "atomic_linux_zero.inline.hpp"
# include "orderAccess_linux_zero.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_arm
-# include "atomic_linux_arm.inline.hpp"
# include "orderAccess_linux_arm.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_linux_ppc
-# include "atomic_linux_ppc.inline.hpp"
# include "orderAccess_linux_ppc.inline.hpp"
#endif
@@ -71,14 +68,6 @@
return ":";
}
-inline const char* os::jlong_format_specifier() {
- return "%lld";
-}
-
-inline const char* os::julong_format_specifier() {
- return "%llu";
-}
-
// File names are case-sensitive on windows only
inline int os::file_name_strcmp(const char* s1, const char* s2) {
return strcmp(s1, s2);
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/linux/vm/perfMemory_linux.cpp
--- a/src/os/linux/vm/perfMemory_linux.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/linux/vm/perfMemory_linux.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -30,6 +30,7 @@
#include "os_linux.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/perfMemory.hpp"
+#include "services/memTracker.hpp"
#include "utilities/exceptions.hpp"
// put OS-includes here
@@ -753,6 +754,10 @@
// clear the shared memory region
(void)::memset((void*) mapAddress, 0, size);
+ // it does not go through os api, the operation has to record from here
+ MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC);
+ MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal);
+
return mapAddress;
}
@@ -912,6 +917,10 @@
"Could not map PerfMemory");
}
+ // it does not go through os api, the operation has to record from here
+ MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC);
+ MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal);
+
*addr = mapAddress;
*sizep = size;
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/linux/vm/threadCritical_linux.cpp
--- a/src/os/linux/vm/threadCritical_linux.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/linux/vm/threadCritical_linux.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/threadCritical.hpp"
-#include "thread_linux.inline.hpp"
// put OS-includes here
# include
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/linux/vm/thread_linux.inline.hpp
--- a/src/os/linux/vm/thread_linux.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/linux/vm/thread_linux.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,6 +25,10 @@
#ifndef OS_LINUX_VM_THREAD_LINUX_INLINE_HPP
#define OS_LINUX_VM_THREAD_LINUX_INLINE_HPP
+#ifndef SHARE_VM_RUNTIME_THREAD_INLINE_HPP_SCOPE
+#error "This file should only be included from thread.inline.hpp"
+#endif
+
#include "runtime/atomic.hpp"
#include "runtime/prefetch.hpp"
#include "runtime/thread.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/posix/launcher/java_md.c
--- a/src/os/posix/launcher/java_md.c Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/posix/launcher/java_md.c Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1876,11 +1876,6 @@
}
}
-const char *
-jlong_format_specifier() {
- return "%lld";
-}
-
/*
* Block current thread and continue execution in a new thread
*/
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/posix/launcher/java_md.h
--- a/src/os/posix/launcher/java_md.h Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/posix/launcher/java_md.h Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -64,6 +64,12 @@
#define Counter2Micros(counts) (1)
#endif /* HAVE_GETHRTIME */
+#ifdef _LP64
+#define JLONG_FORMAT "%ld"
+#else
+#define JLONG_FORMAT "%lld"
+#endif
+
/*
* Function prototypes.
*/
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/posix/vm/os_posix.cpp
--- a/src/os/posix/vm/os_posix.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/posix/vm/os_posix.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -93,6 +93,47 @@
return;
}
+// Multiple threads can race in this code, and can remap over each other with MAP_FIXED,
+// so on posix, unmap the section at the start and at the end of the chunk that we mapped
+// rather than unmapping and remapping the whole chunk to get requested alignment.
+char* os::reserve_memory_aligned(size_t size, size_t alignment) {
+ assert((alignment & (os::vm_allocation_granularity() - 1)) == 0,
+ "Alignment must be a multiple of allocation granularity (page size)");
+ assert((size & (alignment -1)) == 0, "size must be 'alignment' aligned");
+
+ size_t extra_size = size + alignment;
+ assert(extra_size >= size, "overflow, size is too large to allow alignment");
+
+ char* extra_base = os::reserve_memory(extra_size, NULL, alignment);
+
+ if (extra_base == NULL) {
+ return NULL;
+ }
+
+ // Do manual alignment
+ char* aligned_base = (char*) align_size_up((uintptr_t) extra_base, alignment);
+
+ // [ | | ]
+ // ^ extra_base
+ // ^ extra_base + begin_offset == aligned_base
+ // extra_base + begin_offset + size ^
+ // extra_base + extra_size ^
+ // |<>| == begin_offset
+ // end_offset == |<>|
+ size_t begin_offset = aligned_base - extra_base;
+ size_t end_offset = (extra_base + extra_size) - (aligned_base + size);
+
+ if (begin_offset > 0) {
+ os::release_memory(extra_base, begin_offset);
+ }
+
+ if (end_offset > 0) {
+ os::release_memory(extra_base + begin_offset + size, end_offset);
+ }
+
+ return aligned_base;
+}
+
void os::Posix::print_load_average(outputStream* st) {
st->print("load average:");
double loadavg[3];
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/solaris/vm/mutex_solaris.cpp
--- a/src/os/solaris/vm/mutex_solaris.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/solaris/vm/mutex_solaris.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -26,7 +26,7 @@
#include "mutex_solaris.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/mutex.hpp"
-#include "thread_solaris.inline.hpp"
+#include "runtime/thread.inline.hpp"
#include "utilities/events.hpp"
// Solaris-specific include, therefore not in includeDB_*
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/solaris/vm/mutex_solaris.inline.hpp
--- a/src/os/solaris/vm/mutex_solaris.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/solaris/vm/mutex_solaris.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -27,6 +27,6 @@
#include "os_solaris.inline.hpp"
#include "runtime/interfaceSupport.hpp"
-#include "thread_solaris.inline.hpp"
+#include "runtime/thread.inline.hpp"
#endif // OS_SOLARIS_VM_MUTEX_SOLARIS_INLINE_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/solaris/vm/osThread_solaris.cpp
--- a/src/os/solaris/vm/osThread_solaris.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/solaris/vm/osThread_solaris.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -30,14 +30,8 @@
#include "runtime/osThread.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/vmThread.hpp"
-#ifdef TARGET_ARCH_x86
-# include "assembler_x86.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_sparc
-# include "assembler_sparc.inline.hpp"
-#endif
-# include
+#include
// ***************************************************************
// Platform dependent initialization and cleanup
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/solaris/vm/os_solaris.cpp
--- a/src/os/solaris/vm/os_solaris.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/solaris/vm/os_solaris.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "compiler/compileBroker.hpp"
+#include "compiler/disassembler.hpp"
#include "interpreter/interpreter.hpp"
#include "jvm_solaris.h"
#include "memory/allocation.inline.hpp"
@@ -52,24 +53,17 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/statSampler.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/threadCritical.hpp"
#include "runtime/timer.hpp"
#include "services/attachListener.hpp"
+#include "services/memTracker.hpp"
#include "services/runtimeService.hpp"
-#include "thread_solaris.inline.hpp"
#include "utilities/decoder.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/events.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/vmError.hpp"
-#ifdef TARGET_ARCH_x86
-# include "assembler_x86.inline.hpp"
-# include "nativeInst_x86.hpp"
-#endif
-#ifdef TARGET_ARCH_sparc
-# include "assembler_sparc.inline.hpp"
-# include "nativeInst_sparc.hpp"
-#endif
// put OS-includes here
# include
@@ -740,12 +734,12 @@
// The next steps are taken in the product version:
//
- // Obtain the JAVA_HOME value from the location of libjvm[_g].so.
+ // Obtain the JAVA_HOME value from the location of libjvm.so.
// This library should be located at:
- // /jre/lib//{client|server}/libjvm[_g].so.
+ // /jre/lib//{client|server}/libjvm.so.
//
// If "/jre/lib/" appears at the right place in the path, then we
- // assume libjvm[_g].so is installed in a JDK and we use this path.
+ // assume libjvm.so is installed in a JDK and we use this path.
//
// Otherwise exit with message: "Could not create the Java virtual machine."
//
@@ -755,9 +749,9 @@
// instead of exit check for $JAVA_HOME environment variable.
//
// If it is defined and we are able to locate $JAVA_HOME/jre/lib/,
- // then we append a fake suffix "hotspot/libjvm[_g].so" to this path so
- // it looks like libjvm[_g].so is installed there
- // /jre/lib//hotspot/libjvm[_g].so.
+ // then we append a fake suffix "hotspot/libjvm.so" to this path so
+ // it looks like libjvm.so is installed there
+ // /jre/lib//hotspot/libjvm.so.
//
// Otherwise exit.
//
@@ -1893,18 +1887,19 @@
return os::stat(filename, &statbuf) == 0;
}
-void os::dll_build_name(char* buffer, size_t buflen,
+bool os::dll_build_name(char* buffer, size_t buflen,
const char* pname, const char* fname) {
+ bool retval = false;
const size_t pnamelen = pname ? strlen(pname) : 0;
- // Quietly truncate on buffer overflow. Should be an error.
+ // Return error on buffer overflow.
if (pnamelen + strlen(fname) + 10 > (size_t) buflen) {
- *buffer = '\0';
- return;
+ return retval;
}
if (pnamelen == 0) {
snprintf(buffer, buflen, "lib%s.so", fname);
+ retval = true;
} else if (strchr(pname, *os::path_separator()) != NULL) {
int n;
char** pelements = split_path(pname, &n);
@@ -1915,6 +1910,7 @@
}
snprintf(buffer, buflen, "%s/lib%s.so", pelements[i], fname);
if (file_exists(buffer)) {
+ retval = true;
break;
}
}
@@ -1929,14 +1925,16 @@
}
} else {
snprintf(buffer, buflen, "%s/lib%s.so", pname, fname);
- }
+ retval = true;
+ }
+ return retval;
}
const char* os::get_current_directory(char *buf, int buflen) {
return getcwd(buf, buflen);
}
-// check if addr is inside libjvm[_g].so
+// check if addr is inside libjvm.so
bool os::address_is_in_vm(address addr) {
static address libjvm_base_addr;
Dl_info dlinfo;
@@ -2476,7 +2474,7 @@
static char saved_jvm_path[MAXPATHLEN] = { 0 };
-// Find the full path to the current module, libjvm.so or libjvm_g.so
+// Find the full path to the current module, libjvm.so
void os::jvm_path(char *buf, jint buflen) {
// Error checking.
if (buflen < MAXPATHLEN) {
@@ -2524,10 +2522,9 @@
strcpy(cpu_arch, "amd64");
}
#endif
- // Check the current module name "libjvm.so" or "libjvm_g.so".
+ // Check the current module name "libjvm.so".
p = strrchr(buf, '/');
assert(strstr(p, "/libjvm") == p, "invalid library name");
- p = strstr(p, "_g") ? "_g" : "";
realpath(java_home_var, buf);
// determine if this is a legacy image or modules image
@@ -2540,11 +2537,9 @@
}
if (0 == access(buf, F_OK)) {
- // Use current module name "libjvm[_g].so" instead of
- // "libjvm"debug_only("_g")".so" since for fastdebug version
- // we should have "libjvm.so" but debug_only("_g") adds "_g"!
+ // Use current module name "libjvm.so"
len = strlen(buf);
- snprintf(buf + len, buflen-len, "/hotspot/libjvm%s.so", p);
+ snprintf(buf + len, buflen-len, "/hotspot/libjvm.so");
} else {
// Go back to path of .so
realpath((char *)dlinfo.dli_fname, buf);
@@ -3072,11 +3067,12 @@
// Since snv_84, Solaris attempts to honor the address hint - see 5003415.
// Give it a try, if the kernel honors the hint we can return immediately.
char* addr = Solaris::anon_mmap(requested_addr, bytes, 0, false);
+
volatile int err = errno;
if (addr == requested_addr) {
return addr;
} else if (addr != NULL) {
- unmap_memory(addr, bytes);
+ pd_unmap_memory(addr, bytes);
}
if (PrintMiscellaneous && Verbose) {
@@ -6018,6 +6014,9 @@
_Event = 0 ;
status = os::Solaris::mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
+ // Paranoia to ensure our locked and lock-free paths interact
+ // correctly with each other.
+ OrderAccess::fence();
}
}
@@ -6059,51 +6058,43 @@
_Event = 0 ;
status = os::Solaris::mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock");
+ // Paranoia to ensure our locked and lock-free paths interact
+ // correctly with each other.
+ OrderAccess::fence();
return ret;
}
void os::PlatformEvent::unpark() {
- int v, AnyWaiters;
-
- // Increment _Event.
- // Another acceptable implementation would be to simply swap 1
- // into _Event:
- // if (Swap (&_Event, 1) < 0) {
- // mutex_lock (_mutex) ; AnyWaiters = nParked; mutex_unlock (_mutex) ;
- // if (AnyWaiters) cond_signal (_cond) ;
- // }
-
- for (;;) {
- v = _Event ;
- if (v > 0) {
- // The LD of _Event could have reordered or be satisfied
- // by a read-aside from this processor's write buffer.
- // To avoid problems execute a barrier and then
- // ratify the value. A degenerate CAS() would also work.
- // Viz., CAS (v+0, &_Event, v) == v).
- OrderAccess::fence() ;
- if (_Event == v) return ;
- continue ;
- }
- if (Atomic::cmpxchg (v+1, &_Event, v) == v) break ;
- }
+ // Transitions for _Event:
+ // 0 :=> 1
+ // 1 :=> 1
+ // -1 :=> either 0 or 1; must signal target thread
+ // That is, we can safely transition _Event from -1 to either
+ // 0 or 1. Forcing 1 is slightly more efficient for back-to-back
+ // unpark() calls.
+ // See also: "Semaphores in Plan 9" by Mullender & Cox
+ //
+ // Note: Forcing a transition from "-1" to "1" on an unpark() means
+ // that it will take two back-to-back park() calls for the owning
+ // thread to block. This has the benefit of forcing a spurious return
+ // from the first park() call after an unpark() call which will help
+ // shake out uses of park() and unpark() without condition variables.
+
+ if (Atomic::xchg(1, &_Event) >= 0) return;
// If the thread associated with the event was parked, wake it.
- if (v < 0) {
- int status ;
- // Wait for the thread assoc with the PlatformEvent to vacate.
- status = os::Solaris::mutex_lock(_mutex);
- assert_status(status == 0, status, "mutex_lock");
- AnyWaiters = _nParked ;
- status = os::Solaris::mutex_unlock(_mutex);
- assert_status(status == 0, status, "mutex_unlock");
- guarantee (AnyWaiters == 0 || AnyWaiters == 1, "invariant") ;
- if (AnyWaiters != 0) {
- // We intentional signal *after* dropping the lock
- // to avoid a common class of futile wakeups.
- status = os::Solaris::cond_signal(_cond);
- assert_status(status == 0, status, "cond_signal");
- }
+ // Wait for the thread assoc with the PlatformEvent to vacate.
+ int status = os::Solaris::mutex_lock(_mutex);
+ assert_status(status == 0, status, "mutex_lock");
+ int AnyWaiters = _nParked;
+ status = os::Solaris::mutex_unlock(_mutex);
+ assert_status(status == 0, status, "mutex_unlock");
+ guarantee(AnyWaiters == 0 || AnyWaiters == 1, "invariant");
+ if (AnyWaiters != 0) {
+ // We intentional signal *after* dropping the lock
+ // to avoid a common class of futile wakeups.
+ status = os::Solaris::cond_signal(_cond);
+ assert_status(status == 0, status, "cond_signal");
}
}
@@ -6181,14 +6172,14 @@
}
void Parker::park(bool isAbsolute, jlong time) {
+ // Ideally we'd do something useful while spinning, such
+ // as calling unpackTime().
// Optional fast-path check:
// Return immediately if a permit is available.
- if (_counter > 0) {
- _counter = 0 ;
- OrderAccess::fence();
- return ;
- }
+ // We depend on Atomic::xchg() having full barrier semantics
+ // since we are doing a lock-free update to _counter.
+ if (Atomic::xchg(0, &_counter) > 0) return;
// Optional fast-exit: Check interrupt before trying to wait
Thread* thread = Thread::current();
@@ -6230,6 +6221,8 @@
_counter = 0;
status = os::Solaris::mutex_unlock(_mutex);
assert (status == 0, "invariant") ;
+ // Paranoia to ensure our locked and lock-free paths interact
+ // correctly with each other and Java-level accesses.
OrderAccess::fence();
return;
}
@@ -6271,12 +6264,14 @@
_counter = 0 ;
status = os::Solaris::mutex_unlock(_mutex);
assert_status(status == 0, status, "mutex_unlock") ;
+ // Paranoia to ensure our locked and lock-free paths interact
+ // correctly with each other and Java-level accesses.
+ OrderAccess::fence();
// If externally suspended while waiting, re-suspend
if (jt->handle_special_suspend_equivalent_condition()) {
jt->java_suspend_self();
}
- OrderAccess::fence();
}
void Parker::unpark() {
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/solaris/vm/os_solaris.inline.hpp
--- a/src/os/solaris/vm/os_solaris.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/solaris/vm/os_solaris.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,13 +26,13 @@
#define OS_SOLARIS_VM_OS_SOLARIS_INLINE_HPP
#include "runtime/atomic.hpp"
+#include "runtime/atomic.inline.hpp"
#include "runtime/os.hpp"
+
#ifdef TARGET_OS_ARCH_solaris_x86
-# include "atomic_solaris_x86.inline.hpp"
# include "orderAccess_solaris_x86.inline.hpp"
#endif
#ifdef TARGET_OS_ARCH_solaris_sparc
-# include "atomic_solaris_sparc.inline.hpp"
# include "orderAccess_solaris_sparc.inline.hpp"
#endif
@@ -50,9 +50,6 @@
inline const char* os::line_separator() { return "\n"; }
inline const char* os::path_separator() { return ":"; }
-inline const char* os::jlong_format_specifier() { return "%lld"; }
-inline const char* os::julong_format_specifier() { return "%llu"; }
-
// File names are case-sensitive on windows only
inline int os::file_name_strcmp(const char* s1, const char* s2) {
return strcmp(s1, s2);
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/solaris/vm/perfMemory_solaris.cpp
--- a/src/os/solaris/vm/perfMemory_solaris.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/solaris/vm/perfMemory_solaris.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -30,6 +30,7 @@
#include "os_solaris.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/perfMemory.hpp"
+#include "services/memTracker.hpp"
#include "utilities/exceptions.hpp"
// put OS-includes here
@@ -768,6 +769,10 @@
// clear the shared memory region
(void)::memset((void*) mapAddress, 0, size);
+ // it does not go through os api, the operation has to record from here
+ MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC);
+ MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal);
+
return mapAddress;
}
@@ -927,6 +932,10 @@
"Could not map PerfMemory");
}
+ // it does not go through os api, the operation has to record from here
+ MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC);
+ MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal);
+
*addr = mapAddress;
*sizep = size;
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/solaris/vm/threadCritical_solaris.cpp
--- a/src/os/solaris/vm/threadCritical_solaris.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/solaris/vm/threadCritical_solaris.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/threadCritical.hpp"
-#include "thread_solaris.inline.hpp"
// OS-includes here
#include
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/solaris/vm/thread_solaris.inline.hpp
--- a/src/os/solaris/vm/thread_solaris.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/solaris/vm/thread_solaris.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,6 +25,10 @@
#ifndef OS_SOLARIS_VM_THREAD_SOLARIS_INLINE_HPP
#define OS_SOLARIS_VM_THREAD_SOLARIS_INLINE_HPP
+#ifndef SHARE_VM_RUNTIME_THREAD_INLINE_HPP_SCOPE
+#error "This file should only be included from thread.inline.hpp"
+#endif
+
#include "runtime/atomic.hpp"
#include "runtime/prefetch.hpp"
#include "runtime/thread.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/windows/launcher/java_md.c
--- a/src/os/windows/launcher/java_md.c Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/windows/launcher/java_md.c Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1323,11 +1323,6 @@
}
}
-const char *
-jlong_format_specifier() {
- return "%I64d";
-}
-
/*
* Block current thread and continue execution in a new thread
*/
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/windows/launcher/java_md.h
--- a/src/os/windows/launcher/java_md.h Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/windows/launcher/java_md.h Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -69,6 +69,8 @@
extern int _main(int argc, char **argv);
#endif
+#define JLONG_FORMAT "%I64d"
+
/*
* Function prototypes.
*/
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/windows/vm/decoder_windows.cpp
--- a/src/os/windows/vm/decoder_windows.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/windows/vm/decoder_windows.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -49,7 +49,7 @@
pfn_SymSetOptions _pfnSymSetOptions = (pfn_SymSetOptions)::GetProcAddress(handle, "SymSetOptions");
pfn_SymInitialize _pfnSymInitialize = (pfn_SymInitialize)::GetProcAddress(handle, "SymInitialize");
_pfnSymGetSymFromAddr64 = (pfn_SymGetSymFromAddr64)::GetProcAddress(handle, "SymGetSymFromAddr64");
- _pfnUndecorateSymbolName = (pfn_UndecorateSymbolName)GetProcAddress(handle, "UnDecorateSymbolName");
+ _pfnUndecorateSymbolName = (pfn_UndecorateSymbolName)::GetProcAddress(handle, "UnDecorateSymbolName");
if (_pfnSymSetOptions == NULL || _pfnSymInitialize == NULL || _pfnSymGetSymFromAddr64 == NULL) {
_pfnSymGetSymFromAddr64 = NULL;
@@ -60,8 +60,9 @@
return;
}
- _pfnSymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);
- if (!_pfnSymInitialize(GetCurrentProcess(), NULL, TRUE)) {
+ HANDLE hProcess = ::GetCurrentProcess();
+ _pfnSymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS);
+ if (!_pfnSymInitialize(hProcess, NULL, TRUE)) {
_pfnSymGetSymFromAddr64 = NULL;
_pfnUndecorateSymbolName = NULL;
::FreeLibrary(handle);
@@ -70,6 +71,77 @@
return;
}
+ // set pdb search paths
+ pfn_SymSetSearchPath _pfn_SymSetSearchPath =
+ (pfn_SymSetSearchPath)::GetProcAddress(handle, "SymSetSearchPath");
+ pfn_SymGetSearchPath _pfn_SymGetSearchPath =
+ (pfn_SymGetSearchPath)::GetProcAddress(handle, "SymGetSearchPath");
+ if (_pfn_SymSetSearchPath != NULL && _pfn_SymGetSearchPath != NULL) {
+ char paths[MAX_PATH];
+ int len = sizeof(paths);
+ if (!_pfn_SymGetSearchPath(hProcess, paths, len)) {
+ paths[0] = '\0';
+ } else {
+ // available spaces in path buffer
+ len -= (int)strlen(paths);
+ }
+
+ char tmp_path[MAX_PATH];
+ DWORD dwSize;
+ HMODULE hJVM = ::GetModuleHandle("jvm.dll");
+ tmp_path[0] = '\0';
+ // append the path where jvm.dll is located
+ if (hJVM != NULL && (dwSize = ::GetModuleFileName(hJVM, tmp_path, sizeof(tmp_path))) > 0) {
+ while (dwSize > 0 && tmp_path[dwSize] != '\\') {
+ dwSize --;
+ }
+
+ tmp_path[dwSize] = '\0';
+
+ if (dwSize > 0 && len > (int)dwSize + 1) {
+ strncat(paths, os::path_separator(), 1);
+ strncat(paths, tmp_path, dwSize);
+ len -= dwSize + 1;
+ }
+ }
+
+ // append $JRE/bin. Arguments::get_java_home actually returns $JRE
+ // path
+ char *p = Arguments::get_java_home();
+ assert(p != NULL, "empty java home");
+ size_t java_home_len = strlen(p);
+ if (len > (int)java_home_len + 5) {
+ strncat(paths, os::path_separator(), 1);
+ strncat(paths, p, java_home_len);
+ strncat(paths, "\\bin", 4);
+ len -= (int)(java_home_len + 5);
+ }
+
+ // append $JDK/bin path if it exists
+ assert(java_home_len < MAX_PATH, "Invalid path length");
+ // assume $JRE is under $JDK, construct $JDK/bin path and
+ // see if it exists or not
+ if (strncmp(&p[java_home_len - 3], "jre", 3) == 0) {
+ strncpy(tmp_path, p, java_home_len - 3);
+ tmp_path[java_home_len - 3] = '\0';
+ strncat(tmp_path, "bin", 3);
+
+ // if the directory exists
+ DWORD dwAttrib = GetFileAttributes(tmp_path);
+ if (dwAttrib != INVALID_FILE_ATTRIBUTES &&
+ (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) {
+ // tmp_path should have the same length as java_home_len, since we only
+ // replaced 'jre' with 'bin'
+ if (len > (int)java_home_len + 1) {
+ strncat(paths, os::path_separator(), 1);
+ strncat(paths, tmp_path, java_home_len);
+ }
+ }
+ }
+
+ _pfn_SymSetSearchPath(hProcess, paths);
+ }
+
// find out if jvm.dll contains private symbols, by decoding
// current function and comparing the result
address addr = (address)Decoder::demangle;
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/windows/vm/decoder_windows.hpp
--- a/src/os/windows/vm/decoder_windows.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/windows/vm/decoder_windows.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -35,6 +35,8 @@
typedef BOOL (WINAPI *pfn_SymInitialize)(HANDLE, PCTSTR, BOOL);
typedef BOOL (WINAPI *pfn_SymGetSymFromAddr64)(HANDLE, DWORD64, PDWORD64, PIMAGEHLP_SYMBOL64);
typedef DWORD (WINAPI *pfn_UndecorateSymbolName)(const char*, char*, DWORD, DWORD);
+typedef BOOL (WINAPI *pfn_SymSetSearchPath)(HANDLE, PCTSTR);
+typedef BOOL (WINAPI *pfn_SymGetSearchPath)(HANDLE, PTSTR, int);
class WindowsDecoder : public AbstractDecoder {
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/windows/vm/mutex_windows.cpp
--- a/src/os/windows/vm/mutex_windows.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/windows/vm/mutex_windows.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -26,7 +26,7 @@
#include "mutex_windows.inline.hpp"
#include "runtime/interfaceSupport.hpp"
#include "runtime/mutex.hpp"
-#include "thread_windows.inline.hpp"
+#include "runtime/thread.inline.hpp"
#include "utilities/events.hpp"
// put OS-includes here
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/windows/vm/mutex_windows.inline.hpp
--- a/src/os/windows/vm/mutex_windows.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/windows/vm/mutex_windows.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -27,6 +27,6 @@
#include "os_windows.inline.hpp"
#include "runtime/interfaceSupport.hpp"
-#include "thread_windows.inline.hpp"
+#include "runtime/thread.inline.hpp"
#endif // OS_WINDOWS_VM_MUTEX_WINDOWS_INLINE_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/windows/vm/osThread_windows.cpp
--- a/src/os/windows/vm/osThread_windows.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/windows/vm/osThread_windows.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -30,9 +30,6 @@
#include "runtime/osThread.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/vmThread.hpp"
-#ifdef TARGET_ARCH_x86
-# include "assembler_x86.inline.hpp"
-#endif
void OSThread::pd_initialize() {
set_thread_handle(NULL);
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/windows/vm/os_windows.cpp
--- a/src/os/windows/vm/os_windows.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/windows/vm/os_windows.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,7 +22,7 @@
*
*/
-// Must be at least Windows 2000 or XP to use VectoredExceptions and IsDebuggerPresent
+// Must be at least Windows 2000 or XP to use IsDebuggerPresent
#define _WIN32_WINNT 0x500
// no precompiled headers
@@ -32,6 +32,7 @@
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "compiler/compileBroker.hpp"
+#include "compiler/disassembler.hpp"
#include "interpreter/interpreter.hpp"
#include "jvm_windows.h"
#include "memory/allocation.inline.hpp"
@@ -55,20 +56,16 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/statSampler.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/threadCritical.hpp"
#include "runtime/timer.hpp"
#include "services/attachListener.hpp"
#include "services/runtimeService.hpp"
-#include "thread_windows.inline.hpp"
#include "utilities/decoder.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/events.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/vmError.hpp"
-#ifdef TARGET_ARCH_x86
-# include "assembler_x86.inline.hpp"
-# include "nativeInst_x86.hpp"
-#endif
#ifdef _DEBUG
#include
@@ -110,10 +107,6 @@
static FILETIME process_user_time;
static FILETIME process_kernel_time;
-#ifdef _WIN64
-PVOID topLevelVectoredExceptionHandler = NULL;
-#endif
-
#ifdef _M_IA64
#define __CPU__ ia64
#elif _M_AMD64
@@ -136,12 +129,6 @@
case DLL_PROCESS_DETACH:
if(ForceTimeHighResolution)
timeEndPeriod(1L);
-#ifdef _WIN64
- if (topLevelVectoredExceptionHandler != NULL) {
- RemoveVectoredExceptionHandler(topLevelVectoredExceptionHandler);
- topLevelVectoredExceptionHandler = NULL;
- }
-#endif
break;
default:
break;
@@ -195,7 +182,7 @@
if (!getenv("_ALT_JAVA_HOME_DIR", home_dir, MAX_PATH)) {
os::jvm_path(home_dir, sizeof(home_dir));
- // Found the full path to jvm[_g].dll.
+ // Found the full path to jvm.dll.
// Now cut the path to /jre if we can.
*(strrchr(home_dir, '\\')) = '\0'; /* get rid of \jvm.dll */
pslash = strrchr(home_dir, '\\');
@@ -408,20 +395,14 @@
}
- if (UseVectoredExceptions) {
- // If we are using vectored exception we don't need to set a SEH
- thread->run();
- }
- else {
- // Install a win32 structured exception handler around every thread created
- // by VM, so VM can genrate error dump when an exception occurred in non-
- // Java thread (e.g. VM thread).
- __try {
- thread->run();
- } __except(topLevelExceptionFilter(
- (_EXCEPTION_POINTERS*)_exception_info())) {
- // Nothing to do.
- }
+ // Install a win32 structured exception handler around every thread created
+ // by VM, so VM can genrate error dump when an exception occurred in non-
+ // Java thread (e.g. VM thread).
+ __try {
+ thread->run();
+ } __except(topLevelExceptionFilter(
+ (_EXCEPTION_POINTERS*)_exception_info())) {
+ // Nothing to do.
}
// One less thread is executing
@@ -1148,21 +1129,23 @@
return GetFileAttributes(filename) != INVALID_FILE_ATTRIBUTES;
}
-void os::dll_build_name(char *buffer, size_t buflen,
+bool os::dll_build_name(char *buffer, size_t buflen,
const char* pname, const char* fname) {
+ bool retval = false;
const size_t pnamelen = pname ? strlen(pname) : 0;
const char c = (pnamelen > 0) ? pname[pnamelen-1] : 0;
- // Quietly truncates on buffer overflow. Should be an error.
+ // Return error on buffer overflow.
if (pnamelen + strlen(fname) + 10 > buflen) {
- *buffer = '\0';
- return;
+ return retval;
}
if (pnamelen == 0) {
jio_snprintf(buffer, buflen, "%s.dll", fname);
+ retval = true;
} else if (c == ':' || c == '\\') {
jio_snprintf(buffer, buflen, "%s%s.dll", pname, fname);
+ retval = true;
} else if (strchr(pname, *os::path_separator()) != NULL) {
int n;
char** pelements = split_path(pname, &n);
@@ -1180,6 +1163,7 @@
jio_snprintf(buffer, buflen, "%s\\%s.dll", path, fname);
}
if (file_exists(buffer)) {
+ retval = true;
break;
}
}
@@ -1194,7 +1178,9 @@
}
} else {
jio_snprintf(buffer, buflen, "%s\\%s.dll", pname, fname);
- }
+ retval = true;
+ }
+ return retval;
}
// Needs to be in os specific directory because windows requires another
@@ -1729,7 +1715,7 @@
static char saved_jvm_path[MAX_PATH] = {0};
-// Find the full path to the current module, jvm.dll or jvm_g.dll
+// Find the full path to the current module, jvm.dll
void os::jvm_path(char *buf, jint buflen) {
// Error checking.
if (buflen < MAX_PATH) {
@@ -1888,8 +1874,22 @@
}
return TRUE;
break;
+ case CTRL_LOGOFF_EVENT: {
+ // Don't terminate JVM if it is running in a non-interactive session,
+ // such as a service process.
+ USEROBJECTFLAGS flags;
+ HANDLE handle = GetProcessWindowStation();
+ if (handle != NULL &&
+ GetUserObjectInformation(handle, UOI_FLAGS, &flags,
+ sizeof( USEROBJECTFLAGS), NULL)) {
+ // If it is a non-interactive session, let next handler to deal
+ // with it.
+ if ((flags.dwFlags & WSF_VISIBLE) == 0) {
+ return FALSE;
+ }
+ }
+ }
case CTRL_CLOSE_EVENT:
- case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
os::signal_raise(SIGTERM);
return TRUE;
@@ -2489,16 +2489,6 @@
}
#endif
-#ifdef _WIN64
- // Windows will sometimes generate an access violation
- // when we call malloc. Since we use VectoredExceptions
- // on 64 bit platforms, we see this exception. We must
- // pass this exception on so Windows can recover.
- // We check to see if the pc of the fault is in NTDLL.DLL
- // if so, we pass control on to Windows for handling.
- if (UseVectoredExceptions && _addr_in_ntdll(pc)) return EXCEPTION_CONTINUE_SEARCH;
-#endif
-
// Stack overflow or null pointer exception in native code.
report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord,
exceptionInfo->ContextRecord);
@@ -2527,30 +2517,8 @@
}
if (exception_code != EXCEPTION_BREAKPOINT) {
-#ifndef _WIN64
report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord,
exceptionInfo->ContextRecord);
-#else
- // Itanium Windows uses a VectoredExceptionHandler
- // Which means that C++ programatic exception handlers (try/except)
- // will get here. Continue the search for the right except block if
- // the exception code is not a fatal code.
- switch ( exception_code ) {
- case EXCEPTION_ACCESS_VIOLATION:
- case EXCEPTION_STACK_OVERFLOW:
- case EXCEPTION_ILLEGAL_INSTRUCTION:
- case EXCEPTION_ILLEGAL_INSTRUCTION_2:
- case EXCEPTION_INT_OVERFLOW:
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- case EXCEPTION_UNCAUGHT_CXX_EXCEPTION:
- { report_error(t, exception_code, pc, exceptionInfo->ExceptionRecord,
- exceptionInfo->ContextRecord);
- }
- break;
- default:
- break;
- }
-#endif
}
return EXCEPTION_CONTINUE_SEARCH;
}
@@ -2941,6 +2909,36 @@
}
}
+// Multiple threads can race in this code but it's not possible to unmap small sections of
+// virtual space to get requested alignment, like posix-like os's.
+// Windows prevents multiple thread from remapping over each other so this loop is thread-safe.
+char* os::reserve_memory_aligned(size_t size, size_t alignment) {
+ assert((alignment & (os::vm_allocation_granularity() - 1)) == 0,
+ "Alignment must be a multiple of allocation granularity (page size)");
+ assert((size & (alignment -1)) == 0, "size must be 'alignment' aligned");
+
+ size_t extra_size = size + alignment;
+ assert(extra_size >= size, "overflow, size is too large to allow alignment");
+
+ char* aligned_base = NULL;
+
+ do {
+ char* extra_base = os::reserve_memory(extra_size, NULL, alignment);
+ if (extra_base == NULL) {
+ return NULL;
+ }
+ // Do manual alignment
+ aligned_base = (char*) align_size_up((uintptr_t) extra_base, alignment);
+
+ os::release_memory(extra_base, extra_size);
+
+ aligned_base = os::reserve_memory(size, aligned_base);
+
+ } while (aligned_base == NULL);
+
+ return aligned_base;
+}
+
char* os::pd_reserve_memory(size_t bytes, char* addr, size_t alignment_hint) {
assert((size_t)addr % os::vm_allocation_granularity() == 0,
"reserve alignment");
@@ -2962,7 +2960,7 @@
}
if( Verbose && PrintMiscellaneous ) {
reserveTimer.stop();
- tty->print_cr("reserve_memory of %Ix bytes took %ld ms (%ld ticks)", bytes,
+ tty->print_cr("reserve_memory of %Ix bytes took " JLONG_FORMAT " ms (" JLONG_FORMAT " ticks)", bytes,
reserveTimer.milliseconds(), reserveTimer.ticks());
}
}
@@ -3706,18 +3704,6 @@
// Setup Windows Exceptions
- // On Itanium systems, Structured Exception Handling does not
- // work since stack frames must be walkable by the OS. Since
- // much of our code is dynamically generated, and we do not have
- // proper unwind .xdata sections, the system simply exits
- // rather than delivering the exception. To work around
- // this we use VectorExceptions instead.
-#ifdef _WIN64
- if (UseVectoredExceptions) {
- topLevelVectoredExceptionHandler = AddVectoredExceptionHandler( 1, topLevelExceptionFilter);
- }
-#endif
-
// for debugging float code generation bugs
if (ForceFloatExceptions) {
#ifndef _WIN64
@@ -4333,7 +4319,7 @@
if (hFile == NULL) {
if (PrintMiscellaneous && Verbose) {
DWORD err = GetLastError();
- tty->print_cr("CreateFile() failed: GetLastError->%ld.");
+ tty->print_cr("CreateFile() failed: GetLastError->%ld.", err);
}
return NULL;
}
@@ -4383,7 +4369,7 @@
if (hMap == NULL) {
if (PrintMiscellaneous && Verbose) {
DWORD err = GetLastError();
- tty->print_cr("CreateFileMapping() failed: GetLastError->%ld.");
+ tty->print_cr("CreateFileMapping() failed: GetLastError->%ld.", err);
}
CloseHandle(hFile);
return NULL;
@@ -4593,6 +4579,7 @@
}
v = _Event ;
_Event = 0 ;
+ // see comment at end of os::PlatformEvent::park() below:
OrderAccess::fence() ;
// If we encounter a nearly simultanous timeout expiry and unpark()
// we return OS_OK indicating we awoke via unpark().
@@ -4630,25 +4617,25 @@
void os::PlatformEvent::unpark() {
guarantee (_ParkHandle != NULL, "Invariant") ;
- int v ;
- for (;;) {
- v = _Event ; // Increment _Event if it's < 1.
- if (v > 0) {
- // If it's already signaled just return.
- // The LD of _Event could have reordered or be satisfied
- // by a read-aside from this processor's write buffer.
- // To avoid problems execute a barrier and then
- // ratify the value. A degenerate CAS() would also work.
- // Viz., CAS (v+0, &_Event, v) == v).
- OrderAccess::fence() ;
- if (_Event == v) return ;
- continue ;
- }
- if (Atomic::cmpxchg (v+1, &_Event, v) == v) break ;
- }
- if (v < 0) {
- ::SetEvent (_ParkHandle) ;
- }
+
+ // Transitions for _Event:
+ // 0 :=> 1
+ // 1 :=> 1
+ // -1 :=> either 0 or 1; must signal target thread
+ // That is, we can safely transition _Event from -1 to either
+ // 0 or 1. Forcing 1 is slightly more efficient for back-to-back
+ // unpark() calls.
+ // See also: "Semaphores in Plan 9" by Mullender & Cox
+ //
+ // Note: Forcing a transition from "-1" to "1" on an unpark() means
+ // that it will take two back-to-back park() calls for the owning
+ // thread to block. This has the benefit of forcing a spurious return
+ // from the first park() call after an unpark() call which will help
+ // shake out uses of park() and unpark() without condition variables.
+
+ if (Atomic::xchg(1, &_Event) >= 0) return;
+
+ ::SetEvent(_ParkHandle);
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/windows/vm/os_windows.inline.hpp
--- a/src/os/windows/vm/os_windows.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/windows/vm/os_windows.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,9 +26,10 @@
#define OS_WINDOWS_VM_OS_WINDOWS_INLINE_HPP
#include "runtime/atomic.hpp"
+#include "runtime/atomic.inline.hpp"
#include "runtime/os.hpp"
+
#ifdef TARGET_OS_ARCH_windows_x86
-# include "atomic_windows_x86.inline.hpp"
# include "orderAccess_windows_x86.inline.hpp"
#endif
@@ -37,9 +38,6 @@
inline const char* os::path_separator() { return ";"; }
inline const char* os::dll_file_extension() { return ".dll"; }
-inline const char* os::jlong_format_specifier() { return "%I64d"; }
-inline const char* os::julong_format_specifier() { return "%I64u"; }
-
inline const int os::default_file_open_flags() { return O_BINARY | O_NOINHERIT;}
// File names are case-insensitive on windows only
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/windows/vm/perfMemory_windows.cpp
--- a/src/os/windows/vm/perfMemory_windows.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/windows/vm/perfMemory_windows.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -30,6 +30,7 @@
#include "os_windows.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/perfMemory.hpp"
+#include "services/memTracker.hpp"
#include "utilities/exceptions.hpp"
#include
@@ -1496,6 +1497,10 @@
// clear the shared memory region
(void)memset(mapAddress, '\0', size);
+ // it does not go through os api, the operation has to record from here
+ MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC);
+ MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal);
+
return (char*) mapAddress;
}
@@ -1672,6 +1677,11 @@
"Could not map PerfMemory");
}
+ // it does not go through os api, the operation has to record from here
+ MemTracker::record_virtual_memory_reserve((address)mapAddress, size, CURRENT_PC);
+ MemTracker::record_virtual_memory_type((address)mapAddress, mtInternal);
+
+
*addrp = (char*)mapAddress;
*sizep = size;
@@ -1824,6 +1834,8 @@
}
remove_file_mapping(addr);
+ // it does not go through os api, the operation has to record from here
+ MemTracker::record_virtual_memory_release((address)addr, bytes);
}
char* PerfMemory::backing_store_filename() {
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/windows/vm/threadCritical_windows.cpp
--- a/src/os/windows/vm/threadCritical_windows.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/windows/vm/threadCritical_windows.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/threadCritical.hpp"
-#include "thread_windows.inline.hpp"
// OS-includes here
# include
diff -r 77443715ec55 -r b5cb079ecaa4 src/os/windows/vm/thread_windows.inline.hpp
--- a/src/os/windows/vm/thread_windows.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os/windows/vm/thread_windows.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,6 +25,10 @@
#ifndef OS_WINDOWS_VM_THREAD_WINDOWS_INLINE_HPP
#define OS_WINDOWS_VM_THREAD_WINDOWS_INLINE_HPP
+#ifndef SHARE_VM_RUNTIME_THREAD_INLINE_HPP_SCOPE
+#error "This file should only be included from thread.inline.hpp"
+#endif
+
#include "runtime/atomic.hpp"
#include "runtime/prefetch.hpp"
#include "runtime/thread.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/bsd_x86/vm/assembler_bsd_x86.cpp
--- a/src/os_cpu/bsd_x86/vm/assembler_bsd_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/bsd_x86/vm/assembler_bsd_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "runtime/os.hpp"
#include "runtime/threadLocalStorage.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/bsd_x86/vm/bytes_bsd_x86.inline.hpp
--- a/src/os_cpu/bsd_x86/vm/bytes_bsd_x86.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/bsd_x86/vm/bytes_bsd_x86.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,10 +25,6 @@
#ifndef OS_CPU_BSD_X86_VM_BYTES_BSD_X86_INLINE_HPP
#define OS_CPU_BSD_X86_VM_BYTES_BSD_X86_INLINE_HPP
-#ifndef _ALLBSD_SOURCE
-#include
-#endif
-
#ifdef __APPLE__
#include
#endif
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp
--- a/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/bsd_x86/vm/globals_bsd_x86.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -48,7 +48,5 @@
// Used on 64 bit platforms for UseCompressedOops base address or CDS
define_pd_global(uintx, HeapBaseMinAddress, 2*G);
-// Only used on 64 bit Windows platforms
-define_pd_global(bool, UseVectoredExceptions, false);
#endif // OS_CPU_BSD_X86_VM_GLOBALS_BSD_X86_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp
--- a/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
// no precompiled headers
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
@@ -33,7 +33,6 @@
#include "jvm_bsd.h"
#include "memory/allocation.inline.hpp"
#include "mutex_bsd.inline.hpp"
-#include "nativeInst_x86.hpp"
#include "os_share_bsd.hpp"
#include "prims/jniFastGetField.hpp"
#include "prims/jvm.h"
@@ -48,8 +47,8 @@
#include "runtime/osThread.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/timer.hpp"
-#include "thread_bsd.inline.hpp"
#include "utilities/events.hpp"
#include "utilities/vmError.hpp"
@@ -76,7 +75,7 @@
# include
#endif
-#if defined(_ALLBSD_SOURCE) && !defined(__APPLE__) && !defined(__NetBSD__)
+#if !defined(__APPLE__) && !defined(__NetBSD__)
# include
#endif
@@ -489,23 +488,6 @@
// to handle_unexpected_exception way down below.
thread->disable_stack_red_zone();
tty->print_raw_cr("An irrecoverable stack overflow has occurred.");
-#ifndef _ALLBSD_SOURCE
- } else {
- // Accessing stack address below sp may cause SEGV if current
- // thread has MAP_GROWSDOWN stack. This should only happen when
- // current thread was created by user code with MAP_GROWSDOWN flag
- // and then attached to VM. See notes in os_bsd.cpp.
- if (thread->osthread()->expanding_stack() == 0) {
- thread->osthread()->set_expanding_stack();
- if (os::Bsd::manually_expand_stack(thread, addr)) {
- thread->osthread()->clear_expanding_stack();
- return 1;
- }
- thread->osthread()->clear_expanding_stack();
- } else {
- fatal("recursive segv. expanding stack.");
- }
-#endif
}
}
}
@@ -744,61 +726,21 @@
ShouldNotReachHere();
}
-#ifdef _ALLBSD_SOURCE
// From solaris_i486.s ported to bsd_i486.s
extern "C" void fixcw();
-#endif
void os::Bsd::init_thread_fpu_state(void) {
#ifndef AMD64
-# ifdef _ALLBSD_SOURCE
// Set fpu to 53 bit precision. This happens too early to use a stub.
fixcw();
-# else
- // set fpu to 53 bit precision
- set_fpu_control_word(0x27f);
-# endif
#endif // !AMD64
}
-#ifndef _ALLBSD_SOURCE
-int os::Bsd::get_fpu_control_word(void) {
-#ifdef AMD64
- return 0;
-#else
- int fpu_control;
- _FPU_GETCW(fpu_control);
- return fpu_control & 0xffff;
-#endif // AMD64
-}
-
-void os::Bsd::set_fpu_control_word(int fpu_control) {
-#ifndef AMD64
- _FPU_SETCW(fpu_control);
-#endif // !AMD64
-}
-#endif
// Check that the bsd kernel version is 2.4 or higher since earlier
// versions do not support SSE without patches.
bool os::supports_sse() {
-#if defined(AMD64) || defined(_ALLBSD_SOURCE)
return true;
-#else
- struct utsname uts;
- if( uname(&uts) != 0 ) return false; // uname fails?
- char *minor_string;
- int major = strtol(uts.release,&minor_string,10);
- int minor = strtol(minor_string+1,NULL,10);
- bool result = (major > 2 || (major==2 && minor >= 4));
-#ifndef PRODUCT
- if (PrintMiscellaneous && Verbose) {
- tty->print("OS version is %d.%d, which %s support SSE/SSE2\n",
- major,minor, result ? "DOES" : "does NOT");
- }
-#endif
- return result;
-#endif // AMD64
}
bool os::is_allocatable(size_t bytes) {
@@ -836,46 +778,7 @@
#define GET_GS() ({int gs; __asm__ volatile("movw %%gs, %w0":"=q"(gs)); gs&0xffff;})
#endif
-#ifdef _ALLBSD_SOURCE
bool os::Bsd::supports_variable_stack_size() { return true; }
-#else
-// Test if pthread library can support variable thread stack size. BsdThreads
-// in fixed stack mode allocates 2M fixed slot for each thread. BsdThreads
-// in floating stack mode and NPTL support variable stack size.
-bool os::Bsd::supports_variable_stack_size() {
- if (os::Bsd::is_NPTL()) {
- // NPTL, yes
- return true;
-
- } else {
- // Note: We can't control default stack size when creating a thread.
- // If we use non-default stack size (pthread_attr_setstacksize), both
- // floating stack and non-floating stack BsdThreads will return the
- // same value. This makes it impossible to implement this function by
- // detecting thread stack size directly.
- //
- // An alternative approach is to check %gs. Fixed-stack BsdThreads
- // do not use %gs, so its value is 0. Floating-stack BsdThreads use
- // %gs (either as LDT selector or GDT selector, depending on kernel)
- // to access thread specific data.
- //
- // Note that %gs is a reserved glibc register since early 2001, so
- // applications are not allowed to change its value (Ulrich Drepper from
- // Redhat confirmed that all known offenders have been modified to use
- // either %fs or TSD). In the worst case scenario, when VM is embedded in
- // a native application that plays with %gs, we might see non-zero %gs
- // even BsdThreads is running in fixed stack mode. As the result, we'll
- // return true and skip _thread_safety_check(), so we may not be able to
- // detect stack-heap collisions. But otherwise it's harmless.
- //
-#ifdef __GNUC__
- return (GET_GS() != 0);
-#else
- return false;
-#endif
- }
-}
-#endif
#endif // AMD64
// return default stack size for thr_type
@@ -943,7 +846,7 @@
*bottom = (address)((char *)ss.ss_sp - ss.ss_size);
*size = ss.ss_size;
-#elif defined(_ALLBSD_SOURCE)
+#else
pthread_attr_t attr;
int rslt = pthread_attr_init(&attr);
@@ -963,33 +866,6 @@
}
pthread_attr_destroy(&attr);
-#else
- if (os::Bsd::is_initial_thread()) {
- // initial thread needs special handling because pthread_getattr_np()
- // may return bogus value.
- *bottom = os::Bsd::initial_thread_stack_bottom();
- *size = os::Bsd::initial_thread_stack_size();
- } else {
- pthread_attr_t attr;
-
- int rslt = pthread_getattr_np(pthread_self(), &attr);
-
- // JVM needs to know exact stack location, abort if it fails
- if (rslt != 0) {
- if (rslt == ENOMEM) {
- vm_exit_out_of_memory(0, "pthread_getattr_np");
- } else {
- fatal(err_msg("pthread_getattr_np failed with errno = %d", rslt));
- }
- }
-
- if (pthread_attr_getstack(&attr, (void **)bottom, size) != 0) {
- fatal("Can not locate current stack attributes!");
- }
-
- pthread_attr_destroy(&attr);
-
- }
#endif
assert(os::current_stack_pointer() >= *bottom &&
os::current_stack_pointer() < *bottom + *size, "just checking");
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/bsd_x86/vm/threadLS_bsd_x86.cpp
--- a/src/os_cpu/bsd_x86/vm/threadLS_bsd_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/bsd_x86/vm/threadLS_bsd_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/threadLocalStorage.hpp"
-#include "thread_bsd.inline.hpp"
// Map stack pointer (%esp) to thread pointer for faster TLS access
//
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp
--- a/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/bsd_x86/vm/thread_bsd_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "runtime/frame.inline.hpp"
-#include "thread_bsd.inline.hpp"
+#include "runtime/thread.inline.hpp"
// For Forte Analyzer AsyncGetCallTrace profiling support - thread is
// currently interrupted by SIGPROF
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/bsd_x86/vm/vmStructs_bsd_x86.hpp
--- a/src/os_cpu/bsd_x86/vm/vmStructs_bsd_x86.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/bsd_x86/vm/vmStructs_bsd_x86.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -29,37 +29,26 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
\
/******************************/ \
/* Threads (NOTE: incomplete) */ \
/******************************/ \
nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
- nonstatic_field(OSThread, _pthread_id, pthread_t) \
- /* This must be the last entry, and must be present */ \
- last_entry()
+ nonstatic_field(OSThread, _pthread_id, pthread_t)
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
\
/**********************/ \
/* Posix Thread IDs */ \
/**********************/ \
\
declare_unsigned_integer_type(OSThread::thread_id_t) \
- declare_unsigned_integer_type(pthread_t) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+ declare_unsigned_integer_type(pthread_t)
-#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
-#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
#endif // OS_CPU_BSD_X86_VM_VMSTRUCTS_BSD_X86_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/bsd_zero/vm/globals_bsd_zero.hpp
--- a/src/os_cpu/bsd_zero/vm/globals_bsd_zero.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/bsd_zero/vm/globals_bsd_zero.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -41,7 +41,6 @@
define_pd_global(intx, CompilerThreadStackSize, 0);
define_pd_global(uintx, JVMInvokeMethodSlack, 8192);
-define_pd_global(bool, UseVectoredExceptions, false);
// Used on 64 bit platforms for UseCompressedOops base address or CDS
define_pd_global(uintx, HeapBaseMinAddress, 2*G);
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp
--- a/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/bsd_zero/vm/os_bsd_zero.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*
*/
-#if defined(_ALLBSD_SOURCE) && !defined(__APPLE__) && !defined(__NetBSD__)
+#if !defined(__APPLE__) && !defined(__NetBSD__)
#include
# include /* For pthread_attr_get_np */
#endif
@@ -54,8 +54,8 @@
#include "runtime/osThread.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/timer.hpp"
-#include "thread_bsd.inline.hpp"
#include "utilities/events.hpp"
#include "utilities/vmError.hpp"
@@ -178,26 +178,6 @@
thread->disable_stack_red_zone();
ShouldNotCallThis();
}
-#ifndef _ALLBSD_SOURCE
- else {
- // Accessing stack address below sp may cause SEGV if
- // current thread has MAP_GROWSDOWN stack. This should
- // only happen when current thread was created by user
- // code with MAP_GROWSDOWN flag and then attached to VM.
- // See notes in os_bsd.cpp.
- if (thread->osthread()->expanding_stack() == 0) {
- thread->osthread()->set_expanding_stack();
- if (os::Bsd::manually_expand_stack(thread, addr)) {
- thread->osthread()->clear_expanding_stack();
- return true;
- }
- thread->osthread()->clear_expanding_stack();
- }
- else {
- fatal("recursive segv. expanding stack.");
- }
- }
-#endif
}
}
@@ -266,16 +246,6 @@
// Nothing to do
}
-#ifndef _ALLBSD_SOURCE
-int os::Bsd::get_fpu_control_word() {
- ShouldNotCallThis();
-}
-
-void os::Bsd::set_fpu_control_word(int fpu) {
- ShouldNotCallThis();
-}
-#endif
-
bool os::is_allocatable(size_t bytes) {
#ifdef _LP64
return true;
@@ -339,7 +309,7 @@
stack_top = (address) ss.ss_sp;
stack_bytes = ss.ss_size;
stack_bottom = stack_top - stack_bytes;
-#elif defined(_ALLBSD_SOURCE)
+#else
pthread_attr_t attr;
int rslt = pthread_attr_init(&attr);
@@ -362,67 +332,6 @@
pthread_attr_destroy(&attr);
stack_top = stack_bottom + stack_bytes;
-#else /* Linux */
- pthread_attr_t attr;
- int res = pthread_getattr_np(pthread_self(), &attr);
- if (res != 0) {
- if (res == ENOMEM) {
- vm_exit_out_of_memory(0, "pthread_getattr_np");
- }
- else {
- fatal(err_msg("pthread_getattr_np failed with errno = " INT32_FORMAT,
- res));
- }
- }
-
- res = pthread_attr_getstack(&attr, (void **) &stack_bottom, &stack_bytes);
- if (res != 0) {
- fatal(err_msg("pthread_attr_getstack failed with errno = " INT32_FORMAT,
- res));
- }
- stack_top = stack_bottom + stack_bytes;
-
- // The block of memory returned by pthread_attr_getstack() includes
- // guard pages where present. We need to trim these off.
- size_t page_bytes = os::Bsd::page_size();
- assert(((intptr_t) stack_bottom & (page_bytes - 1)) == 0, "unaligned stack");
-
- size_t guard_bytes;
- res = pthread_attr_getguardsize(&attr, &guard_bytes);
- if (res != 0) {
- fatal(err_msg(
- "pthread_attr_getguardsize failed with errno = " INT32_FORMAT, res));
- }
- int guard_pages = align_size_up(guard_bytes, page_bytes) / page_bytes;
- assert(guard_bytes == guard_pages * page_bytes, "unaligned guard");
-
-#ifdef IA64
- // IA64 has two stacks sharing the same area of memory, a normal
- // stack growing downwards and a register stack growing upwards.
- // Guard pages, if present, are in the centre. This code splits
- // the stack in two even without guard pages, though in theory
- // there's nothing to stop us allocating more to the normal stack
- // or more to the register stack if one or the other were found
- // to grow faster.
- int total_pages = align_size_down(stack_bytes, page_bytes) / page_bytes;
- stack_bottom += (total_pages - guard_pages) / 2 * page_bytes;
-#endif // IA64
-
- stack_bottom += guard_bytes;
-
- pthread_attr_destroy(&attr);
-
- // The initial thread has a growable stack, and the size reported
- // by pthread_attr_getstack is the maximum size it could possibly
- // be given what currently mapped. This can be huge, so we cap it.
- if (os::Bsd::is_initial_thread()) {
- stack_bytes = stack_top - stack_bottom;
-
- if (stack_bytes > JavaThread::stack_size_at_create())
- stack_bytes = JavaThread::stack_size_at_create();
-
- stack_bottom = stack_top - stack_bytes;
- }
#endif
assert(os::current_stack_pointer() >= stack_bottom, "should do");
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/bsd_zero/vm/threadLS_bsd_zero.cpp
--- a/src/os_cpu/bsd_zero/vm/threadLS_bsd_zero.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/bsd_zero/vm/threadLS_bsd_zero.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -24,8 +24,8 @@
*/
#include "precompiled.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/threadLocalStorage.hpp"
-#include "thread_bsd.inline.hpp"
void ThreadLocalStorage::generate_code_for_get_thread() {
// nothing to do
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/bsd_zero/vm/thread_bsd_zero.cpp
--- a/src/os_cpu/bsd_zero/vm/thread_bsd_zero.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/bsd_zero/vm/thread_bsd_zero.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,7 +25,7 @@
#include "precompiled.hpp"
#include "runtime/frame.inline.hpp"
-#include "thread_bsd.inline.hpp"
+#include "runtime/thread.inline.hpp"
void JavaThread::cache_global_variables() {
// nothing to do
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/bsd_zero/vm/vmStructs_bsd_zero.hpp
--- a/src/os_cpu/bsd_zero/vm/vmStructs_bsd_zero.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/bsd_zero/vm/vmStructs_bsd_zero.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -30,21 +30,13 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
-#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
-#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
#endif // OS_CPU_BSD_ZERO_VM_VMSTRUCTS_BSD_ZERO_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_sparc/vm/assembler_linux_sparc.cpp
--- a/src/os_cpu/linux_sparc/vm/assembler_linux_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_sparc/vm/assembler_linux_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_sparc.inline.hpp"
+#include "asm/macroAssembler.hpp"
#include "runtime/os.hpp"
#include "runtime/threadLocalStorage.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp
--- a/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_sparc/vm/globals_linux_sparc.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -35,7 +35,5 @@
// Used on 64 bit platforms for UseCompressedOops base address or CDS
define_pd_global(uintx, HeapBaseMinAddress, CONST64(4)*G);
-// Only used on 64 bit Windows platforms
-define_pd_global(bool, UseVectoredExceptions, false);
#endif // OS_CPU_LINUX_SPARC_VM_GLOBALS_LINUX_SPARC_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp
--- a/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
// no precompiled headers
-#include "assembler_sparc.inline.hpp"
+#include "asm/macroAssembler.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
@@ -48,8 +48,8 @@
#include "runtime/osThread.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/timer.hpp"
-#include "thread_linux.inline.hpp"
#include "utilities/events.hpp"
#include "utilities/vmError.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_sparc/vm/threadLS_linux_sparc.cpp
--- a/src/os_cpu/linux_sparc/vm/threadLS_linux_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_sparc/vm/threadLS_linux_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/threadLocalStorage.hpp"
-#include "thread_linux.inline.hpp"
void ThreadLocalStorage::generate_code_for_get_thread() {
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_sparc/vm/thread_linux_sparc.cpp
--- a/src/os_cpu/linux_sparc/vm/thread_linux_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_sparc/vm/thread_linux_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "runtime/frame.inline.hpp"
-#include "thread_linux.inline.hpp"
+#include "runtime/thread.inline.hpp"
// For Forte Analyzer AsyncGetCallTrace profiling support - thread is
// currently interrupted by SIGPROF
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_sparc/vm/vmStructs_linux_sparc.hpp
--- a/src/os_cpu/linux_sparc/vm/vmStructs_linux_sparc.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_sparc/vm/vmStructs_linux_sparc.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -29,7 +29,7 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
\
/******************************/ \
/* Threads (NOTE: incomplete) */ \
@@ -37,38 +37,27 @@
\
nonstatic_field(JavaThread, _base_of_stack_pointer, intptr_t*) \
nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
- nonstatic_field(OSThread, _pthread_id, pthread_t) \
- /* This must be the last entry, and must be present */ \
- last_entry()
+ nonstatic_field(OSThread, _pthread_id, pthread_t)
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
\
/**********************/ \
/* POSIX Thread IDs */ \
/**********************/ \
\
declare_integer_type(OSThread::thread_id_t) \
- declare_unsigned_integer_type(pthread_t) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+ declare_unsigned_integer_type(pthread_t)
-#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
+#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \
\
/************************/ \
/* JavaThread constants */ \
/************************/ \
\
- declare_constant(JavaFrameAnchor::flushed) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+ declare_constant(JavaFrameAnchor::flushed)
-#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
#endif // OS_CPU_LINUX_SPARC_VM_VMSTRUCTS_LINUX_SPARC_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_x86/vm/assembler_linux_x86.cpp
--- a/src/os_cpu/linux_x86/vm/assembler_linux_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_x86/vm/assembler_linux_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "runtime/os.hpp"
#include "runtime/threadLocalStorage.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_x86/vm/globals_linux_x86.hpp
--- a/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -46,7 +46,5 @@
// Used on 64 bit platforms for UseCompressedOops base address or CDS
define_pd_global(uintx,HeapBaseMinAddress, 2*G);
-// Only used on 64 bit Windows platforms
-define_pd_global(bool, UseVectoredExceptions, false);
#endif // OS_CPU_LINUX_X86_VM_GLOBALS_LINUX_X86_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_x86/vm/os_linux_x86.cpp
--- a/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
// no precompiled headers
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
@@ -33,7 +33,6 @@
#include "jvm_linux.h"
#include "memory/allocation.inline.hpp"
#include "mutex_linux.inline.hpp"
-#include "nativeInst_x86.hpp"
#include "os_share_linux.hpp"
#include "prims/jniFastGetField.hpp"
#include "prims/jvm.h"
@@ -48,8 +47,8 @@
#include "runtime/osThread.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/timer.hpp"
-#include "thread_linux.inline.hpp"
#include "utilities/events.hpp"
#include "utilities/vmError.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_x86/vm/threadLS_linux_x86.cpp
--- a/src/os_cpu/linux_x86/vm/threadLS_linux_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_x86/vm/threadLS_linux_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/threadLocalStorage.hpp"
-#include "thread_linux.inline.hpp"
// Map stack pointer (%esp) to thread pointer for faster TLS access
//
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_x86/vm/thread_linux_x86.cpp
--- a/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_x86/vm/thread_linux_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "runtime/frame.inline.hpp"
-#include "thread_linux.inline.hpp"
+#include "runtime/thread.inline.hpp"
// For Forte Analyzer AsyncGetCallTrace profiling support - thread is
// currently interrupted by SIGPROF
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_x86/vm/vmStructs_linux_x86.hpp
--- a/src/os_cpu/linux_x86/vm/vmStructs_linux_x86.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_x86/vm/vmStructs_linux_x86.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -29,37 +29,26 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
\
/******************************/ \
/* Threads (NOTE: incomplete) */ \
/******************************/ \
nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
- nonstatic_field(OSThread, _pthread_id, pthread_t) \
- /* This must be the last entry, and must be present */ \
- last_entry()
+ nonstatic_field(OSThread, _pthread_id, pthread_t)
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
\
/**********************/ \
/* Posix Thread IDs */ \
/**********************/ \
\
declare_integer_type(OSThread::thread_id_t) \
- declare_unsigned_integer_type(pthread_t) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+ declare_unsigned_integer_type(pthread_t)
-#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
-#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
#endif // OS_CPU_LINUX_X86_VM_VMSTRUCTS_LINUX_X86_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_zero/vm/globals_linux_zero.hpp
--- a/src/os_cpu/linux_zero/vm/globals_linux_zero.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_zero/vm/globals_linux_zero.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -41,7 +41,6 @@
define_pd_global(intx, CompilerThreadStackSize, 0);
define_pd_global(uintx, JVMInvokeMethodSlack, 8192);
-define_pd_global(bool, UseVectoredExceptions, false);
// Used on 64 bit platforms for UseCompressedOops base address or CDS
define_pd_global(uintx, HeapBaseMinAddress, 2*G);
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_zero/vm/os_linux_zero.cpp
--- a/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_zero/vm/os_linux_zero.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -49,8 +49,8 @@
#include "runtime/osThread.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/timer.hpp"
-#include "thread_linux.inline.hpp"
#include "utilities/events.hpp"
#include "utilities/vmError.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_zero/vm/threadLS_linux_zero.cpp
--- a/src/os_cpu/linux_zero/vm/threadLS_linux_zero.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_zero/vm/threadLS_linux_zero.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -24,8 +24,8 @@
*/
#include "precompiled.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/threadLocalStorage.hpp"
-#include "thread_linux.inline.hpp"
void ThreadLocalStorage::generate_code_for_get_thread() {
// nothing to do
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_zero/vm/thread_linux_zero.cpp
--- a/src/os_cpu/linux_zero/vm/thread_linux_zero.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_zero/vm/thread_linux_zero.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,7 +25,7 @@
#include "precompiled.hpp"
#include "runtime/frame.inline.hpp"
-#include "thread_linux.inline.hpp"
+#include "runtime/thread.inline.hpp"
void JavaThread::cache_global_variables() {
// nothing to do
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/linux_zero/vm/vmStructs_linux_zero.hpp
--- a/src/os_cpu/linux_zero/vm/vmStructs_linux_zero.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/linux_zero/vm/vmStructs_linux_zero.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -30,21 +30,12 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
-#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
- /* This must be the last entry, and must be present */ \
- last_entry()
-
-#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
#endif // OS_CPU_LINUX_ZERO_VM_VMSTRUCTS_LINUX_ZERO_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/solaris_sparc/vm/assembler_solaris_sparc.cpp
--- a/src/os_cpu/solaris_sparc/vm/assembler_solaris_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/solaris_sparc/vm/assembler_solaris_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,7 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_sparc.inline.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "runtime/os.hpp"
#include "runtime/threadLocalStorage.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp
--- a/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/solaris_sparc/vm/globals_solaris_sparc.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -39,8 +39,6 @@
#else
define_pd_global(uintx, HeapBaseMinAddress, 2*G);
#endif
-// Only used on 64 bit Windows platforms
-define_pd_global(bool, UseVectoredExceptions, false);
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp
--- a/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
// no precompiled headers
-#include "assembler_sparc.inline.hpp"
+#include "asm/macroAssembler.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
@@ -48,8 +48,8 @@
#include "runtime/osThread.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/timer.hpp"
-#include "thread_solaris.inline.hpp"
#include "utilities/events.hpp"
#include "utilities/vmError.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.cpp
--- a/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/solaris_sparc/vm/threadLS_solaris_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/threadLocalStorage.hpp"
-#include "thread_solaris.inline.hpp"
// Provides an entry point we can link against and
// a buffer we can emit code into. The buffer is
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp
--- a/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/solaris_sparc/vm/thread_solaris_sparc.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "runtime/frame.inline.hpp"
-#include "thread_solaris.inline.hpp"
+#include "runtime/thread.inline.hpp"
// For Forte Analyzer AsyncGetCallTrace profiling support - thread is
// currently interrupted by SIGPROF
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/solaris_sparc/vm/vmStructs_solaris_sparc.hpp
--- a/src/os_cpu/solaris_sparc/vm/vmStructs_solaris_sparc.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/solaris_sparc/vm/vmStructs_solaris_sparc.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -29,44 +29,32 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
\
/******************************/ \
/* Threads (NOTE: incomplete) */ \
/******************************/ \
\
nonstatic_field(JavaThread, _base_of_stack_pointer, intptr_t*) \
- nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
- /* This must be the last entry, and must be present */ \
- last_entry()
+ nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t)
-
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
\
/**********************/ \
/* Solaris Thread IDs */ \
/**********************/ \
\
- declare_unsigned_integer_type(OSThread::thread_id_t) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+ declare_unsigned_integer_type(OSThread::thread_id_t)
-#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
+#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant) \
\
/************************/ \
/* JavaThread constants */ \
/************************/ \
\
- declare_constant(JavaFrameAnchor::flushed) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+ declare_constant(JavaFrameAnchor::flushed)
-#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
#endif // OS_CPU_SOLARIS_SPARC_VM_VMSTRUCTS_SOLARIS_SPARC_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/solaris_x86/vm/assembler_solaris_x86.cpp
--- a/src/os_cpu/solaris_x86/vm/assembler_solaris_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/solaris_x86/vm/assembler_solaris_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "runtime/os.hpp"
#include "runtime/threadLocalStorage.hpp"
@@ -116,7 +116,7 @@
ThreadLocalStorage::pd_tlsAccessMode tlsMode = ThreadLocalStorage::pd_getTlsAccessMode ();
if (tlsMode == ThreadLocalStorage::pd_tlsAccessIndirect) { // T1
// Use thread as a temporary: mov r, gs:[0]; mov r, [r+tlsOffset]
- emit_byte (segment);
+ emit_int8 (segment);
// ExternalAddress doesn't work because it can't take NULL
AddressLiteral null(0, relocInfo::none);
movptr (thread, null);
@@ -125,7 +125,7 @@
} else
if (tlsMode == ThreadLocalStorage::pd_tlsAccessDirect) { // T2
// mov r, gs:[tlsOffset]
- emit_byte (segment);
+ emit_int8 (segment);
AddressLiteral tls_off((address)ThreadLocalStorage::pd_getTlsOffset(), relocInfo::none);
movptr (thread, tls_off);
return ;
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp
--- a/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -45,7 +45,5 @@
// Used on 64 bit platforms for UseCompressedOops base address or CDS
define_pd_global(uintx,HeapBaseMinAddress, 256*M);
-// Only used on 64 bit Windows platforms
-define_pd_global(bool, UseVectoredExceptions, false);
#endif // OS_CPU_SOLARIS_X86_VM_GLOBALS_SOLARIS_X86_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp
--- a/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/solaris_x86/vm/orderAccess_solaris_x86.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -27,6 +27,7 @@
#include "runtime/atomic.hpp"
#include "runtime/orderAccess.hpp"
+#include "runtime/os.hpp"
#include "vm_version_x86.hpp"
// Implementation of class OrderAccess.
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp
--- a/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
// no precompiled headers
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
@@ -33,7 +33,6 @@
#include "jvm_solaris.h"
#include "memory/allocation.inline.hpp"
#include "mutex_solaris.inline.hpp"
-#include "nativeInst_x86.hpp"
#include "os_share_solaris.hpp"
#include "prims/jniFastGetField.hpp"
#include "prims/jvm.h"
@@ -48,8 +47,8 @@
#include "runtime/osThread.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/timer.hpp"
-#include "thread_solaris.inline.hpp"
#include "utilities/events.hpp"
#include "utilities/vmError.hpp"
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.cpp
--- a/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/solaris_x86/vm/threadLS_solaris_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/threadLocalStorage.hpp"
-#include "thread_solaris.inline.hpp"
#ifdef AMD64
extern "C" Thread* fs_load(ptrdiff_t tlsOffset);
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp
--- a/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/solaris_x86/vm/thread_solaris_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "runtime/frame.inline.hpp"
-#include "thread_solaris.inline.hpp"
+#include "runtime/thread.inline.hpp"
// For Forte Analyzer AsyncGetCallTrace profiling support - thread is
// currently interrupted by SIGPROF
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/solaris_x86/vm/vmStructs_solaris_x86.hpp
--- a/src/os_cpu/solaris_x86/vm/vmStructs_solaris_x86.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/solaris_x86/vm/vmStructs_solaris_x86.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -29,36 +29,24 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
\
/******************************/ \
/* Threads (NOTE: incomplete) */ \
/******************************/ \
\
- nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+ nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t)
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
\
/**********************/ \
/* Solaris Thread IDs */ \
/**********************/ \
\
- declare_unsigned_integer_type(OSThread::thread_id_t) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+ declare_unsigned_integer_type(OSThread::thread_id_t)
-#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
-#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
#endif // OS_CPU_SOLARIS_X86_VM_VMSTRUCTS_SOLARIS_X86_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp
--- a/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/windows_x86/vm/assembler_windows_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,14 +23,14 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "runtime/os.hpp"
#include "runtime/threadLocalStorage.hpp"
void MacroAssembler::int3() {
- emit_byte(0xCC);
+ emit_int8((unsigned char)0xCC);
}
#ifndef _LP64
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/windows_x86/vm/globals_windows_x86.hpp
--- a/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -47,7 +47,5 @@
// Used on 64 bit platforms for UseCompressedOops base address or CDS
define_pd_global(uintx, HeapBaseMinAddress, 2*G);
-// Only used on 64 bit Windows platforms
-define_pd_global(bool, UseVectoredExceptions, false);
#endif // OS_CPU_WINDOWS_X86_VM_GLOBALS_WINDOWS_X86_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/windows_x86/vm/os_windows_x86.cpp
--- a/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,7 +23,7 @@
*/
// no precompiled headers
-#include "assembler_x86.inline.hpp"
+#include "asm/macroAssembler.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
@@ -48,8 +48,8 @@
#include "runtime/osThread.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/timer.hpp"
-#include "thread_windows.inline.hpp"
#include "utilities/events.hpp"
#include "utilities/vmError.hpp"
@@ -175,9 +175,6 @@
PRUNTIME_FUNCTION prt;
PUNWIND_INFO_EH_ONLY punwind;
- // If we are using Vectored Exceptions we don't need this registration
- if (UseVectoredExceptions) return true;
-
BufferBlob* blob = BufferBlob::create("CodeCache Exception Handler", sizeof(DynamicCodeData));
CodeBuffer cb(blob);
MacroAssembler* masm = new MacroAssembler(&cb);
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/windows_x86/vm/threadLS_windows_x86.cpp
--- a/src/os_cpu/windows_x86/vm/threadLS_windows_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/windows_x86/vm/threadLS_windows_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,8 +23,8 @@
*/
#include "precompiled.hpp"
+#include "runtime/thread.inline.hpp"
#include "runtime/threadLocalStorage.hpp"
-#include "thread_windows.inline.hpp"
// Provides an entry point we can link against and
// a buffer we can emit code into. The buffer is
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/windows_x86/vm/thread_windows_x86.cpp
--- a/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/windows_x86/vm/thread_windows_x86.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "runtime/frame.inline.hpp"
-#include "thread_windows.inline.hpp"
+#include "runtime/thread.inline.hpp"
// For Forte Analyzer AsyncGetCallTrace profiling support - thread is
// currently interrupted by SIGPROF
diff -r 77443715ec55 -r b5cb079ecaa4 src/os_cpu/windows_x86/vm/vmStructs_windows_x86.hpp
--- a/src/os_cpu/windows_x86/vm/vmStructs_windows_x86.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/os_cpu/windows_x86/vm/vmStructs_windows_x86.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -29,32 +29,21 @@
// constants required by the Serviceability Agent. This file is
// referenced by vmStructs.cpp.
-#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field, last_entry) \
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
\
/******************************/ \
/* Threads (NOTE: incomplete) */ \
/******************************/ \
\
nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t) \
- unchecked_nonstatic_field(OSThread, _thread_handle, sizeof(HANDLE)) /* NOTE: no type */ \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+ unchecked_nonstatic_field(OSThread, _thread_handle, sizeof(HANDLE)) /* NOTE: no type */
-#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type, last_entry) \
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
\
- declare_unsigned_integer_type(OSThread::thread_id_t) \
- /* This must be the last entry, and must be present */ \
- last_entry()
+ declare_unsigned_integer_type(OSThread::thread_id_t)
-#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
-#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant, last_entry) \
- \
- /* This must be the last entry, and must be present */ \
- last_entry()
+#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
#endif // OS_CPU_WINDOWS_X86_VM_VMSTRUCTS_WINDOWS_X86_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/tools/LogCompilation/README
--- a/src/share/tools/LogCompilation/README Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/tools/LogCompilation/README Sun Feb 03 22:43:57 2013 +0100
@@ -13,6 +13,6 @@
More information about the LogCompilation output can be found at
-http://wikis.sun.com/display/HotSpotInternals/LogCompilation+overview
-http://wikis.sun.com/display/HotSpotInternals/PrintCompilation
-http://wikis.sun.com/display/HotSpotInternals/LogCompilation+tool
+https://wikis.oracle.com/display/HotSpotInternals/LogCompilation+overview
+https://wikis.oracle.com/display/HotSpotInternals/PrintCompilation
+https://wikis.oracle.com/display/HotSpotInternals/LogCompilation+tool
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/CallSite.java
--- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/CallSite.java Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/CallSite.java Sun Feb 03 22:43:57 2013 +0100
@@ -38,6 +38,7 @@
private String reason;
private List calls;
private int endNodes;
+ private int endLiveNodes;
private double timeStamp;
CallSite() {
@@ -106,7 +107,7 @@
}
}
if (getEndNodes() > 0) {
- stream.printf(" (end time: %6.4f nodes: %d)", getTimeStamp(), getEndNodes());
+ stream.printf(" (end time: %6.4f nodes: %d live: %d)", getTimeStamp(), getEndNodes(), getEndLiveNodes());
}
stream.println("");
if (getReceiver() != null) {
@@ -195,6 +196,14 @@
return endNodes;
}
+ void setEndLiveNodes(int n) {
+ endLiveNodes = n;
+ }
+
+ public int getEndLiveNodes() {
+ return endLiveNodes;
+ }
+
void setTimeStamp(double time) {
timeStamp = time;
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCompilation.java
--- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCompilation.java Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogCompilation.java Sun Feb 03 22:43:57 2013 +0100
@@ -37,13 +37,13 @@
public class LogCompilation extends DefaultHandler implements ErrorHandler, Constants {
public static void usage(int exitcode) {
- System.out.println("Usage: LogCompilation [ -v ] [ -c ] [ -s ] [ -e | -N ] file1 ...");
+ System.out.println("Usage: LogCompilation [ -v ] [ -c ] [ -s ] [ -e | -n ] file1 ...");
System.out.println(" -c: clean up malformed 1.5 xml");
System.out.println(" -i: print inlining decisions");
System.out.println(" -S: print compilation statistics");
System.out.println(" -s: sort events by start time");
System.out.println(" -e: sort events by elapsed time");
- System.out.println(" -N: sort events by name and start");
+ System.out.println(" -n: sort events by name and start");
System.exit(exitcode);
}
@@ -137,7 +137,11 @@
v2 = Integer.valueOf(0);
}
phaseNodes.put(phase.getName(), Integer.valueOf(v2.intValue() + phase.getNodes()));
- out.printf("\t%s %6.4f %d %d\n", phase.getName(), phase.getElapsedTime(), phase.getStartNodes(), phase.getNodes());
+ /* Print phase name, elapsed time, nodes at the start of the phase,
+ nodes created in the phase, live nodes at the start of the phase,
+ live nodes added in the phase.
+ */
+ out.printf("\t%s %6.4f %d %d %d %d\n", phase.getName(), phase.getElapsedTime(), phase.getStartNodes(), phase.getNodes(), phase.getStartLiveNodes(), phase.getLiveNodes());
}
} else if (e instanceof MakeNotEntrantEvent) {
MakeNotEntrantEvent mne = (MakeNotEntrantEvent) e;
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java
--- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java Sun Feb 03 22:43:57 2013 +0100
@@ -224,7 +224,6 @@
throw new InternalError("can't find " + name);
}
int indent = 0;
- String compile_id;
String type(String id) {
String result = types.get(id);
@@ -268,12 +267,18 @@
if (qname.equals("phase")) {
Phase p = new Phase(search(atts, "name"),
Double.parseDouble(search(atts, "stamp")),
- Integer.parseInt(search(atts, "nodes")));
+ Integer.parseInt(search(atts, "nodes", "0")),
+ Integer.parseInt(search(atts, "live")));
phaseStack.push(p);
} else if (qname.equals("phase_done")) {
Phase p = phaseStack.pop();
- p.setEndNodes(Integer.parseInt(search(atts, "nodes")));
+ if (! p.getId().equals(search(atts, "name"))) {
+ System.out.println("phase: " + p.getId());
+ throw new InternalError("phase name mismatch");
+ }
p.setEnd(Double.parseDouble(search(atts, "stamp")));
+ p.setEndNodes(Integer.parseInt(search(atts, "nodes", "0")));
+ p.setEndLiveNodes(Integer.parseInt(search(atts, "live")));
compile.getPhases().add(p);
} else if (qname.equals("task")) {
compile = new Compilation(Integer.parseInt(search(atts, "compile_id", "-1")));
@@ -317,13 +322,16 @@
m.setName(search(atts, "name"));
m.setReturnType(type(search(atts, "return")));
m.setArguments(search(atts, "arguments", "void"));
- m.setBytes(search(atts, "bytes"));
- m.setIICount(search(atts, "iicount"));
- m.setFlags(search(atts, "flags"));
+
+ if (search(atts, "unloaded", "0").equals("0")) {
+ m.setBytes(search(atts, "bytes"));
+ m.setIICount(search(atts, "iicount"));
+ m.setFlags(search(atts, "flags"));
+ }
methods.put(id, m);
} else if (qname.equals("call")) {
site = new CallSite(bci, method(search(atts, "method")));
- site.setCount(Integer.parseInt(search(atts, "count")));
+ site.setCount(Integer.parseInt(search(atts, "count", "0")));
String receiver = atts.getValue("receiver");
if (receiver != null) {
site.setReceiver(type(receiver));
@@ -406,6 +414,7 @@
} else if (qname.equals("parse_done")) {
CallSite call = scopes.pop();
call.setEndNodes(Integer.parseInt(search(atts, "nodes", "1")));
+ call.setEndLiveNodes(Integer.parseInt(search(atts, "live", "1")));
call.setTimeStamp(Double.parseDouble(search(atts, "stamp")));
scopes.push(call);
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Phase.java
--- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Phase.java Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/Phase.java Sun Feb 03 22:43:57 2013 +0100
@@ -30,10 +30,13 @@
private final int startNodes;
private int endNodes;
+ private final int startLiveNodes;
+ private int endLiveNodes;
- Phase(String n, double s, int nodes) {
+ Phase(String n, double s, int nodes, int live) {
super(s, n);
startNodes = nodes;
+ startLiveNodes = live;
}
int getNodes() {
@@ -55,6 +58,22 @@
public int getEndNodes() {
return endNodes;
}
+ /* Number of live nodes added by the phase */
+ int getLiveNodes() {
+ return getEndLiveNodes() - getStartLiveNodes();
+ }
+
+ void setEndLiveNodes(int n) {
+ endLiveNodes = n;
+ }
+
+ public int getStartLiveNodes() {
+ return startLiveNodes;
+ }
+
+ public int getEndLiveNodes() {
+ return endLiveNodes;
+ }
@Override
public void print(PrintStream stream) {
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/tools/ProjectCreator/ProjectCreator.java
--- a/src/share/tools/ProjectCreator/ProjectCreator.java Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/tools/ProjectCreator/ProjectCreator.java Sun Feb 03 22:43:57 2013 +0100
@@ -36,7 +36,7 @@
+ "into .dsp file, substituting for path given in "
+ "-sourceBase. Example: HotSpotWorkSpace>");
System.err.println(" -dllLoc ");
+ + "jvm.dll; no trailing slash>");
System.err.println(" If any of the above are specified, "
+ "they must all be.");
System.err.println(" Additional, optional arguments, which can be "
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/tools/hsdis/hsdis-demo.c
--- a/src/share/tools/hsdis/hsdis-demo.c Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/tools/hsdis/hsdis-demo.c Sun Feb 03 22:43:57 2013 +0100
@@ -85,9 +85,11 @@
#include "dlfcn.h"
-#define DECODE_INSTRUCTIONS_NAME "decode_instructions_virtual"
+#define DECODE_INSTRUCTIONS_VIRTUAL_NAME "decode_instructions_virtual"
+#define DECODE_INSTRUCTIONS_NAME "decode_instructions"
#define HSDIS_NAME "hsdis"
static void* decode_instructions_pv = 0;
+static void* decode_instructions_sv = 0;
static const char* hsdis_path[] = {
HSDIS_NAME"-"LIBARCH LIB_EXT,
"./" HSDIS_NAME"-"LIBARCH LIB_EXT,
@@ -101,11 +103,12 @@
void* dllib = NULL;
const char* *next_in_path = hsdis_path;
while (1) {
- decode_instructions_pv = dlsym(dllib, DECODE_INSTRUCTIONS_NAME);
- if (decode_instructions_pv != NULL)
+ decode_instructions_pv = dlsym(dllib, DECODE_INSTRUCTIONS_VIRTUAL_NAME);
+ decode_instructions_sv = dlsym(dllib, DECODE_INSTRUCTIONS_NAME);
+ if (decode_instructions_pv != NULL || decode_instructions_sv != NULL)
return NULL;
if (dllib != NULL)
- return "plugin does not defined "DECODE_INSTRUCTIONS_NAME;
+ return "plugin does not defined "DECODE_INSTRUCTIONS_VIRTUAL_NAME" and "DECODE_INSTRUCTIONS_NAME;
for (dllib = NULL; dllib == NULL; ) {
const char* next_lib = (*next_in_path++);
if (next_lib == NULL)
@@ -213,20 +216,44 @@
printf("%s: %s\n", err, dlerror());
exit(1);
}
- printf("Decoding from %p to %p...\n", from, to);
- decode_instructions_ftype decode_instructions
- = (decode_instructions_ftype) decode_instructions_pv;
+ decode_func_vtype decode_instructions_v
+ = (decode_func_vtype) decode_instructions_pv;
+ decode_func_stype decode_instructions_s
+ = (decode_func_stype) decode_instructions_sv;
void* res;
- if (raw && xml) {
- res = (*decode_instructions)(from, to, (unsigned char*)from, to - from, simple_handle_event, stdout, NULL, stdout, options);
- } else if (raw) {
- res = (*decode_instructions)(from, to, (unsigned char*)from, to - from, simple_handle_event, stdout, NULL, stdout, options);
- } else {
- res = (*decode_instructions)(from, to, (unsigned char*)from, to - from,
- handle_event, (void*) event_cookie,
- fprintf_callback, stdout,
- options);
+ if (decode_instructions_pv != NULL) {
+ printf("\nDecoding from %p to %p...with %s\n", from, to, DECODE_INSTRUCTIONS_VIRTUAL_NAME);
+ if (raw) {
+ res = (*decode_instructions_v)(from, to,
+ (unsigned char*)from, to - from,
+ simple_handle_event, stdout,
+ NULL, stdout,
+ options, 0);
+ } else {
+ res = (*decode_instructions_v)(from, to,
+ (unsigned char*)from, to - from,
+ handle_event, (void*) event_cookie,
+ fprintf_callback, stdout,
+ options, 0);
+ }
+ if (res != (void*)to)
+ printf("*** Result was %p!\n", res);
}
- if (res != (void*)to)
- printf("*** Result was %p!\n", res);
+ void* sres;
+ if (decode_instructions_sv != NULL) {
+ printf("\nDecoding from %p to %p...with old decode_instructions\n", from, to, DECODE_INSTRUCTIONS_NAME);
+ if (raw) {
+ sres = (*decode_instructions_s)(from, to,
+ simple_handle_event, stdout,
+ NULL, stdout,
+ options);
+ } else {
+ sres = (*decode_instructions_s)(from, to,
+ handle_event, (void*) event_cookie,
+ fprintf_callback, stdout,
+ options);
+ }
+ if (sres != (void *)to)
+ printf("*** Result of decode_instructions %p!\n", sres);
+ }
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/tools/hsdis/hsdis.c
--- a/src/share/tools/hsdis/hsdis.c Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/tools/hsdis/hsdis.c Sun Feb 03 22:43:57 2013 +0100
@@ -99,7 +99,7 @@
unsigned char* buffer, uintptr_t length,
event_callback_t event_callback_arg, void* event_stream_arg,
printf_callback_t printf_callback_arg, void* printf_stream_arg,
- const char* options) {
+ const char* options, int newline) {
struct hsdis_app_data app_data;
memset(&app_data, 0, sizeof(app_data));
app_data.start_va = start_va;
@@ -110,7 +110,7 @@
app_data.event_stream = event_stream_arg;
app_data.printf_callback = printf_callback_arg;
app_data.printf_stream = printf_stream_arg;
- app_data.do_newline = false;
+ app_data.do_newline = newline == 0 ? false : true;
return decode(&app_data, options);
}
@@ -132,7 +132,7 @@
event_stream_arg,
printf_callback_arg,
printf_stream_arg,
- options);
+ options, false);
}
static void* decode(struct hsdis_app_data* app_data, const char* options) {
@@ -173,7 +173,7 @@
if (!app_data->losing) {
const char* insn_close = format_insn_close("/insn", &app_data->dinfo,
buf, sizeof(buf));
- (*event_callback)(event_stream, insn_close, (void*) p) != NULL;
+ (*event_callback)(event_stream, insn_close, (void*) p);
if (app_data->do_newline) {
/* follow each complete insn by a nice newline */
@@ -182,13 +182,14 @@
}
}
- (*event_callback)(event_stream, "/insns", (void*) p);
+ if (app_data->losing) (*event_callback)(event_stream, "/insns", (void*) p);
return (void*) p;
}
}
/* take the address of the function, for luck, and also test the typedef: */
-const decode_instructions_ftype decode_instructions_address = &decode_instructions_virtual;
+const decode_func_vtype decode_func_virtual_address = &decode_instructions_virtual;
+const decode_func_stype decode_func_address = &decode_instructions;
static const char* format_insn_close(const char* close,
disassemble_info* dinfo,
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/tools/hsdis/hsdis.h
--- a/src/share/tools/hsdis/hsdis.h Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/tools/hsdis/hsdis.h Sun Feb 03 22:43:57 2013 +0100
@@ -47,6 +47,9 @@
where tag is a simple identifier, signifying (as in XML) a element start,
element end, and standalone element. (To render as XML, add angle brackets.)
*/
+#ifndef SHARED_TOOLS_HSDIS_H
+#define SHARED_TOOLS_HSDIS_H
+
extern
#ifdef DLL_EXPORT
DLL_EXPORT
@@ -57,16 +60,37 @@
void* event_stream,
int (*printf_callback)(void*, const char*, ...),
void* printf_stream,
- const char* options);
+ const char* options,
+ int newline /* bool value for nice new line */);
+
+/* This is the compatability interface for older versions of hotspot */
+extern
+#ifdef DLL_ENTRY
+ DLL_ENTRY
+#endif
+void* decode_instructions(void* start_pv, void* end_pv,
+ void* (*event_callback)(void*, const char*, void*),
+ void* event_stream,
+ int (*printf_callback)(void*, const char*, ...),
+ void* printf_stream,
+ const char* options);
/* convenience typedefs */
typedef void* (*decode_instructions_event_callback_ftype) (void*, const char*, void*);
typedef int (*decode_instructions_printf_callback_ftype) (void*, const char*, ...);
-typedef void* (*decode_instructions_ftype) (uintptr_t start_va, uintptr_t end_va,
- unsigned char* buffer, uintptr_t length,
- decode_instructions_event_callback_ftype event_callback,
- void* event_stream,
- decode_instructions_printf_callback_ftype printf_callback,
- void* printf_stream,
- const char* options);
+typedef void* (*decode_func_vtype) (uintptr_t start_va, uintptr_t end_va,
+ unsigned char* buffer, uintptr_t length,
+ decode_instructions_event_callback_ftype event_callback,
+ void* event_stream,
+ decode_instructions_printf_callback_ftype printf_callback,
+ void* printf_stream,
+ const char* options,
+ int newline);
+typedef void* (*decode_func_stype) (void* start_pv, void* end_pv,
+ decode_instructions_event_callback_ftype event_callback,
+ void* event_stream,
+ decode_instructions_printf_callback_ftype printf_callback,
+ void* printf_stream,
+ const char* options);
+#endif /* SHARED_TOOLS_HSDIS_H */
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/tools/launcher/java.c
--- a/src/share/tools/launcher/java.c Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/tools/launcher/java.c Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -808,7 +808,7 @@
static int
parse_stack_size(const char *s, jlong *result) {
jlong n = 0;
- int args_read = sscanf(s, jlong_format_specifier(), &n);
+ int args_read = sscanf(s, JLONG_FORMAT, &n);
if (args_read != 1) {
return 0;
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/tools/launcher/java.h
--- a/src/share/tools/launcher/java.h Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/tools/launcher/java.h Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -86,7 +86,6 @@
jboolean RemovableMachineDependentOption(char * option);
void PrintMachineDependentOptions();
-const char *jlong_format_specifier();
/*
* Block current thread and continue execution in new thread
*/
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/adlc/formssel.cpp
--- a/src/share/vm/adlc/formssel.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/adlc/formssel.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -862,8 +862,10 @@
( strcmp(_matrule->_rChild->_opType,"AryEq" )==0 ||
strcmp(_matrule->_rChild->_opType,"StrComp" )==0 ||
strcmp(_matrule->_rChild->_opType,"StrEquals" )==0 ||
- strcmp(_matrule->_rChild->_opType,"StrIndexOf")==0 )) {
+ strcmp(_matrule->_rChild->_opType,"StrIndexOf")==0 ||
+ strcmp(_matrule->_rChild->_opType,"EncodeISOArray")==0)) {
// String.(compareTo/equals/indexOf) and Arrays.equals
+ // and sun.nio.cs.iso8859_1$Encoder.EncodeISOArray
// take 1 control and 1 memory edges.
return 2;
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/adlc/main.cpp
--- a/src/share/vm/adlc/main.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/adlc/main.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -212,7 +212,7 @@
AD.addInclude(AD._CPP_file, "adfiles", get_basename(AD._VM_file._name));
AD.addInclude(AD._CPP_file, "adfiles", get_basename(AD._HPP_file._name));
AD.addInclude(AD._CPP_file, "memory/allocation.inline.hpp");
- AD.addInclude(AD._CPP_file, "asm/assembler.hpp");
+ AD.addInclude(AD._CPP_file, "asm/macroAssembler.inline.hpp");
AD.addInclude(AD._CPP_file, "code/vmreg.hpp");
AD.addInclude(AD._CPP_file, "gc_interface/collectedHeap.inline.hpp");
AD.addInclude(AD._CPP_file, "oops/compiledICHolder.hpp");
@@ -231,17 +231,14 @@
AD.addInclude(AD._CPP_file, "runtime/stubRoutines.hpp");
AD.addInclude(AD._CPP_file, "utilities/growableArray.hpp");
#ifdef TARGET_ARCH_x86
- AD.addInclude(AD._CPP_file, "assembler_x86.inline.hpp");
AD.addInclude(AD._CPP_file, "nativeInst_x86.hpp");
AD.addInclude(AD._CPP_file, "vmreg_x86.inline.hpp");
#endif
#ifdef TARGET_ARCH_sparc
- AD.addInclude(AD._CPP_file, "assembler_sparc.inline.hpp");
AD.addInclude(AD._CPP_file, "nativeInst_sparc.hpp");
AD.addInclude(AD._CPP_file, "vmreg_sparc.inline.hpp");
#endif
#ifdef TARGET_ARCH_arm
- AD.addInclude(AD._CPP_file, "assembler_arm.inline.hpp");
AD.addInclude(AD._CPP_file, "nativeInst_arm.hpp");
AD.addInclude(AD._CPP_file, "vmreg_arm.inline.hpp");
#endif
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/asm/assembler.cpp
--- a/src/share/vm/asm/assembler.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/asm/assembler.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -23,26 +23,13 @@
*/
#include "precompiled.hpp"
-#include "asm/assembler.hpp"
-#include "asm/assembler.inline.hpp"
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
#include "asm/codeBuffer.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/atomic.inline.hpp"
#include "runtime/icache.hpp"
#include "runtime/os.hpp"
-#ifdef TARGET_ARCH_x86
-# include "assembler_x86.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_sparc
-# include "assembler_sparc.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_zero
-# include "assembler_zero.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_arm
-# include "assembler_arm.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_ppc
-# include "assembler_ppc.inline.hpp"
-#endif
// Implementation of AbstractAssembler
@@ -56,16 +43,13 @@
if (code == NULL) return;
CodeSection* cs = code->insts();
cs->clear_mark(); // new assembler kills old mark
- _code_section = cs;
- _code_begin = cs->start();
- _code_limit = cs->limit();
- _code_pos = cs->end();
- _oop_recorder= code->oop_recorder();
- DEBUG_ONLY( _short_branch_delta = 0; )
- if (_code_begin == NULL) {
+ if (cs->start() == NULL) {
vm_exit_out_of_memory(0, err_msg("CodeCache: no room for %s",
code->name()));
}
+ _code_section = cs;
+ _oop_recorder= code->oop_recorder();
+ DEBUG_ONLY( _short_branch_delta = 0; )
}
void AbstractAssembler::set_code_section(CodeSection* cs) {
@@ -73,9 +57,6 @@
assert(cs->is_allocated(), "need to pre-allocate this section");
cs->clear_mark(); // new assembly into this section kills old mark
_code_section = cs;
- _code_begin = cs->start();
- _code_limit = cs->limit();
- _code_pos = cs->end();
}
// Inform CodeBuffer that incoming code and relocation will be for stubs
@@ -83,7 +64,6 @@
CodeBuffer* cb = code();
CodeSection* cs = cb->stubs();
assert(_code_section == cb->insts(), "not in insts?");
- sync();
if (cs->maybe_expand_to_ensure_remaining(required_space)
&& cb->blob() == NULL) {
return NULL;
@@ -96,7 +76,6 @@
// Should not be called if start_a_stub() returned NULL
void AbstractAssembler::end_a_stub() {
assert(_code_section == code()->stubs(), "not in stubs?");
- sync();
set_code_section(code()->insts());
}
@@ -104,8 +83,7 @@
address AbstractAssembler::start_a_const(int required_space, int required_align) {
CodeBuffer* cb = code();
CodeSection* cs = cb->consts();
- assert(_code_section == cb->insts(), "not in insts?");
- sync();
+ assert(_code_section == cb->insts() || _code_section == cb->stubs(), "not in insts/stubs?");
address end = cs->end();
int pad = -(intptr_t)end & (required_align-1);
if (cs->maybe_expand_to_ensure_remaining(pad + required_space)) {
@@ -121,50 +99,16 @@
}
// Inform CodeBuffer that incoming code and relocation will be code
-// Should not be called if start_a_const() returned NULL
-void AbstractAssembler::end_a_const() {
+// in section cs (insts or stubs).
+void AbstractAssembler::end_a_const(CodeSection* cs) {
assert(_code_section == code()->consts(), "not in consts?");
- sync();
- set_code_section(code()->insts());
-}
-
-
-void AbstractAssembler::flush() {
- sync();
- ICache::invalidate_range(addr_at(0), offset());
-}
-
-
-void AbstractAssembler::a_byte(int x) {
- emit_byte(x);
+ set_code_section(cs);
}
-
-void AbstractAssembler::a_long(jint x) {
- emit_long(x);
+void AbstractAssembler::flush() {
+ ICache::invalidate_range(addr_at(0), offset());
}
-// Labels refer to positions in the (to be) generated code. There are bound
-// and unbound
-//
-// Bound labels refer to known positions in the already generated code.
-// offset() is the position the label refers to.
-//
-// Unbound labels refer to unknown positions in the code to be generated; it
-// may contain a list of unresolved displacements that refer to it
-#ifndef PRODUCT
-void AbstractAssembler::print(Label& L) {
- if (L.is_bound()) {
- tty->print_cr("bound label to %d|%d", L.loc_pos(), L.loc_sect());
- } else if (L.is_unbound()) {
- L.print_instructions((MacroAssembler*)this);
- } else {
- tty->print_cr("label in inconsistent state (loc = %d)", L.loc());
- }
-}
-#endif // PRODUCT
-
-
void AbstractAssembler::bind(Label& L) {
if (L.is_bound()) {
// Assembler can bind a label more than once to the same place.
@@ -367,28 +311,3 @@
#endif
return offset < 0 || os::vm_page_size() <= offset;
}
-
-#ifndef PRODUCT
-void Label::print_instructions(MacroAssembler* masm) const {
- CodeBuffer* cb = masm->code();
- for (int i = 0; i < _patch_index; ++i) {
- int branch_loc;
- if (i >= PatchCacheSize) {
- branch_loc = _patch_overflow->at(i - PatchCacheSize);
- } else {
- branch_loc = _patches[i];
- }
- int branch_pos = CodeBuffer::locator_pos(branch_loc);
- int branch_sect = CodeBuffer::locator_sect(branch_loc);
- address branch = cb->locator_address(branch_loc);
- tty->print_cr("unbound label");
- tty->print("@ %d|%d ", branch_pos, branch_sect);
- if (branch_sect == CodeBuffer::SECT_CONSTS) {
- tty->print_cr(PTR_FORMAT, *(address*)branch);
- continue;
- }
- masm->pd_print_patched_instruction(branch);
- tty->cr();
- }
-}
-#endif // ndef PRODUCT
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/asm/assembler.hpp
--- a/src/share/vm/asm/assembler.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/asm/assembler.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,12 +25,14 @@
#ifndef SHARE_VM_ASM_ASSEMBLER_HPP
#define SHARE_VM_ASM_ASSEMBLER_HPP
+#include "asm/codeBuffer.hpp"
#include "code/oopRecorder.hpp"
#include "code/relocInfo.hpp"
#include "memory/allocation.hpp"
#include "utilities/debug.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/top.hpp"
+
#ifdef TARGET_ARCH_x86
# include "register_x86.hpp"
# include "vm_version_x86.hpp"
@@ -54,7 +56,6 @@
// This file contains platform-independent assembler declarations.
-class CodeBuffer;
class MacroAssembler;
class AbstractAssembler;
class Label;
@@ -122,7 +123,7 @@
assert(_loc == -1, "already bound");
_loc = loc;
}
- void bind_loc(int pos, int sect); // = bind_loc(locator(pos, sect))
+ void bind_loc(int pos, int sect) { bind_loc(CodeBuffer::locator(pos, sect)); }
#ifndef PRODUCT
// Iterates over all unresolved instructions for printing
@@ -137,8 +138,8 @@
assert(_loc >= 0, "unbound label");
return _loc;
}
- int loc_pos() const; // == locator_pos(loc())
- int loc_sect() const; // == locator_sect(loc())
+ int loc_pos() const { return CodeBuffer::locator_pos(loc()); }
+ int loc_sect() const { return CodeBuffer::locator_sect(loc()); }
bool is_bound() const { return _loc >= 0; }
bool is_unbound() const { return _loc == -1 && _patch_index > 0; }
@@ -201,27 +202,20 @@
protected:
CodeSection* _code_section; // section within the code buffer
- address _code_begin; // first byte of code buffer
- address _code_limit; // first byte after code buffer
- address _code_pos; // current code generation position
OopRecorder* _oop_recorder; // support for relocInfo::oop_type
// Code emission & accessing
- address addr_at(int pos) const { return _code_begin + pos; }
+ address addr_at(int pos) const { return code_section()->start() + pos; }
+
// This routine is called with a label is used for an address.
// Labels and displacements truck in offsets, but target must return a PC.
- address target(Label& L); // return _code_section->target(L)
+ address target(Label& L) { return code_section()->target(L, pc()); }
bool is8bit(int x) const { return -0x80 <= x && x < 0x80; }
bool isByte(int x) const { return 0 <= x && x < 0x100; }
bool isShiftCount(int x) const { return 0 <= x && x < 32; }
- void emit_byte(int x); // emit a single byte
- void emit_word(int x); // emit a 16-bit word (not a wordSize word!)
- void emit_long(jint x); // emit a 32-bit word (not a longSize word!)
- void emit_address(address x); // emit an address (not a longSize word!)
-
// Instruction boundaries (required when emitting relocatable values).
class InstructionMark: public StackObj {
private:
@@ -237,10 +231,10 @@
}
};
friend class InstructionMark;
- #ifdef ASSERT
+#ifdef ASSERT
// Make it return true on platforms which need to verify
// instruction boundaries for some operations.
- inline static bool pd_check_instruction_mark();
+ static bool pd_check_instruction_mark();
// Add delta to short branch distance to verify that it still fit into imm8.
int _short_branch_delta;
@@ -262,28 +256,31 @@
_assm->clear_short_branch_delta();
}
};
- #else
+#else
// Dummy in product.
class ShortBranchVerifier: public StackObj {
public:
ShortBranchVerifier(AbstractAssembler* assm) {}
};
- #endif
-
- // Label functions
- void print(Label& L);
+#endif
public:
// Creation
AbstractAssembler(CodeBuffer* code);
- // save end pointer back to code buf.
- void sync();
-
// ensure buf contains all code (call this before using/copying the code)
void flush();
+ void emit_int8( int8_t x) { code_section()->emit_int8( x); }
+ void emit_int16( int16_t x) { code_section()->emit_int16( x); }
+ void emit_int32( int32_t x) { code_section()->emit_int32( x); }
+ void emit_int64( int64_t x) { code_section()->emit_int64( x); }
+
+ void emit_float( jfloat x) { code_section()->emit_float( x); }
+ void emit_double( jdouble x) { code_section()->emit_double( x); }
+ void emit_address(address x) { code_section()->emit_address(x); }
+
// min and max values for signed immediate ranges
static int min_simm(int nbits) { return -(intptr_t(1) << (nbits - 1)) ; }
static int max_simm(int nbits) { return (intptr_t(1) << (nbits - 1)) - 1; }
@@ -308,26 +305,29 @@
static bool is_simm32(intptr_t x) { return is_simm(x, 32); }
// Accessors
- CodeBuffer* code() const; // _code_section->outer()
CodeSection* code_section() const { return _code_section; }
- int sect() const; // return _code_section->index()
- address pc() const { return _code_pos; }
- int offset() const { return _code_pos - _code_begin; }
- int locator() const; // CodeBuffer::locator(offset(), sect())
+ CodeBuffer* code() const { return code_section()->outer(); }
+ int sect() const { return code_section()->index(); }
+ address pc() const { return code_section()->end(); }
+ int offset() const { return code_section()->size(); }
+ int locator() const { return CodeBuffer::locator(offset(), sect()); }
+
OopRecorder* oop_recorder() const { return _oop_recorder; }
void set_oop_recorder(OopRecorder* r) { _oop_recorder = r; }
- address inst_mark() const;
- void set_inst_mark();
- void clear_inst_mark();
+ address inst_mark() const { return code_section()->mark(); }
+ void set_inst_mark() { code_section()->set_mark(); }
+ void clear_inst_mark() { code_section()->clear_mark(); }
// Constants in code
- void a_byte(int x);
- void a_long(jint x);
- void relocate(RelocationHolder const& rspec, int format = 0);
+ void relocate(RelocationHolder const& rspec, int format = 0) {
+ assert(!pd_check_instruction_mark()
+ || inst_mark() == NULL || inst_mark() == code_section()->end(),
+ "call relocate() between instructions");
+ code_section()->relocate(code_section()->end(), rspec, format);
+ }
void relocate( relocInfo::relocType rtype, int format = 0) {
- if (rtype != relocInfo::none)
- relocate(Relocation::spec_simple(rtype), format);
+ code_section()->relocate(code_section()->end(), rtype, format);
}
static int code_fill_byte(); // used to pad out odd-sized code buffers
@@ -348,52 +348,55 @@
void end_a_stub();
// Ditto for constants.
address start_a_const(int required_space, int required_align = sizeof(double));
- void end_a_const();
+ void end_a_const(CodeSection* cs); // Pass the codesection to continue in (insts or stubs?).
// constants support
+ //
+ // We must remember the code section (insts or stubs) in c1
+ // so we can reset to the proper section in end_a_const().
address long_constant(jlong c) {
+ CodeSection* c1 = _code_section;
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
- *(jlong*)ptr = c;
- _code_pos = ptr + sizeof(c);
- end_a_const();
+ emit_int64(c);
+ end_a_const(c1);
}
return ptr;
}
address double_constant(jdouble c) {
+ CodeSection* c1 = _code_section;
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
- *(jdouble*)ptr = c;
- _code_pos = ptr + sizeof(c);
- end_a_const();
+ emit_double(c);
+ end_a_const(c1);
}
return ptr;
}
address float_constant(jfloat c) {
+ CodeSection* c1 = _code_section;
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
- *(jfloat*)ptr = c;
- _code_pos = ptr + sizeof(c);
- end_a_const();
+ emit_float(c);
+ end_a_const(c1);
}
return ptr;
}
address address_constant(address c) {
+ CodeSection* c1 = _code_section;
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
- *(address*)ptr = c;
- _code_pos = ptr + sizeof(c);
- end_a_const();
+ emit_address(c);
+ end_a_const(c1);
}
return ptr;
}
address address_constant(address c, RelocationHolder const& rspec) {
+ CodeSection* c1 = _code_section;
address ptr = start_a_const(sizeof(c), sizeof(c));
if (ptr != NULL) {
relocate(rspec);
- *(address*)ptr = c;
- _code_pos = ptr + sizeof(c);
- end_a_const();
+ emit_address(c);
+ end_a_const(c1);
}
return ptr;
}
@@ -429,15 +432,6 @@
*/
void pd_patch_instruction(address branch, address target);
-#ifndef PRODUCT
- /**
- * Platform-dependent method of printing an instruction that needs to be
- * patched.
- *
- * @param branch the instruction to be patched in the buffer.
- */
- static void pd_print_patched_instruction(address branch);
-#endif // PRODUCT
};
#ifdef TARGET_ARCH_x86
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/asm/assembler.inline.hpp
--- a/src/share/vm/asm/assembler.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/asm/assembler.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -26,92 +26,21 @@
#define SHARE_VM_ASM_ASSEMBLER_INLINE_HPP
#include "asm/assembler.hpp"
-#include "asm/codeBuffer.hpp"
-#include "compiler/disassembler.hpp"
-#include "runtime/threadLocalStorage.hpp"
-inline void AbstractAssembler::sync() {
- CodeSection* cs = code_section();
- guarantee(cs->start() == _code_begin, "must not shift code buffer");
- cs->set_end(_code_pos);
-}
-
-inline void AbstractAssembler::emit_byte(int x) {
- assert(isByte(x), "not a byte");
- *(unsigned char*)_code_pos = (unsigned char)x;
- _code_pos += sizeof(unsigned char);
- sync();
-}
-
-
-inline void AbstractAssembler::emit_word(int x) {
- *(short*)_code_pos = (short)x;
- _code_pos += sizeof(short);
- sync();
-}
-
-
-inline void AbstractAssembler::emit_long(jint x) {
- *(jint*)_code_pos = x;
- _code_pos += sizeof(jint);
- sync();
-}
-
-inline void AbstractAssembler::emit_address(address x) {
- *(address*)_code_pos = x;
- _code_pos += sizeof(address);
- sync();
-}
-
-inline address AbstractAssembler::inst_mark() const {
- return code_section()->mark();
-}
-
-
-inline void AbstractAssembler::set_inst_mark() {
- code_section()->set_mark();
-}
-
-
-inline void AbstractAssembler::clear_inst_mark() {
- code_section()->clear_mark();
-}
-
-
-inline void AbstractAssembler::relocate(RelocationHolder const& rspec, int format) {
- assert(!pd_check_instruction_mark()
- || inst_mark() == NULL || inst_mark() == _code_pos,
- "call relocate() between instructions");
- code_section()->relocate(_code_pos, rspec, format);
-}
-
-
-inline CodeBuffer* AbstractAssembler::code() const {
- return code_section()->outer();
-}
-
-inline int AbstractAssembler::sect() const {
- return code_section()->index();
-}
-
-inline int AbstractAssembler::locator() const {
- return CodeBuffer::locator(offset(), sect());
-}
-
-inline address AbstractAssembler::target(Label& L) {
- return code_section()->target(L, pc());
-}
-
-inline int Label::loc_pos() const {
- return CodeBuffer::locator_pos(loc());
-}
-
-inline int Label::loc_sect() const {
- return CodeBuffer::locator_sect(loc());
-}
-
-inline void Label::bind_loc(int pos, int sect) {
- bind_loc(CodeBuffer::locator(pos, sect));
-}
+#ifdef TARGET_ARCH_x86
+# include "assembler_x86.inline.hpp"
+#endif
+#ifdef TARGET_ARCH_sparc
+# include "assembler_sparc.inline.hpp"
+#endif
+#ifdef TARGET_ARCH_zero
+# include "assembler_zero.inline.hpp"
+#endif
+#ifdef TARGET_ARCH_arm
+# include "assembler_arm.inline.hpp"
+#endif
+#ifdef TARGET_ARCH_ppc
+# include "assembler_ppc.inline.hpp"
+#endif
#endif // SHARE_VM_ASM_ASSEMBLER_INLINE_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/asm/codeBuffer.cpp
--- a/src/share/vm/asm/codeBuffer.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/asm/codeBuffer.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -254,6 +254,10 @@
return start + locator_pos(locator);
}
+bool CodeBuffer::is_backward_branch(Label& L) {
+ return L.is_bound() && insts_end() <= locator_address(L.loc());
+}
+
address CodeBuffer::decode_begin() {
address begin = _insts.start();
if (_decode_begin != NULL && _decode_begin > begin)
@@ -492,6 +496,14 @@
dest->verify_section_allocation();
}
+// Append an oop reference that keeps the class alive.
+static void append_oop_references(GrowableArray* oops, Klass* k) {
+ oop cl = k->klass_holder();
+ if (cl != NULL && !oops->contains(cl)) {
+ oops->append(cl);
+ }
+}
+
void CodeBuffer::finalize_oop_references(methodHandle mh) {
No_Safepoint_Verifier nsv;
@@ -509,7 +521,6 @@
if (md->metadata_is_immediate()) {
Metadata* m = md->metadata_value();
if (oop_recorder()->is_real(m)) {
- oop o = NULL;
if (m->is_methodData()) {
m = ((MethodData*)m)->method();
}
@@ -517,16 +528,13 @@
m = ((Method*)m)->method_holder();
}
if (m->is_klass()) {
- o = ((Klass*)m)->class_loader();
+ append_oop_references(&oops, (Klass*)m);
} else {
// XXX This will currently occur for MDO which don't
// have a backpointer. This has to be fixed later.
m->print();
ShouldNotReachHere();
}
- if (o != NULL && oops.find(o) == -1) {
- oops.append(o);
- }
}
}
}
@@ -537,7 +545,6 @@
for (int i = 0; i < oop_recorder()->metadata_count(); i++) {
Metadata* m = oop_recorder()->metadata_at(i);
if (oop_recorder()->is_real(m)) {
- oop o = NULL;
if (m->is_methodData()) {
m = ((MethodData*)m)->method();
}
@@ -545,24 +552,18 @@
m = ((Method*)m)->method_holder();
}
if (m->is_klass()) {
- o = ((Klass*)m)->class_loader();
+ append_oop_references(&oops, (Klass*)m);
} else {
m->print();
ShouldNotReachHere();
}
- if (o != NULL && oops.find(o) == -1) {
- oops.append(o);
- }
}
}
}
// Add the class loader of Method* for the nmethod itself
- oop cl = mh->method_holder()->class_loader();
- if (cl != NULL) {
- oops.append(cl);
- }
+ append_oop_references(&oops, mh->method_holder());
// Add any oops that we've found
Thread* thread = Thread::current();
@@ -749,7 +750,18 @@
// Make the new code copy use the old copy's relocations:
dest_cs->initialize_locs_from(cs);
+ }
+ // Do relocation after all sections are copied.
+ // This is necessary if the code uses constants in stubs, which are
+ // relocated when the corresponding instruction in the code (e.g., a
+ // call) is relocated. Stubs are placed behind the main code
+ // section, so that section has to be copied before relocating.
+ for (int n = (int) SECT_FIRST; n < (int)SECT_LIMIT; n++) {
+ // pull code out of each section
+ const CodeSection* cs = code_section(n);
+ if (cs->is_empty()) continue; // skip trivial section
+ CodeSection* dest_cs = dest->code_section(n);
{ // Repair the pc relative information in the code after the move
RelocIterator iter(dest_cs);
while (iter.next()) {
@@ -758,7 +770,7 @@
}
}
- if (dest->blob() == NULL) {
+ if (dest->blob() == NULL && dest_filled != NULL) {
// Destination is a final resting place, not just another buffer.
// Normalize uninitialized bytes in the final padding.
Copy::fill_to_bytes(dest_filled, dest_end - dest_filled,
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/asm/codeBuffer.hpp
--- a/src/share/vm/asm/codeBuffer.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/asm/codeBuffer.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,17 +25,15 @@
#ifndef SHARE_VM_ASM_CODEBUFFER_HPP
#define SHARE_VM_ASM_CODEBUFFER_HPP
-#include "asm/assembler.hpp"
#include "code/oopRecorder.hpp"
#include "code/relocInfo.hpp"
-class CodeComments;
-class AbstractAssembler;
-class MacroAssembler;
-class PhaseCFG;
-class Compile;
-class BufferBlob;
-class CodeBuffer;
+class CodeComments;
+class PhaseCFG;
+class Compile;
+class BufferBlob;
+class CodeBuffer;
+class Label;
class CodeOffsets: public StackObj {
public:
@@ -194,10 +192,14 @@
}
// Code emission
- void emit_int8 (int8_t x) { *((int8_t*) end()) = x; set_end(end() + 1); }
- void emit_int16(int16_t x) { *((int16_t*) end()) = x; set_end(end() + 2); }
- void emit_int32(int32_t x) { *((int32_t*) end()) = x; set_end(end() + 4); }
- void emit_int64(int64_t x) { *((int64_t*) end()) = x; set_end(end() + 8); }
+ void emit_int8 ( int8_t x) { *((int8_t*) end()) = x; set_end(end() + sizeof(int8_t)); }
+ void emit_int16( int16_t x) { *((int16_t*) end()) = x; set_end(end() + sizeof(int16_t)); }
+ void emit_int32( int32_t x) { *((int32_t*) end()) = x; set_end(end() + sizeof(int32_t)); }
+ void emit_int64( int64_t x) { *((int64_t*) end()) = x; set_end(end() + sizeof(int64_t)); }
+
+ void emit_float( jfloat x) { *((jfloat*) end()) = x; set_end(end() + sizeof(jfloat)); }
+ void emit_double(jdouble x) { *((jdouble*) end()) = x; set_end(end() + sizeof(jdouble)); }
+ void emit_address(address x) { *((address*) end()) = x; set_end(end() + sizeof(address)); }
// Share a scratch buffer for relocinfo. (Hacky; saves a resource allocation.)
void initialize_shared_locs(relocInfo* buf, int length);
@@ -451,6 +453,9 @@
int locator(address addr) const;
address locator_address(int locator) const;
+ // Heuristic for pre-packing the taken/not-taken bit of a predicted branch.
+ bool is_backward_branch(Label& L);
+
// Properties
const char* name() const { return _name; }
CodeBuffer* before_expand() const { return _before_expand; }
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/asm/macroAssembler.hpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/asm/macroAssembler.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_ASM_MACROASSEMBLER_HPP
+#define SHARE_VM_ASM_MACROASSEMBLER_HPP
+
+#include "asm/assembler.hpp"
+
+#ifdef TARGET_ARCH_x86
+# include "macroAssembler_x86.hpp"
+#endif
+#ifdef TARGET_ARCH_sparc
+# include "macroAssembler_sparc.hpp"
+#endif
+#ifdef TARGET_ARCH_zero
+# include "assembler_zero.hpp"
+#endif
+#ifdef TARGET_ARCH_arm
+# include "assembler_arm.hpp"
+#endif
+#ifdef TARGET_ARCH_ppc
+# include "assembler_ppc.hpp"
+#endif
+
+#endif // SHARE_VM_ASM_MACROASSEMBLER_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/asm/macroAssembler.inline.hpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/asm/macroAssembler.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_ASM_MACROASSEMBLER_INLINE_HPP
+#define SHARE_VM_ASM_MACROASSEMBLER_INLINE_HPP
+
+#include "asm/macroAssembler.hpp"
+
+#ifdef TARGET_ARCH_x86
+// no macroAssembler_x86.inline.hpp
+#endif
+#ifdef TARGET_ARCH_sparc
+# include "macroAssembler_sparc.inline.hpp"
+#endif
+#ifdef TARGET_ARCH_zero
+# include "assembler_zero.inline.hpp"
+#endif
+#ifdef TARGET_ARCH_arm
+# include "assembler_arm.inline.hpp"
+#endif
+#ifdef TARGET_ARCH_ppc
+# include "assembler_ppc.inline.hpp"
+#endif
+
+#endif // SHARE_VM_ASM_MACROASSEMBLER_INLINE_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/asm/register.hpp
--- a/src/share/vm/asm/register.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/asm/register.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -93,6 +93,21 @@
#define REGISTER_DEFINITION(type, name) \
const type name = ((type)name##_##type##EnumValue)
+#ifdef TARGET_ARCH_x86
+# include "register_x86.hpp"
+#endif
+#ifdef TARGET_ARCH_sparc
+# include "register_sparc.hpp"
+#endif
+#ifdef TARGET_ARCH_zero
+# include "register_zero.hpp"
+#endif
+#ifdef TARGET_ARCH_arm
+# include "register_arm.hpp"
+#endif
+#ifdef TARGET_ARCH_ppc
+# include "register_ppc.hpp"
+#endif
// Debugging support
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/c1/c1_Compilation.cpp
--- a/src/share/vm/c1/c1_Compilation.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/c1/c1_Compilation.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -129,7 +129,15 @@
CHECK_BAILOUT();
// setup ir
+ CompileLog* log = this->log();
+ if (log != NULL) {
+ log->begin_head("parse method='%d' ",
+ log->identify(_method));
+ log->stamp();
+ log->end_head();
+ }
_hir = new IR(this, method(), osr_bci());
+ if (log) log->done("parse");
if (!_hir->is_valid()) {
bailout("invalid parsing");
return;
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/c1/c1_GraphBuilder.cpp
--- a/src/share/vm/c1/c1_GraphBuilder.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/c1/c1_GraphBuilder.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -1836,7 +1836,7 @@
// check if we could do inlining
if (!PatchALot && Inline && klass->is_loaded() &&
(klass->is_initialized() || klass->is_interface() && target->holder()->is_initialized())
- && target->will_link(klass, callee_holder, code)) {
+ && target->is_loaded()) {
// callee is known => check if we have static binding
assert(target->is_loaded(), "callee must be known");
if (code == Bytecodes::_invokestatic ||
@@ -1844,17 +1844,12 @@
code == Bytecodes::_invokevirtual && target->is_final_method() ||
code == Bytecodes::_invokedynamic) {
ciMethod* inline_target = (cha_monomorphic_target != NULL) ? cha_monomorphic_target : target;
- bool success = false;
- if (target->is_method_handle_intrinsic()) {
- // method handle invokes
- success = try_method_handle_inline(target);
- } else {
- // static binding => check if callee is ok
- success = try_inline(inline_target, (cha_monomorphic_target != NULL) || (exact_target != NULL), code, better_receiver);
- }
+ // static binding => check if callee is ok
+ bool success = try_inline(inline_target, (cha_monomorphic_target != NULL) || (exact_target != NULL), code, better_receiver);
+
CHECK_BAILOUT();
-
clear_inline_bailout();
+
if (success) {
// Register dependence if JVMTI has either breakpoint
// setting or hotswapping of methods capabilities since they may
@@ -3201,6 +3196,11 @@
return false;
}
+ // method handle invokes
+ if (callee->is_method_handle_intrinsic()) {
+ return try_method_handle_inline(callee);
+ }
+
// handle intrinsics
if (callee->intrinsic_id() != vmIntrinsics::_none) {
if (try_inline_intrinsics(callee)) {
@@ -3223,7 +3223,12 @@
}
if (try_inline_full(callee, holder_known, bc, receiver))
return true;
- print_inlining(callee, _inline_bailout_msg, /*success*/ false);
+
+ // Entire compilation could fail during try_inline_full call.
+ // In that case printing inlining decision info is useless.
+ if (!bailed_out())
+ print_inlining(callee, _inline_bailout_msg, /*success*/ false);
+
return false;
}
@@ -3442,6 +3447,11 @@
preserves_state = true;
break;
+ case vmIntrinsics::_loadFence :
+ case vmIntrinsics::_storeFence:
+ case vmIntrinsics::_fullFence :
+ break;
+
default : return false; // do not inline
}
// create intrinsic node
@@ -3748,7 +3758,8 @@
push_scope(callee, cont);
// the BlockListBuilder for the callee could have bailed out
- CHECK_BAILOUT_(false);
+ if (bailed_out())
+ return false;
// Temporarily set up bytecode stream so we can append instructions
// (only using the bci of this stream)
@@ -3814,7 +3825,8 @@
iterate_all_blocks(callee_start_block == NULL);
// If we bailed out during parsing, return immediately (this is bad news)
- if (bailed_out()) return false;
+ if (bailed_out())
+ return false;
// iterate_all_blocks theoretically traverses in random order; in
// practice, we have only traversed the continuation if we are
@@ -3823,9 +3835,6 @@
!continuation()->is_set(BlockBegin::was_visited_flag),
"continuation should not have been parsed yet if we created it");
- // If we bailed out during parsing, return immediately (this is bad news)
- CHECK_BAILOUT_(false);
-
// At this point we are almost ready to return and resume parsing of
// the caller back in the GraphBuilder. The only thing we want to do
// first is an optimization: during parsing of the callee we
@@ -3885,10 +3894,14 @@
ValueType* type = state()->stack_at(args_base)->type();
if (type->is_constant()) {
ciMethod* target = type->as_ObjectType()->constant_value()->as_method_handle()->get_vmtarget();
- guarantee(!target->is_method_handle_intrinsic(), "should not happen"); // XXX remove
- Bytecodes::Code bc = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual;
- if (try_inline(target, /*holder_known*/ true, bc)) {
- return true;
+ // We don't do CHA here so only inline static and statically bindable methods.
+ if (target->is_static() || target->can_be_statically_bound()) {
+ Bytecodes::Code bc = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual;
+ if (try_inline(target, /*holder_known*/ true, bc)) {
+ return true;
+ }
+ } else {
+ print_inlining(target, "not static or statically bindable", /*success*/ false);
}
} else {
print_inlining(callee, "receiver not constant", /*success*/ false);
@@ -3941,9 +3954,14 @@
}
j += t->size(); // long and double take two slots
}
- Bytecodes::Code bc = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual;
- if (try_inline(target, /*holder_known*/ true, bc)) {
- return true;
+ // We don't do CHA here so only inline static and statically bindable methods.
+ if (target->is_static() || target->can_be_statically_bound()) {
+ Bytecodes::Code bc = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual;
+ if (try_inline(target, /*holder_known*/ true, bc)) {
+ return true;
+ }
+ } else {
+ print_inlining(target, "not static or statically bindable", /*success*/ false);
}
}
} else {
@@ -4157,7 +4175,10 @@
else
log->inline_success("receiver is statically known");
} else {
- log->inline_fail(msg);
+ if (msg != NULL)
+ log->inline_fail(msg);
+ else
+ log->inline_fail("reason unknown");
}
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/c1/c1_InstructionPrinter.cpp
--- a/src/share/vm/c1/c1_InstructionPrinter.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/c1/c1_InstructionPrinter.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -360,7 +360,7 @@
ValueType* t = x->type();
switch (t->tag()) {
case intTag : output()->print("%d" , t->as_IntConstant ()->value()); break;
- case longTag : output()->print(os::jlong_format_specifier(), t->as_LongConstant()->value()); output()->print("L"); break;
+ case longTag : output()->print(JLONG_FORMAT, t->as_LongConstant()->value()); output()->print("L"); break;
case floatTag : output()->print("%g" , t->as_FloatConstant ()->value()); break;
case doubleTag : output()->print("%gD" , t->as_DoubleConstant()->value()); break;
case objectTag : print_object(x); break;
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/c1/c1_LIR.cpp
--- a/src/share/vm/c1/c1_LIR.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/c1/c1_LIR.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1563,7 +1563,7 @@
switch (type()) {
case T_ADDRESS:out->print("address:%d",as_jint()); break;
case T_INT: out->print("int:%d", as_jint()); break;
- case T_LONG: out->print("lng:%lld", as_jlong()); break;
+ case T_LONG: out->print("lng:" JLONG_FORMAT, as_jlong()); break;
case T_FLOAT: out->print("flt:%f", as_jfloat()); break;
case T_DOUBLE: out->print("dbl:%f", as_jdouble()); break;
case T_OBJECT: out->print("obj:0x%x", as_jobject()); break;
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/c1/c1_LIR.hpp
--- a/src/share/vm/c1/c1_LIR.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/c1/c1_LIR.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -2259,7 +2259,7 @@
typedef enum { inputMode, firstMode = inputMode, tempMode, outputMode, numModes, invalidMode = -1 } OprMode;
enum {
- maxNumberOfOperands = 16,
+ maxNumberOfOperands = 20,
maxNumberOfInfos = 4
};
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/c1/c1_LIRGenerator.cpp
--- a/src/share/vm/c1/c1_LIRGenerator.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/c1/c1_LIRGenerator.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -2977,6 +2977,16 @@
do_CompareAndSwap(x, longType);
break;
+ case vmIntrinsics::_loadFence :
+ if (os::is_MP()) __ membar_acquire();
+ break;
+ case vmIntrinsics::_storeFence:
+ if (os::is_MP()) __ membar_release();
+ break;
+ case vmIntrinsics::_fullFence :
+ if (os::is_MP()) __ membar();
+ break;
+
case vmIntrinsics::_Reference_get:
do_Reference_get(x);
break;
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/c1/c1_MacroAssembler.hpp
--- a/src/share/vm/c1/c1_MacroAssembler.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/c1/c1_MacroAssembler.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,22 +25,8 @@
#ifndef SHARE_VM_C1_C1_MACROASSEMBLER_HPP
#define SHARE_VM_C1_C1_MACROASSEMBLER_HPP
-#include "asm/assembler.hpp"
-#ifdef TARGET_ARCH_x86
-# include "assembler_x86.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_sparc
-# include "assembler_sparc.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_zero
-# include "assembler_zero.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_arm
-# include "assembler_arm.inline.hpp"
-#endif
-#ifdef TARGET_ARCH_ppc
-# include "assembler_ppc.inline.hpp"
-#endif
+#include "asm/macroAssembler.hpp"
+#include "asm/macroAssembler.inline.hpp"
class CodeEmitInfo;
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/c1/c1_Runtime1.cpp
--- a/src/share/vm/c1/c1_Runtime1.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/c1/c1_Runtime1.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -374,7 +374,7 @@
JRT_ENTRY(void, Runtime1::throw_array_store_exception(JavaThread* thread, oopDesc* obj))
ResourceMark rm(thread);
- const char* klass_name = Klass::cast(obj->klass())->external_name();
+ const char* klass_name = obj->klass()->external_name();
SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_ArrayStoreException(), klass_name);
JRT_END
@@ -631,7 +631,7 @@
NOT_PRODUCT(_throw_class_cast_exception_count++;)
ResourceMark rm(thread);
char* message = SharedRuntime::generate_class_cast_message(
- thread, Klass::cast(object->klass())->external_name());
+ thread, object->klass()->external_name());
SharedRuntime::throw_and_post_jvmti_exception(
thread, vmSymbols::java_lang_ClassCastException(), message);
JRT_END
@@ -876,7 +876,7 @@
case Bytecodes::_anewarray:
{ Bytecode_anewarray anew(caller_method(), caller_method->bcp_from(bci));
Klass* ek = caller_method->constants()->klass_at(anew.index(), CHECK);
- k = Klass::cast(ek)->array_klass(CHECK);
+ k = ek->array_klass(CHECK);
}
break;
case Bytecodes::_ldc:
@@ -1236,7 +1236,7 @@
} else {
Klass* bound = ObjArrayKlass::cast(dst->klass())->element_klass();
Klass* stype = ObjArrayKlass::cast(src->klass())->element_klass();
- if (stype == bound || Klass::cast(stype)->is_subtype_of(bound)) {
+ if (stype == bound || stype->is_subtype_of(bound)) {
// Elements are guaranteed to be subtypes, so no check necessary
bs->write_ref_array_pre(dst_addr, length);
Copy::conjoint_oops_atomic(src_addr, dst_addr, length);
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/c1/c1_globals.hpp
--- a/src/share/vm/c1/c1_globals.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/c1/c1_globals.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -147,7 +147,7 @@
"Inline methods containing exception handlers " \
"(NOTE: does not work with current backend)") \
\
- develop(bool, InlineSynchronizedMethods, true, \
+ product(bool, InlineSynchronizedMethods, true, \
"Inline synchronized methods") \
\
develop(bool, InlineNIOCheckIndex, true, \
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/bcEscapeAnalyzer.cpp
--- a/src/share/vm/ci/bcEscapeAnalyzer.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/bcEscapeAnalyzer.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -282,7 +282,7 @@
ciMethod* inline_target = NULL;
if (target->is_loaded() && klass->is_loaded()
&& (klass->is_initialized() || klass->is_interface() && target->holder()->is_initialized())
- && target->will_link(klass, callee_holder, code)) {
+ && target->is_loaded()) {
if (code == Bytecodes::_invokestatic
|| code == Bytecodes::_invokespecial
|| code == Bytecodes::_invokevirtual && target->is_final_method()) {
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciClassList.hpp
--- a/src/share/vm/ci/ciClassList.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciClassList.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -106,6 +106,7 @@
friend class ciArray; \
friend class ciObjArray; \
friend class ciMetadata; \
+friend class ciReplay; \
friend class ciTypeArray; \
friend class ciType; \
friend class ciReturnAddress; \
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciEnv.cpp
--- a/src/share/vm/ci/ciEnv.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciEnv.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -30,6 +30,7 @@
#include "ci/ciInstanceKlass.hpp"
#include "ci/ciMethod.hpp"
#include "ci/ciNullObject.hpp"
+#include "ci/ciReplay.hpp"
#include "ci/ciUtilities.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
@@ -426,7 +427,7 @@
for (int i = cpool->length() - 1; i >= 1; i--) {
if (cpool->tag_at(i).is_klass()) {
Klass* kls = cpool->resolved_klass_at(i);
- if (Klass::cast(kls)->name() == sym) {
+ if (kls->name() == sym) {
found_klass = KlassHandle(THREAD, kls);
break;
}
@@ -768,10 +769,15 @@
Method* 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->method_holder()->is_not_initialized()
+ : !m->method_holder()->is_loaded())) {
m = NULL;
}
+#ifdef ASSERT
+ if (m != NULL && ReplayCompiles && !ciReplay::is_loaded(m)) {
+ m = NULL;
+ }
+#endif
if (m != NULL) {
// We found the method.
return get_method(m);
@@ -1056,7 +1062,7 @@
method_name,
entry_bci);
}
- InstanceKlass::cast(method->method_holder())->add_osr_nmethod(nm);
+ method->method_holder()->add_osr_nmethod(nm);
}
}
@@ -1144,3 +1150,43 @@
// If memory is low, we stop compiling methods.
record_method_not_compilable("out of memory");
}
+
+fileStream* ciEnv::_replay_data_stream = NULL;
+
+void ciEnv::dump_replay_data() {
+ VM_ENTRY_MARK;
+ MutexLocker ml(Compile_lock);
+ if (_replay_data_stream == NULL) {
+ _replay_data_stream = new (ResourceObj::C_HEAP, mtCompiler) fileStream(ReplayDataFile);
+ if (_replay_data_stream == NULL) {
+ fatal(err_msg("Can't open %s for replay data", ReplayDataFile));
+ }
+ }
+ dump_replay_data(_replay_data_stream);
+}
+
+
+void ciEnv::dump_replay_data(outputStream* out) {
+ ASSERT_IN_VM;
+
+#if INCLUDE_JVMTI
+ out->print_cr("JvmtiExport can_access_local_variables %d", _jvmti_can_access_local_variables);
+ out->print_cr("JvmtiExport can_hotswap_or_post_breakpoint %d", _jvmti_can_hotswap_or_post_breakpoint);
+ out->print_cr("JvmtiExport can_post_on_exceptions %d", _jvmti_can_post_on_exceptions);
+#endif // INCLUDE_JVMTI
+
+ GrowableArray* objects = _factory->get_ci_metadata();
+ out->print_cr("# %d ciObject found", objects->length());
+ for (int i = 0; i < objects->length(); i++) {
+ objects->at(i)->dump_replay_data(out);
+ }
+ Method* method = task()->method();
+ int entry_bci = task()->osr_bci();
+ // Klass holder = method->method_holder();
+ out->print_cr("compile %s %s %s %d",
+ method->klass_name()->as_quoted_ascii(),
+ method->name()->as_quoted_ascii(),
+ method->signature()->as_quoted_ascii(),
+ entry_bci);
+ out->flush();
+}
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciEnv.hpp
--- a/src/share/vm/ci/ciEnv.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciEnv.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -46,6 +46,8 @@
friend class CompileBroker;
friend class Dependencies; // for get_object, during logging
+ static fileStream* _replay_data_stream;
+
private:
Arena* _arena; // Alias for _ciEnv_arena except in init_shared_objects()
Arena _ciEnv_arena;
@@ -448,6 +450,13 @@
// RedefineClasses support
void metadata_do(void f(Metadata*)) { _factory->metadata_do(f); }
+
+ // Dump the compilation replay data for this ciEnv to
+ // ReplayDataFile, creating the file if needed.
+ void dump_replay_data();
+
+ // Dump the compilation replay data for the ciEnv to the stream.
+ void dump_replay_data(outputStream* out);
};
#endif // SHARE_VM_CI_CIENV_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciField.cpp
--- a/src/share/vm/ci/ciField.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciField.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -366,10 +366,12 @@
// ------------------------------------------------------------------
// ciField::print
void ciField::print() {
- tty->print("print("print_symbol();
+ tty->print(" signature=");
+ _signature->print_symbol();
tty->print(" offset=%d type=", _offset);
if (_type != NULL) _type->print_name();
else tty->print("(reference)");
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciInstanceKlass.cpp
--- a/src/share/vm/ci/ciInstanceKlass.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciInstanceKlass.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -561,3 +561,114 @@
}
return impl;
}
+
+// Utility class for printing of the contents of the static fields for
+// use by compilation replay. It only prints out the information that
+// could be consumed by the compiler, so for primitive types it prints
+// out the actual value. For Strings it's the actual string value.
+// For array types it it's first level array size since that's the
+// only value which statically unchangeable. For all other reference
+// types it simply prints out the dynamic type.
+
+class StaticFinalFieldPrinter : public FieldClosure {
+ outputStream* _out;
+ const char* _holder;
+ public:
+ StaticFinalFieldPrinter(outputStream* out, const char* holder) :
+ _out(out),
+ _holder(holder) {
+ }
+ void do_field(fieldDescriptor* fd) {
+ if (fd->is_final() && !fd->has_initial_value()) {
+ oop mirror = fd->field_holder()->java_mirror();
+ _out->print("staticfield %s %s %s ", _holder, fd->name()->as_quoted_ascii(), fd->signature()->as_quoted_ascii());
+ switch (fd->field_type()) {
+ case T_BYTE: _out->print_cr("%d", mirror->byte_field(fd->offset())); break;
+ case T_BOOLEAN: _out->print_cr("%d", mirror->bool_field(fd->offset())); break;
+ case T_SHORT: _out->print_cr("%d", mirror->short_field(fd->offset())); break;
+ case T_CHAR: _out->print_cr("%d", mirror->char_field(fd->offset())); break;
+ case T_INT: _out->print_cr("%d", mirror->int_field(fd->offset())); break;
+ case T_LONG: _out->print_cr(INT64_FORMAT, mirror->long_field(fd->offset())); break;
+ case T_FLOAT: {
+ float f = mirror->float_field(fd->offset());
+ _out->print_cr("%d", *(int*)&f);
+ break;
+ }
+ case T_DOUBLE: {
+ double d = mirror->double_field(fd->offset());
+ _out->print_cr(INT64_FORMAT, *(jlong*)&d);
+ break;
+ }
+ case T_ARRAY: {
+ oop value = mirror->obj_field_acquire(fd->offset());
+ if (value == NULL) {
+ _out->print_cr("null");
+ } else {
+ typeArrayOop ta = (typeArrayOop)value;
+ _out->print("%d", ta->length());
+ if (value->is_objArray()) {
+ objArrayOop oa = (objArrayOop)value;
+ const char* klass_name = value->klass()->name()->as_quoted_ascii();
+ _out->print(" %s", klass_name);
+ }
+ _out->cr();
+ }
+ break;
+ }
+ case T_OBJECT: {
+ oop value = mirror->obj_field_acquire(fd->offset());
+ if (value == NULL) {
+ _out->print_cr("null");
+ } else if (value->is_instance()) {
+ if (value->is_a(SystemDictionary::String_klass())) {
+ _out->print("\"");
+ _out->print_raw(java_lang_String::as_quoted_ascii(value));
+ _out->print_cr("\"");
+ } else {
+ const char* klass_name = value->klass()->name()->as_quoted_ascii();
+ _out->print_cr(klass_name);
+ }
+ } else {
+ ShouldNotReachHere();
+ }
+ break;
+ }
+ default:
+ ShouldNotReachHere();
+ }
+ }
+ }
+};
+
+
+void ciInstanceKlass::dump_replay_data(outputStream* out) {
+ ASSERT_IN_VM;
+ InstanceKlass* ik = get_instanceKlass();
+ ConstantPool* cp = ik->constants();
+
+ // Try to record related loaded classes
+ Klass* sub = ik->subklass();
+ while (sub != NULL) {
+ if (sub->oop_is_instance()) {
+ out->print_cr("instanceKlass %s", sub->name()->as_quoted_ascii());
+ }
+ sub = sub->next_sibling();
+ }
+
+ // Dump out the state of the constant pool tags. During replay the
+ // tags will be validated for things which shouldn't change and
+ // classes will be resolved if the tags indicate that they were
+ // resolved at compile time.
+ out->print("ciInstanceKlass %s %d %d %d", ik->name()->as_quoted_ascii(),
+ is_linked(), is_initialized(), cp->length());
+ for (int index = 1; index < cp->length(); index++) {
+ out->print(" %d", cp->tags()->at(index));
+ }
+ out->cr();
+ if (is_initialized()) {
+ // Dump out the static final fields in case the compilation relies
+ // on their value for correct replay.
+ StaticFinalFieldPrinter sffp(out, ik->name()->as_quoted_ascii());
+ ik->do_local_static_fields(&sffp);
+ }
+}
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciInstanceKlass.hpp
--- a/src/share/vm/ci/ciInstanceKlass.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciInstanceKlass.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -230,6 +230,9 @@
// What kind of ciObject is this?
bool is_instance_klass() const { return true; }
bool is_java_klass() const { return true; }
+
+ // Dump the current state of this klass for compilation replay.
+ virtual void dump_replay_data(outputStream* out);
};
#endif // SHARE_VM_CI_CIINSTANCEKLASS_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciMetadata.hpp
--- a/src/share/vm/ci/ciMetadata.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciMetadata.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -61,6 +61,7 @@
virtual bool is_array_klass() const { return false; }
virtual bool is_obj_array_klass() const { return false; }
virtual bool is_type_array_klass() const { return false; }
+ virtual void dump_replay_data(outputStream* st) { /* do nothing */ }
ciMethod* as_method() {
assert(is_method(), "bad cast");
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciMethod.cpp
--- a/src/share/vm/ci/ciMethod.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciMethod.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -31,6 +31,7 @@
#include "ci/ciMethodData.hpp"
#include "ci/ciStreams.hpp"
#include "ci/ciSymbol.hpp"
+#include "ci/ciReplay.hpp"
#include "ci/ciUtilities.hpp"
#include "classfile/systemDictionary.hpp"
#include "compiler/abstractCompiler.hpp"
@@ -105,7 +106,7 @@
CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
}
- if (InstanceKlass::cast(h_m()->method_holder())->is_linked()) {
+ if (h_m()->method_holder()->is_linked()) {
_can_be_statically_bound = h_m()->can_be_statically_bound();
} else {
// Have to use a conservative value in this case.
@@ -139,6 +140,12 @@
}
if (_interpreter_invocation_count == 0)
_interpreter_invocation_count = 1;
+ _instructions_size = -1;
+#ifdef ASSERT
+ if (ReplayCompiles) {
+ ciReplay::initialize(this);
+ }
+#endif
}
@@ -161,7 +168,8 @@
#if defined(COMPILER2) || defined(SHARK)
,
_flow( NULL),
- _bcea( NULL)
+ _bcea( NULL),
+ _instructions_size(-1)
#endif // COMPILER2 || SHARK
{
// Usually holder and accessor are the same type but in some cases
@@ -188,7 +196,7 @@
// Revert any breakpoint bytecodes in ci's copy
if (me->number_of_breakpoints() > 0) {
- BreakpointInfo* bp = InstanceKlass::cast(me->method_holder())->breakpoints();
+ BreakpointInfo* bp = me->method_holder()->breakpoints();
for (; bp != NULL; bp = bp->next()) {
if (bp->match(me)) {
code_at_put(bp->bci(), bp->orig_bytecode());
@@ -734,6 +742,24 @@
}
// ------------------------------------------------------------------
+// ciMethod::get_field_at_bci
+ciField* ciMethod::get_field_at_bci(int bci, bool &will_link) {
+ ciBytecodeStream iter(this);
+ iter.reset_to_bci(bci);
+ iter.next();
+ return iter.get_field(will_link);
+}
+
+// ------------------------------------------------------------------
+// ciMethod::get_method_at_bci
+ciMethod* ciMethod::get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature) {
+ ciBytecodeStream iter(this);
+ iter.reset_to_bci(bci);
+ iter.next();
+ return iter.get_method(will_link, declared_signature);
+}
+
+// ------------------------------------------------------------------
// Adjust a CounterData count to be commensurate with
// interpreter_invocation_count. If the MDO exists for
// only 25% of the time the method exists, then the
@@ -868,25 +894,6 @@
}
// ------------------------------------------------------------------
-// ciMethod::will_link
-//
-// Will this method link in a specific calling context?
-bool ciMethod::will_link(ciKlass* accessing_klass,
- ciKlass* declared_method_holder,
- Bytecodes::Code bc) {
- if (!is_loaded()) {
- // Method lookup failed.
- return false;
- }
-
- // The link checks have been front-loaded into the get_method
- // call. This method (ciMethod::will_link()) will be removed
- // in the future.
-
- return true;
-}
-
-// ------------------------------------------------------------------
// ciMethod::should_exclude
//
// Should this method be excluded from compilation?
@@ -1000,8 +1007,7 @@
// ------------------------------------------------------------------
// ciMethod::has_compiled_code
bool ciMethod::has_compiled_code() {
- VM_ENTRY_MARK;
- return get_Method()->code() != NULL;
+ return instructions_size() > 0;
}
int ciMethod::comp_level() {
@@ -1039,14 +1045,18 @@
// junk like exception handler, stubs, and constant table, which are
// not highly relevant to an inlined method. So we use the more
// specific accessor nmethod::insts_size.
-int ciMethod::instructions_size(int comp_level) {
- GUARDED_VM_ENTRY(
- nmethod* code = get_Method()->code();
- if (code != NULL && (comp_level == CompLevel_any || comp_level == code->comp_level())) {
- return code->insts_end() - code->verified_entry_point();
- }
- return 0;
- )
+int ciMethod::instructions_size() {
+ if (_instructions_size == -1) {
+ GUARDED_VM_ENTRY(
+ nmethod* code = get_Method()->code();
+ if (code != NULL && (code->comp_level() == CompLevel_full_optimization)) {
+ _instructions_size = code->insts_end() - code->verified_entry_point();
+ } else {
+ _instructions_size = 0;
+ }
+ );
+ }
+ return _instructions_size;
}
// ------------------------------------------------------------------
@@ -1166,6 +1176,20 @@
#undef FETCH_FLAG_FROM_VM
+void ciMethod::dump_replay_data(outputStream* st) {
+ ASSERT_IN_VM;
+ Method* method = get_Method();
+ Klass* holder = method->method_holder();
+ st->print_cr("ciMethod %s %s %s %d %d %d %d %d",
+ holder->name()->as_quoted_ascii(),
+ method->name()->as_quoted_ascii(),
+ method->signature()->as_quoted_ascii(),
+ method->invocation_counter()->raw_counter(),
+ method->backedge_counter()->raw_counter(),
+ interpreter_invocation_count(),
+ interpreter_throwout_count(),
+ _instructions_size);
+}
// ------------------------------------------------------------------
// ciMethod::print_codes
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciMethod.hpp
--- a/src/share/vm/ci/ciMethod.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciMethod.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -51,6 +51,7 @@
friend class ciExceptionHandlerStream;
friend class ciBytecodeStream;
friend class ciMethodHandle;
+ friend class ciReplay;
private:
// General method information.
@@ -69,6 +70,7 @@
int _handler_count;
int _interpreter_invocation_count;
int _interpreter_throwout_count;
+ int _instructions_size;
bool _uses_monitors;
bool _balanced_monitors;
@@ -224,6 +226,9 @@
ciCallProfile call_profile_at_bci(int bci);
int interpreter_call_site_count(int bci);
+ ciField* get_field_at_bci( int bci, bool &will_link);
+ ciMethod* get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature);
+
// Given a certain calling environment, find the monomorphic target
// for the call. Return NULL if the call is not monomorphic in
// its calling environment.
@@ -239,9 +244,6 @@
int resolve_vtable_index(ciKlass* caller, ciKlass* receiver);
// Compilation directives
- bool will_link(ciKlass* accessing_klass,
- ciKlass* declared_method_holder,
- Bytecodes::Code bc);
bool should_exclude();
bool should_inline();
bool should_not_inline();
@@ -252,7 +254,6 @@
bool can_be_osr_compiled(int entry_bci);
void set_not_compilable();
bool has_compiled_code();
- int instructions_size(int comp_level = CompLevel_any);
void log_nmethod_identity(xmlStream* log);
bool is_not_reached(int bci);
bool was_executed_more_than(int times);
@@ -260,6 +261,7 @@
bool is_klass_loaded(int refinfo_index, bool must_be_resolved) const;
bool check_call(int refinfo_index, bool is_static) const;
bool ensure_method_data(); // make sure it exists in the VM also
+ int instructions_size();
int scale_count(int count, float prof_factor = 1.); // make MDO count commensurate with IIC
// JSR 292 support
@@ -291,6 +293,7 @@
bool is_accessor () const;
bool is_initializer () const;
bool can_be_statically_bound() const { return _can_be_statically_bound; }
+ void dump_replay_data(outputStream* st);
// Print the bytecodes of this method.
void print_codes_on(outputStream* st);
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciMethodData.cpp
--- a/src/share/vm/ci/ciMethodData.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciMethodData.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "ci/ciMetadata.hpp"
#include "ci/ciMethodData.hpp"
+#include "ci/ciReplay.hpp"
#include "ci/ciUtilities.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
@@ -115,6 +116,11 @@
_arg_local = mdo->arg_local();
_arg_stack = mdo->arg_stack();
_arg_returned = mdo->arg_returned();
+#ifndef PRODUCT
+ if (ReplayCompiles) {
+ ciReplay::initialize(this);
+ }
+#endif
}
void ciReceiverTypeData::translate_receiver_data_from(ProfileData* data) {
@@ -366,6 +372,79 @@
ciMetadata::print_impl(st);
}
+void ciMethodData::dump_replay_data(outputStream* out) {
+ ASSERT_IN_VM;
+ MethodData* mdo = get_MethodData();
+ Method* method = mdo->method();
+ Klass* holder = method->method_holder();
+ out->print("ciMethodData %s %s %s %d %d",
+ holder->name()->as_quoted_ascii(),
+ method->name()->as_quoted_ascii(),
+ method->signature()->as_quoted_ascii(),
+ _state,
+ current_mileage());
+
+ // dump the contents of the MDO header as raw data
+ unsigned char* orig = (unsigned char*)&_orig;
+ int length = sizeof(_orig);
+ out->print(" orig %d", length);
+ for (int i = 0; i < length; i++) {
+ out->print(" %d", orig[i]);
+ }
+
+ // dump the MDO data as raw data
+ int elements = data_size() / sizeof(intptr_t);
+ out->print(" data %d", elements);
+ for (int i = 0; i < elements; i++) {
+ // We could use INTPTR_FORMAT here but that's a zero justified
+ // which makes comparing it with the SA version of this output
+ // harder.
+#ifdef _LP64
+ out->print(" 0x%" FORMAT64_MODIFIER "x", data()[i]);
+#else
+ out->print(" 0x%x", data()[i]);
+#endif
+ }
+
+ // The MDO contained oop references as ciObjects, so scan for those
+ // and emit pairs of offset and klass name so that they can be
+ // reconstructed at runtime. The first round counts the number of
+ // oop references and the second actually emits them.
+ int count = 0;
+ for (int round = 0; round < 2; round++) {
+ if (round == 1) out->print(" oops %d", count);
+ ProfileData* pdata = first_data();
+ for ( ; is_valid(pdata); pdata = next_data(pdata)) {
+ if (pdata->is_ReceiverTypeData()) {
+ ciReceiverTypeData* vdata = (ciReceiverTypeData*)pdata;
+ for (uint i = 0; i < vdata->row_limit(); i++) {
+ ciKlass* k = vdata->receiver(i);
+ if (k != NULL) {
+ if (round == 0) {
+ count++;
+ } else {
+ out->print(" %d %s", dp_to_di(vdata->dp() + in_bytes(vdata->receiver_offset(i))) / sizeof(intptr_t), k->name()->as_quoted_ascii());
+ }
+ }
+ }
+ } else if (pdata->is_VirtualCallData()) {
+ ciVirtualCallData* vdata = (ciVirtualCallData*)pdata;
+ for (uint i = 0; i < vdata->row_limit(); i++) {
+ ciKlass* k = vdata->receiver(i);
+ if (k != NULL) {
+ if (round == 0) {
+ count++;
+ } else {
+ out->print(" %d %s", dp_to_di(vdata->dp() + in_bytes(vdata->receiver_offset(i))) / sizeof(intptr_t), k->name()->as_quoted_ascii());
+ }
+ }
+ }
+ }
+ }
+ }
+ out->cr();
+}
+
#ifndef PRODUCT
void ciMethodData::print() {
print_data_on(tty);
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciMethodData.hpp
--- a/src/share/vm/ci/ciMethodData.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciMethodData.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -144,6 +144,7 @@
class ciMethodData : public ciMetadata {
CI_PACKAGE_ACCESS
+ friend class ciReplay;
private:
// Size in bytes
@@ -320,6 +321,7 @@
void print();
void print_data_on(outputStream* st);
#endif
+ void dump_replay_data(outputStream* out);
};
#endif // SHARE_VM_CI_CIMETHODDATA_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciObject.hpp
--- a/src/share/vm/ci/ciObject.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciObject.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -131,6 +131,7 @@
// Is this a type or value which has no associated class?
// It is true of primitive types and null objects.
virtual bool is_classless() const { return false; }
+ virtual void dump_replay_data(outputStream* st) { /* do nothing */ }
// Note: some ciObjects refer to oops which have yet to be created.
// We refer to these as "unloaded". Specifically, there are
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciObjectFactory.hpp
--- a/src/share/vm/ci/ciObjectFactory.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciObjectFactory.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -137,6 +137,7 @@
ciReturnAddress* get_return_address(int bci);
+ GrowableArray* get_ci_metadata() const { return _ci_metadata; }
// RedefineClasses support
void metadata_do(void f(Metadata*));
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciReplay.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/ci/ciReplay.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -0,0 +1,942 @@
+/* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "ci/ciMethodData.hpp"
+#include "ci/ciReplay.hpp"
+#include "ci/ciUtilities.hpp"
+#include "compiler/compileBroker.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/oopFactory.hpp"
+#include "memory/resourceArea.hpp"
+#include "utilities/copy.hpp"
+
+#ifndef PRODUCT
+
+// ciReplay
+
+typedef struct _ciMethodDataRecord {
+ const char* klass;
+ const char* method;
+ const char* signature;
+ int state;
+ int current_mileage;
+ intptr_t* data;
+ int data_length;
+ char* orig_data;
+ int orig_data_length;
+ int oops_length;
+ jobject* oops_handles;
+ int* oops_offsets;
+} ciMethodDataRecord;
+
+typedef struct _ciMethodRecord {
+ const char* klass;
+ const char* method;
+ const char* signature;
+ int instructions_size;
+ int interpreter_invocation_count;
+ int interpreter_throwout_count;
+ int invocation_counter;
+ int backedge_counter;
+} ciMethodRecord;
+
+class CompileReplay;
+static CompileReplay* replay_state;
+
+class CompileReplay : public StackObj {
+ private:
+ FILE* stream;
+ Thread* thread;
+ Handle protection_domain;
+ Handle loader;
+
+ GrowableArray ci_method_records;
+ GrowableArray ci_method_data_records;
+
+ const char* _error_message;
+
+ char* bufptr;
+ char* buffer;
+ int buffer_length;
+ int buffer_end;
+ int line_no;
+
+ public:
+ CompileReplay(const char* filename, TRAPS) {
+ thread = THREAD;
+ loader = Handle(thread, SystemDictionary::java_system_loader());
+ stream = fopen(filename, "rt");
+ if (stream == NULL) {
+ fprintf(stderr, "Can't open replay file %s\n", filename);
+ }
+ buffer_length = 32;
+ buffer = NEW_RESOURCE_ARRAY(char, buffer_length);
+ _error_message = NULL;
+
+ test();
+ }
+
+ ~CompileReplay() {
+ if (stream != NULL) fclose(stream);
+ }
+
+ void test() {
+ strcpy(buffer, "1 2 foo 4 bar 0x9 \"this is it\"");
+ bufptr = buffer;
+ assert(parse_int("test") == 1, "what");
+ assert(parse_int("test") == 2, "what");
+ assert(strcmp(parse_string(), "foo") == 0, "what");
+ assert(parse_int("test") == 4, "what");
+ assert(strcmp(parse_string(), "bar") == 0, "what");
+ assert(parse_intptr_t("test") == 9, "what");
+ assert(strcmp(parse_quoted_string(), "this is it") == 0, "what");
+ }
+
+ bool had_error() {
+ return _error_message != NULL || thread->has_pending_exception();
+ }
+
+ bool can_replay() {
+ return !(stream == NULL || had_error());
+ }
+
+ void report_error(const char* msg) {
+ _error_message = msg;
+ // Restore the buffer contents for error reporting
+ for (int i = 0; i < buffer_end; i++) {
+ if (buffer[i] == '\0') buffer[i] = ' ';
+ }
+ }
+
+ int parse_int(const char* label) {
+ if (had_error()) {
+ return 0;
+ }
+
+ int v = 0;
+ int read;
+ if (sscanf(bufptr, "%i%n", &v, &read) != 1) {
+ report_error(label);
+ } else {
+ bufptr += read;
+ }
+ return v;
+ }
+
+ intptr_t parse_intptr_t(const char* label) {
+ if (had_error()) {
+ return 0;
+ }
+
+ intptr_t v = 0;
+ int read;
+ if (sscanf(bufptr, INTPTR_FORMAT "%n", &v, &read) != 1) {
+ report_error(label);
+ } else {
+ bufptr += read;
+ }
+ return v;
+ }
+
+ void skip_ws() {
+ // Skip any leading whitespace
+ while (*bufptr == ' ' || *bufptr == '\t') {
+ bufptr++;
+ }
+ }
+
+
+ char* scan_and_terminate(char delim) {
+ char* str = bufptr;
+ while (*bufptr != delim && *bufptr != '\0') {
+ bufptr++;
+ }
+ if (*bufptr != '\0') {
+ *bufptr++ = '\0';
+ }
+ if (bufptr == str) {
+ // nothing here
+ return NULL;
+ }
+ return str;
+ }
+
+ char* parse_string() {
+ if (had_error()) return NULL;
+
+ skip_ws();
+ return scan_and_terminate(' ');
+ }
+
+ char* parse_quoted_string() {
+ if (had_error()) return NULL;
+
+ skip_ws();
+
+ if (*bufptr == '"') {
+ bufptr++;
+ return scan_and_terminate('"');
+ } else {
+ return scan_and_terminate(' ');
+ }
+ }
+
+ const char* parse_escaped_string() {
+ char* result = parse_quoted_string();
+ if (result != NULL) {
+ unescape_string(result);
+ }
+ return result;
+ }
+
+ // Look for the tag 'tag' followed by an
+ bool parse_tag_and_count(const char* tag, int& length) {
+ const char* t = parse_string();
+ if (t == NULL) {
+ return false;
+ }
+
+ if (strcmp(tag, t) != 0) {
+ report_error(tag);
+ return false;
+ }
+ length = parse_int("parse_tag_and_count");
+ return !had_error();
+ }
+
+ // Parse a sequence of raw data encoded as bytes and return the
+ // resulting data.
+ char* parse_data(const char* tag, int& length) {
+ if (!parse_tag_and_count(tag, length)) {
+ return NULL;
+ }
+
+ char * result = NEW_RESOURCE_ARRAY(char, length);
+ for (int i = 0; i < length; i++) {
+ int val = parse_int("data");
+ result[i] = val;
+ }
+ return result;
+ }
+
+ // Parse a standard chunk of data emitted as:
+ // 'tag' # # ...
+ // Where each # is an intptr_t item
+ intptr_t* parse_intptr_data(const char* tag, int& length) {
+ if (!parse_tag_and_count(tag, length)) {
+ return NULL;
+ }
+
+ intptr_t* result = NEW_RESOURCE_ARRAY(intptr_t, length);
+ for (int i = 0; i < length; i++) {
+ skip_ws();
+ intptr_t val = parse_intptr_t("data");
+ result[i] = val;
+ }
+ return result;
+ }
+
+ // Parse a possibly quoted version of a symbol into a symbolOop
+ Symbol* parse_symbol(TRAPS) {
+ const char* str = parse_escaped_string();
+ if (str != NULL) {
+ Symbol* sym = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL);
+ return sym;
+ }
+ return NULL;
+ }
+
+ // Parse a valid klass name and look it up
+ Klass* parse_klass(TRAPS) {
+ const char* str = parse_escaped_string();
+ Symbol* klass_name = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL);
+ if (klass_name != NULL) {
+ Klass* k = SystemDictionary::resolve_or_fail(klass_name, loader, protection_domain, true, THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ oop throwable = PENDING_EXCEPTION;
+ java_lang_Throwable::print(throwable, tty);
+ tty->cr();
+ report_error(str);
+ return NULL;
+ }
+ return k;
+ }
+ return NULL;
+ }
+
+ // Lookup a klass
+ Klass* resolve_klass(const char* klass, TRAPS) {
+ Symbol* klass_name = SymbolTable::lookup(klass, (int)strlen(klass), CHECK_NULL);
+ return SystemDictionary::resolve_or_fail(klass_name, loader, protection_domain, true, CHECK_NULL);
+ }
+
+ // Parse the standard tuple of
+ Method* parse_method(TRAPS) {
+ InstanceKlass* k = (InstanceKlass*)parse_klass(CHECK_NULL);
+ Symbol* method_name = parse_symbol(CHECK_NULL);
+ Symbol* method_signature = parse_symbol(CHECK_NULL);
+ Method* m = k->find_method(method_name, method_signature);
+ if (m == NULL) {
+ report_error("can't find method");
+ }
+ return m;
+ }
+
+ // Process each line of the replay file executing each command until
+ // the file ends.
+ void process(TRAPS) {
+ line_no = 1;
+ int pos = 0;
+ int c = getc(stream);
+ while(c != EOF) {
+ if (pos + 1 >= buffer_length) {
+ int newl = buffer_length * 2;
+ char* newb = NEW_RESOURCE_ARRAY(char, newl);
+ memcpy(newb, buffer, pos);
+ buffer = newb;
+ buffer_length = newl;
+ }
+ if (c == '\n') {
+ // null terminate it, reset the pointer and process the line
+ buffer[pos] = '\0';
+ buffer_end = pos++;
+ bufptr = buffer;
+ process_command(CHECK);
+ if (had_error()) {
+ tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message);
+ tty->print_cr("%s", buffer);
+ assert(false, "error");
+ return;
+ }
+ pos = 0;
+ buffer_end = 0;
+ line_no++;
+ } else if (c == '\r') {
+ // skip LF
+ } else {
+ buffer[pos++] = c;
+ }
+ c = getc(stream);
+ }
+ }
+
+ void process_command(TRAPS) {
+ char* cmd = parse_string();
+ if (cmd == NULL) {
+ return;
+ }
+ if (strcmp("#", cmd) == 0) {
+ // ignore
+ } else if (strcmp("compile", cmd) == 0) {
+ process_compile(CHECK);
+ } else if (strcmp("ciMethod", cmd) == 0) {
+ process_ciMethod(CHECK);
+ } else if (strcmp("ciMethodData", cmd) == 0) {
+ process_ciMethodData(CHECK);
+ } else if (strcmp("staticfield", cmd) == 0) {
+ process_staticfield(CHECK);
+ } else if (strcmp("ciInstanceKlass", cmd) == 0) {
+ process_ciInstanceKlass(CHECK);
+ } else if (strcmp("instanceKlass", cmd) == 0) {
+ process_instanceKlass(CHECK);
+#if INCLUDE_JVMTI
+ } else if (strcmp("JvmtiExport", cmd) == 0) {
+ process_JvmtiExport(CHECK);
+#endif // INCLUDE_JVMTI
+ } else {
+ report_error("unknown command");
+ }
+ }
+
+ // compile
+ void process_compile(TRAPS) {
+ // methodHandle method;
+ Method* method = parse_method(CHECK);
+ int entry_bci = parse_int("entry_bci");
+ Klass* k = method->method_holder();
+ ((InstanceKlass*)k)->initialize(THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ oop throwable = PENDING_EXCEPTION;
+ java_lang_Throwable::print(throwable, tty);
+ tty->cr();
+ if (ReplayIgnoreInitErrors) {
+ CLEAR_PENDING_EXCEPTION;
+ ((InstanceKlass*)k)->set_init_state(InstanceKlass::fully_initialized);
+ } else {
+ return;
+ }
+ }
+ // Make sure the existence of a prior compile doesn't stop this one
+ nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, CompLevel_full_optimization, true) : method->code();
+ if (nm != NULL) {
+ nm->make_not_entrant();
+ }
+ replay_state = this;
+ CompileBroker::compile_method(method, entry_bci, CompLevel_full_optimization,
+ methodHandle(), 0, "replay", THREAD);
+ replay_state = NULL;
+ reset();
+ }
+
+ // ciMethod
+ //
+ //
+ void process_ciMethod(TRAPS) {
+ Method* method = parse_method(CHECK);
+ ciMethodRecord* rec = new_ciMethod(method);
+ rec->invocation_counter = parse_int("invocation_counter");
+ rec->backedge_counter = parse_int("backedge_counter");
+ rec->interpreter_invocation_count = parse_int("interpreter_invocation_count");
+ rec->interpreter_throwout_count = parse_int("interpreter_throwout_count");
+ rec->instructions_size = parse_int("instructions_size");
+ }
+
+ // ciMethodData orig # # ... data # # ... oops
+ void process_ciMethodData(TRAPS) {
+ Method* method = parse_method(CHECK);
+ /* jsut copied from Method, to build interpret data*/
+ if (InstanceRefKlass::owns_pending_list_lock((JavaThread*)THREAD)) {
+ return;
+ }
+ // methodOopDesc::build_interpreter_method_data(method, CHECK);
+ {
+ // Grab a lock here to prevent multiple
+ // MethodData*s from being created.
+ MutexLocker ml(MethodData_lock, THREAD);
+ if (method->method_data() == NULL) {
+ ClassLoaderData* loader_data = method->method_holder()->class_loader_data();
+ MethodData* method_data = MethodData::allocate(loader_data, method, CHECK);
+ method->set_method_data(method_data);
+ }
+ }
+
+ // collect and record all the needed information for later
+ ciMethodDataRecord* rec = new_ciMethodData(method);
+ rec->state = parse_int("state");
+ rec->current_mileage = parse_int("current_mileage");
+
+ rec->orig_data = parse_data("orig", rec->orig_data_length);
+ if (rec->orig_data == NULL) {
+ return;
+ }
+ rec->data = parse_intptr_data("data", rec->data_length);
+ if (rec->data == NULL) {
+ return;
+ }
+ if (!parse_tag_and_count("oops", rec->oops_length)) {
+ return;
+ }
+ rec->oops_handles = NEW_RESOURCE_ARRAY(jobject, rec->oops_length);
+ rec->oops_offsets = NEW_RESOURCE_ARRAY(int, rec->oops_length);
+ for (int i = 0; i < rec->oops_length; i++) {
+ int offset = parse_int("offset");
+ if (had_error()) {
+ return;
+ }
+ Klass* k = parse_klass(CHECK);
+ rec->oops_offsets[i] = offset;
+ rec->oops_handles[i] = (jobject)(new KlassHandle(THREAD, k));
+ }
+ }
+
+ // instanceKlass
+ //
+ // Loads and initializes the klass 'name'. This can be used to
+ // create particular class loading environments
+ void process_instanceKlass(TRAPS) {
+ // just load the referenced class
+ Klass* k = parse_klass(CHECK);
+ }
+
+ // ciInstanceKlass tag # # # ...
+ //
+ // Load the klass 'name' and link or initialize it. Verify that the
+ // constant pool is the same length as 'length' and make sure the
+ // constant pool tags are in the same state.
+ void process_ciInstanceKlass(TRAPS) {
+ InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK);
+ int is_linked = parse_int("is_linked");
+ int is_initialized = parse_int("is_initialized");
+ int length = parse_int("length");
+ if (is_initialized) {
+ k->initialize(THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ oop throwable = PENDING_EXCEPTION;
+ java_lang_Throwable::print(throwable, tty);
+ tty->cr();
+ if (ReplayIgnoreInitErrors) {
+ CLEAR_PENDING_EXCEPTION;
+ k->set_init_state(InstanceKlass::fully_initialized);
+ } else {
+ return;
+ }
+ }
+ } else if (is_linked) {
+ k->link_class(CHECK);
+ }
+ ConstantPool* cp = k->constants();
+ if (length != cp->length()) {
+ report_error("constant pool length mismatch: wrong class files?");
+ return;
+ }
+
+ int parsed_two_word = 0;
+ for (int i = 1; i < length; i++) {
+ int tag = parse_int("tag");
+ if (had_error()) {
+ return;
+ }
+ switch (cp->tag_at(i).value()) {
+ case JVM_CONSTANT_UnresolvedClass: {
+ if (tag == JVM_CONSTANT_Class) {
+ tty->print_cr("Resolving klass %s at %d", cp->unresolved_klass_at(i)->as_utf8(), i);
+ Klass* k = cp->klass_at(i, CHECK);
+ }
+ break;
+ }
+ case JVM_CONSTANT_Long:
+ case JVM_CONSTANT_Double:
+ parsed_two_word = i + 1;
+
+ case JVM_CONSTANT_ClassIndex:
+ case JVM_CONSTANT_StringIndex:
+ case JVM_CONSTANT_String:
+ case JVM_CONSTANT_UnresolvedClassInError:
+ case JVM_CONSTANT_Fieldref:
+ case JVM_CONSTANT_Methodref:
+ case JVM_CONSTANT_InterfaceMethodref:
+ case JVM_CONSTANT_NameAndType:
+ case JVM_CONSTANT_Utf8:
+ case JVM_CONSTANT_Integer:
+ case JVM_CONSTANT_Float:
+ if (tag != cp->tag_at(i).value()) {
+ report_error("tag mismatch: wrong class files?");
+ return;
+ }
+ break;
+
+ case JVM_CONSTANT_Class:
+ if (tag == JVM_CONSTANT_Class) {
+ } else if (tag == JVM_CONSTANT_UnresolvedClass) {
+ tty->print_cr("Warning: entry was unresolved in the replay data");
+ } else {
+ report_error("Unexpected tag");
+ return;
+ }
+ break;
+
+ case 0:
+ if (parsed_two_word == i) continue;
+
+ default:
+ ShouldNotReachHere();
+ break;
+ }
+
+ }
+ }
+
+ // Initialize a class and fill in the value for a static field.
+ // This is useful when the compile was dependent on the value of
+ // static fields but it's impossible to properly rerun the static
+ // initiailizer.
+ void process_staticfield(TRAPS) {
+ InstanceKlass* k = (InstanceKlass *)parse_klass(CHECK);
+
+ if (ReplaySuppressInitializers == 0 ||
+ ReplaySuppressInitializers == 2 && k->class_loader() == NULL) {
+ return;
+ }
+
+ assert(k->is_initialized(), "must be");
+
+ const char* field_name = parse_escaped_string();;
+ const char* field_signature = parse_string();
+ fieldDescriptor fd;
+ Symbol* name = SymbolTable::lookup(field_name, (int)strlen(field_name), CHECK);
+ Symbol* sig = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK);
+ if (!k->find_local_field(name, sig, &fd) ||
+ !fd.is_static() ||
+ fd.has_initial_value()) {
+ report_error(field_name);
+ return;
+ }
+
+ oop java_mirror = k->java_mirror();
+ if (field_signature[0] == '[') {
+ int length = parse_int("array length");
+ oop value = NULL;
+
+ if (field_signature[1] == '[') {
+ // multi dimensional array
+ ArrayKlass* kelem = (ArrayKlass *)parse_klass(CHECK);
+ int rank = 0;
+ while (field_signature[rank] == '[') {
+ rank++;
+ }
+ int* dims = NEW_RESOURCE_ARRAY(int, rank);
+ dims[0] = length;
+ for (int i = 1; i < rank; i++) {
+ dims[i] = 1; // These aren't relevant to the compiler
+ }
+ value = kelem->multi_allocate(rank, dims, CHECK);
+ } else {
+ if (strcmp(field_signature, "[B") == 0) {
+ value = oopFactory::new_byteArray(length, CHECK);
+ } else if (strcmp(field_signature, "[Z") == 0) {
+ value = oopFactory::new_boolArray(length, CHECK);
+ } else if (strcmp(field_signature, "[C") == 0) {
+ value = oopFactory::new_charArray(length, CHECK);
+ } else if (strcmp(field_signature, "[S") == 0) {
+ value = oopFactory::new_shortArray(length, CHECK);
+ } else if (strcmp(field_signature, "[F") == 0) {
+ value = oopFactory::new_singleArray(length, CHECK);
+ } else if (strcmp(field_signature, "[D") == 0) {
+ value = oopFactory::new_doubleArray(length, CHECK);
+ } else if (strcmp(field_signature, "[I") == 0) {
+ value = oopFactory::new_intArray(length, CHECK);
+ } else if (strcmp(field_signature, "[J") == 0) {
+ value = oopFactory::new_longArray(length, CHECK);
+ } else if (field_signature[0] == '[' && field_signature[1] == 'L') {
+ KlassHandle kelem = resolve_klass(field_signature + 1, CHECK);
+ value = oopFactory::new_objArray(kelem(), length, CHECK);
+ } else {
+ report_error("unhandled array staticfield");
+ }
+ }
+ java_mirror->obj_field_put(fd.offset(), value);
+ } else {
+ const char* string_value = parse_escaped_string();
+ if (strcmp(field_signature, "I") == 0) {
+ int value = atoi(string_value);
+ java_mirror->int_field_put(fd.offset(), value);
+ } else if (strcmp(field_signature, "B") == 0) {
+ int value = atoi(string_value);
+ java_mirror->byte_field_put(fd.offset(), value);
+ } else if (strcmp(field_signature, "C") == 0) {
+ int value = atoi(string_value);
+ java_mirror->char_field_put(fd.offset(), value);
+ } else if (strcmp(field_signature, "S") == 0) {
+ int value = atoi(string_value);
+ java_mirror->short_field_put(fd.offset(), value);
+ } else if (strcmp(field_signature, "Z") == 0) {
+ int value = atol(string_value);
+ java_mirror->bool_field_put(fd.offset(), value);
+ } else if (strcmp(field_signature, "J") == 0) {
+ jlong value;
+ if (sscanf(string_value, JLONG_FORMAT, &value) != 1) {
+ fprintf(stderr, "Error parsing long: %s\n", string_value);
+ return;
+ }
+ java_mirror->long_field_put(fd.offset(), value);
+ } else if (strcmp(field_signature, "F") == 0) {
+ float value = atof(string_value);
+ java_mirror->float_field_put(fd.offset(), value);
+ } else if (strcmp(field_signature, "D") == 0) {
+ double value = atof(string_value);
+ java_mirror->double_field_put(fd.offset(), value);
+ } else if (strcmp(field_signature, "Ljava/lang/String;") == 0) {
+ Handle value = java_lang_String::create_from_str(string_value, CHECK);
+ java_mirror->obj_field_put(fd.offset(), value());
+ } else if (field_signature[0] == 'L') {
+ Symbol* klass_name = SymbolTable::lookup(field_signature, (int)strlen(field_signature), CHECK);
+ KlassHandle kelem = resolve_klass(field_signature, CHECK);
+ oop value = ((InstanceKlass*)kelem())->allocate_instance(CHECK);
+ java_mirror->obj_field_put(fd.offset(), value);
+ } else {
+ report_error("unhandled staticfield");
+ }
+ }
+ }
+
+#if INCLUDE_JVMTI
+ void process_JvmtiExport(TRAPS) {
+ const char* field = parse_string();
+ bool value = parse_int("JvmtiExport flag") != 0;
+ if (strcmp(field, "can_access_local_variables") == 0) {
+ JvmtiExport::set_can_access_local_variables(value);
+ } else if (strcmp(field, "can_hotswap_or_post_breakpoint") == 0) {
+ JvmtiExport::set_can_hotswap_or_post_breakpoint(value);
+ } else if (strcmp(field, "can_post_on_exceptions") == 0) {
+ JvmtiExport::set_can_post_on_exceptions(value);
+ } else {
+ report_error("Unrecognized JvmtiExport directive");
+ }
+ }
+#endif // INCLUDE_JVMTI
+
+ // Create and initialize a record for a ciMethod
+ ciMethodRecord* new_ciMethod(Method* method) {
+ ciMethodRecord* rec = NEW_RESOURCE_OBJ(ciMethodRecord);
+ rec->klass = method->method_holder()->name()->as_utf8();
+ rec->method = method->name()->as_utf8();
+ rec->signature = method->signature()->as_utf8();
+ ci_method_records.append(rec);
+ return rec;
+ }
+
+ // Lookup data for a ciMethod
+ ciMethodRecord* find_ciMethodRecord(Method* method) {
+ const char* klass_name = method->method_holder()->name()->as_utf8();
+ const char* method_name = method->name()->as_utf8();
+ const char* signature = method->signature()->as_utf8();
+ for (int i = 0; i < ci_method_records.length(); i++) {
+ ciMethodRecord* rec = ci_method_records.at(i);
+ if (strcmp(rec->klass, klass_name) == 0 &&
+ strcmp(rec->method, method_name) == 0 &&
+ strcmp(rec->signature, signature) == 0) {
+ return rec;
+ }
+ }
+ return NULL;
+ }
+
+ // Create and initialize a record for a ciMethodData
+ ciMethodDataRecord* new_ciMethodData(Method* method) {
+ ciMethodDataRecord* rec = NEW_RESOURCE_OBJ(ciMethodDataRecord);
+ rec->klass = method->method_holder()->name()->as_utf8();
+ rec->method = method->name()->as_utf8();
+ rec->signature = method->signature()->as_utf8();
+ ci_method_data_records.append(rec);
+ return rec;
+ }
+
+ // Lookup data for a ciMethodData
+ ciMethodDataRecord* find_ciMethodDataRecord(Method* method) {
+ const char* klass_name = method->method_holder()->name()->as_utf8();
+ const char* method_name = method->name()->as_utf8();
+ const char* signature = method->signature()->as_utf8();
+ for (int i = 0; i < ci_method_data_records.length(); i++) {
+ ciMethodDataRecord* rec = ci_method_data_records.at(i);
+ if (strcmp(rec->klass, klass_name) == 0 &&
+ strcmp(rec->method, method_name) == 0 &&
+ strcmp(rec->signature, signature) == 0) {
+ return rec;
+ }
+ }
+ return NULL;
+ }
+
+ const char* error_message() {
+ return _error_message;
+ }
+
+ void reset() {
+ _error_message = NULL;
+ ci_method_records.clear();
+ ci_method_data_records.clear();
+ }
+
+ // Take an ascii string contain \u#### escapes and convert it to utf8
+ // in place.
+ static void unescape_string(char* value) {
+ char* from = value;
+ char* to = value;
+ while (*from != '\0') {
+ if (*from != '\\') {
+ *from++ = *to++;
+ } else {
+ switch (from[1]) {
+ case 'u': {
+ from += 2;
+ jchar value=0;
+ for (int i=0; i<4; i++) {
+ char c = *from++;
+ switch (c) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ value = (value << 4) + c - '0';
+ break;
+ case 'a': case 'b': case 'c':
+ case 'd': case 'e': case 'f':
+ value = (value << 4) + 10 + c - 'a';
+ break;
+ case 'A': case 'B': case 'C':
+ case 'D': case 'E': case 'F':
+ value = (value << 4) + 10 + c - 'A';
+ break;
+ default:
+ ShouldNotReachHere();
+ }
+ }
+ UNICODE::convert_to_utf8(&value, 1, to);
+ to++;
+ break;
+ }
+ case 't': *to++ = '\t'; from += 2; break;
+ case 'n': *to++ = '\n'; from += 2; break;
+ case 'r': *to++ = '\r'; from += 2; break;
+ case 'f': *to++ = '\f'; from += 2; break;
+ default:
+ ShouldNotReachHere();
+ }
+ }
+ }
+ *from = *to;
+ }
+};
+
+void ciReplay::replay(TRAPS) {
+ int exit_code = replay_impl(THREAD);
+
+ Threads::destroy_vm();
+
+ vm_exit(exit_code);
+}
+
+int ciReplay::replay_impl(TRAPS) {
+ HandleMark hm;
+ ResourceMark rm;
+ // Make sure we don't run with background compilation
+ BackgroundCompilation = false;
+
+ if (ReplaySuppressInitializers > 2) {
+ // ReplaySuppressInitializers > 2 means that we want to allow
+ // normal VM bootstrap but once we get into the replay itself
+ // don't allow any intializers to be run.
+ ReplaySuppressInitializers = 1;
+ }
+
+ // Load and parse the replay data
+ CompileReplay rp(ReplayDataFile, THREAD);
+ int exit_code = 0;
+ if (rp.can_replay()) {
+ rp.process(THREAD);
+ } else {
+ exit_code = 1;
+ return exit_code;
+ }
+
+ if (HAS_PENDING_EXCEPTION) {
+ oop throwable = PENDING_EXCEPTION;
+ CLEAR_PENDING_EXCEPTION;
+ java_lang_Throwable::print(throwable, tty);
+ tty->cr();
+ java_lang_Throwable::print_stack_trace(throwable, tty);
+ tty->cr();
+ exit_code = 2;
+ }
+
+ if (rp.had_error()) {
+ tty->print_cr("Failed on %s", rp.error_message());
+ exit_code = 1;
+ }
+ return exit_code;
+}
+
+
+void ciReplay::initialize(ciMethodData* m) {
+ if (replay_state == NULL) {
+ return;
+ }
+
+ ASSERT_IN_VM;
+ ResourceMark rm;
+
+ Method* method = m->get_MethodData()->method();
+ ciMethodDataRecord* rec = replay_state->find_ciMethodDataRecord(method);
+ if (rec == NULL) {
+ // This indicates some mismatch with the original environment and
+ // the replay environment though it's not always enough to
+ // interfere with reproducing a bug
+ tty->print_cr("Warning: requesting ciMethodData record for method with no data: ");
+ method->print_name(tty);
+ tty->cr();
+ } else {
+ m->_state = rec->state;
+ m->_current_mileage = rec->current_mileage;
+ if (rec->data_length != 0) {
+ assert(m->_data_size == rec->data_length * (int)sizeof(rec->data[0]), "must agree");
+
+ // Write the correct ciObjects back into the profile data
+ ciEnv* env = ciEnv::current();
+ for (int i = 0; i < rec->oops_length; i++) {
+ KlassHandle *h = (KlassHandle *)rec->oops_handles[i];
+ *(ciMetadata**)(rec->data + rec->oops_offsets[i]) =
+ env->get_metadata((*h)());
+ }
+ // Copy the updated profile data into place as intptr_ts
+#ifdef _LP64
+ Copy::conjoint_jlongs_atomic((jlong *)rec->data, (jlong *)m->_data, rec->data_length);
+#else
+ Copy::conjoint_jints_atomic((jint *)rec->data, (jint *)m->_data, rec->data_length);
+#endif
+ }
+
+ // copy in the original header
+ Copy::conjoint_jbytes(rec->orig_data, (char*)&m->_orig, rec->orig_data_length);
+ }
+}
+
+
+bool ciReplay::should_not_inline(ciMethod* method) {
+ if (replay_state == NULL) {
+ return false;
+ }
+
+ VM_ENTRY_MARK;
+ // ciMethod without a record shouldn't be inlined.
+ return replay_state->find_ciMethodRecord(method->get_Method()) == NULL;
+}
+
+
+void ciReplay::initialize(ciMethod* m) {
+ if (replay_state == NULL) {
+ return;
+ }
+
+ ASSERT_IN_VM;
+ ResourceMark rm;
+
+ Method* method = m->get_Method();
+ ciMethodRecord* rec = replay_state->find_ciMethodRecord(method);
+ if (rec == NULL) {
+ // This indicates some mismatch with the original environment and
+ // the replay environment though it's not always enough to
+ // interfere with reproducing a bug
+ tty->print_cr("Warning: requesting ciMethod record for method with no data: ");
+ method->print_name(tty);
+ tty->cr();
+ } else {
+ // m->_instructions_size = rec->instructions_size;
+ m->_instructions_size = -1;
+ m->_interpreter_invocation_count = rec->interpreter_invocation_count;
+ m->_interpreter_throwout_count = rec->interpreter_throwout_count;
+ method->invocation_counter()->_counter = rec->invocation_counter;
+ method->backedge_counter()->_counter = rec->backedge_counter;
+ }
+}
+
+bool ciReplay::is_loaded(Method* method) {
+ if (replay_state == NULL) {
+ return true;
+ }
+
+ ASSERT_IN_VM;
+ ResourceMark rm;
+
+ ciMethodRecord* rec = replay_state->find_ciMethodRecord(method);
+ return rec != NULL;
+}
+#endif // PRODUCT
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciReplay.hpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/ci/ciReplay.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_CI_CIREPLAY_HPP
+#define SHARE_VM_CI_CIREPLAY_HPP
+
+#include "ci/ciMethod.hpp"
+
+// ciReplay
+
+class ciReplay {
+ CI_PACKAGE_ACCESS
+
+#ifndef PRODUCT
+ private:
+ static int replay_impl(TRAPS);
+
+ public:
+ static void replay(TRAPS);
+
+ // These are used by the CI to fill in the cached data from the
+ // replay file when replaying compiles.
+ static void initialize(ciMethodData* method);
+ static void initialize(ciMethod* method);
+
+ static bool is_loaded(Method* method);
+ static bool is_loaded(Klass* klass);
+
+ static bool should_not_inline(ciMethod* method);
+
+#endif
+};
+
+#endif // SHARE_VM_CI_CIREPLAY_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciSignature.hpp
--- a/src/share/vm/ci/ciSignature.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciSignature.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -57,12 +57,14 @@
ciSymbol* as_symbol() const { return _symbol; }
ciKlass* accessing_klass() const { return _accessing_klass; }
- ciType* return_type() const;
- ciType* type_at(int index) const;
+ ciType* return_type() const;
+ ciType* type_at(int index) const;
int size() const { return _size; }
int count() const { return _count; }
+ int arg_size_for_bc(Bytecodes::Code bc) { return size() + (Bytecodes::has_receiver(bc) ? 1 : 0); }
+
bool equals(ciSignature* that);
void print_signature();
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciSymbol.cpp
--- a/src/share/vm/ci/ciSymbol.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciSymbol.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -63,6 +63,11 @@
return s->as_utf8();
}
+// The text of the symbol as a null-terminated C string.
+const char* ciSymbol::as_quoted_ascii() {
+ GUARDED_VM_QUICK_ENTRY(return get_symbol()->as_quoted_ascii();)
+}
+
// ------------------------------------------------------------------
// ciSymbol::base
const jbyte* ciSymbol::base() {
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciSymbol.hpp
--- a/src/share/vm/ci/ciSymbol.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciSymbol.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -73,6 +73,9 @@
const char* as_utf8();
int utf8_length();
+ // The text of the symbol as ascii with all non-printable characters quoted as \u####
+ const char* as_quoted_ascii();
+
// Return the i-th utf8 byte, where i < utf8_length
int byte_at(int i);
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciType.cpp
--- a/src/share/vm/ci/ciType.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciType.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -45,7 +45,7 @@
}
ciType::ciType(KlassHandle k) : ciMetadata(k()) {
- _basic_type = Klass::cast(k())->oop_is_array() ? T_ARRAY : T_OBJECT;
+ _basic_type = k()->oop_is_array() ? T_ARRAY : T_OBJECT;
}
@@ -60,6 +60,19 @@
}
// ------------------------------------------------------------------
+// ciType::name
+//
+// Return the name of this type
+const char* ciType::name() {
+ if (is_primitive_type()) {
+ return type2name(basic_type());
+ } else {
+ assert(is_klass(), "must be");
+ return as_klass()->name()->as_utf8();
+ }
+}
+
+// ------------------------------------------------------------------
// ciType::print_impl
//
// Implementation of the print method.
@@ -73,7 +86,8 @@
//
// Print the name of this type
void ciType::print_name_on(outputStream* st) {
- st->print(type2name(basic_type()));
+ ResourceMark rm;
+ st->print(name());
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciType.hpp
--- a/src/share/vm/ci/ciType.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciType.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -77,6 +77,7 @@
bool is_type() const { return true; }
bool is_classless() const { return is_primitive_type(); }
+ const char* name();
virtual void print_name_on(outputStream* st);
void print_name() {
print_name_on(tty);
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/ci/ciUtilities.hpp
--- a/src/share/vm/ci/ciUtilities.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/ci/ciUtilities.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2012, 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
@@ -80,6 +80,9 @@
#define GUARDED_VM_ENTRY(action) \
{if (IS_IN_VM) { action } else { VM_ENTRY_MARK; { action }}}
+#define GUARDED_VM_QUICK_ENTRY(action) \
+ {if (IS_IN_VM) { action } else { VM_QUICK_ENTRY_MARK; { action }}}
+
// Redefine this later.
#define KILL_COMPILE_ON_FATAL_(result) \
THREAD); \
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/classfile/bytecodeAssembler.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/classfile/bytecodeAssembler.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+
+#include "classfile/bytecodeAssembler.hpp"
+#include "interpreter/bytecodes.hpp"
+#include "memory/oopFactory.hpp"
+#include "oops/constantPool.hpp"
+
+#ifdef TARGET_ARCH_x86
+# include "bytes_x86.hpp"
+#endif
+#ifdef TARGET_ARCH_sparc
+# include "bytes_sparc.hpp"
+#endif
+#ifdef TARGET_ARCH_zero
+# include "bytes_zero.hpp"
+#endif
+#ifdef TARGET_ARCH_arm
+# include "bytes_arm.hpp"
+#endif
+#ifdef TARGET_ARCH_ppc
+# include "bytes_ppc.hpp"
+#endif
+
+u2 BytecodeConstantPool::find_or_add(BytecodeCPEntry const& bcpe) {
+ u2 index;
+ u2* probe = _indices.get(bcpe);
+ if (probe == NULL) {
+ index = _entries.length();
+ _entries.append(bcpe);
+ _indices.put(bcpe, index);
+ } else {
+ index = *probe;
+ }
+ return index + _orig->length();
+}
+
+ConstantPool* BytecodeConstantPool::create_constant_pool(TRAPS) const {
+ if (_entries.length() == 0) {
+ return _orig;
+ }
+
+ ConstantPool* cp = ConstantPool::allocate(
+ _orig->pool_holder()->class_loader_data(),
+ _orig->length() + _entries.length(), CHECK_NULL);
+
+ cp->set_pool_holder(_orig->pool_holder());
+ _orig->copy_cp_to(1, _orig->length() - 1, cp, 1, CHECK_NULL);
+
+ for (int i = 0; i < _entries.length(); ++i) {
+ BytecodeCPEntry entry = _entries.at(i);
+ int idx = i + _orig->length();
+ switch (entry._tag) {
+ case BytecodeCPEntry::UTF8:
+ cp->symbol_at_put(idx, entry._u.utf8);
+ entry._u.utf8->increment_refcount();
+ break;
+ case BytecodeCPEntry::KLASS:
+ cp->unresolved_klass_at_put(
+ idx, cp->symbol_at(entry._u.klass));
+ break;
+ case BytecodeCPEntry::STRING:
+ cp->unresolved_string_at_put(
+ idx, cp->symbol_at(entry._u.string));
+ break;
+ case BytecodeCPEntry::NAME_AND_TYPE:
+ cp->name_and_type_at_put(idx,
+ entry._u.name_and_type.name_index,
+ entry._u.name_and_type.type_index);
+ break;
+ case BytecodeCPEntry::METHODREF:
+ cp->method_at_put(idx,
+ entry._u.methodref.class_index,
+ entry._u.methodref.name_and_type_index);
+ break;
+ default:
+ ShouldNotReachHere();
+ }
+ }
+ return cp;
+}
+
+void BytecodeAssembler::append(u1 imm_u1) {
+ _code->append(imm_u1);
+}
+
+void BytecodeAssembler::append(u2 imm_u2) {
+ _code->append(0);
+ _code->append(0);
+ Bytes::put_Java_u2(_code->adr_at(_code->length() - 2), imm_u2);
+}
+
+void BytecodeAssembler::append(u4 imm_u4) {
+ _code->append(0);
+ _code->append(0);
+ _code->append(0);
+ _code->append(0);
+ Bytes::put_Java_u4(_code->adr_at(_code->length() - 4), imm_u4);
+}
+
+void BytecodeAssembler::xload(u4 index, u1 onebyteop, u1 twobyteop) {
+ if (index < 4) {
+ _code->append(onebyteop + index);
+ } else {
+ _code->append(twobyteop);
+ _code->append((u2)index);
+ }
+}
+
+void BytecodeAssembler::dup() {
+ _code->append(Bytecodes::_dup);
+}
+
+void BytecodeAssembler::_new(Symbol* sym) {
+ u2 cpool_index = _cp->klass(sym);
+ _code->append(Bytecodes::_new);
+ append(cpool_index);
+}
+
+void BytecodeAssembler::load_string(Symbol* sym) {
+ u2 cpool_index = _cp->string(sym);
+ if (cpool_index < 0x100) {
+ ldc(cpool_index);
+ } else {
+ ldc_w(cpool_index);
+ }
+}
+
+void BytecodeAssembler::ldc(u1 index) {
+ _code->append(Bytecodes::_ldc);
+ append(index);
+}
+
+void BytecodeAssembler::ldc_w(u2 index) {
+ _code->append(Bytecodes::_ldc_w);
+ append(index);
+}
+
+void BytecodeAssembler::athrow() {
+ _code->append(Bytecodes::_athrow);
+}
+
+void BytecodeAssembler::iload(u4 index) {
+ xload(index, Bytecodes::_iload_0, Bytecodes::_iload);
+}
+
+void BytecodeAssembler::lload(u4 index) {
+ xload(index, Bytecodes::_lload_0, Bytecodes::_lload);
+}
+
+void BytecodeAssembler::fload(u4 index) {
+ xload(index, Bytecodes::_fload_0, Bytecodes::_fload);
+}
+
+void BytecodeAssembler::dload(u4 index) {
+ xload(index, Bytecodes::_dload_0, Bytecodes::_dload);
+}
+
+void BytecodeAssembler::aload(u4 index) {
+ xload(index, Bytecodes::_aload_0, Bytecodes::_aload);
+}
+
+void BytecodeAssembler::load(BasicType bt, u4 index) {
+ switch (bt) {
+ case T_BOOLEAN:
+ case T_CHAR:
+ case T_BYTE:
+ case T_SHORT:
+ case T_INT: iload(index); break;
+ case T_FLOAT: fload(index); break;
+ case T_DOUBLE: dload(index); break;
+ case T_LONG: lload(index); break;
+ case T_OBJECT:
+ case T_ARRAY: aload(index); break;
+ default:
+ ShouldNotReachHere();
+ }
+}
+
+void BytecodeAssembler::checkcast(Symbol* sym) {
+ u2 cpool_index = _cp->klass(sym);
+ _code->append(Bytecodes::_checkcast);
+ append(cpool_index);
+}
+
+void BytecodeAssembler::invokespecial(Method* method) {
+ invokespecial(method->klass_name(), method->name(), method->signature());
+}
+
+void BytecodeAssembler::invokespecial(Symbol* klss, Symbol* name, Symbol* sig) {
+ u2 methodref_index = _cp->methodref(klss, name, sig);
+ _code->append(Bytecodes::_invokespecial);
+ append(methodref_index);
+}
+
+void BytecodeAssembler::invokevirtual(Method* method) {
+ invokevirtual(method->klass_name(), method->name(), method->signature());
+}
+
+void BytecodeAssembler::invokevirtual(Symbol* klss, Symbol* name, Symbol* sig) {
+ u2 methodref_index = _cp->methodref(klss, name, sig);
+ _code->append(Bytecodes::_invokevirtual);
+ append(methodref_index);
+}
+
+void BytecodeAssembler::ireturn() {
+ _code->append(Bytecodes::_ireturn);
+}
+
+void BytecodeAssembler::lreturn() {
+ _code->append(Bytecodes::_lreturn);
+}
+
+void BytecodeAssembler::freturn() {
+ _code->append(Bytecodes::_freturn);
+}
+
+void BytecodeAssembler::dreturn() {
+ _code->append(Bytecodes::_dreturn);
+}
+
+void BytecodeAssembler::areturn() {
+ _code->append(Bytecodes::_areturn);
+}
+
+void BytecodeAssembler::_return() {
+ _code->append(Bytecodes::_return);
+}
+
+void BytecodeAssembler::_return(BasicType bt) {
+ switch (bt) {
+ case T_BOOLEAN:
+ case T_CHAR:
+ case T_BYTE:
+ case T_SHORT:
+ case T_INT: ireturn(); break;
+ case T_FLOAT: freturn(); break;
+ case T_DOUBLE: dreturn(); break;
+ case T_LONG: lreturn(); break;
+ case T_OBJECT:
+ case T_ARRAY: areturn(); break;
+ case T_VOID: _return(); break;
+ default:
+ ShouldNotReachHere();
+ }
+}
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/classfile/bytecodeAssembler.hpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/classfile/bytecodeAssembler.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_CLASSFILE_BYTECODEASSEMBLER_HPP
+#define SHARE_VM_CLASSFILE_BYTECODEASSEMBLER_HPP
+
+#include "memory/allocation.hpp"
+#include "oops/method.hpp"
+#include "oops/symbol.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/growableArray.hpp"
+#include "utilities/resourceHash.hpp"
+
+
+/**
+ * Bytecode Assembler
+ *
+ * These classes are used to synthesize code for creating new methods from
+ * within the VM. This is only a partial implementation of an assembler;
+ * only the bytecodes that are needed by clients are implemented at this time.
+ * This is used during default method analysis to create overpass methods
+ * and add them to a call during parsing. Other uses (such as creating
+ * bridges) may come later. Any missing bytecodes can be implemented on an
+ * as-need basis.
+ */
+
+class BytecodeBuffer : public GrowableArray {
+ public:
+ BytecodeBuffer() : GrowableArray(20) {}
+};
+
+// Entries in a yet-to-be-created constant pool. Limited types for now.
+class BytecodeCPEntry VALUE_OBJ_CLASS_SPEC {
+ public:
+ enum tag {
+ ERROR_TAG,
+ UTF8,
+ KLASS,
+ STRING,
+ NAME_AND_TYPE,
+ METHODREF
+ };
+
+ u1 _tag;
+ union {
+ Symbol* utf8;
+ u2 klass;
+ u2 string;
+ struct {
+ u2 name_index;
+ u2 type_index;
+ } name_and_type;
+ struct {
+ u2 class_index;
+ u2 name_and_type_index;
+ } methodref;
+ uintptr_t hash;
+ } _u;
+
+ BytecodeCPEntry() : _tag(ERROR_TAG) { _u.hash = 0; }
+ BytecodeCPEntry(u1 tag) : _tag(tag) { _u.hash = 0; }
+
+ static BytecodeCPEntry utf8(Symbol* symbol) {
+ BytecodeCPEntry bcpe(UTF8);
+ bcpe._u.utf8 = symbol;
+ return bcpe;
+ }
+
+ static BytecodeCPEntry klass(u2 index) {
+ BytecodeCPEntry bcpe(KLASS);
+ bcpe._u.klass = index;
+ return bcpe;
+ }
+
+ static BytecodeCPEntry string(u2 index) {
+ BytecodeCPEntry bcpe(STRING);
+ bcpe._u.string = index;
+ return bcpe;
+ }
+
+ static BytecodeCPEntry name_and_type(u2 name, u2 type) {
+ BytecodeCPEntry bcpe(NAME_AND_TYPE);
+ bcpe._u.name_and_type.name_index = name;
+ bcpe._u.name_and_type.type_index = type;
+ return bcpe;
+ }
+
+ static BytecodeCPEntry methodref(u2 class_index, u2 nat) {
+ BytecodeCPEntry bcpe(METHODREF);
+ bcpe._u.methodref.class_index = class_index;
+ bcpe._u.methodref.name_and_type_index = nat;
+ return bcpe;
+ }
+
+ static bool equals(BytecodeCPEntry const& e0, BytecodeCPEntry const& e1) {
+ return e0._tag == e1._tag && e0._u.hash == e1._u.hash;
+ }
+
+ static unsigned hash(BytecodeCPEntry const& e0) {
+ return (unsigned)(e0._tag ^ e0._u.hash);
+ }
+};
+
+class BytecodeConstantPool : ResourceObj {
+ private:
+ typedef ResourceHashtable IndexHash;
+
+ ConstantPool* _orig;
+ GrowableArray _entries;
+ IndexHash _indices;
+
+ u2 find_or_add(BytecodeCPEntry const& bcpe);
+
+ public:
+
+ BytecodeConstantPool(ConstantPool* orig) : _orig(orig) {}
+
+ BytecodeCPEntry const& at(u2 index) const { return _entries.at(index); }
+
+ InstanceKlass* pool_holder() const {
+ return InstanceKlass::cast(_orig->pool_holder());
+ }
+
+ u2 utf8(Symbol* sym) {
+ return find_or_add(BytecodeCPEntry::utf8(sym));
+ }
+
+ u2 klass(Symbol* class_name) {
+ return find_or_add(BytecodeCPEntry::klass(utf8(class_name)));
+ }
+
+ u2 string(Symbol* str) {
+ return find_or_add(BytecodeCPEntry::string(utf8(str)));
+ }
+
+ u2 name_and_type(Symbol* name, Symbol* sig) {
+ return find_or_add(BytecodeCPEntry::name_and_type(utf8(name), utf8(sig)));
+ }
+
+ u2 methodref(Symbol* class_name, Symbol* name, Symbol* sig) {
+ return find_or_add(BytecodeCPEntry::methodref(
+ klass(class_name), name_and_type(name, sig)));
+ }
+
+ ConstantPool* create_constant_pool(TRAPS) const;
+};
+
+// Partial bytecode assembler - only what we need for creating
+// overpass methods for default methods is implemented
+class BytecodeAssembler : StackObj {
+ private:
+ BytecodeBuffer* _code;
+ BytecodeConstantPool* _cp;
+
+ void append(u1 imm_u1);
+ void append(u2 imm_u2);
+ void append(u4 imm_u4);
+
+ void xload(u4 index, u1 quick, u1 twobyte);
+
+ public:
+ BytecodeAssembler(BytecodeBuffer* buffer, BytecodeConstantPool* cp)
+ : _code(buffer), _cp(cp) {}
+
+ void aload(u4 index);
+ void areturn();
+ void athrow();
+ void checkcast(Symbol* sym);
+ void dload(u4 index);
+ void dreturn();
+ void dup();
+ void fload(u4 index);
+ void freturn();
+ void iload(u4 index);
+ void invokespecial(Method* method);
+ void invokespecial(Symbol* cls, Symbol* name, Symbol* sig);
+ void invokevirtual(Method* method);
+ void invokevirtual(Symbol* cls, Symbol* name, Symbol* sig);
+ void ireturn();
+ void ldc(u1 index);
+ void ldc_w(u2 index);
+ void lload(u4 index);
+ void lreturn();
+ void _new(Symbol* sym);
+ void _return();
+
+ void load_string(Symbol* sym);
+ void load(BasicType bt, u4 index);
+ void _return(BasicType bt);
+};
+
+#endif // SHARE_VM_CLASSFILE_BYTECODEASSEMBLER_HPP
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/classfile/classFileParser.cpp
--- a/src/share/vm/classfile/classFileParser.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/classfile/classFileParser.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,8 @@
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.hpp"
#include "classfile/classLoaderData.inline.hpp"
+#include "classfile/defaultMethods.hpp"
+#include "classfile/genericSignatures.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
@@ -57,6 +59,7 @@
#include "services/classLoadingService.hpp"
#include "services/threadService.hpp"
#include "utilities/array.hpp"
+#include "utilities/globalDefinitions.hpp"
// We generally try to create the oops directly when parsing, rather than
// allocating temporary data structures and copying the bytes twice. A
@@ -84,6 +87,9 @@
// - to check NameAndType_info signatures more aggressively
#define JAVA_7_VERSION 51
+// Extension method support.
+#define JAVA_8_VERSION 52
+
void ClassFileParser::parse_constant_pool_entries(ClassLoaderData* loader_data, constantPoolHandle cp, int length, TRAPS) {
// Use a local copy of ClassFileStream. It helps the C++ compiler to optimize
@@ -785,6 +791,7 @@
ClassLoaderData* loader_data,
Handle protection_domain,
Symbol* class_name,
+ bool* has_default_methods,
TRAPS) {
ClassFileStream* cfs = stream();
assert(length > 0, "only called for length>0");
@@ -818,9 +825,12 @@
interf = KlassHandle(THREAD, k);
}
- if (!Klass::cast(interf())->is_interface()) {
+ if (!interf()->is_interface()) {
THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", NULL);
}
+ if (InstanceKlass::cast(interf())->has_default_methods()) {
+ *has_default_methods = true;
+ }
interfaces->at_put(index, interf());
}
@@ -897,6 +907,7 @@
bool* is_synthetic_addr,
u2* generic_signature_index_addr,
AnnotationArray** field_annotations,
+ AnnotationArray** field_type_annotations,
ClassFileParser::FieldAnnotationCollector* parsed_annotations,
TRAPS) {
ClassFileStream* cfs = stream();
@@ -908,6 +919,10 @@
int runtime_visible_annotations_length = 0;
u1* runtime_invisible_annotations = NULL;
int runtime_invisible_annotations_length = 0;
+ u1* runtime_visible_type_annotations = NULL;
+ int runtime_visible_type_annotations_length = 0;
+ u1* runtime_invisible_type_annotations = NULL;
+ int runtime_invisible_type_annotations_length = 0;
while (attributes_count--) {
cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length
u2 attribute_name_index = cfs->get_u2_fast();
@@ -956,12 +971,28 @@
runtime_visible_annotations_length = attribute_length;
runtime_visible_annotations = cfs->get_u1_buffer();
assert(runtime_visible_annotations != NULL, "null visible annotations");
+ parse_annotations(loader_data,
+ runtime_visible_annotations,
+ runtime_visible_annotations_length,
+ cp,
+ parsed_annotations,
+ CHECK);
cfs->skip_u1(runtime_visible_annotations_length, CHECK);
} else if (PreserveAllAnnotations && attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
runtime_invisible_annotations_length = attribute_length;
runtime_invisible_annotations = cfs->get_u1_buffer();
assert(runtime_invisible_annotations != NULL, "null invisible annotations");
cfs->skip_u1(runtime_invisible_annotations_length, CHECK);
+ } else if (attribute_name == vmSymbols::tag_runtime_visible_type_annotations()) {
+ runtime_visible_type_annotations_length = attribute_length;
+ runtime_visible_type_annotations = cfs->get_u1_buffer();
+ assert(runtime_visible_type_annotations != NULL, "null visible type annotations");
+ cfs->skip_u1(runtime_visible_type_annotations_length, CHECK);
+ } else if (PreserveAllAnnotations && attribute_name == vmSymbols::tag_runtime_invisible_type_annotations()) {
+ runtime_invisible_type_annotations_length = attribute_length;
+ runtime_invisible_type_annotations = cfs->get_u1_buffer();
+ assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
+ cfs->skip_u1(runtime_invisible_type_annotations_length, CHECK);
} else {
cfs->skip_u1(attribute_length, CHECK); // Skip unknown attributes
}
@@ -979,6 +1010,12 @@
runtime_invisible_annotations,
runtime_invisible_annotations_length,
CHECK);
+ *field_type_annotations = assemble_annotations(loader_data,
+ runtime_visible_type_annotations,
+ runtime_visible_type_annotations_length,
+ runtime_invisible_type_annotations,
+ runtime_invisible_type_annotations_length,
+ CHECK);
return;
}
@@ -1075,6 +1112,7 @@
bool is_interface,
FieldAllocationCount *fac,
Array** fields_annotations,
+ Array** fields_type_annotations,
u2* java_fields_count_ptr, TRAPS) {
ClassFileStream* cfs = stream();
cfs->guarantee_more(2, CHECK_NULL); // length
@@ -1110,6 +1148,7 @@
THREAD, u2, total_fields * (FieldInfo::field_slots + 1));
AnnotationArray* field_annotations = NULL;
+ AnnotationArray* field_type_annotations = NULL;
// The generic signature slots start after all other fields' data.
int generic_signature_slot = total_fields * FieldInfo::field_slots;
int num_generic_signature = 0;
@@ -1151,7 +1190,7 @@
cp, attributes_count, is_static, signature_index,
&constantvalue_index, &is_synthetic,
&generic_signature_index, &field_annotations,
- &parsed_annotations,
+ &field_type_annotations, &parsed_annotations,
CHECK_NULL);
if (field_annotations != NULL) {
if (*fields_annotations == NULL) {
@@ -1161,6 +1200,14 @@
}
(*fields_annotations)->at_put(n, field_annotations);
}
+ if (field_type_annotations != NULL) {
+ if (*fields_type_annotations == NULL) {
+ *fields_type_annotations = MetadataFactory::new_array(
+ loader_data, length, NULL,
+ CHECK_NULL);
+ }
+ (*fields_type_annotations)->at_put(n, field_type_annotations);
+ }
if (is_synthetic) {
access_flags.set_is_synthetic();
}
@@ -1176,19 +1223,16 @@
field->initialize(access_flags.as_short(),
name_index,
signature_index,
- constantvalue_index,
- 0);
- if (parsed_annotations.has_any_annotations())
- parsed_annotations.apply_to(field);
-
+ constantvalue_index);
BasicType type = cp->basic_type_for_signature_at(signature_index);
// Remember how many oops we encountered and compute allocation type
FieldAllocationType atype = fac->update(is_static, type);
-
- // The correct offset is computed later (all oop fields will be located together)
- // We temporarily store the allocation type in the offset field
- field->set_offset(atype);
+ field->set_allocation_type(atype);
+
+ // After field is initialized with type, we can augment it with aux info
+ if (parsed_annotations.has_any_annotations())
+ parsed_annotations.apply_to(field);
}
int index = length;
@@ -1219,17 +1263,13 @@
field->initialize(JVM_ACC_FIELD_INTERNAL,
injected[n].name_index,
injected[n].signature_index,
- 0,
0);
BasicType type = FieldType::basic_type(injected[n].signature());
// Remember how many oops we encountered and compute allocation type
FieldAllocationType atype = fac->update(false, type);
-
- // The correct offset is computed later (all oop fields will be located together)
- // We temporarily store the allocation type in the offset field
- field->set_offset(atype);
+ field->set_allocation_type(atype);
index++;
}
}
@@ -1695,7 +1735,8 @@
}
// Sift through annotations, looking for those significant to the VM:
-void ClassFileParser::parse_annotations(u1* buffer, int limit,
+void ClassFileParser::parse_annotations(ClassLoaderData* loader_data,
+ u1* buffer, int limit,
constantPoolHandle cp,
ClassFileParser::AnnotationCollector* coll,
TRAPS) {
@@ -1712,9 +1753,12 @@
e_type_off = 7, // utf8 such as 'Ljava/lang/annotation/RetentionPolicy;'
e_con_off = 9, // utf8 payload, such as 'SOURCE', 'CLASS', 'RUNTIME'
e_size = 11, // end of 'e' annotation
- c_tag_val = 'c',
- c_con_off = 7, // utf8 payload, such as 'I' or 'Ljava/lang/String;'
+ c_tag_val = 'c', // payload is type
+ c_con_off = 7, // utf8 payload, such as 'I'
c_size = 9, // end of 'c' annotation
+ s_tag_val = 's', // payload is String
+ s_con_off = 7, // utf8 payload, such as 'Ljava/lang/String;'
+ s_size = 9,
min_size = 6 // smallest possible size (zero members)
};
while ((--nann) >= 0 && (index-2 + min_size <= limit)) {
@@ -1733,57 +1777,63 @@
}
// Here is where parsing particular annotations will take place.
- AnnotationCollector::ID id = coll->annotation_index(aname);
+ AnnotationCollector::ID id = coll->annotation_index(loader_data, aname);
if (id == AnnotationCollector::_unknown) continue;
coll->set_annotation(id);
- // If there are no values, just set the bit and move on:
- if (count == 0) continue;
-
- // For the record, here is how annotation payloads can be collected.
- // Suppose we want to capture @Retention.value. Here is how:
- //if (id == AnnotationCollector::_class_Retention) {
- // Symbol* payload = NULL;
- // if (count == 1
- // && e_size == (index0 - index) // match size
- // && e_tag_val == *(abase + tag_off)
- // && (check_symbol_at(cp, Bytes::get_Java_u2(abase + e_type_off))
- // == vmSymbols::RetentionPolicy_signature())
- // && member == vmSymbols::value_name()) {
- // payload = check_symbol_at(cp, Bytes::get_Java_u2(abase + e_con_off));
- // }
- // check_property(payload != NULL,
- // "Invalid @Retention annotation at offset %u in class file %s",
- // index0, CHECK);
- // if (payload != NULL) {
- // payload->increment_refcount();
- // coll->_class_RetentionPolicy = payload;
- // }
- //}
+
+ if (id == AnnotationCollector::_sun_misc_Contended) {
+ if (count == 1
+ && s_size == (index - index0) // match size
+ && s_tag_val == *(abase + tag_off)
+ && member == vmSymbols::value_name()) {
+ u2 group_index = Bytes::get_Java_u2(abase + s_con_off);
+ coll->set_contended_group(group_index);
+ } else {
+ coll->set_contended_group(0); // default contended group
+ }
+ coll->set_contended(true);
+ } else {
+ coll->set_contended(false);
+ }
}
}
-ClassFileParser::AnnotationCollector::ID ClassFileParser::AnnotationCollector::annotation_index(Symbol* name) {
+ClassFileParser::AnnotationCollector::ID
+ClassFileParser::AnnotationCollector::annotation_index(ClassLoaderData* loader_data,
+ Symbol* name) {
vmSymbols::SID sid = vmSymbols::find_sid(name);
+ // Privileged code can use all annotations. Other code silently drops some.
+ bool privileged = loader_data->is_the_null_class_loader_data() ||
+ loader_data->is_anonymous();
switch (sid) {
case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_ForceInline_signature):
if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
return _method_ForceInline;
case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_DontInline_signature):
if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
return _method_DontInline;
case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Compiled_signature):
if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
return _method_LambdaForm_Compiled;
case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Hidden_signature):
if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
return _method_LambdaForm_Hidden;
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_misc_Contended_signature):
+ if (_location != _in_field && _location != _in_class) break; // only allow for fields and classes
+ if (!EnableContended || (RestrictContended && !privileged)) break; // honor privileges
+ return _sun_misc_Contended;
default: break;
}
return AnnotationCollector::_unknown;
}
void ClassFileParser::FieldAnnotationCollector::apply_to(FieldInfo* f) {
- fatal("no field annotations yet");
+ if (is_contended())
+ f->set_contended_group(contended_group());
}
void ClassFileParser::MethodAnnotationCollector::apply_to(methodHandle m) {
@@ -1798,7 +1848,7 @@
}
void ClassFileParser::ClassAnnotationCollector::apply_to(instanceKlassHandle k) {
- fatal("no class annotations yet");
+ k->set_is_contended(is_contended());
}
@@ -1822,6 +1872,7 @@
AnnotationArray** method_annotations,
AnnotationArray** method_parameter_annotations,
AnnotationArray** method_default_annotations,
+ AnnotationArray** method_type_annotations,
TRAPS) {
ClassFileStream* cfs = stream();
methodHandle nullHandle;
@@ -1894,6 +1945,8 @@
u2** localvariable_table_start;
u2* localvariable_type_table_length;
u2** localvariable_type_table_start;
+ u2 method_parameters_length = 0;
+ u1* method_parameters_data = NULL;
bool parsed_code_attribute = false;
bool parsed_checked_exceptions_attribute = false;
bool parsed_stackmap_attribute = false;
@@ -1909,6 +1962,10 @@
int runtime_visible_parameter_annotations_length = 0;
u1* runtime_invisible_parameter_annotations = NULL;
int runtime_invisible_parameter_annotations_length = 0;
+ u1* runtime_visible_type_annotations = NULL;
+ int runtime_visible_type_annotations_length = 0;
+ u1* runtime_invisible_type_annotations = NULL;
+ int runtime_invisible_type_annotations_length = 0;
u1* annotation_default = NULL;
int annotation_default_length = 0;
@@ -1928,7 +1985,8 @@
if (method_attribute_name == vmSymbols::tag_code()) {
// Parse Code attribute
if (_need_verify) {
- guarantee_property(!access_flags.is_native() && !access_flags.is_abstract(),
+ guarantee_property(
+ !access_flags.is_native() && !access_flags.is_abstract(),
"Code attribute in native or abstract methods in class file %s",
CHECK_(nullHandle));
}
@@ -2098,6 +2156,26 @@
parse_checked_exceptions(&checked_exceptions_length,
method_attribute_length,
cp, CHECK_(nullHandle));
+ } else if (method_attribute_name == vmSymbols::tag_method_parameters()) {
+ method_parameters_length = cfs->get_u1_fast();
+ // Track the actual size (note: this is written for clarity; a
+ // decent compiler will CSE and constant-fold this into a single
+ // expression)
+ u2 actual_size = 1;
+ method_parameters_data = cfs->get_u1_buffer();
+ actual_size += 2 * method_parameters_length;
+ cfs->skip_u2_fast(method_parameters_length);
+ actual_size += 4 * method_parameters_length;
+ cfs->skip_u4_fast(method_parameters_length);
+ // Enforce attribute length
+ if (method_attribute_length != actual_size) {
+ classfile_parse_error(
+ "Invalid MethodParameters method attribute length %u in class file %s",
+ method_attribute_length, CHECK_(nullHandle));
+ }
+ // ignore this attribute if it cannot be reflected
+ if (!SystemDictionary::Parameter_klass_loaded())
+ method_parameters_length = 0;
} else if (method_attribute_name == vmSymbols::tag_synthetic()) {
if (method_attribute_length != 0) {
classfile_parse_error(
@@ -2125,7 +2203,10 @@
runtime_visible_annotations_length = method_attribute_length;
runtime_visible_annotations = cfs->get_u1_buffer();
assert(runtime_visible_annotations != NULL, "null visible annotations");
- parse_annotations(runtime_visible_annotations, runtime_visible_annotations_length, cp, &parsed_annotations, CHECK_(nullHandle));
+ parse_annotations(loader_data,
+ runtime_visible_annotations,
+ runtime_visible_annotations_length, cp, &parsed_annotations,
+ CHECK_(nullHandle));
cfs->skip_u1(runtime_visible_annotations_length, CHECK_(nullHandle));
} else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
runtime_invisible_annotations_length = method_attribute_length;
@@ -2147,6 +2228,17 @@
annotation_default = cfs->get_u1_buffer();
assert(annotation_default != NULL, "null annotation default");
cfs->skip_u1(annotation_default_length, CHECK_(nullHandle));
+ } else if (method_attribute_name == vmSymbols::tag_runtime_visible_type_annotations()) {
+ runtime_visible_type_annotations_length = method_attribute_length;
+ runtime_visible_type_annotations = cfs->get_u1_buffer();
+ assert(runtime_visible_type_annotations != NULL, "null visible type annotations");
+ // No need for the VM to parse Type annotations
+ cfs->skip_u1(runtime_visible_type_annotations_length, CHECK_(nullHandle));
+ } else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_type_annotations()) {
+ runtime_invisible_type_annotations_length = method_attribute_length;
+ runtime_invisible_type_annotations = cfs->get_u1_buffer();
+ assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
+ cfs->skip_u1(runtime_invisible_type_annotations_length, CHECK_(nullHandle));
} else {
// Skip unknown attributes
cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
@@ -2169,12 +2261,11 @@
}
// All sizing information for a Method* is finally available, now create it
- Method* m = Method::allocate(loader_data, code_length, access_flags,
- linenumber_table_length,
- total_lvt_length,
- exception_table_length,
- checked_exceptions_length,
- CHECK_(nullHandle));
+ Method* m = Method::allocate(
+ loader_data, code_length, access_flags, linenumber_table_length,
+ total_lvt_length, exception_table_length, checked_exceptions_length,
+ method_parameters_length, generic_signature_index,
+ ConstMethod::NORMAL, CHECK_(nullHandle));
ClassLoadingService::add_class_method_size(m->size()*HeapWordSize);
@@ -2182,7 +2273,6 @@
m->set_constants(cp());
m->set_name_index(name_index);
m->set_signature_index(signature_index);
- m->set_generic_signature_index(generic_signature_index);
#ifdef CC_INTERP
// hmm is there a gc issue here??
ResultTypeFinder rtf(cp->symbol_at(signature_index));
@@ -2204,7 +2294,6 @@
// Fill in code attribute information
m->set_max_stack(max_stack);
m->set_max_locals(max_locals);
-
m->constMethod()->set_stackmap_data(stackmap_data);
// Copy byte codes
@@ -2224,6 +2313,21 @@
exception_table_start, size);
}
+ // Copy method parameters
+ if (method_parameters_length > 0) {
+ MethodParametersElement* elem = m->constMethod()->method_parameters_start();
+ for(int i = 0; i < method_parameters_length; i++) {
+ elem[i].name_cp_index =
+ Bytes::get_Java_u2(method_parameters_data);
+ method_parameters_data += 2;
+ u4 flags = Bytes::get_Java_u4(method_parameters_data);
+ // This caused an alignment fault on Sparc, if flags was a u4
+ elem[i].flags_lo = extract_low_short_from_int(flags);
+ elem[i].flags_hi = extract_high_short_from_int(flags);
+ method_parameters_data += 4;
+ }
+ }
+
// Copy checked exceptions
if (checked_exceptions_length > 0) {
int size = checked_exceptions_length * sizeof(CheckedExceptionElement) / sizeof(u2);
@@ -2325,6 +2429,12 @@
NULL,
0,
CHECK_(nullHandle));
+ *method_type_annotations = assemble_annotations(loader_data,
+ runtime_visible_type_annotations,
+ runtime_visible_type_annotations_length,
+ runtime_invisible_type_annotations,
+ runtime_invisible_type_annotations_length,
+ CHECK_(nullHandle));
if (name == vmSymbols::finalize_method_name() &&
signature == vmSymbols::void_method_signature()) {
@@ -2356,11 +2466,14 @@
Array** methods_annotations,
Array** methods_parameter_annotations,
Array** methods_default_annotations,
+ Array** methods_type_annotations,
+ bool* has_default_methods,
TRAPS) {
ClassFileStream* cfs = stream();
AnnotationArray* method_annotations = NULL;
AnnotationArray* method_parameter_annotations = NULL;
AnnotationArray* method_default_annotations = NULL;
+ AnnotationArray* method_type_annotations = NULL;
cfs->guarantee_more(2, CHECK_NULL); // length
u2 length = cfs->get_u2_fast();
if (length == 0) {
@@ -2377,28 +2490,51 @@
&method_annotations,
&method_parameter_annotations,
&method_default_annotations,
+ &method_type_annotations,
CHECK_NULL);
if (method->is_final()) {
*has_final_method = true;
}
+ if (is_interface && !method->is_abstract() && !method->is_static()) {
+ // default method
+ *has_default_methods = true;
+ }
methods->at_put(index, method());
- if (*methods_annotations == NULL) {
- *methods_annotations =
- MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL);
+
+ if (method_annotations != NULL) {
+ if (*methods_annotations == NULL) {
+ *methods_annotations =
+ MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL);
+ }
+ (*methods_annotations)->at_put(index, method_annotations);
}
- (*methods_annotations)->at_put(index, method_annotations);
- if (*methods_parameter_annotations == NULL) {
- *methods_parameter_annotations =
- MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL);
+
+ if (method_parameter_annotations != NULL) {
+ if (*methods_parameter_annotations == NULL) {
+ *methods_parameter_annotations =
+ MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL);
+ }
+ (*methods_parameter_annotations)->at_put(index, method_parameter_annotations);
}
- (*methods_parameter_annotations)->at_put(index, method_parameter_annotations);
- if (*methods_default_annotations == NULL) {
- *methods_default_annotations =
- MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL);
+
+ if (method_default_annotations != NULL) {
+ if (*methods_default_annotations == NULL) {
+ *methods_default_annotations =
+ MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL);
+ }
+ (*methods_default_annotations)->at_put(index, method_default_annotations);
}
- (*methods_default_annotations)->at_put(index, method_default_annotations);
+
+ if (method_type_annotations != NULL) {
+ if (*methods_type_annotations == NULL) {
+ *methods_type_annotations =
+ MetadataFactory::new_array(loader_data, length, NULL, CHECK_NULL);
+ }
+ (*methods_type_annotations)->at_put(index, method_type_annotations);
+ }
}
+
if (_need_verify && length > 1) {
// Check duplicated methods
ResourceMark rm(THREAD);
@@ -2432,6 +2568,7 @@
Array* methods_annotations,
Array* methods_parameter_annotations,
Array* methods_default_annotations,
+ Array* methods_type_annotations,
TRAPS) {
int length = methods->length();
// If JVMTI original method ordering or sharing is enabled we have to
@@ -2450,7 +2587,8 @@
// Note that the ordering is not alphabetical, see Symbol::fast_compare
Method::sort_methods(methods, methods_annotations,
methods_parameter_annotations,
- methods_default_annotations);
+ methods_default_annotations,
+ methods_type_annotations);
// If JVMTI original method ordering or sharing is enabled construct int
// array remembering the original ordering
@@ -2715,6 +2853,10 @@
int runtime_visible_annotations_length = 0;
u1* runtime_invisible_annotations = NULL;
int runtime_invisible_annotations_length = 0;
+ u1* runtime_visible_type_annotations = NULL;
+ int runtime_visible_type_annotations_length = 0;
+ u1* runtime_invisible_type_annotations = NULL;
+ int runtime_invisible_type_annotations_length = 0;
u1* inner_classes_attribute_start = NULL;
u4 inner_classes_attribute_length = 0;
u2 enclosing_method_class_index = 0;
@@ -2782,7 +2924,8 @@
runtime_visible_annotations_length = attribute_length;
runtime_visible_annotations = cfs->get_u1_buffer();
assert(runtime_visible_annotations != NULL, "null visible annotations");
- parse_annotations(runtime_visible_annotations,
+ parse_annotations(loader_data,
+ runtime_visible_annotations,
runtime_visible_annotations_length,
cp,
parsed_annotations,
@@ -2821,6 +2964,17 @@
classfile_parse_error("Multiple BootstrapMethods attributes in class file %s", CHECK);
parsed_bootstrap_methods_attribute = true;
parse_classfile_bootstrap_methods_attribute(loader_data, cp, attribute_length, CHECK);
+ } else if (tag == vmSymbols::tag_runtime_visible_type_annotations()) {
+ runtime_visible_type_annotations_length = attribute_length;
+ runtime_visible_type_annotations = cfs->get_u1_buffer();
+ assert(runtime_visible_type_annotations != NULL, "null visible type annotations");
+ // No need for the VM to parse Type annotations
+ cfs->skip_u1(runtime_visible_type_annotations_length, CHECK);
+ } else if (PreserveAllAnnotations && tag == vmSymbols::tag_runtime_invisible_type_annotations()) {
+ runtime_invisible_type_annotations_length = attribute_length;
+ runtime_invisible_type_annotations = cfs->get_u1_buffer();
+ assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
+ cfs->skip_u1(runtime_invisible_type_annotations_length, CHECK);
} else {
// Unknown attribute
cfs->skip_u1(attribute_length, CHECK);
@@ -2837,6 +2991,13 @@
runtime_invisible_annotations_length,
CHECK);
set_class_annotations(annotations);
+ AnnotationArray* type_annotations = assemble_annotations(loader_data,
+ runtime_visible_type_annotations,
+ runtime_visible_type_annotations_length,
+ runtime_invisible_type_annotations,
+ runtime_invisible_type_annotations_length,
+ CHECK);
+ set_class_type_annotations(type_annotations);
if (parsed_innerclasses_attribute || parsed_enclosingmethod_attribute) {
u2 num_of_classes = parse_classfile_inner_classes_attribute(
@@ -2907,14 +3068,43 @@
}
+#ifndef PRODUCT
+static void parseAndPrintGenericSignatures(
+ instanceKlassHandle this_klass, TRAPS) {
+ assert(ParseAllGenericSignatures == true, "Shouldn't call otherwise");
+ ResourceMark rm;
+
+ if (this_klass->generic_signature() != NULL) {
+ using namespace generic;
+ ClassDescriptor* spec = ClassDescriptor::parse_generic_signature(this_klass(), CHECK);
+
+ tty->print_cr("Parsing %s", this_klass->generic_signature()->as_C_string());
+ spec->print_on(tty);
+
+ for (int i = 0; i < this_klass->methods()->length(); ++i) {
+ Method* m = this_klass->methods()->at(i);
+ MethodDescriptor* method_spec = MethodDescriptor::parse_generic_signature(m, spec);
+ Symbol* sig = m->generic_signature();
+ if (sig == NULL) {
+ sig = m->signature();
+ }
+ tty->print_cr("Parsing %s", sig->as_C_string());
+ method_spec->print_on(tty);
+ }
+ }
+}
+#endif // ndef PRODUCT
+
+
instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
- Handle class_loader,
+ ClassLoaderData* loader_data,
Handle protection_domain,
KlassHandle host_klass,
GrowableArray* cp_patches,
TempNewSymbol& parsed_name,
bool verify,
TRAPS) {
+
// When a retransformable agent is attached, JVMTI caches the
// class bytes that existed before the first retransformation.
// If RedefineClasses() was used before the retransformable
@@ -2922,7 +3112,9 @@
// original class bytes.
unsigned char *cached_class_file_bytes = NULL;
jint cached_class_file_length;
- ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader());
+ Handle class_loader(THREAD, loader_data->class_loader());
+ bool has_default_methods = false;
+ ResourceMark rm(THREAD);
ClassFileStream* cfs = stream();
// Timing
@@ -2961,7 +3153,7 @@
unsigned char* ptr = cfs->buffer();
unsigned char* end_ptr = cfs->buffer() + cfs->length();
- JvmtiExport::post_class_file_load_hook(name, class_loader, protection_domain,
+ JvmtiExport::post_class_file_load_hook(name, class_loader(), protection_domain,
&ptr, &end_ptr,
&cached_class_file_bytes,
&cached_class_file_length);
@@ -3138,25 +3330,29 @@
if (itfs_len == 0) {
local_interfaces = Universe::the_empty_klass_array();
} else {
- local_interfaces = parse_interfaces(cp, itfs_len, loader_data, protection_domain, _class_name, CHECK_(nullHandle));
+ local_interfaces = parse_interfaces(
+ cp, itfs_len, loader_data, protection_domain, _class_name,
+ &has_default_methods, CHECK_(nullHandle));
}
u2 java_fields_count = 0;
// Fields (offsets are filled in later)
FieldAllocationCount fac;
Array* fields_annotations = NULL;
+ Array* fields_type_annotations = NULL;
Array* fields = parse_fields(loader_data, class_name, cp, access_flags.is_interface(), &fac, &fields_annotations,
+ &fields_type_annotations,
&java_fields_count,
CHECK_(nullHandle));
// Methods
bool has_final_method = false;
AccessFlags promoted_flags;
promoted_flags.set_flags(0);
- // These need to be oop pointers because they are allocated lazily
- // inside parse_methods inside a nested HandleMark
+
Array* methods_annotations = NULL;
Array* methods_parameter_annotations = NULL;
Array* methods_default_annotations = NULL;
+ Array* methods_type_annotations = NULL;
Array* methods = parse_methods(loader_data,
cp, access_flags.is_interface(),
&promoted_flags,
@@ -3164,6 +3360,8 @@
&methods_annotations,
&methods_parameter_annotations,
&methods_default_annotations,
+ &methods_type_annotations,
+ &has_default_methods,
CHECK_(nullHandle));
// Additional attributes
@@ -3193,6 +3391,11 @@
super_klass = instanceKlassHandle(THREAD, kh());
}
if (super_klass.not_null()) {
+
+ if (super_klass->has_default_methods()) {
+ has_default_methods = true;
+ }
+
if (super_klass->is_interface()) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
@@ -3219,6 +3422,7 @@
methods_annotations,
methods_parameter_annotations,
methods_default_annotations,
+ methods_type_annotations,
CHECK_(nullHandle));
// promote flags from parse_methods() to the klass' flags
@@ -3229,31 +3433,31 @@
int itable_size = 0;
int num_miranda_methods = 0;
- klassVtable::compute_vtable_size_and_num_mirandas(vtable_size,
- num_miranda_methods,
- super_klass(),
- methods,
- access_flags,
- class_loader,
- class_name,
- local_interfaces,
+ GrowableArray all_mirandas(20);
+
+ klassVtable::compute_vtable_size_and_num_mirandas(
+ &vtable_size, &num_miranda_methods, &all_mirandas, super_klass(), methods,
+ access_flags, class_loader, class_name, local_interfaces,
CHECK_(nullHandle));
// Size of Java itable (in words)
itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(transitive_interfaces);
+ // get the padding width from the option
+ // TODO: Ask VM about specific CPU we are running on
+ int pad_size = ContendedPaddingWidth;
+
// Field size and offset computation
int nonstatic_field_size = super_klass() == NULL ? 0 : super_klass->nonstatic_field_size();
#ifndef PRODUCT
int orig_nonstatic_field_size = 0;
#endif
- int static_field_size = 0;
int next_static_oop_offset;
int next_static_double_offset;
int next_static_word_offset;
int next_static_short_offset;
int next_static_byte_offset;
- int next_static_type_offset;
+ int next_static_padded_offset;
int next_nonstatic_oop_offset;
int next_nonstatic_double_offset;
int next_nonstatic_word_offset;
@@ -3263,11 +3467,36 @@
int first_nonstatic_oop_offset;
int first_nonstatic_field_offset;
int next_nonstatic_field_offset;
+ int next_nonstatic_padded_offset;
+
+ // Count the contended fields by type.
+ int static_contended_count = 0;
+ int nonstatic_contended_count = 0;
+ FieldAllocationCount fac_contended;
+ for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) {
+ FieldAllocationType atype = (FieldAllocationType) fs.allocation_type();
+ if (fs.is_contended()) {
+ fac_contended.count[atype]++;
+ if (fs.access_flags().is_static()) {
+ static_contended_count++;
+ } else {
+ nonstatic_contended_count++;
+ }
+ }
+ }
+ int contended_count = static_contended_count + nonstatic_contended_count;
+
// Calculate the starting byte offsets
next_static_oop_offset = InstanceMirrorKlass::offset_of_static_fields();
+
+ // class is contended, pad before all the fields
+ if (parsed_annotations.is_contended()) {
+ next_static_oop_offset += pad_size;
+ }
+
next_static_double_offset = next_static_oop_offset +
- (fac.count[STATIC_OOP] * heapOopSize);
+ ((fac.count[STATIC_OOP] - fac_contended.count[STATIC_OOP]) * heapOopSize);
if ( fac.count[STATIC_DOUBLE] &&
(Universe::field_type_should_be_aligned(T_DOUBLE) ||
Universe::field_type_should_be_aligned(T_LONG)) ) {
@@ -3275,25 +3504,29 @@
}
next_static_word_offset = next_static_double_offset +
- (fac.count[STATIC_DOUBLE] * BytesPerLong);
+ ((fac.count[STATIC_DOUBLE] - fac_contended.count[STATIC_DOUBLE]) * BytesPerLong);
next_static_short_offset = next_static_word_offset +
- (fac.count[STATIC_WORD] * BytesPerInt);
+ ((fac.count[STATIC_WORD] - fac_contended.count[STATIC_WORD]) * BytesPerInt);
next_static_byte_offset = next_static_short_offset +
- (fac.count[STATIC_SHORT] * BytesPerShort);
- next_static_type_offset = align_size_up((next_static_byte_offset +
- fac.count[STATIC_BYTE] ), wordSize );
- static_field_size = (next_static_type_offset -
- next_static_oop_offset) / wordSize;
+ ((fac.count[STATIC_SHORT] - fac_contended.count[STATIC_SHORT]) * BytesPerShort);
+ next_static_padded_offset = next_static_byte_offset +
+ ((fac.count[STATIC_BYTE] - fac_contended.count[STATIC_BYTE]) * 1);
first_nonstatic_field_offset = instanceOopDesc::base_offset_in_bytes() +
nonstatic_field_size * heapOopSize;
+
+ // class is contended, pad before all the fields
+ if (parsed_annotations.is_contended()) {
+ first_nonstatic_field_offset += pad_size;
+ }
+
next_nonstatic_field_offset = first_nonstatic_field_offset;
- unsigned int nonstatic_double_count = fac.count[NONSTATIC_DOUBLE];
- unsigned int nonstatic_word_count = fac.count[NONSTATIC_WORD];
- unsigned int nonstatic_short_count = fac.count[NONSTATIC_SHORT];
- unsigned int nonstatic_byte_count = fac.count[NONSTATIC_BYTE];
- unsigned int nonstatic_oop_count = fac.count[NONSTATIC_OOP];
+ unsigned int nonstatic_double_count = fac.count[NONSTATIC_DOUBLE] - fac_contended.count[NONSTATIC_DOUBLE];
+ unsigned int nonstatic_word_count = fac.count[NONSTATIC_WORD] - fac_contended.count[NONSTATIC_WORD];
+ unsigned int nonstatic_short_count = fac.count[NONSTATIC_SHORT] - fac_contended.count[NONSTATIC_SHORT];
+ unsigned int nonstatic_byte_count = fac.count[NONSTATIC_BYTE] - fac_contended.count[NONSTATIC_BYTE];
+ unsigned int nonstatic_oop_count = fac.count[NONSTATIC_OOP] - fac_contended.count[NONSTATIC_OOP];
bool super_has_nonstatic_fields =
(super_klass() != NULL && super_klass->has_nonstatic_fields());
@@ -3366,12 +3599,12 @@
}
if( allocation_style == 0 ) {
- // Fields order: oops, longs/doubles, ints, shorts/chars, bytes
+ // Fields order: oops, longs/doubles, ints, shorts/chars, bytes, padded fields
next_nonstatic_oop_offset = next_nonstatic_field_offset;
next_nonstatic_double_offset = next_nonstatic_oop_offset +
(nonstatic_oop_count * heapOopSize);
} else if( allocation_style == 1 ) {
- // Fields order: longs/doubles, ints, shorts/chars, bytes, oops
+ // Fields order: longs/doubles, ints, shorts/chars, bytes, oops, padded fields
next_nonstatic_double_offset = next_nonstatic_field_offset;
} else if( allocation_style == 2 ) {
// Fields allocation: oops fields in super and sub classes are together.
@@ -3450,27 +3683,33 @@
(nonstatic_word_count * BytesPerInt);
next_nonstatic_byte_offset = next_nonstatic_short_offset +
(nonstatic_short_count * BytesPerShort);
-
- int notaligned_offset;
- if( allocation_style == 0 ) {
- notaligned_offset = next_nonstatic_byte_offset + nonstatic_byte_count;
- } else { // allocation_style == 1
- next_nonstatic_oop_offset = next_nonstatic_byte_offset + nonstatic_byte_count;
+ next_nonstatic_padded_offset = next_nonstatic_byte_offset +
+ nonstatic_byte_count;
+
+ // let oops jump before padding with this allocation style
+ if( allocation_style == 1 ) {
+ next_nonstatic_oop_offset = next_nonstatic_padded_offset;
if( nonstatic_oop_count > 0 ) {
next_nonstatic_oop_offset = align_size_up(next_nonstatic_oop_offset, heapOopSize);
}
- notaligned_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize);
+ next_nonstatic_padded_offset = next_nonstatic_oop_offset + (nonstatic_oop_count * heapOopSize);
}
- next_nonstatic_type_offset = align_size_up(notaligned_offset, heapOopSize );
- nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset
- - first_nonstatic_field_offset)/heapOopSize);
// Iterate over fields again and compute correct offsets.
// The field allocation type was temporarily stored in the offset slot.
// oop fields are located before non-oop fields (static and non-static).
for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) {
+
+ // skip already laid out fields
+ if (fs.is_offset_set()) continue;
+
+ // contended fields are handled below
+ if (fs.is_contended()) continue;
+
int real_offset;
- FieldAllocationType atype = (FieldAllocationType) fs.offset();
+ FieldAllocationType atype = (FieldAllocationType) fs.allocation_type();
+
+ // pack the rest of the fields
switch (atype) {
case STATIC_OOP:
real_offset = next_static_oop_offset;
@@ -3559,13 +3798,225 @@
fs.set_offset(real_offset);
}
+
+ // Handle the contended cases.
+ //
+ // Each contended field should not intersect the cache line with another contended field.
+ // In the absence of alignment information, we end up with pessimistically separating
+ // the fields with full-width padding.
+ //
+ // Additionally, this should not break alignment for the fields, so we round the alignment up
+ // for each field.
+ if (contended_count > 0) {
+
+ // if there is at least one contended field, we need to have pre-padding for them
+ if (nonstatic_contended_count > 0) {
+ next_nonstatic_padded_offset += pad_size;
+ }
+
+ // collect all contended groups
+ BitMap bm(cp->size());
+ for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) {
+ // skip already laid out fields
+ if (fs.is_offset_set()) continue;
+
+ if (fs.is_contended()) {
+ bm.set_bit(fs.contended_group());
+ }
+ }
+
+ int current_group = -1;
+ while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) {
+
+ for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) {
+
+ // skip already laid out fields
+ if (fs.is_offset_set()) continue;
+
+ // skip non-contended fields and fields from different group
+ if (!fs.is_contended() || (fs.contended_group() != current_group)) continue;
+
+ // handle statics below
+ if (fs.access_flags().is_static()) continue;
+
+ int real_offset;
+ FieldAllocationType atype = (FieldAllocationType) fs.allocation_type();
+
+ switch (atype) {
+ case NONSTATIC_BYTE:
+ next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, 1);
+ real_offset = next_nonstatic_padded_offset;
+ next_nonstatic_padded_offset += 1;
+ break;
+
+ case NONSTATIC_SHORT:
+ next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerShort);
+ real_offset = next_nonstatic_padded_offset;
+ next_nonstatic_padded_offset += BytesPerShort;
+ break;
+
+ case NONSTATIC_WORD:
+ next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerInt);
+ real_offset = next_nonstatic_padded_offset;
+ next_nonstatic_padded_offset += BytesPerInt;
+ break;
+
+ case NONSTATIC_DOUBLE:
+ next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, BytesPerLong);
+ real_offset = next_nonstatic_padded_offset;
+ next_nonstatic_padded_offset += BytesPerLong;
+ break;
+
+ case NONSTATIC_OOP:
+ next_nonstatic_padded_offset = align_size_up(next_nonstatic_padded_offset, heapOopSize);
+ real_offset = next_nonstatic_padded_offset;
+ next_nonstatic_padded_offset += heapOopSize;
+
+ // Create new oop map
+ nonstatic_oop_offsets[nonstatic_oop_map_count] = real_offset;
+ nonstatic_oop_counts [nonstatic_oop_map_count] = 1;
+ nonstatic_oop_map_count += 1;
+ if( first_nonstatic_oop_offset == 0 ) { // Undefined
+ first_nonstatic_oop_offset = real_offset;
+ }
+ break;
+
+ default:
+ ShouldNotReachHere();
+ }
+
+ if (fs.contended_group() == 0) {
+ // Contended group defines the equivalence class over the fields:
+ // the fields within the same contended group are not inter-padded.
+ // The only exception is default group, which does not incur the
+ // equivalence, and so requires intra-padding.
+ next_nonstatic_padded_offset += pad_size;
+ }
+
+ fs.set_offset(real_offset);
+ } // for
+
+ // Start laying out the next group.
+ // Note that this will effectively pad the last group in the back;
+ // this is expected to alleviate memory contention effects for
+ // subclass fields and/or adjacent object.
+ // If this was the default group, the padding is already in place.
+ if (current_group != 0) {
+ next_nonstatic_padded_offset += pad_size;
+ }
+ }
+
+ // handle static fields
+
+ // if there is at least one contended field, we need to have pre-padding for them
+ if (static_contended_count > 0) {
+ next_static_padded_offset += pad_size;
+ }
+
+ current_group = -1;
+ while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) {
+
+ for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) {
+
+ // skip already laid out fields
+ if (fs.is_offset_set()) continue;
+
+ // skip non-contended fields and fields from different group
+ if (!fs.is_contended() || (fs.contended_group() != current_group)) continue;
+
+ // non-statics already handled above
+ if (!fs.access_flags().is_static()) continue;
+
+ int real_offset;
+ FieldAllocationType atype = (FieldAllocationType) fs.allocation_type();
+
+ switch (atype) {
+
+ case STATIC_BYTE:
+ next_static_padded_offset = align_size_up(next_static_padded_offset, 1);
+ real_offset = next_static_padded_offset;
+ next_static_padded_offset += 1;
+ break;
+
+ case STATIC_SHORT:
+ next_static_padded_offset = align_size_up(next_static_padded_offset, BytesPerShort);
+ real_offset = next_static_padded_offset;
+ next_static_padded_offset += BytesPerShort;
+ break;
+
+ case STATIC_WORD:
+ next_static_padded_offset = align_size_up(next_static_padded_offset, BytesPerInt);
+ real_offset = next_static_padded_offset;
+ next_static_padded_offset += BytesPerInt;
+ break;
+
+ case STATIC_DOUBLE:
+ next_static_padded_offset = align_size_up(next_static_padded_offset, BytesPerLong);
+ real_offset = next_static_padded_offset;
+ next_static_padded_offset += BytesPerLong;
+ break;
+
+ case STATIC_OOP:
+ next_static_padded_offset = align_size_up(next_static_padded_offset, heapOopSize);
+ real_offset = next_static_padded_offset;
+ next_static_padded_offset += heapOopSize;
+ break;
+
+ default:
+ ShouldNotReachHere();
+ }
+
+ if (fs.contended_group() == 0) {
+ // Contended group defines the equivalence class over the fields:
+ // the fields within the same contended group are not inter-padded.
+ // The only exception is default group, which does not incur the
+ // equivalence, and so requires intra-padding.
+ next_static_padded_offset += pad_size;
+ }
+
+ fs.set_offset(real_offset);
+ } // for
+
+ // Start laying out the next group.
+ // Note that this will effectively pad the last group in the back;
+ // this is expected to alleviate memory contention effects for
+ // subclass fields and/or adjacent object.
+ // If this was the default group, the padding is already in place.
+ if (current_group != 0) {
+ next_static_padded_offset += pad_size;
+ }
+
+ }
+
+ } // handle contended
+
// Size of instances
int instance_size;
+ int notaligned_offset = next_nonstatic_padded_offset;
+
+ // Entire class is contended, pad in the back.
+ // This helps to alleviate memory contention effects for subclass fields
+ // and/or adjacent object.
+ if (parsed_annotations.is_contended()) {
+ notaligned_offset += pad_size;
+ next_static_padded_offset += pad_size;
+ }
+
+ int next_static_type_offset = align_size_up(next_static_padded_offset, wordSize);
+ int static_field_size = (next_static_type_offset -
+ InstanceMirrorKlass::offset_of_static_fields()) / wordSize;
+
+ next_nonstatic_type_offset = align_size_up(notaligned_offset, heapOopSize );
+ nonstatic_field_size = nonstatic_field_size + ((next_nonstatic_type_offset
+ - first_nonstatic_field_offset)/heapOopSize);
+
next_nonstatic_type_offset = align_size_up(notaligned_offset, wordSize );
instance_size = align_object_size(next_nonstatic_type_offset / wordSize);
- assert(instance_size == align_object_size(align_size_up((instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize), wordSize) / wordSize), "consistent layout helper value");
+ assert(instance_size == align_object_size(align_size_up(
+ (instanceOopDesc::base_offset_in_bytes() + nonstatic_field_size*heapOopSize + ((parsed_annotations.is_contended()) ? pad_size : 0)),
+ wordSize) / wordSize), "consistent layout helper value");
// Number of non-static oop map blocks allocated at end of klass.
const unsigned int total_oop_map_count =
@@ -3639,11 +4090,13 @@
if (is_anonymous()) // I am well known to myself
cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve
+ // Allocate an annotation type if needed.
if (fields_annotations != NULL ||
methods_annotations != NULL ||
methods_parameter_annotations != NULL ||
- methods_default_annotations != NULL) {
- // Allocate an annotation type if needed.
+ methods_default_annotations != NULL ||
+ fields_type_annotations != NULL ||
+ methods_type_annotations != NULL) {
Annotations* anno = Annotations::allocate(loader_data,
fields_annotations, methods_annotations,
methods_parameter_annotations,
@@ -3653,9 +4106,20 @@
this_klass->set_annotations(NULL);
}
+ if (fields_type_annotations != NULL ||
+ methods_type_annotations != NULL) {
+ assert(this_klass->annotations() != NULL, "annotations should have been allocated");
+ Annotations* anno = Annotations::allocate(loader_data,
+ fields_type_annotations,
+ methods_type_annotations,
+ NULL,
+ NULL, CHECK_(nullHandle));
+ this_klass->annotations()->set_type_annotations(anno);
+ }
this_klass->set_minor_version(minor_version);
this_klass->set_major_version(major_version);
+ this_klass->set_has_default_methods(has_default_methods);
// Set up Method*::intrinsic_id as soon as we know the names of methods.
// (We used to do this lazily, but now we query it in Rewriter,
@@ -3673,6 +4137,30 @@
cached_class_file_length);
}
+ // Fill in field values obtained by parse_classfile_attributes
+ if (parsed_annotations.has_any_annotations())
+ parsed_annotations.apply_to(this_klass);
+
+ // Create annotations
+ if (_annotations != NULL && this_klass->annotations() == NULL) {
+ Annotations* anno = Annotations::allocate(loader_data, CHECK_NULL);
+ this_klass->set_annotations(anno);
+ }
+ apply_parsed_class_attributes(this_klass);
+
+ // Create type annotations
+ if (_type_annotations != NULL) {
+ if (this_klass->annotations() == NULL) {
+ Annotations* anno = Annotations::allocate(loader_data, CHECK_NULL);
+ this_klass->set_annotations(anno);
+ }
+ if (this_klass->annotations()->type_annotations() == NULL) {
+ Annotations* anno = Annotations::allocate(loader_data, CHECK_NULL);
+ this_klass->annotations()->set_type_annotations(anno);
+ }
+ this_klass->annotations()->type_annotations()->set_class_annotations(_type_annotations);
+ }
+
// Miranda methods
if ((num_miranda_methods > 0) ||
// if this class introduced new miranda methods or
@@ -3682,18 +4170,6 @@
this_klass->set_has_miranda_methods(); // then set a flag
}
- // Fill in field values obtained by parse_classfile_attributes
- if (parsed_annotations.has_any_annotations()) {
- parsed_annotations.apply_to(this_klass);
- }
- // Create annotations
- if (_annotations != NULL && this_klass->annotations() == NULL) {
- Annotations* anno = Annotations::allocate(loader_data, CHECK_NULL);
- this_klass->set_annotations(anno);
- }
- apply_parsed_class_attributes(this_klass);
-
- // Compute transitive closure of interfaces this class implements
this_klass->set_transitive_interfaces(transitive_interfaces);
// Fill in information needed to compute superclasses.
@@ -3702,6 +4178,7 @@
// Initialize itable offset tables
klassItable::setup_itable_offset_table(this_klass);
+ // Compute transitive closure of interfaces this class implements
// Do final class setup
fill_oop_maps(this_klass, nonstatic_oop_map_count, nonstatic_oop_offsets, nonstatic_oop_counts);
@@ -3723,7 +4200,25 @@
// check that if this class is an interface then it doesn't have static methods
if (this_klass->is_interface()) {
- check_illegal_static_method(this_klass, CHECK_(nullHandle));
+ /* An interface in a JAVA 8 classfile can be static */
+ if (_major_version < JAVA_8_VERSION) {
+ check_illegal_static_method(this_klass, CHECK_(nullHandle));
+ }
+ }
+
+
+#ifdef ASSERT
+ if (ParseAllGenericSignatures) {
+ parseAndPrintGenericSignatures(this_klass, CHECK_(nullHandle));
+ }
+#endif
+
+ // Generate any default methods - default methods are interface methods
+ // that have a default implementation. This is new with Lambda project.
+ if (has_default_methods && !access_flags.is_interface() &&
+ local_interfaces->length() > 0) {
+ DefaultMethods::generate_default_methods(
+ this_klass(), &all_mirandas, CHECK_(nullHandle));
}
// Allocate mirror and initialize static fields
@@ -3744,6 +4239,7 @@
false /* not shared class */);
if (TraceClassLoading) {
+ ResourceMark rm;
// print in a single call to reduce interleaving of output
if (cfs->source() != NULL) {
tty->print("[Loaded %s from %s]\n", this_klass->external_name(),
@@ -3758,15 +4254,15 @@
tty->print("[Loaded %s]\n", this_klass->external_name());
}
} else {
- ResourceMark rm;
tty->print("[Loaded %s from %s]\n", this_klass->external_name(),
InstanceKlass::cast(class_loader->klass())->external_name());
}
}
if (TraceClassResolution) {
+ ResourceMark rm;
// print out the superclass.
- const char * from = Klass::cast(this_klass())->external_name();
+ const char * from = this_klass()->external_name();
if (this_klass->java_super() != NULL) {
tty->print("RESOLVE %s %s (super)\n", from, InstanceKlass::cast(this_klass->java_super())->external_name());
}
@@ -3785,6 +4281,7 @@
#ifndef PRODUCT
if( PrintCompactFieldsSavings ) {
+ ResourceMark rm;
if( nonstatic_field_size < orig_nonstatic_field_size ) {
tty->print("[Saved %d of %d bytes in %s]\n",
(orig_nonstatic_field_size - nonstatic_field_size)*heapOopSize,
@@ -3799,6 +4296,18 @@
}
#endif
+#ifndef PRODUCT
+ if (PrintFieldLayout) {
+ print_field_layout(name,
+ fields,
+ cp,
+ instance_size,
+ first_nonstatic_field_offset,
+ next_nonstatic_field_offset,
+ next_static_type_offset);
+ }
+#endif
+
// preserve result across HandleMark
preserve_this_klass = this_klass();
}
@@ -3811,6 +4320,37 @@
return this_klass;
}
+void ClassFileParser::print_field_layout(Symbol* name,
+ Array* fields,
+ constantPoolHandle cp,
+ int instance_size,
+ int instance_fields_start,
+ int instance_fields_end,
+ int static_fields_end) {
+ tty->print("%s: field layout\n", name->as_klass_external_name());
+ tty->print(" @%3d %s\n", instance_fields_start, "--- instance fields start ---");
+ for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) {
+ if (!fs.access_flags().is_static()) {
+ tty->print(" @%3d \"%s\" %s\n",
+ fs.offset(),
+ fs.name()->as_klass_external_name(),
+ fs.signature()->as_klass_external_name());
+ }
+ }
+ tty->print(" @%3d %s\n", instance_fields_end, "--- instance fields end ---");
+ tty->print(" @%3d %s\n", instance_size * wordSize, "--- instance ends ---");
+ tty->print(" @%3d %s\n", InstanceMirrorKlass::offset_of_static_fields(), "--- static fields start ---");
+ for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) {
+ if (fs.access_flags().is_static()) {
+ tty->print(" @%3d \"%s\" %s\n",
+ fs.offset(),
+ fs.name()->as_klass_external_name(),
+ fs.signature()->as_klass_external_name());
+ }
+ }
+ tty->print(" @%3d %s\n", static_fields_end, "--- static fields end ---");
+ tty->print("\n");
+}
unsigned int
ClassFileParser::compute_oop_map_count(instanceKlassHandle super,
@@ -3917,13 +4457,13 @@
// java.lang.Object has empty default constructor
k->set_has_vanilla_constructor();
} else {
- if (Klass::cast(super)->has_vanilla_constructor() &&
+ if (super->has_vanilla_constructor() &&
_has_vanilla_constructor) {
k->set_has_vanilla_constructor();
}
#ifdef ASSERT
bool v = false;
- if (Klass::cast(super)->has_vanilla_constructor()) {
+ if (super->has_vanilla_constructor()) {
Method* constructor = k->find_method(vmSymbols::object_initializer_name(
), vmSymbols::void_method_signature());
if (constructor != NULL && constructor->is_vanilla_constructor()) {
@@ -3939,8 +4479,7 @@
assert(k->size_helper() > 0, "layout_helper is initialized");
if ((!RegisterFinalizersAtInit && k->has_finalizer())
|| k->is_abstract() || k->is_interface()
- || (k->name() == vmSymbols::java_lang_Class()
- && k->class_loader_data()->is_the_null_class_loader_data())
+ || (k->name() == vmSymbols::java_lang_Class() && k->class_loader() == NULL)
|| k->size_helper() >= FastAllocateSizeLimit) {
// Forbid fast-path allocation.
jint lh = Klass::instance_layout_helper(k->size_helper(), true);
@@ -4065,7 +4604,7 @@
int lng = local_interfaces->length();
for (int i = lng - 1; i >= 0; i--) {
Klass* k = local_interfaces->at(i);
- assert (k != NULL && Klass::cast(k)->is_interface(), "invalid interface");
+ assert (k != NULL && k->is_interface(), "invalid interface");
if (!Reflection::verify_class_access(this_klass(), k, false)) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
@@ -4128,7 +4667,7 @@
}
// continue to look from super_m's holder's super.
- k = InstanceKlass::cast(super_m->method_holder())->super();
+ k = super_m->method_holder()->super();
continue;
}
@@ -4262,15 +4801,41 @@
const bool is_bridge = (flags & JVM_ACC_BRIDGE) != 0;
const bool is_strict = (flags & JVM_ACC_STRICT) != 0;
const bool is_synchronized = (flags & JVM_ACC_SYNCHRONIZED) != 0;
+ const bool is_protected = (flags & JVM_ACC_PROTECTED) != 0;
const bool major_gte_15 = _major_version >= JAVA_1_5_VERSION;
+ const bool major_gte_8 = _major_version >= JAVA_8_VERSION;
const bool is_initializer = (name == vmSymbols::object_initializer_name());
bool is_illegal = false;
if (is_interface) {
- if (!is_abstract || !is_public || is_static || is_final ||
- is_native || (major_gte_15 && (is_synchronized || is_strict))) {
- is_illegal = true;
+ if (major_gte_8) {
+ // Class file version is JAVA_8_VERSION or later Methods of
+ // interfaces may set any of the flags except ACC_PROTECTED,
+ // ACC_FINAL, ACC_NATIVE, and ACC_SYNCHRONIZED; they must
+ // have exactly one of the ACC_PUBLIC or ACC_PRIVATE flags set.
+ if ((is_public == is_private) || /* Only one of private and public should be true - XNOR */
+ (is_native || is_protected || is_final || is_synchronized) ||
+ // If a specific method of a class or interface has its
+ // ACC_ABSTRACT flag set, it must not have any of its
+ // ACC_FINAL, ACC_NATIVE, ACC_PRIVATE, ACC_STATIC,
+ // ACC_STRICT, or ACC_SYNCHRONIZED flags set. No need to
+ // check for ACC_FINAL, ACC_NATIVE or ACC_SYNCHRONIZED as
+ // those flags are illegal irrespective of ACC_ABSTRACT being set or not.
+ (is_abstract && (is_private || is_static || is_strict))) {
+ is_illegal = true;
+ }
+ } else if (major_gte_15) {
+ // Class file version in the interval [JAVA_1_5_VERSION, JAVA_8_VERSION)
+ if (!is_public || is_static || is_final || is_synchronized ||
+ is_native || !is_abstract || is_strict) {
+ is_illegal = true;
+ }
+ } else {
+ // Class file version is pre-JAVA_1_5_VERSION
+ if (!is_public || is_static || is_final || is_native || !is_abstract) {
+ is_illegal = true;
+ }
}
} else { // not interface
if (is_initializer) {
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/classfile/classFileParser.hpp
--- a/src/share/vm/classfile/classFileParser.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/classfile/classFileParser.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -64,6 +64,7 @@
int _sde_length;
Array* _inner_classes;
AnnotationArray* _annotations;
+ AnnotationArray* _type_annotations;
void set_class_synthetic_flag(bool x) { _synthetic_flag = x; }
void set_class_sourcefile(Symbol* x) { _sourcefile = x; }
@@ -71,12 +72,14 @@
void set_class_sde_buffer(char* x, int len) { _sde_buffer = x; _sde_length = len; }
void set_class_inner_classes(Array* x) { _inner_classes = x; }
void set_class_annotations(AnnotationArray* x) { _annotations = x; }
+ void set_class_type_annotations(AnnotationArray* x) { _type_annotations = x; }
void init_parsed_class_attributes() {
_synthetic_flag = false;
_sourcefile = NULL;
_generic_signature = NULL;
_sde_buffer = NULL;
_sde_length = 0;
+ _annotations = _type_annotations = NULL;
// initialize the other flags too:
_has_finalizer = _has_empty_finalizer = _has_vanilla_constructor = false;
_max_bootstrap_specifier_index = -1;
@@ -92,17 +95,20 @@
_method_DontInline,
_method_LambdaForm_Compiled,
_method_LambdaForm_Hidden,
+ _sun_misc_Contended,
_annotation_LIMIT
};
const Location _location;
int _annotations_present;
+ u2 _contended_group;
+
AnnotationCollector(Location location)
: _location(location), _annotations_present(0)
{
assert((int)_annotation_LIMIT <= (int)sizeof(_annotations_present) * BitsPerByte, "");
}
// If this annotation name has an ID, report it (or _none).
- ID annotation_index(Symbol* name);
+ ID annotation_index(ClassLoaderData* loader_data, Symbol* name);
// Set the annotation name:
void set_annotation(ID id) {
assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
@@ -111,6 +117,12 @@
// Report if the annotation is present.
bool has_any_annotations() { return _annotations_present != 0; }
bool has_annotation(ID id) { return (nth_bit((int)id) & _annotations_present) != 0; }
+
+ void set_contended_group(u2 group) { _contended_group = group; }
+ u2 contended_group() { return _contended_group; }
+
+ void set_contended(bool contended) { set_annotation(_sun_misc_Contended); }
+ bool is_contended() { return has_annotation(_sun_misc_Contended); }
};
class FieldAnnotationCollector: public AnnotationCollector {
public:
@@ -151,6 +163,7 @@
ClassLoaderData* loader_data,
Handle protection_domain,
Symbol* class_name,
+ bool* has_default_methods,
TRAPS);
void record_defined_class_dependencies(instanceKlassHandle defined_klass, TRAPS);
@@ -162,6 +175,7 @@
bool* is_synthetic_addr,
u2* generic_signature_index_addr,
AnnotationArray** field_annotations,
+ AnnotationArray** field_type_annotations,
FieldAnnotationCollector* parsed_annotations,
TRAPS);
Array* parse_fields(ClassLoaderData* loader_data,
@@ -169,8 +183,17 @@
constantPoolHandle cp, bool is_interface,
FieldAllocationCount *fac,
Array** fields_annotations,
+ Array** fields_type_annotations,
u2* java_fields_count_ptr, TRAPS);
+ void print_field_layout(Symbol* name,
+ Array* fields,
+ constantPoolHandle cp,
+ int instance_size,
+ int instance_fields_start,
+ int instance_fields_end,
+ int static_fields_end);
+
// Method parsing
methodHandle parse_method(ClassLoaderData* loader_data,
constantPoolHandle cp,
@@ -179,6 +202,7 @@
AnnotationArray** method_annotations,
AnnotationArray** method_parameter_annotations,
AnnotationArray** method_default_annotations,
+ AnnotationArray** method_type_annotations,
TRAPS);
Array* parse_methods(ClassLoaderData* loader_data,
constantPoolHandle cp,
@@ -188,12 +212,15 @@
Array** methods_annotations,
Array** methods_parameter_annotations,
Array** methods_default_annotations,
+ Array** methods_type_annotations,
+ bool* has_default_method,
TRAPS);
Array* sort_methods(ClassLoaderData* loader_data,
Array* methods,
Array* methods_annotations,
Array* methods_parameter_annotations,
Array* methods_default_annotations,
+ Array* methods_type_annotations,
TRAPS);
u2* parse_exception_table(ClassLoaderData* loader_data,
u4 code_length, u4 exception_table_length,
@@ -237,7 +264,8 @@
int runtime_invisible_annotations_length, TRAPS);
int skip_annotation(u1* buffer, int limit, int index);
int skip_annotation_value(u1* buffer, int limit, int index);
- void parse_annotations(u1* buffer, int limit, constantPoolHandle cp,
+ void parse_annotations(ClassLoaderData* loader_data,
+ u1* buffer, int limit, constantPoolHandle cp,
/* Results (currently, only one result is supported): */
AnnotationCollector* result,
TRAPS);
@@ -361,16 +389,16 @@
// "parsed_name" is updated by this method, and is the name found
// while parsing the stream.
instanceKlassHandle parseClassFile(Symbol* name,
- Handle class_loader,
+ ClassLoaderData* loader_data,
Handle protection_domain,
TempNewSymbol& parsed_name,
bool verify,
TRAPS) {
KlassHandle no_host_klass;
- return parseClassFile(name, class_loader, protection_domain, no_host_klass, NULL, parsed_name, verify, THREAD);
+ return parseClassFile(name, loader_data, protection_domain, no_host_klass, NULL, parsed_name, verify, THREAD);
}
instanceKlassHandle parseClassFile(Symbol* name,
- Handle class_loader,
+ ClassLoaderData* loader_data,
Handle protection_domain,
KlassHandle host_klass,
GrowableArray* cp_patches,
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/classfile/classFileStream.cpp
--- a/src/share/vm/classfile/classFileStream.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/classfile/classFileStream.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -93,3 +93,10 @@
}
_current += length * 2;
}
+
+void ClassFileStream::skip_u4(int length, TRAPS) {
+ if (_need_verify) {
+ guarantee_more(length * 4, CHECK);
+ }
+ _current += length * 4;
+}
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/classfile/classFileStream.hpp
--- a/src/share/vm/classfile/classFileStream.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/classfile/classFileStream.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -133,6 +133,11 @@
_current += 2 * length;
}
+ void skip_u4(int length, TRAPS);
+ void skip_u4_fast(int length) {
+ _current += 4 * length;
+ }
+
// Tells whether eos is reached
bool at_eos() const { return _current == _buffer_end; }
};
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/classfile/classLoader.cpp
--- a/src/share/vm/classfile/classLoader.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/classfile/classLoader.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -26,6 +26,7 @@
#include "classfile/classFileParser.hpp"
#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
+#include "classfile/classLoaderData.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
@@ -605,8 +606,10 @@
// Load zip library
char path[JVM_MAXPATHLEN];
char ebuf[1024];
- os::dll_build_name(path, sizeof(path), Arguments::get_dll_dir(), "zip");
- void* handle = os::dll_load(path, ebuf, sizeof ebuf);
+ void* handle = NULL;
+ if (os::dll_build_name(path, sizeof(path), Arguments::get_dll_dir(), "zip")) {
+ handle = os::dll_load(path, ebuf, sizeof ebuf);
+ }
if (handle == NULL) {
vm_exit_during_initialization("Unable to load ZIP library", path);
}
@@ -908,11 +911,11 @@
// class file found, parse it
ClassFileParser parser(stream);
- Handle class_loader;
+ ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
Handle protection_domain;
TempNewSymbol parsed_name = NULL;
instanceKlassHandle result = parser.parseClassFile(h_name,
- class_loader,
+ loader_data,
protection_domain,
parsed_name,
false,
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/classfile/classLoaderData.cpp
--- a/src/share/vm/classfile/classLoaderData.cpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/classfile/classLoaderData.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -64,14 +64,22 @@
ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL;
-ClassLoaderData::ClassLoaderData(Handle h_class_loader) : _class_loader(h_class_loader()),
+ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) :
+ _class_loader(h_class_loader()),
+ _is_anonymous(is_anonymous), _keep_alive(is_anonymous), // initially
_metaspace(NULL), _unloading(false), _klasses(NULL),
- _claimed(0), _jmethod_ids(NULL), _handles(NULL),
- _deallocate_list(NULL), _next(NULL),
+ _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL),
+ _next(NULL), _dependencies(NULL),
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) {
// empty
}
+void ClassLoaderData::init_dependencies(TRAPS) {
+ // Create empty dependencies array to add to. CMS requires this to be
+ // an oop so that it can track additions via card marks. We think.
+ _dependencies = (oop)oopFactory::new_objectArray(2, CHECK);
+}
+
bool ClassLoaderData::claim() {
if (_claimed == 1) {
return false;
@@ -86,6 +94,7 @@
}
f->do_oop(&_class_loader);
+ f->do_oop(&_dependencies);
_handles->oops_do(f);
if (klass_closure != NULL) {
classes_do(klass_closure);
@@ -110,70 +119,102 @@
ClassLoaderData * const from_cld = this;
ClassLoaderData * const to_cld = k->class_loader_data();
- // Records dependency between non-null class loaders only.
- if (to_cld->is_the_null_class_loader_data() || from_cld->is_the_null_class_loader_data()) {
+ // Dependency to the null class loader data doesn't need to be recorded
+ // because the null class loader data never goes away.
+ if (to_cld->is_the_null_class_loader_data()) {
return;
}
- // Check that this dependency isn't from the same or parent class_loader
- oop to = to_cld->class_loader();
- oop from = from_cld->class_loader();
+ oop to;
+ if (to_cld->is_anonymous()) {
+ // Anonymous class dependencies are through the mirror.
+ to = k->java_mirror();
+ } else {
+ to = to_cld->class_loader();
- oop curr = from;
- while (curr != NULL) {
- if (curr == to) {
- return; // this class loader is in the parent list, no need to add it.
+ // If from_cld is anonymous, even if it's class_loader is a parent of 'to'
+ // we still have to add it. The class_loader won't keep from_cld alive.
+ if (!from_cld->is_anonymous()) {
+ // Check that this dependency isn't from the same or parent class_loader
+ oop from = from_cld->class_loader();
+
+ oop curr = from;
+ while (curr != NULL) {
+ if (curr == to) {
+ return; // this class loader is in the parent list, no need to add it.
+ }
+ curr = java_lang_ClassLoader::parent(curr);
+ }
}
- curr = java_lang_ClassLoader::parent(curr);
}
// It's a dependency we won't find through GC, add it. This is relatively rare
- from_cld->add_dependency(to_cld, CHECK);
+ // Must handle over GC point.
+ Handle dependency(THREAD, to);
+ from_cld->add_dependency(dependency, CHECK);
}
-bool ClassLoaderData::has_dependency(ClassLoaderData* dependency) {
- oop loader = dependency->class_loader();
- // Get objArrayOop out of the class_loader oop and see if this dependency
- // is there. Don't safepoint! These are all oops.
- // Dependency list is (oop class_loader, objArrayOop next)
- objArrayOop ok = (objArrayOop)java_lang_ClassLoader::dependencies(class_loader());
+void ClassLoaderData::add_dependency(Handle dependency, TRAPS) {
+ // Check first if this dependency is already in the list.
+ // Save a pointer to the last to add to under the lock.
+ objArrayOop ok = (objArrayOop)_dependencies;
+ objArrayOop last = NULL;
while (ok != NULL) {
- if (ok->obj_at(0) == loader) {
- return true;
+ last = ok;
+ if (ok->obj_at(0) == dependency()) {
+ // Don't need to add it
+ return;
}
ok = (objArrayOop)ok->obj_at(1);
}
- return false;
+
+ // Must handle over GC points
+ assert (last != NULL, "dependencies should be initialized");
+ objArrayHandle last_handle(THREAD, last);
+
+ // Create a new dependency node with fields for (class_loader or mirror, next)
+ objArrayOop deps = oopFactory::new_objectArray(2, CHECK);
+ deps->obj_at_put(0, dependency());
+
+ // Must handle over GC points
+ objArrayHandle new_dependency(THREAD, deps);
+
+ // Add the dependency under lock
+ locked_add_dependency(last_handle, new_dependency);
}
-void ClassLoaderData::add_dependency(ClassLoaderData* dependency, TRAPS) {
- // Minimize the number of duplicates in the list.
- if (has_dependency(dependency)) {
- return;
- }
+void ClassLoaderData::locked_add_dependency(objArrayHandle last_handle,
+ objArrayHandle new_dependency) {
- // Create a new dependency node with fields for (class_loader, next)
- objArrayOop deps = oopFactory::new_objectArray(2, CHECK);
- deps->obj_at_put(0, dependency->class_loader());
+ // Have to lock and put the new dependency on the end of the dependency
+ // array so the card mark for CMS sees that this dependency is new.
+ // Can probably do this lock free with some effort.
+ MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
+
+ oop loader_or_mirror = new_dependency->obj_at(0);
- // Add this lock free, using compare and exchange, need barriers for GC
- // Do the barrier first.
- HeapWord* addr = java_lang_ClassLoader::dependencies_addr(class_loader());
- while (true) {
- oop old_dependency = java_lang_ClassLoader::dependencies(class_loader());
- deps->obj_at_put(1, old_dependency);
-
- oop newold = oopDesc::atomic_compare_exchange_oop((oop)deps, addr, old_dependency, true);
- if (newold == old_dependency) {
- update_barrier_set((void*)addr, (oop)deps);
- // we won the race to add this dependency
- break;
+ // Since the dependencies are only added, add to the end.
+ objArrayOop end = last_handle();
+ objArrayOop last = NULL;
+ while (end != NULL) {
+ last = end;
+ // check again if another thread added it to the end.
+ if (end->obj_at(0) == loader_or_mirror) {
+ // Don't need to add it
+ return;
}
+ end = (objArrayOop)end->obj_at(1);
+ }
+ assert (last != NULL, "dependencies should be initialized");
+ // fill in the first element with the oop in new_dependency.
+ if (last->obj_at(0) == NULL) {
+ last->obj_at_put(0, new_dependency->obj_at(0));
+ } else {
+ last->obj_at_put(1, new_dependency());
}
}
-
void ClassLoaderDataGraph::clear_claimed_marks() {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
cld->clear_claimed();
@@ -187,7 +228,7 @@
// link the new item into the list
_klasses = k;
- if (TraceClassLoaderData && k->class_loader_data() != NULL) {
+ if (TraceClassLoaderData && Verbose && k->class_loader_data() != NULL) {
ResourceMark rm;
tty->print_cr("[TraceClassLoaderData] Adding k: " PTR_FORMAT " %s to CLD: "
PTR_FORMAT " loader: " PTR_FORMAT " %s",
@@ -195,8 +236,7 @@
k->external_name(),
k->class_loader_data(),
k->class_loader(),
- k->class_loader() != NULL ? k->class_loader()->klass()->external_name() : "NULL"
- );
+ loader_name());
}
}
@@ -221,6 +261,31 @@
ShouldNotReachHere(); // should have found this class!!
}
+void ClassLoaderData::unload() {
+ _unloading = true;
+
+ if (TraceClassLoaderData) {
+ ResourceMark rm;
+ tty->print("[ClassLoaderData: unload loader data "PTR_FORMAT, this);
+ tty->print(" for instance "PTR_FORMAT" of %s", class_loader(),
+ loader_name());
+ if (is_anonymous()) {
+ tty->print(" for anonymous class "PTR_FORMAT " ", _klasses);
+ }
+ tty->print_cr("]");
+ }
+}
+
+bool ClassLoaderData::is_alive(BoolObjectClosure* is_alive_closure) const {
+ bool alive =
+ is_anonymous() ?
+ is_alive_closure->do_object_b(_klasses->java_mirror()) :
+ class_loader() == NULL || is_alive_closure->do_object_b(class_loader());
+ assert(!alive || claimed(), "must be claimed");
+ return alive;
+}
+
+
ClassLoaderData::~ClassLoaderData() {
Metaspace *m = _metaspace;
if (m != NULL) {
@@ -253,6 +318,7 @@
}
Metaspace* ClassLoaderData::metaspace_non_null() {
+ assert(!DumpSharedSpaces, "wrong metaspace!");
// If the metaspace has not been allocated, create a new one. Might want
// to create smaller arena for Reflection class loaders also.
// The reason for the delayed allocation is because some class loaders are
@@ -263,12 +329,21 @@
if (_metaspace != NULL) {
return _metaspace;
}
- if (class_loader() == NULL) {
- assert(this == the_null_class_loader_data(), "Must be");
- size_t word_size = Metaspace::first_chunk_word_size();
- set_metaspace(new Metaspace(_metaspace_lock, word_size));
+ if (this == the_null_class_loader_data()) {
+ assert (class_loader() == NULL, "Must be");
+ set_metaspace(new Metaspace(_metaspace_lock, Metaspace::BootMetaspaceType));
+ } else if (is_anonymous()) {
+ if (TraceClassLoaderData && Verbose && class_loader() != NULL) {
+ tty->print_cr("is_anonymous: %s", class_loader()->klass()->internal_name());
+ }
+ set_metaspace(new Metaspace(_metaspace_lock, Metaspace::AnonymousMetaspaceType));
+ } else if (class_loader()->is_a(SystemDictionary::reflect_DelegatingClassLoader_klass())) {
+ if (TraceClassLoaderData && Verbose && class_loader() != NULL) {
+ tty->print_cr("is_reflection: %s", class_loader()->klass()->internal_name());
+ }
+ set_metaspace(new Metaspace(_metaspace_lock, Metaspace::ReflectionMetaspaceType));
} else {
- set_metaspace(new Metaspace(_metaspace_lock)); // default size for now.
+ set_metaspace(new Metaspace(_metaspace_lock, Metaspace::StandardMetaspaceType));
}
}
return _metaspace;
@@ -325,12 +400,18 @@
}
}
-#ifndef PRODUCT
-void ClassLoaderData::print_loader(ClassLoaderData *loader_data, outputStream* out) {
- oop class_loader = loader_data->class_loader();
- out->print("%s", SystemDictionary::loader_name(class_loader));
+// These anonymous class loaders are to contain classes used for JSR292
+ClassLoaderData* ClassLoaderData::anonymous_class_loader_data(oop loader, TRAPS) {
+ // Add a new class loader data to the graph.
+ return ClassLoaderDataGraph::add(NULL, loader, CHECK_NULL);
}
+const char* ClassLoaderData::loader_name() {
+ // Handles null class loader
+ return SystemDictionary::loader_name(class_loader());
+}
+
+#ifndef PRODUCT
// Define to dump klasses
#undef CLD_DUMP_KLASSES
@@ -338,8 +419,7 @@
ResourceMark rm;
out->print("ClassLoaderData CLD: "PTR_FORMAT", loader: "PTR_FORMAT", loader_klass: "PTR_FORMAT" %s {",
this, class_loader(),
- class_loader() != NULL ? class_loader()->klass() : NULL,
- class_loader() != NULL ? class_loader()->klass()->external_name() : "NULL");
+ class_loader() != NULL ? class_loader()->klass() : NULL, loader_name());
if (claimed()) out->print(" claimed ");
if (is_unloading()) out->print(" unloading ");
out->print(" handles " INTPTR_FORMAT, handles());
@@ -373,8 +453,8 @@
void ClassLoaderData::verify() {
oop cl = class_loader();
- guarantee(this == class_loader_data(cl), "Must be the same");
- guarantee(cl != NULL || this == ClassLoaderData::the_null_class_loader_data(), "must be");
+ guarantee(this == class_loader_data(cl) || is_anonymous(), "Must be the same");
+ guarantee(cl != NULL || this == ClassLoaderData::the_null_class_loader_data() || is_anonymous(), "must be");
// Verify the integrity of the allocated space.
if (metaspace_or_null() != NULL) {
@@ -387,6 +467,7 @@
}
}
+
// GC root of class loader data created.
ClassLoaderData* ClassLoaderDataGraph::_head = NULL;
ClassLoaderData* ClassLoaderDataGraph::_unloading = NULL;
@@ -395,19 +476,23 @@
// Add a new class loader data node to the list. Assign the newly created
// ClassLoaderData into the java/lang/ClassLoader object as a hidden field
-ClassLoaderData* ClassLoaderDataGraph::add(ClassLoaderData** cld_addr, Handle loader_data) {
+ClassLoaderData* ClassLoaderDataGraph::add(ClassLoaderData** cld_addr, Handle loader, TRAPS) {
// Not assigned a class loader data yet.
// Create one.
ClassLoaderData* *list_head = &_head;
ClassLoaderData* next = _head;
- ClassLoaderData* cld = new ClassLoaderData(loader_data);
+
+ bool is_anonymous = (cld_addr == NULL);
+ ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous);
- // First, Atomically set it.
- ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL);
- if (old != NULL) {
- delete cld;
- // Returns the data.
- return old;
+ if (cld_addr != NULL) {
+ // First, Atomically set it
+ ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL);
+ if (old != NULL) {
+ delete cld;
+ // Returns the data.
+ return old;
+ }
}
// We won the race, and therefore the task of adding the data to the list of
@@ -417,16 +502,22 @@
ClassLoaderData* exchanged = (ClassLoaderData*)Atomic::cmpxchg_ptr(cld, list_head, next);
if (exchanged == next) {
if (TraceClassLoaderData) {
+ ResourceMark rm;
tty->print("[ClassLoaderData: ");
tty->print("create class loader data "PTR_FORMAT, cld);
- tty->print(" for instance "PTR_FORMAT" of ", cld->class_loader());
- loader_data->klass()->name()->print_symbol_on(tty);
+ tty->print(" for instance "PTR_FORMAT" of %s", cld->class_loader(),
+ cld->loader_name());
tty->print_cr("]");
}
+ // Create dependencies after the CLD is added to the list. Otherwise,
+ // the GC GC will not find the CLD and the _class_loader field will
+ // not be updated.
+ cld->init_dependencies(CHECK_NULL);
return cld;
}
next = exchanged;
} while (true);
+
}
void ClassLoaderDataGraph::oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
@@ -435,9 +526,19 @@
}
}
+void ClassLoaderDataGraph::keep_alive_oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
+ for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
+ if (cld->keep_alive()) {
+ cld->oops_do(f, klass_closure, must_claim);
+ }
+ }
+}
+
void ClassLoaderDataGraph::always_strong_oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
if (ClassUnloading) {
ClassLoaderData::the_null_class_loader_data()->oops_do(f, klass_closure, must_claim);
+ // keep any special CLDs alive.
+ ClassLoaderDataGraph::keep_alive_oops_do(f, klass_closure, must_claim);
} else {
ClassLoaderDataGraph::oops_do(f, klass_closure, must_claim);
}
@@ -516,9 +617,10 @@
}
#endif // PRODUCT
+
// Move class loader data from main list to the unloaded list for unloading
// and deallocation later.
-bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive) {
+bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure) {
ClassLoaderData* data = _head;
ClassLoaderData* prev = NULL;
bool seen_dead_loader = false;
@@ -527,8 +629,7 @@
bool has_redefined_a_class = JvmtiExport::has_redefined_a_class();
MetadataOnStackMark md_on_stack;
while (data != NULL) {
- if (data->class_loader() == NULL || is_alive->do_object_b(data->class_loader())) {
- assert(data->claimed(), "class loader data must have been claimed");
+ if (data->keep_alive() || data->is_alive(is_alive_closure)) {
if (has_redefined_a_class) {
data->classes_do(InstanceKlass::purge_previous_versions);
}
@@ -539,13 +640,7 @@
}
seen_dead_loader = true;
ClassLoaderData* dead = data;
- dead->mark_for_unload();
- if (TraceClassLoaderData) {
- tty->print("[ClassLoaderData: unload loader data "PTR_FORMAT, dead);
- tty->print(" for instance "PTR_FORMAT" of ", dead->class_loader());
- dead->class_loader()->klass()->name()->print_symbol_on(tty);
- tty->print_cr("]");
- }
+ dead->unload();
data = data->next();
// Remove from loader list.
if (prev != NULL) {
@@ -587,8 +682,8 @@
"only supported for null loader data for now");
assert (!_shared_metaspaces_initialized, "only initialize once");
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
- _ro_metaspace = new Metaspace(_metaspace_lock, SharedReadOnlySize/wordSize);
- _rw_metaspace = new Metaspace(_metaspace_lock, SharedReadWriteSize/wordSize);
+ _ro_metaspace = new Metaspace(_metaspace_lock, Metaspace::ROMetaspaceType);
+ _rw_metaspace = new Metaspace(_metaspace_lock, Metaspace::ReadWriteMetaspaceType);
_shared_metaspaces_initialized = true;
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/classfile/classLoaderData.hpp
--- a/src/share/vm/classfile/classLoaderData.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/classfile/classLoaderData.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -8,7 +8,7 @@
*
* 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
+ * 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).
*
@@ -62,13 +62,14 @@
// CMS support.
static ClassLoaderData* _saved_head;
- static ClassLoaderData* add(ClassLoaderData** loader_data_addr, Handle class_loader);
+ static ClassLoaderData* add(ClassLoaderData** loader_data_addr, Handle class_loader, TRAPS);
public:
- static ClassLoaderData* find_or_create(Handle class_loader);
+ static ClassLoaderData* find_or_create(Handle class_loader, TRAPS);
static void purge();
static void clear_claimed_marks();
static void oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim);
static void always_strong_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim);
+ static void keep_alive_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim);
static void classes_do(KlassClosure* klass_closure);
static bool do_unloading(BoolObjectClosure* is_alive);
@@ -101,10 +102,14 @@
oop _class_loader; // oop used to uniquely identify a class loader
// class loader or a canonical class path
+ oop _dependencies; // oop to hold dependencies from this class loader
+ // data to others.
Metaspace * _metaspace; // Meta-space where meta-data defined by the
// classes in the class loader are allocated.
Mutex* _metaspace_lock; // Locks the metaspace for allocations and setup.
bool _unloading; // true if this class loader goes away
+ bool _keep_alive; // if this CLD can be unloaded for anonymous loaders
+ bool _is_anonymous; // if this CLD is for an anonymous class
volatile int _claimed; // true if claimed, for example during GC traces.
// To avoid applying oop closure more than once.
// Has to be an int because we cas it.
@@ -129,13 +134,13 @@
static Metaspace* _ro_metaspace;
static Metaspace* _rw_metaspace;
- bool has_dependency(ClassLoaderData* cld);
- void add_dependency(ClassLoaderData* to_loader_data, TRAPS);
+ void add_dependency(Handle dependency, TRAPS);
+ void locked_add_dependency(objArrayHandle last, objArrayHandle new_dependency);
void set_next(ClassLoaderData* next) { _next = next; }
ClassLoaderData* next() const { return _next; }
- ClassLoaderData(Handle h_class_loader);
+ ClassLoaderData(Handle h_class_loader, bool is_anonymous);
~ClassLoaderData();
void set_metaspace(Metaspace* m) { _metaspace = m; }
@@ -150,7 +155,9 @@
bool claimed() const { return _claimed == 1; }
bool claim();
- void mark_for_unload() { _unloading = true; }
+ void unload();
+ bool keep_alive() const { return _keep_alive; }
+ bool is_alive(BoolObjectClosure* is_alive_closure) const;
void classes_do(void f(InstanceKlass*));
@@ -168,10 +175,12 @@
return _the_null_class_loader_data;
}
+ bool is_anonymous() const { return _is_anonymous; }
+
static void init_null_class_loader_data() {
assert(_the_null_class_loader_data == NULL, "cannot initialize twice");
assert(ClassLoaderDataGraph::_head == NULL, "cannot initialize twice");
- _the_null_class_loader_data = new ClassLoaderData((oop)NULL);
+ _the_null_class_loader_data = new ClassLoaderData((oop)NULL, false);
ClassLoaderDataGraph::_head = _the_null_class_loader_data;
assert(_the_null_class_loader_data->is_the_null_class_loader_data(), "Must be");
if (DumpSharedSpaces) {
@@ -194,6 +203,9 @@
assert(!(is_the_null_class_loader_data() && _unloading), "The null class loader can never be unloaded");
return _unloading;
}
+ // Anonymous class loader data doesn't have anything to keep them from
+ // being unloaded during parsing the anonymous class.
+ void set_keep_alive(bool value) { _keep_alive = value; }
unsigned int identity_hash() {
return _class_loader == NULL ? 0 : _class_loader->identity_hash();
@@ -211,15 +223,18 @@
void print_value_on(outputStream* out) const PRODUCT_RETURN;
void dump(outputStream * const out) PRODUCT_RETURN;
void verify();
+ const char* loader_name();
jobject add_handle(Handle h);
void add_class(Klass* k);
void remove_class(Klass* k);
void record_dependency(Klass* to, TRAPS);
+ void init_dependencies(TRAPS);
void add_to_deallocate_list(Metadata* m);
static ClassLoaderData* class_loader_data(oop loader);
+ static ClassLoaderData* anonymous_class_loader_data(oop loader, TRAPS);
static void print_loader(ClassLoaderData *loader_data, outputStream *out);
// CDS support
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/classfile/classLoaderData.inline.hpp
--- a/src/share/vm/classfile/classLoaderData.inline.hpp Mon Nov 05 17:03:33 2012 -0500
+++ b/src/share/vm/classfile/classLoaderData.inline.hpp Sun Feb 03 22:43:57 2013 +0100
@@ -33,7 +33,7 @@
}
-inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader) {
+inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader, TRAPS) {
assert(loader() != NULL,"Must be a class loader");
// Gets the class loader data out of the java/lang/ClassLoader object, if non-null
// it's already in the loader_data, so no need to add
@@ -42,5 +42,5 @@
if (loader_data_id) {
return loader_data_id;
}
- return ClassLoaderDataGraph::add(loader_data_addr, loader);
+ return ClassLoaderDataGraph::add(loader_data_addr, loader, THREAD);
}
diff -r 77443715ec55 -r b5cb079ecaa4 src/share/vm/classfile/defaultMethods.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/classfile/defaultMethods.cpp Sun Feb 03 22:43:57 2013 +0100
@@ -0,0 +1,1395 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/bytecodeAssembler.hpp"
+#include "classfile/defaultMethods.hpp"
+#include "classfile/genericSignatures.hpp"
+#include "classfile/symbolTable.hpp"
+#include "memory/allocation.hpp"
+#include "memory/metadataFactory.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/signature.hpp"
+#include "runtime/thread.hpp"
+#include "oops/instanceKlass.hpp"
+#include "oops/klass.hpp"
+#include "oops/method.hpp"
+#include "utilities/accessFlags.hpp"
+#include "utilities/exceptions.hpp"
+#include "utilities/ostream.hpp"
+#include "utilities/pair.hpp"
+#include "utilities/resourceHash.hpp"
+
+typedef enum { QUALIFIED, DISQUALIFIED } QualifiedState;
+
+// Because we use an iterative algorithm when iterating over the type
+// hierarchy, we can't use traditional scoped objects which automatically do
+// cleanup in the destructor when the scope is exited. PseudoScope (and
+// PseudoScopeMark) provides a similar functionality, but for when you want a
+// scoped object in non-stack memory (such as in resource memory, as we do
+// here). You've just got to remember to call 'destroy()' on the scope when
+// leaving it (and marks have to be explicitly added).
+class PseudoScopeMark : public ResourceObj {
+ public:
+ virtual void destroy() = 0;
+};
+
+class PseudoScope : public ResourceObj {
+ private:
+ GrowableArray _marks;
+ public:
+
+ static PseudoScope* cast(void* data) {
+ return static_cast(data);
+ }
+
+ void add_mark(PseudoScopeMark* psm) {
+ _marks.append(psm);
+ }
+
+ void destroy() {
+ for (int i = 0; i < _marks.length(); ++i) {
+ _marks.at(i)->destroy();
+ }
+ }
+};
+
+class ContextMark : public PseudoScopeMark {
+ private:
+ generic::Context::Mark _mark;
+ public:
+ ContextMark(const generic::Context::Mark& cm) : _mark(cm) {}
+ virtual void destroy() { _mark.destroy(); }
+};
+
+#ifndef PRODUCT
+static void print_slot(outputStream* str, Symbol* name, Symbol* signature) {
+ ResourceMark rm;
+ str->print("%s%s", name->as_C_string(), signature->as_C_string());
+}
+
+static void print_method(outputStream* str, Method* mo, bool with_class=true) {
+ ResourceMark rm;
+ if (with_class) {
+ str->print("%s.", mo->klass_name()->as_C_string());
+ }
+ print_slot(str, mo->name(), mo->signature());
+}
+#endif // ndef PRODUCT
+
+/**
+ * Perform a depth-first iteration over the class hierarchy, applying
+ * algorithmic logic as it goes.
+ *
+ * This class is one half of the inheritance hierarchy analysis mechanism.
+ * It is meant to be used in conjunction with another class, the algorithm,
+ * which is indicated by the ALGO template parameter. This class can be
+ * paired with any algorithm class that provides the required methods.
+ *
+ * This class contains all the mechanics for iterating over the class hierarchy
+ * starting at a particular root, without recursing (thus limiting stack growth
+ * from this point). It visits each superclass (if present) and superinterface
+ * in a depth-first manner, with callbacks to the ALGO class as each class is
+ * encountered (visit()), The algorithm can cut-off further exploration of a
+ * particular branch by returning 'false' from a visit() call.
+ *
+ * The ALGO class, must provide a visit() method, which each of which will be
+ * called once for each node in the inheritance tree during the iteration. In
+ * addition, it can provide a memory block via new_node_data(InstanceKlass*),
+ * which it can use for node-specific storage (and access via the
+ * current_data() and data_at_depth(int) methods).
+ *
+ * Bare minimum needed to be an ALGO class:
+ * class Algo : public HierarchyVisitor {
+ * void* new_node_data(InstanceKlass* cls) { return NULL; }
+ * void free_node_data(void* data) { return; }
+ * bool visit() { return true; }
+ * };
+ */
+template
+class HierarchyVisitor : StackObj {
+ private:
+
+ class Node : public ResourceObj {
+ public:
+ InstanceKlass* _class;
+ bool _super_was_visited;
+ int _interface_index;
+ void* _algorithm_data;
+
+ Node(InstanceKlass* cls, void* data, bool visit_super)
+ : _class(cls), _super_was_visited(!visit_super),
+ _interface_index(0), _algorithm_data(data) {}
+
+ int number_of_interfaces() { return _class->local_interfaces()->length(); }
+ int interface_index() { return _interface_index; }
+ void set_super_visited() { _super_was_visited = true; }
+ void increment_visited_interface() { ++_interface_index; }
+ void set_all_interfaces_visited() {
+ _interface_index = number_of_interfaces();
+ }
+ bool has_visited_super() { return _super_was_visited; }
+ bool has_visited_all_interfaces() {
+ return interface_index() >= number_of_interfaces();
+ }
+ InstanceKlass* interface_at(int index) {
+ return InstanceKlass::cast(_class->local_interfaces()->at(index));
+ }
+ InstanceKlass* next_super() { return _class->java_super(); }
+ InstanceKlass* next_interface() {
+ return interface_at(interface_index());
+ }
+ };
+
+ bool _cancelled;
+ GrowableArray _path;
+
+ Node* current_top() const { return _path.top(); }
+ bool has_more_nodes() const { return !_path.is_empty(); }
+ void push(InstanceKlass* cls, void* data) {
+ assert(cls != NULL, "Requires a valid instance class");
+ Node* node = new Node(cls, data, has_super(cls));
+ _path.push(node);
+ }
+ void pop() { _path.pop(); }
+
+ void reset_iteration() {
+ _cancelled = false;
+ _path.clear();
+ }
+ bool is_cancelled() const { return _cancelled; }
+
+ static bool has_super(InstanceKlass* cls) {
+ return cls->super() != NULL && !cls->is_interface();
+ }
+
+ Node* node_at_depth(int i) const {
+ return (i >= _path.length()) ? NULL : _path.at(_path.length() - i - 1);
+ }
+
+ protected:
+
+ // Accessors available to the algorithm
+ int current_depth() const { return _path.length() - 1; }
+
+ InstanceKlass* class_at_depth(int i) {
+ Node* n = node_at_depth(i);
+ return n == NULL ? NULL : n->_class;
+ }
+ InstanceKlass* current_class() { return class_at_depth(0); }
+
+ void* data_at_depth(int i) {
+ Node* n = node_at_depth(i);
+ return n == NULL ? NULL : n->_algorithm_data;
+ }
+ void* current_data() { return data_at_depth(0); }
+
+ void cancel_iteration() { _cancelled = true; }
+
+ public:
+
+ void run(InstanceKlass* root) {
+ ALGO* algo = static_cast(this);
+
+ reset_iteration();
+
+ void* algo_data = algo->new_node_data(root);
+ push(root, algo_data);
+ bool top_needs_visit = true;
+
+ do {
+ Node* top = current_top();
+ if (top_needs_visit) {
+ if (algo->visit() == false) {
+ // algorithm does not want to continue along this path. Arrange
+ // it so that this state is immediately popped off the stack
+ top->set_super_visited();
+ top->set_all_interfaces_visited();
+ }
+ top_needs_visit = false;
+ }
+
+ if (top->has_visited_super() && top->has_visited_all_interfaces()) {
+ algo->free_node_data(top->_algorithm_data);
+ pop();
+ } else {
+ InstanceKlass* next = NULL;
+ if (top->has_visited_super() == false) {
+ next = top->next_super();
+ top->set_super_visited();
+ } else {
+ next = top->next_interface();
+ top->increment_visited_interface();
+ }
+ assert(next != NULL, "Otherwise we shouldn't be here");
+ algo_data = algo->new_node_data(next);
+ push(next, algo_data);
+ top_needs_visit = true;
+ }
+ } while (!is_cancelled() && has_more_nodes());
+ }
+};
+
+#ifndef PRODUCT
+class PrintHierarchy : public HierarchyVisitor {
+ public:
+
+ bool visit() {
+ InstanceKlass* cls = current_class();
+ streamIndentor si(tty, current_depth() * 2);
+ tty->indent().print_cr("%s", cls->name()->as_C_string());
+ return true;
+ }
+
+ void* new_node_data(InstanceKlass* cls) { return NULL; }
+ void free_node_data(void* data) { return; }
+};
+#endif // ndef PRODUCT
+
+// Used to register InstanceKlass objects and all related metadata structures
+// (Methods, ConstantPools) as "in-use" by the current thread so that they can't
+// be deallocated by class redefinition while we're using them. The classes are
+// de-registered when this goes out of scope.
+//
+// Once a class is registered, we need not bother with methodHandles or
+// constantPoolHandles for it's associated metadata.
+class KeepAliveRegistrar : public StackObj {
+ private:
+ Thread* _thread;
+ GrowableArray _keep_alive;
+
+ public:
+ KeepAliveRegistrar(Thread* thread) : _thread(thread), _keep_alive(20) {
+ assert(thread == Thread::current(), "Must be current thread");
+ }
+
+ ~KeepAliveRegistrar() {
+ for (int i = _keep_alive.length() - 1; i >= 0; --i) {
+ ConstantPool* cp = _keep_alive.at(i);
+ int idx = _thread->metadata_handles()->find_from_end(cp);
+ assert(idx > 0, "Must be in the list");
+ _thread->metadata_handles()->remove_at(idx);
+ }
+ }
+
+ // Register a class as 'in-use' by the thread. It's fine to register a class
+ // multiple times (though perhaps inefficient)
+ void register_class(InstanceKlass* ik) {
+ ConstantPool* cp = ik->constants();
+ _keep_alive.push(cp);
+ _thread->metadata_handles()->push(cp);
+ }
+};
+
+class KeepAliveVisitor : public HierarchyVisitor {
+ private:
+ KeepAliveRegistrar* _registrar;
+
+ public:
+ KeepAliveVisitor(KeepAliveRegistrar* registrar) : _registrar(registrar) {}
+
+ void* new_node_data(InstanceKlass* cls) { return NULL; }
+ void free_node_data(void* data) { return; }
+
+ bool visit() {
+ _registrar->register_class(current_class());
+ return true;
+ }
+};
+
+// A method family contains a set of all methods that implement a single
+// language-level method. Because of erasure, these methods may have different
+// signatures. As members of the set are collected while walking over the
+// hierarchy, they are tagged with a qualification state. The qualification
+// state for an erased method is set to disqualified if there exists a path
+// from the root of hierarchy to the method that contains an interleaving
+// language-equivalent method defined in an interface.
+class MethodFamily : public ResourceObj {
+ private:
+
+ generic::MethodDescriptor* _descriptor; // language-level description
+ GrowableArray > _members;
+ ResourceHashtable _member_index;
+
+ Method* _selected_target; // Filled in later, if a unique target exists
+ Symbol* _exception_message; // If no unique target is found
+
+ bool contains_method(Method* method) {
+ int* lookup = _member_index.get(method);
+ return lookup != NULL;
+ }
+
+ void add_method(Method* method, QualifiedState state) {
+ Pair entry(method, state);
+ _member_index.put(method, _members.length());
+ _members.append(entry);
+ }
+
+ void disqualify_method(Method* method) {
+ int* index = _member_index.get(method);
+ assert(index != NULL && *index >= 0 && *index < _members.length(), "bad index");
+ _members.at(*index).second = DISQUALIFIED;
+ }
+
+ Symbol* generate_no_defaults_message(TRAPS) const;
+ Symbol* generate_abstract_method_message(Method* method, TRAPS) const;
+ Symbol* generate_conflicts_message(GrowableArray* methods, TRAPS) const;
+
+ public:
+
+ MethodFamily(generic::MethodDescriptor* canonical_desc)
+ : _descriptor(canonical_desc), _selected_target(NULL),
+ _exception_message(NULL) {}
+
+ generic::MethodDescriptor* descriptor() const { return _descriptor; }
+
+ bool descriptor_matches(generic::MethodDescriptor* md, generic::Context* ctx) {
+ return descriptor()->covariant_match(md, ctx);
+ }
+
+ void set_target_if_empty(Method* m) {
+ if (_selected_target == NULL && !m->is_overpass()) {
+ _selected_target = m;
+ }
+ }
+
+ void record_qualified_method(Method* m) {
+ // If the method already exists in the set as qualified, this operation is
+ // redundant. If it already exists as disqualified, then we leave it as
+ // disqualfied. Thus we only add to the set if it's not already in the
+ // set.
+ if (!contains_method(m)) {
+ add_method(m, QUALIFIED);
+ }
+ }
+
+ void record_disqualified_method(Method* m) {
+ // If not in the set, add it as disqualified. If it's already in the set,
+ // then set the state to disqualified no matter what the previous state was.
+ if (!contains_method(m)) {
+ add_method(m, DISQUALIFIED);
+ } else {
+ disqualify_method(m);
+ }
+ }
+
+ bool has_target() const { return _selected_target != NULL; }
+ bool throws_exception() { return _exception_message != NULL; }
+
+ Method* get_selected_target() { return _selected_target; }
+ Symbol* get_exception_message() { return _exception_message; }
+
+ // Either sets the target or the exception error message
+ void determine_target(InstanceKlass* root, TRAPS) {
+ if (has_target() || throws_exception()) {
+ return;
+ }
+
+ GrowableArray qualified_methods;
+ for (int i = 0; i < _members.length(); ++i) {
+ Pair entry = _members.at(i);
+ if (entry.second == QUALIFIED) {
+ qualified_methods.append(entry.first);
+ }
+ }
+
+ if (qualified_methods.length() == 0) {
+ _exception_message = generate_no_defaults_message(CHECK);
+ } else if (qualified_methods.length() == 1) {
+ Method* method = qualified_methods.at(0);
+ if (method->is_abstract()) {
+ _exception_message = generate_abstract_method_message(method, CHECK);
+ } else {
+ _selected_target = qualified_methods.at(0);
+ }
+ } else {
+ _exception_message = generate_conflicts_message(&qualified_methods,CHECK);
+ }
+
+ assert((has_target() ^ throws_exception()) == 1,
+ "One and only one must be true");
+ }
+
+ bool contains_signature(Symbol* query) {
+ for (int i = 0; i < _members.length(); ++i) {
+ if (query == _members.at(i).first->signature()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+#ifndef PRODUCT
+ void print_on(outputStream* str) const {
+ print_on(str, 0);
+ }
+
+ void print_on(outputStream* str, int indent) const {
+ streamIndentor si(str, indent * 2);
+
+ generic::Context ctx(NULL); // empty, as _descriptor already canonicalized
+ TempNewSymbol family = descriptor()->reify_signature(&ctx, Thread::current());
+ str->indent().print_cr("Logical Method %s:", family->as_C_string());
+
+ streamIndentor si2(str);
+ for (int i = 0; i < _members.length(); ++i) {
+ str->indent();
+ print_method(str, _members.at(i).first);
+ if (_members.at(i).second == DISQUALIFIED) {
+ str->print(" (disqualified)");
+ }
+ str->print_cr("");
+ }
+
+ if (_selected_target != NULL) {
+ print_selected(str, 1);
+ }
+ }
+
+ void print_selected(outputStream* str, int indent) const {
+ assert(has_target(), "Should be called otherwise");
+ streamIndentor si(str, indent * 2);
+ str->indent().print("Selected method: ");
+ print_method(str, _selected_target);
+ str->print_cr("");
+ }
+
+ void print_exception(outputStream* str, int indent) {
+ assert(throws_exception(), "Should be called otherwise");
+ streamIndentor si(str, indent * 2);
+ str->indent().print_cr("%s", _exception_message->as_C_string());
+ }
+#endif // ndef PRODUCT
+};
+
+Symbol* MethodFamily::generate_no_defaults_message(TRAPS) const {
+ return SymbolTable::new_symbol("No qualifying defaults found", CHECK_NULL);
+}
+
+Symbol* MethodFamily::generate_abstract_method_message(Method* method, TRAPS) const {
+ Symbol* klass = method->klass_name();
+ Symbol* name = method->name();
+ Symbol* sig = method->signature();
+ stringStream ss;
+ ss.print("Method ");
+ ss.write((const char*)klass->bytes(), klass->utf8_length());
+ ss.print(".");
+ ss.write((const char*)name->bytes(), name->utf8_length());
+ ss.write((const char*)sig->bytes(), sig->utf8_length());
+ ss.print(" is abstract");
+ return SymbolTable::new_symbol(ss.base(), (int)ss.size(), CHECK_NULL);
+}
+
+Symbol* MethodFamily::generate_conflicts_message(GrowableArray* methods, TRAPS) const {
+ stringStream ss;
+ ss.print("Conflicting default methods:");
+ for (int i = 0; i < methods->length(); ++i) {
+ Method* method = methods->at(i);
+ Symbol* klass = method->klass_name();
+ Symbol* name = method->name();
+ ss.print(" ");
+ ss.write((const char*)klass->bytes(), klass->utf8_length());
+ ss.print(".");
+ ss.write((const char*)name->bytes(), name->utf8_length());
+ }
+ return SymbolTable::new_symbol(ss.base(), (int)ss.size(), CHECK_NULL);
+}
+
+class StateRestorer;
+
+// StatefulMethodFamily is a wrapper around MethodFamily that maintains the
+// qualification state during hierarchy visitation, and applies that state
+// when adding members to the MethodFamily.
+class StatefulMethodFamily : public ResourceObj {
+ friend class StateRestorer;
+ private:
+ MethodFamily* _method;
+ QualifiedState _qualification_state;
+
+ void set_qualification_state(QualifiedState state) {
+ _qualification_state = state;
+ }
+
+ public:
+ StatefulMethodFamily(generic::MethodDescriptor* md, generic::Context* ctx) {
+ _method = new MethodFamily(md->canonicalize(ctx));
+ _qualification_state = QUALIFIED;
+ }
+
+ void set_target_if_empty(Method* m) { _method->set_target_if_empty(m); }
+
+ MethodFamily* get_method_family() { return _method; }
+
+ bool descriptor_matches(generic::MethodDescriptor* md, generic::Context* ctx) {
+ return _method->descriptor_matches(md, ctx);
+ }
+
+ StateRestorer* record_method_and_dq_further(Method* mo);
+};
+
+class StateRestorer : public PseudoScopeMark {
+ private:
+ StatefulMethodFamily* _method;
+ QualifiedState _state_to_restore;
+ public:
+ StateRestorer(StatefulMethodFamily* dm, QualifiedState state)
+ : _method(dm), _state_to_restore(state) {}
+ ~StateRestorer() { destroy(); }
+ void restore_state() { _method->set_qualification_state(_state_to_restore); }
+ virtual void destroy() { restore_state(); }
+};
+
+StateRestorer* StatefulMethodFamily::record_method_and_dq_further(Method* mo) {
+ StateRestorer* mark = new StateRestorer(this, _qualification_state);
+ if (_qualification_state == QUALIFIED) {
+ _method->record_qualified_method(mo);
+ } else {
+ _method->record_disqualified_method(mo);
+ }
+ // Everything found "above"??? this method in the hierarchy walk is set to
+ // disqualified
+ set_qualification_state(DISQUALIFIED);
+ return mark;
+}
+
+class StatefulMethodFamilies : public ResourceObj {
+ private:
+ GrowableArray _methods;
+
+ public:
+ StatefulMethodFamily* find_matching(
+ generic::MethodDescriptor* md, generic::Context* ctx) {
+ for (int i = 0; i < _methods.length(); ++i) {
+ StatefulMethodFamily* existing = _methods.at(i);
+ if (existing->descriptor_matches(md, ctx)) {
+ return existing;
+ }
+ }
+ return NULL;
+ }
+
+ StatefulMethodFamily* find_matching_or_create(
+ generic::MethodDescriptor* md, generic::Context* ctx) {
+ StatefulMethodFamily* method = find_matching(md, ctx);
+ if (method == NULL) {
+ method = new StatefulMethodFamily(md, ctx);
+ _methods.append(method);
+ }
+ return method;
+ }
+
+ void extract_families_into(GrowableArray* array) {
+ for (int i = 0; i < _methods.length(); ++i) {
+ array->append(_methods.at(i)->get_method_family());
+ }
+ }
+};
+
+// Represents a location corresponding to a vtable slot for methods that
+// neither the class nor any of it's ancestors provide an implementaion.
+// Default methods may be present to fill this slot.
+class EmptyVtableSlot : public ResourceObj {
+ private:
+ Symbol* _name;
+ Symbol* _signature;
+ int _size_of_parameters;
+ MethodFamily* _binding;
+
+ public:
+ EmptyVtableSlot(Method* method)
+ : _name(method->name()), _signature(method->signature()),
+ _size_of_parameters(method->size_of_parameters()), _binding(NULL) {}
+
+ Symbol* name() const { return _name; }
+ Symbol* signature() const { return _signature; }
+ int size_of_parameters() const { return _size_of_parameters; }
+
+ void bind_family(MethodFamily* lm) { _binding = lm; }
+ bool is_bound() { return _binding != NULL; }
+ MethodFamily* get_binding() { return _binding; }
+
+#ifndef PRODUCT
+ void print_on(outputStream* str) const {
+ print_slot(str, name(), signature());
+ }
+#endif // ndef PRODUCT
+};
+
+static GrowableArray* find_empty_vtable_slots(
+ InstanceKlass* klass, GrowableArray* mirandas, TRAPS) {
+
+ assert(klass != NULL, "Must be valid class");
+
+ GrowableArray* slots = new GrowableArray();
+
+ // All miranda methods are obvious candidates
+ for (int i = 0; i < mirandas->length(); ++i) {
+ EmptyVtableSlot* slot = new EmptyVtableSlot(mirandas->at(i));
+ slots->append(slot);
+ }
+
+ // Also any overpasses in our superclasses, that we haven't implemented.
+ // (can't use the vtable because it is not guaranteed to be initialized yet)
+ InstanceKlass* super = klass->java_super();
+ while (super != NULL) {
+ for (int i = 0; i < super->methods()->length(); ++i) {
+ Method* m = super->methods()->at(i);
+ if (m->is_overpass()) {
+ // m is a method that would have been a miranda if not for the
+ // default method processing that occurred on behalf of our superclass,
+ // so it's a method we want to re-examine in this new context. That is,
+ // unless we have a real implementation of it in the current class.
+ Method* impl = klass->lookup_method(m->name(), m->signature());
+ if (impl == NULL || impl->is_overpass()) {
+ slots->append(new EmptyVtableSlot(m));
+ }
+ }
+ }
+ super = super->java_super();
+ }
+
+#ifndef PRODUCT
+ if (TraceDefaultMethods) {
+ tty->print_cr("Slots that need filling:");
+ streamIndentor si(tty);
+ for (int i = 0; i < slots->length(); ++i) {
+ tty->indent();
+ slots->at(i)->print_on(tty);
+ tty->print_cr("");
+ }
+ }
+#endif // ndef PRODUCT
+ return slots;
+}
+
+// Iterates over the type hierarchy looking for all methods with a specific
+// method name. The result of this is a set of method families each of
+// which is populated with a set of methods that implement the same
+// language-level signature.
+class FindMethodsByName : public HierarchyVisitor {
+ private:
+ // Context data
+ Thread* THREAD;
+ generic::DescriptorCache* _cache;
+ Symbol* _method_name;
+ generic::Context* _ctx;
+ StatefulMethodFamilies _families;
+
+ public:
+
+ FindMethodsByName(generic::DescriptorCache* cache, Symbol* name,
+ generic::Context* ctx, Thread* thread) :
+ _cache(cache), _method_name(name), _ctx(ctx), THREAD(thread) {}
+
+ void get_discovered_families(GrowableArray* methods) {
+ _families.extract_families_into(methods);
+ }
+
+ void* new_node_data(InstanceKlass* cls) { return new PseudoScope(); }
+ void free_node_data(void* node_data) {
+ PseudoScope::cast(node_data)->destroy();
+ }
+
+ bool visit() {
+ PseudoScope* scope = PseudoScope::cast(current_data());
+ InstanceKlass* klass = current_class();
+ InstanceKlass* sub = current_depth() > 0 ? class_at_depth(1) : NULL;
+
+ ContextMark* cm = new ContextMark(_ctx->mark());
+ scope->add_mark(cm); // will restore context when scope is freed
+
+ _ctx->apply_type_arguments(sub, klass, THREAD);
+
+ int start, end = 0;
+ start = klass->find_method_by_name(_method_name, &end);
+ if (start != -1) {
+ for (int i = start; i < end; ++i) {
+ Method* m = klass->methods()->at(i);
+ // This gets the method's parameter list with its generic type
+ // parameters resolved
+ generic::MethodDescriptor* md = _cache->descriptor_for(m, THREAD);
+
+ // Find all methods on this hierarchy that match this method
+ // (name, signature). This class collects other families of this
+ // method name.
+ StatefulMethodFamily* family =
+ _families.find_matching_or_create(md, _ctx);
+
+ if (klass->is_interface()) {
+ // ???
+ StateRestorer* restorer = family->record_method_and_dq_further(m);
+ scope->add_mark(restorer);
+ } else {
+ // This is the rule that methods in classes "win" (bad word) over
+ // methods in interfaces. This works because of single inheritance
+ family->set_target_if_empty(m);
+ }
+ }
+ }
+ return true;
+ }
+};
+
+#ifndef PRODUCT
+static void print_families(
+ GrowableArray* methods, Symbol* match) {
+ streamIndentor si(tty, 4);
+ if (methods->length() == 0) {
+ tty->indent();
+ tty->print_cr("No Logical Method found");
+ }
+ for (int i = 0; i < methods->length(); ++i) {
+ tty->indent();
+ MethodFamily* lm = methods->at(i);
+ if (lm->contains_signature(match)) {
+ tty->print_cr("");
+ } else {
+ tty->print_cr("");
+ }
+ lm->print_on(tty, 1);
+ }
+}
+#endif // ndef PRODUCT
+
+static void merge_in_new_methods(InstanceKlass* klass,
+ GrowableArray* new_methods, TRAPS);
+static void create_overpasses(
+ GrowableArray* slots, InstanceKlass* klass, TRAPS);
+
+// This is the guts of the default methods implementation. This is called just
+// after the classfile has been parsed if some ancestor has default methods.
+//
+// First if finds any name/signature slots that need any implementation (either
+// because they are miranda or a superclass's implementation is an overpass
+// itself). For each slot, iterate over the hierarchy, using generic signature
+// information to partition any methods that match the name into method families
+// where each family contains methods whose signatures are equivalent at the
+// language level (i.e., their reified parameters match and return values are
+// covariant). Check those sets to see if they contain a signature that matches
+// the slot we're looking at (if we're lucky, there might be other empty slots
+// that we can fill using the same analysis).
+//
+// For each slot filled, we generate an overpass method that either calls the
+// unique default method candidate using invokespecial, or throws an exception
+// (in the case of no default method candidates, or more than one valid
+// candidate). These methods are then added to the class's method list. If
+// the method set we're using contains methods (qualified or not) with a
+// different runtime signature than the method we're creating, then we have to
+// create bridges with those signatures too.
+void DefaultMethods::generate_default_methods(
+ InstanceKlass* klass, GrowableArray* mirandas, TRAPS) {
+
+ // This resource mark is the bound for all memory allocation that takes
+ // place during default method processing. After this goes out of scope,
+ // all (Resource) objects' memory will be reclaimed. Be careful if adding an
+ // embedded resource mark under here as that memory can't be used outside
+ // whatever scope it's in.
+ ResourceMark rm(THREAD);
+
+ generic::DescriptorCache cache;
+
+ // Keep entire hierarchy alive for the duration of the computation
+ KeepAliveRegistrar keepAlive(THREAD);
+ KeepAliveVisitor loadKeepAlive(&keepAlive);
+ loadKeepAlive.run(klass);
+
+#ifndef PRODUCT
+ if (TraceDefaultMethods) {
+ ResourceMark rm; // be careful with these!
+ tty->print_cr("Class %s requires default method processing",
+ klass->name()->as_klass_external_name());
+ PrintHierarchy printer;
+ printer.run(klass);
+ }
+#endif // ndef PRODUCT
+
+ GrowableArray* empty_slots =
+ find_empty_vtable_slots(klass, mirandas, CHECK);
+
+ for (int i = 0; i < empty_slots->length(); ++i) {
+ EmptyVtableSlot* slot = empty_slots->at(i);
+#ifndef PRODUCT
+ if (TraceDefaultMethods) {
+ streamIndentor si(tty, 2);
+ tty->indent().print("Looking for default methods for slot ");
+ slot->print_on(tty);
+ tty->print_cr("");
+ }
+#endif // ndef PRODUCT
+ if (slot->is_bound()) {
+#ifndef PRODUCT
+ if (TraceDefaultMethods) {
+ streamIndentor si(tty, 4);
+ tty->indent().print_cr("Already bound to logical method:");
+ slot->get_binding()->print_on(tty, 1);
+ }
+#endif // ndef PRODUCT
+ continue; // covered by previous processing
+ }
+
+ generic::Context ctx(&cache);
+ FindMethodsByName visitor(&cache, slot->name(), &ctx, CHECK);
+ visitor.run(klass);
+
+ GrowableArray discovered_families;
+ visitor.get_discovered_families(&discovered_families);
+
+#ifndef PRODUCT
+ if (TraceDefaultMethods) {
+ print_families(&discovered_families, slot->signature());
+ }
+#endif // ndef PRODUCT
+
+ // Find and populate any other slots that match the discovered families
+ for (int j = i; j < empty_slots->length(); ++j) {
+ EmptyVtableSlot* open_slot = empty_slots->at(j);
+
+ if (slot->name() == open_slot->name()) {
+ for (int k = 0; k < discovered_families.length(); ++k) {
+ MethodFamily* lm = discovered_families.at(k);
+
+ if (lm->contains_signature(open_slot->signature())) {
+ lm->determine_target(klass, CHECK);
+ open_slot->bind_family(lm);
+ }
+ }
+ }
+ }
+ }
+
+#ifndef PRODUCT
+ if (TraceDefaultMethods) {
+ tty->print_cr("Creating overpasses...");
+ }
+#endif // ndef PRODUCT
+
+ create_overpasses(empty_slots, klass, CHECK);
+
+#ifndef PRODUCT
+ if (TraceDefaultMethods) {
+ tty->print_cr("Default method processing complete");
+ }
+#endif // ndef PRODUCT
+}
+
+
+/**
+ * Generic analysis was used upon interface '_target' and found a unique
+ * default method candidate with generic signature '_method_desc'. This
+ * method is only viable if it would also be in the set of default method
+ * candidates if we ran a full analysis on the current class.
+ *
+ * The only reason that the method would not be in the set of candidates for
+ * the current class is if that there's another covariantly matching method
+ * which is "more specific" than the found method -- i.e., one could find a
+ * path in the interface hierarchy in which the matching method appears
+ * before we get to '_target'.
+ *
+ * In order to determine this, we examine all of the implemented
+ * interfaces. If we find path that leads to the '_target' interface, then
+ * we examine that path to see if there are any methods that would shadow
+ * the selected method along that path.
+ */
+class ShadowChecker : public HierarchyVisitor {
+ private:
+ generic::DescriptorCache* _cache;
+ Thread* THREAD;
+
+ InstanceKlass* _target;
+
+ Symbol* _method_name;
+ InstanceKlass* _method_holder;
+ generic::MethodDescriptor* _method_desc;
+ bool _found_shadow;
+
+ bool path_has_shadow() {
+ generic::Context ctx(_cache);
+
+ for (int i = current_depth() - 1; i > 0; --i) {
+ InstanceKlass* ik = class_at_depth(i);
+ InstanceKlass* sub = class_at_depth(i + 1);
+ ctx.apply_type_arguments(sub, ik, THREAD);
+
+ if (ik->is_interface()) {
+ int end;
+ int start = ik->find_method_by_name(_method_name, &end);
+ if (start != -1) {
+ for (int j = start; j < end; ++j) {
+ Method* mo = ik->methods()->at(j);
+ generic::MethodDescriptor* md = _cache->descriptor_for(mo, THREAD);
+ if (_method_desc->covariant_match(md, &ctx)) {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ public:
+
+ ShadowChecker(generic::DescriptorCache* cache, Thread* thread,
+ Symbol* name, InstanceKlass* holder, generic::MethodDescriptor* desc,
+ InstanceKlass* target)
+ : _cache(cache), THREAD(thread), _method_name(name), _method_holder(holder),
+ _method_desc(desc), _target(target), _found_shadow(false) {}
+
+ void* new_node_data(InstanceKlass* cls) { return NULL; }
+ void free_node_data(void* data) { return; }
+
+ bool visit() {
+ InstanceKlass* ik = current_class();
+ if (ik == _target && current_depth() == 1) {
+ return false; // This was the specified super -- no need to search it
+ }
+ if (ik == _method_holder || ik == _target) {
+ // We found a path that should be examined to see if it shadows _method
+ if (path_has_shadow()) {
+ _found_shadow = true;
+ cancel_iteration();
+ }
+ return false; // no need to continue up hierarchy
+ }
+ return true;
+ }
+
+ bool found_shadow() { return _found_shadow; }
+};
+
+// This is called during linktime when we find an invokespecial call that
+// refers to a direct superinterface. It indicates that we should find the
+// default method in the hierarchy of that superinterface, and if that method
+// would have been a candidate from the point of view of 'this' class, then we
+// return that method.
+Method* DefaultMethods::find_super_default(
+ Klass* cls, Klass* super, Symbol* method_name, Symbol* sig, TRAPS) {
+
+ ResourceMark rm(THREAD);
+
+ assert(cls != NULL && super != NULL, "Need real classes");
+
+ InstanceKlass* current_class = InstanceKlass::cast(cls);
+ InstanceKlass* direction = InstanceKlass::cast(super);
+
+ // Keep entire hierarchy alive for the duration of the computation
+ KeepAliveRegistrar keepAlive(THREAD);
+ KeepAliveVisitor loadKeepAlive(&keepAlive);
+ loadKeepAlive.run(current_class);
+
+#ifndef PRODUCT
+ if (TraceDefaultMethods) {
+ tty->print_cr("Finding super default method %s.%s%s from %s",
+ direction->name()->as_C_string(),
+ method_name->as_C_string(), sig->as_C_string(),
+ current_class->name()->as_C_string());
+ }
+#endif // ndef PRODUCT
+
+ if (!direction->is_interface()) {
+ // We should not be here
+ return NULL;
+ }
+
+ generic::DescriptorCache cache;
+ generic::Context ctx(&cache);
+
+ // Prime the initial generic context for current -> direction
+ ctx.apply_type_arguments(current_class, direction, CHECK_NULL);
+
+ FindMethodsByName visitor(&cache, method_name, &ctx, CHECK_NULL);
+ visitor.run(direction);
+
+ GrowableArray families;
+ visitor.get_discovered_families(&families);
+
+#ifndef PRODUCT
+ if (TraceDefaultMethods) {
+ print_families(&families, sig);
+ }
+#endif // ndef PRODUCT
+
+ MethodFamily* selected_family = NULL;
+
+ for (int i = 0; i < families.length(); ++i) {
+ MethodFamily* lm = families.at(i);
+ if (lm->contains_signature(sig)) {
+ lm->determine_target(current_class, CHECK_NULL);
+ selected_family = lm;
+ }
+ }
+
+ if (selected_family->has_target()) {
+ Method* target = selected_family->get_selected_target();
+ InstanceKlass* holder = InstanceKlass::cast(target->method_holder());
+
+ // Verify that the identified method is valid from the context of
+ // the current class
+ ShadowChecker checker(&cache, THREAD, target->name(),
+ holder, selected_family->descriptor(), direction);
+ checker.run(current_class);
+
+ if (checker.found_shadow()) {
+#ifndef PRODUCT
+ if (TraceDefaultMethods) {
+ tty->print_cr(" Only candidate found was shadowed.");
+ }
+#endif // ndef PRODUCT
+ THROW_MSG_(vmSymbols::java_lang_AbstractMethodError(),
+ "Accessible default method not found", NULL);
+ } else {
+#ifndef PRODUCT
+ if (TraceDefaultMethods) {
+ tty->print(" Returning ");
+ print_method(tty, target, true);
+ tty->print_cr("");
+ }
+#endif // ndef PRODUCT
+ return target;
+ }
+ } else {
+ assert(selected_family->throws_exception(), "must have target or throw");
+ THROW_MSG_(vmSymbols::java_lang_AbstractMethodError(),
+ selected_family->get_exception_message()->as_C_string(), NULL);
+ }
+}
+
+
+static int assemble_redirect(
+ BytecodeConstantPool* cp, BytecodeBuffer* buffer,
+ Symbol* incoming, Method* target, TRAPS) {
+
+ BytecodeAssembler assem(buffer, cp);
+
+ SignatureStream in(incoming, true);
+ SignatureStream out(target->signature(), true);
+ u2 parameter_count = 0;
+
+ assem.aload(parameter_count++); // load 'this'
+
+ while (!in.at_return_type()) {
+ assert(!out.at_return_type(), "Parameter counts do not match");
+ BasicType bt = in.type();
+ assert(out.type() == bt, "Parameter types are not compatible");
+ assem.load(bt, parameter_count);
+ if (in.is_object() && in.as_symbol(THREAD) != out.as_symbol(THREAD)) {
+ assem.checkcast(out.as_symbol(THREAD));
+ } else if (bt == T_LONG || bt == T_DOUBLE) {
+ ++parameter_count; // longs and doubles use two slots
+ }
+ ++parameter_count;
+ in.next();
+ out.next();
+ }
+ assert(out.at_return_type(), "Parameter counts do not match");
+ assert(in.type() == out.type(), "Return types are not compatible");
+
+ if (parameter_count == 1 && (in.type() == T_LONG || in.type() == T_DOUBLE)) {
+ ++parameter_count; // need room for return value
+ }
+ if (target->method_holder()->is_interface()) {
+ assem.invokespecial(target);
+ } else {
+ assem.invokevirtual(target);
+ }
+
+ if (in.is_object() && in.as_symbol(THREAD) != out.as_symbol(THREAD)) {
+ assem.checkcast(in.as_symbol(THREAD));
+ }
+ assem._return(in.type());
+ return parameter_count;
+}
+
+static int assemble_abstract_method_error(
+ BytecodeConstantPool* cp, BytecodeBuffer* buffer, Symbol* message, TRAPS) {
+
+ Symbol* errorName = vmSymbols::java_lang_AbstractMethodError();
+ Symbol* init = vmSymbols::object_initializer_name();
+ Symbol* sig = vmSymbols::string_void_signature();
+
+ BytecodeAssembler assem(buffer, cp);
+
+ assem._new(errorName);
+ assem.dup();
+ assem.load_string(message);
+ assem.invokespecial(errorName, init, sig);
+ assem.athrow();
+
+ return 3; // max stack size: [ exception, exception, string ]
+}
+
+static Method* new_method(
+ BytecodeConstantPool* cp, BytecodeBuffer* bytecodes, Symbol* name,
+ Symbol* sig, AccessFlags flags, int max_stack, int params,
+ ConstMethod::MethodType mt, TRAPS) {
+
+ address code_start = static_cast(bytecodes->adr_at(0));
+ int code_length = bytecodes->length();
+
+ Method* m = Method::allocate(cp->pool_holder()->class_loader_data(),
+ code_length, flags, 0, 0, 0, 0, 0, 0,
+ mt, CHECK_NULL);
+
+ m->set_constants(NULL); // This will get filled in later
+ m->set_name_index(cp->utf8(name));
+ m->set_signature_index(cp->utf8(sig));
+#ifdef CC_INTERP
+ ResultTypeFinder rtf(sig);
+ m->set_result_index(rtf.type());
+#endif
+ m->set_size_of_parameters(params);
+ m->set_max_stack(max_stack);
+ m->set_max_locals(params);
+ m->constMethod()->set_stackmap_data(NULL);
+ m->set_code(code_start);
+ m->set_force_inline(true);
+
+ return m;
+}
+
+static void switchover_constant_pool(BytecodeConstantPool* bpool,
+ InstanceKlass* klass, GrowableArray* new_methods, TRAPS) {
+
+ if (new_methods->length() > 0) {
+ ConstantPool* cp = bpool->create_constant_pool(CHECK);
+ if (cp != klass->constants()) {
+ klass->class_loader_data()->add_to_deallocate_list(klass->constants());
+ klass->set_constants(cp);
+ cp->set_pool_holder(klass);
+
+ for (int i = 0; i < new_methods->length(); ++i) {
+ new_methods->at(i)->set_constants(cp);
+ }
+ for (int i = 0; i < klass->methods()->length(); ++i) {
+ Method* mo = klass->methods()->at(i);
+ mo->set_constants(cp);
+ }
+ }
+ }
+}
+
+// A "bridge" is a method created by javac to bridge the gap between
+// an implementation and a generically-compatible, but different, signature.
+// Bridges have actual bytecode implementation in classfiles.
+// An "overpass", on the other hand, performs the same function as a bridge
+// but does not occur in a classfile; the VM creates overpass itself,
+// when it needs a path to get from a call site to an default method, and
+// a bridge doesn't exist.
+static void create_overpasses(
+ GrowableArray* slots,
+ InstanceKlass* klass, TRAPS) {
+
+ GrowableArray overpasses;
+ BytecodeConstantPool bpool(klass->constants());
+
+ for (int i = 0; i < slots->length(); ++i) {
+ EmptyVtableSlot* slot = slots->at(i);
+
+ if (slot->is_bound()) {
+ MethodFamily* method = slot->get_binding();
+ int max_stack = 0;
+ BytecodeBuffer buffer;
+
+#ifndef PRODUCT
+ if (TraceDefaultMethods) {
+ tty->print("for slot: ");
+ slot->print_on(tty);
+ tty->print_cr("");
+ if (method->has_target()) {
+ method->print_selected(tty, 1);
+ } else {
+ method->print_exception(tty, 1);
+ }
+ }
+#endif // ndef PRODUCT
+ if (method->has_target()) {
+ Method* selected = method->get_selected_target();
+ max_stack = assemble_redirect(
+ &bpool, &buffer, slot->signature(), selected, CHECK);
+ } else if (method->throws_exception()) {
+ max_stack = assemble_abstract_method_error(
+ &bpool, &buffer, method->get_exception_message(), CHECK);
+ }
+ AccessFlags flags = accessFlags_from(
+ JVM_ACC_PUBLIC | JVM_ACC_SYNTHETIC | JVM_ACC_BRIDGE);
+ Method* m = new_method(&bpool, &buffer, slot->name(), slot->signature(),
+ flags, max_stack, slot->size_of_parameters(),
+ ConstMethod::OVERPASS, CHECK);
+ if (m != NULL) {
+ overpasses.push(m);
+ }
+ }
+ }
+
+#ifndef PRODUCT
+ if (TraceDefaultMethods) {
+ tty->print_cr("Created %d overpass methods", overpasses.length());
+ }
+#endif // ndef PRODUCT
+
+ switchover_constant_pool(&bpool, klass, &overpasses, CHECK);
+ merge_in_new_methods(klass, &overpasses, CHECK);
+}
+
+static void sort_methods(GrowableArray* methods) {
+ // Note that this must sort using the same key as is used for sorting
+ // methods in InstanceKlass.
+ bool sorted = true;
+ for (int i = methods->length() - 1; i > 0; --i) {
+ for (int j = 0; j < i; ++j) {
+ Method* m1 = methods->at(j);
+ Method* m2 = methods->at(j + 1);
+ if ((uintptr_t)m1->name() > (uintptr_t)m2->name()) {
+ methods->at_put(j, m2);
+ methods->at_put(j + 1, m1);
+ sorted = false;
+ }
+ }
+ if (sorted) break;
+ sorted = true;
+ }
+#ifdef ASSERT
+ uintptr_t prev = 0;
+ for (int i = 0; i < methods->length(); ++i) {
+ Method* mh = methods->at(i);
+ uintptr_t nv = (uintptr_t)mh->name();
+ assert(nv >= prev, "Incorrect overpass method ordering");
+ prev = nv;
+ }
+#endif
+}
+
+static void merge_in_new_methods(InstanceKlass* klass,
+ GrowableArray* new_methods, TRAPS) {
+
+ enum { ANNOTATIONS, PARAMETERS, DEFAULTS, NUM_ARRAYS };
+
+ Array* original_annots[NUM_ARRAYS] = { NULL };
+
+ Array* original_methods = klass->methods();
+ Annotations* annots = klass->annotations();
+ if (annots != NULL) {
+ original_annots[ANNOTATIONS] = annots->methods_annotations();
+ original_annots[PARAMETERS] = annots->methods_parameter_annotations();
+ original_annots[DEFAULTS] = annots->methods_default_annotations();
+ }
+
+ Array* original_ordering = klass->method_ordering();
+ Array* merged_ordering = Universe::the_empty_int_array();
+
+ int new_size = klass->methods()->length() + new_methods->length();
+
+ Array* merged_annots[NUM_ARRAYS];
+
+ Array