Merge
This commit is contained in:
commit
4bdc9c4528
1
.hgtags
1
.hgtags
@ -166,3 +166,4 @@ c029c972396cea042a0dc67c0f7ccf2fe68007d4 jdk8-b41
|
||||
5c5a64ec0839df5affe9394b99ff338c363acbca jdk8-b42
|
||||
69d8a827cdf9236be9694a46d75c710d71dac7d7 jdk8-b43
|
||||
7e981cb0ad6a194f1fa859f9ad47586db461f269 jdk8-b44
|
||||
9b19b2302c28f4da6d4078f66234abecfed5688a jdk8-b45
|
||||
|
@ -166,3 +166,4 @@ a2b2d435f1d275fa8010774c653197c64e326d3a jdk8-b40
|
||||
1ce5dc16416611c58b7480ca67a2eee5153498a6 jdk8-b42
|
||||
661c9aae602bbd9766d12590800c90f1edd1d8dd jdk8-b43
|
||||
e4f81a817447c3a4f6868f083c81c2fb1b15d44c jdk8-b44
|
||||
633f2378c904c92bb922a6e19e9f62fe8eac14af jdk8-b45
|
||||
|
@ -166,3 +166,4 @@ b8cbfb31139f820e5e094ba71449e58159fbe22e jdk8-b38
|
||||
79cc42c9c71bbd6630ede681642e98f5e4a841fa jdk8-b42
|
||||
cd879aff5d3cc1f58829aab3116880aa19525b78 jdk8-b43
|
||||
439d9bf8e4ff204cc89c9974c1515a508b2cc6ff jdk8-b44
|
||||
747dad9e9d37d244a5c765a1afe9194f7ddae118 jdk8-b45
|
||||
|
@ -256,3 +256,5 @@ bd568544be7fcd12a9327e6c448592198d57b043 hs24-b13
|
||||
e77b8e0ed1f84e3e268239e276c7ab64fa573baa jdk8-b43
|
||||
5ba29a1db46ecb80a321ca873adb56a3fe6ad320 hs24-b14
|
||||
831e5c76a20af18f3c08c5a95ed31be0e128a010 jdk8-b44
|
||||
9d5f20961bc5846fa8d098d534effafbbdae0a58 jdk8-b45
|
||||
40e5a3f2907ed02b335c7caa8ecf068cc801380d hs24-b15
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 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
|
||||
@ -657,7 +657,7 @@ public class BugSpot extends JPanel {
|
||||
while (fr != null) {
|
||||
trace.add(new StackTraceEntry(fr, getCDebugger()));
|
||||
try {
|
||||
fr = fr.sender();
|
||||
fr = fr.sender(t);
|
||||
} catch (AddressException e) {
|
||||
e.printStackTrace();
|
||||
showMessageDialog("Error while walking stack; stack trace will be truncated\n(see console for details)",
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 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
|
||||
@ -25,6 +25,7 @@
|
||||
package sun.jvm.hotspot.debugger.bsd.amd64;
|
||||
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.debugger.amd64.*;
|
||||
import sun.jvm.hotspot.debugger.bsd.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.basic.*;
|
||||
@ -51,8 +52,11 @@ final public class BsdAMD64CFrame extends BasicCFrame {
|
||||
return rbp;
|
||||
}
|
||||
|
||||
public CFrame sender() {
|
||||
if (rbp == null) {
|
||||
public CFrame sender(ThreadProxy thread) {
|
||||
AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext();
|
||||
Address rsp = context.getRegisterAsAddress(AMD64ThreadContext.RSP);
|
||||
|
||||
if ( (rbp == null) || rbp.lessThan(rsp) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 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
|
||||
@ -28,6 +28,7 @@ import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.debugger.bsd.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.basic.*;
|
||||
import sun.jvm.hotspot.debugger.x86.*;
|
||||
|
||||
final public class BsdX86CFrame extends BasicCFrame {
|
||||
// package/class internals only
|
||||
@ -52,8 +53,11 @@ final public class BsdX86CFrame extends BasicCFrame {
|
||||
return ebp;
|
||||
}
|
||||
|
||||
public CFrame sender() {
|
||||
if (ebp == null) {
|
||||
public CFrame sender(ThreadProxy thread) {
|
||||
X86ThreadContext context = (X86ThreadContext) thread.getContext();
|
||||
Address esp = context.getRegisterAsAddress(X86ThreadContext.ESP);
|
||||
|
||||
if ( (ebp == null) || ebp.lessThan(esp) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 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
|
||||
@ -34,7 +34,7 @@ import sun.jvm.hotspot.debugger.*;
|
||||
|
||||
public interface CFrame {
|
||||
/** Returns null when no more frames on stack */
|
||||
public CFrame sender();
|
||||
public CFrame sender(ThreadProxy th);
|
||||
|
||||
/** Get the program counter of this frame */
|
||||
public Address pc();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 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
|
||||
@ -25,6 +25,7 @@
|
||||
package sun.jvm.hotspot.debugger.cdbg.basic.amd64;
|
||||
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.debugger.amd64.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.basic.*;
|
||||
|
||||
@ -43,8 +44,11 @@ public class AMD64CFrame extends BasicCFrame {
|
||||
this.pc = pc;
|
||||
}
|
||||
|
||||
public CFrame sender() {
|
||||
if (rbp == null) {
|
||||
public CFrame sender(ThreadProxy thread) {
|
||||
AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext();
|
||||
Address rsp = context.getRegisterAsAddress(AMD64ThreadContext.RSP);
|
||||
|
||||
if ( (rbp == null) || rbp.lessThan(rsp) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 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
|
||||
@ -25,6 +25,7 @@
|
||||
package sun.jvm.hotspot.debugger.cdbg.basic.x86;
|
||||
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.debugger.x86.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.basic.*;
|
||||
|
||||
@ -43,8 +44,11 @@ public class X86CFrame extends BasicCFrame {
|
||||
this.pc = pc;
|
||||
}
|
||||
|
||||
public CFrame sender() {
|
||||
if (ebp == null) {
|
||||
public CFrame sender(ThreadProxy thread) {
|
||||
X86ThreadContext context = (X86ThreadContext) thread.getContext();
|
||||
Address esp = context.getRegisterAsAddress(X86ThreadContext.ESP);
|
||||
|
||||
if ( (ebp == null) || ebp.lessThan(esp) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 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
|
||||
@ -25,6 +25,7 @@
|
||||
package sun.jvm.hotspot.debugger.linux.amd64;
|
||||
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.debugger.amd64.*;
|
||||
import sun.jvm.hotspot.debugger.linux.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.basic.*;
|
||||
@ -51,8 +52,11 @@ final public class LinuxAMD64CFrame extends BasicCFrame {
|
||||
return rbp;
|
||||
}
|
||||
|
||||
public CFrame sender() {
|
||||
if (rbp == null) {
|
||||
public CFrame sender(ThreadProxy thread) {
|
||||
AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext();
|
||||
Address rsp = context.getRegisterAsAddress(AMD64ThreadContext.RSP);
|
||||
|
||||
if ( (rbp == null) || rbp.lessThan(rsp) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 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
|
||||
@ -57,7 +57,7 @@ final public class LinuxSPARCCFrame extends BasicCFrame {
|
||||
return sp;
|
||||
}
|
||||
|
||||
public CFrame sender() {
|
||||
public CFrame sender(ThreadProxy thread) {
|
||||
if (sp == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 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
|
||||
@ -28,6 +28,7 @@ import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.debugger.linux.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.basic.*;
|
||||
import sun.jvm.hotspot.debugger.x86.*;
|
||||
|
||||
final public class LinuxX86CFrame extends BasicCFrame {
|
||||
// package/class internals only
|
||||
@ -52,8 +53,11 @@ final public class LinuxX86CFrame extends BasicCFrame {
|
||||
return ebp;
|
||||
}
|
||||
|
||||
public CFrame sender() {
|
||||
if (ebp == null) {
|
||||
public CFrame sender(ThreadProxy thread) {
|
||||
X86ThreadContext context = (X86ThreadContext) thread.getContext();
|
||||
Address esp = context.getRegisterAsAddress(X86ThreadContext.ESP);
|
||||
|
||||
if ( (ebp == null) || ebp.lessThan(esp) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 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
|
||||
@ -37,7 +37,7 @@ final class ProcCFrame extends BasicCFrame {
|
||||
return fp;
|
||||
}
|
||||
|
||||
public CFrame sender() {
|
||||
public CFrame sender(ThreadProxy t) {
|
||||
return sender;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 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
|
||||
@ -141,18 +141,19 @@ public class OopUtilities implements /* imports */ JVMTIThreadState {
|
||||
public static String stringOopToString(Oop stringOop) {
|
||||
if (offsetField == null) {
|
||||
InstanceKlass k = (InstanceKlass) stringOop.getKlass();
|
||||
offsetField = (IntField) k.findField("offset", "I");
|
||||
countField = (IntField) k.findField("count", "I");
|
||||
offsetField = (IntField) k.findField("offset", "I"); // optional
|
||||
countField = (IntField) k.findField("count", "I"); // optional
|
||||
valueField = (OopField) k.findField("value", "[C");
|
||||
if (Assert.ASSERTS_ENABLED) {
|
||||
Assert.that(offsetField != null &&
|
||||
countField != null &&
|
||||
valueField != null, "must find all java.lang.String fields");
|
||||
Assert.that(valueField != null, "Field \'value\' of java.lang.String not found");
|
||||
}
|
||||
}
|
||||
return charArrayToString((TypeArray) valueField.getValue(stringOop),
|
||||
offsetField.getValue(stringOop),
|
||||
countField.getValue(stringOop));
|
||||
if (offsetField != null && countField != null) {
|
||||
return charArrayToString((TypeArray) valueField.getValue(stringOop),
|
||||
offsetField.getValue(stringOop),
|
||||
countField.getValue(stringOop));
|
||||
}
|
||||
return charArrayToString((TypeArray) valueField.getValue(stringOop));
|
||||
}
|
||||
|
||||
public static String stringOopToEscapedString(Oop stringOop) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2006, 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
|
||||
@ -158,7 +158,7 @@ public class PStack extends Tool {
|
||||
printUnknown(out);
|
||||
}
|
||||
}
|
||||
f = f.sender();
|
||||
f = f.sender(th);
|
||||
}
|
||||
} catch (Exception exp) {
|
||||
exp.printStackTrace();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -85,6 +85,21 @@ public class ObjectReader {
|
||||
this(new ProcImageClassLoader());
|
||||
}
|
||||
|
||||
static void debugPrintln(String msg) {
|
||||
if (DEBUG) {
|
||||
System.err.println("DEBUG>" + msg);
|
||||
}
|
||||
}
|
||||
|
||||
static void debugPrintStackTrace(Exception exp) {
|
||||
if (DEBUG) {
|
||||
StackTraceElement[] els = exp.getStackTrace();
|
||||
for (int i = 0; i < els.length; i++) {
|
||||
System.err.println("DEBUG>" + els[i].toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Object readObject(Oop oop) throws ClassNotFoundException {
|
||||
if (oop instanceof Instance) {
|
||||
return readInstance((Instance) oop);
|
||||
@ -120,13 +135,96 @@ public class ObjectReader {
|
||||
}
|
||||
|
||||
protected Symbol javaLangString;
|
||||
protected Symbol javaUtilHashtableEntry;
|
||||
protected Symbol javaUtilHashtable;
|
||||
protected Symbol javaUtilProperties;
|
||||
|
||||
protected Symbol getVMSymbol(String name) {
|
||||
return VM.getVM().getSymbolTable().probe(name);
|
||||
}
|
||||
|
||||
protected Symbol javaLangString() {
|
||||
if (javaLangString == null) {
|
||||
javaLangString = VM.getVM().getSymbolTable().probe("java/lang/String");
|
||||
javaLangString = getVMSymbol("java/lang/String");
|
||||
}
|
||||
return javaLangString;
|
||||
}
|
||||
|
||||
protected Symbol javaUtilHashtableEntry() {
|
||||
if (javaUtilHashtableEntry == null) {
|
||||
javaUtilHashtableEntry = getVMSymbol("java/util/Hashtable$Entry");
|
||||
}
|
||||
return javaUtilHashtableEntry;
|
||||
}
|
||||
|
||||
protected Symbol javaUtilHashtable() {
|
||||
if (javaUtilHashtable == null) {
|
||||
javaUtilHashtable = getVMSymbol("java/util/Hashtable");
|
||||
}
|
||||
return javaUtilHashtable;
|
||||
}
|
||||
|
||||
protected Symbol javaUtilProperties() {
|
||||
if (javaUtilProperties == null) {
|
||||
javaUtilProperties = getVMSymbol("java/util/Properties");
|
||||
}
|
||||
return javaUtilProperties;
|
||||
}
|
||||
|
||||
private void setHashtableEntry(java.util.Hashtable p, Oop oop) {
|
||||
InstanceKlass ik = (InstanceKlass)oop.getKlass();
|
||||
OopField keyField = (OopField)ik.findField("key", "Ljava/lang/Object;");
|
||||
OopField valueField = (OopField)ik.findField("value", "Ljava/lang/Object;");
|
||||
OopField nextField = (OopField)ik.findField("next", "Ljava/util/Hashtable$Entry;");
|
||||
if (DEBUG) {
|
||||
if (Assert.ASSERTS_ENABLED) {
|
||||
Assert.that(ik.getName().equals(javaUtilHashtableEntry()), "Not a Hashtable$Entry?");
|
||||
Assert.that(keyField != null && valueField != null && nextField != null, "Invalid fields!");
|
||||
}
|
||||
}
|
||||
|
||||
Object key = null;
|
||||
Object value = null;
|
||||
Oop next = null;
|
||||
try {
|
||||
key = readObject(keyField.getValue(oop));
|
||||
value = readObject(valueField.getValue(oop));
|
||||
next = (Oop)nextField.getValue(oop);
|
||||
// For Properties, should use setProperty(k, v). Since it only runs in SA
|
||||
// using put(k, v) should be OK.
|
||||
p.put(key, value);
|
||||
if (next != null) {
|
||||
setHashtableEntry(p, next);
|
||||
}
|
||||
} catch (ClassNotFoundException ce) {
|
||||
if( DEBUG) {
|
||||
debugPrintln("Class not found " + ce);
|
||||
debugPrintStackTrace(ce);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Object getHashtable(Instance oop, boolean isProperties) {
|
||||
InstanceKlass k = (InstanceKlass)oop.getKlass();
|
||||
OopField tableField = (OopField)k.findField("table", "[Ljava/util/Hashtable$Entry;");
|
||||
if (tableField == null) {
|
||||
debugPrintln("Could not find field of [Ljava/util/Hashtable$Entry;");
|
||||
return null;
|
||||
}
|
||||
java.util.Hashtable table = (isProperties) ? new java.util.Properties()
|
||||
: new java.util.Hashtable();
|
||||
ObjArray kvs = (ObjArray)tableField.getValue(oop);
|
||||
long size = kvs.getLength();
|
||||
debugPrintln("Hashtable$Entry Size = " + size);
|
||||
for (long i=0; i<size; i++) {
|
||||
Oop entry = kvs.getObjAt(i);
|
||||
if (entry != null && entry.isInstance()) {
|
||||
setHashtableEntry(table, entry);
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
public Object readInstance(Instance oop) throws ClassNotFoundException {
|
||||
Object result = getFromObjTable(oop);
|
||||
if (result == null) {
|
||||
@ -134,11 +232,21 @@ public class ObjectReader {
|
||||
// Handle java.lang.String instances differently. As part of JSR-133, fields of immutable
|
||||
// classes have been made final. The algorithm below will not be able to read Strings from
|
||||
// debuggee (can't use reflection to set final fields). But, need to read Strings is very
|
||||
// important. FIXME: need a framework to handle many other special cases.
|
||||
// important.
|
||||
// Same for Hashtable, key and hash are final, could not be set in the algorithm too.
|
||||
// FIXME: need a framework to handle many other special cases.
|
||||
if (kls.getName().equals(javaLangString())) {
|
||||
return OopUtilities.stringOopToString(oop);
|
||||
}
|
||||
|
||||
if (kls.getName().equals(javaUtilHashtable())) {
|
||||
return getHashtable(oop, false);
|
||||
}
|
||||
|
||||
if (kls.getName().equals(javaUtilProperties())) {
|
||||
return getHashtable(oop, true);
|
||||
}
|
||||
|
||||
Class clz = readClass(kls);
|
||||
try {
|
||||
result = clz.newInstance();
|
||||
@ -164,8 +272,8 @@ public class ObjectReader {
|
||||
break;
|
||||
} catch (Exception exp) {
|
||||
if (DEBUG) {
|
||||
System.err.println("Can't create object using " + c);
|
||||
exp.printStackTrace();
|
||||
debugPrintln("Can't create object using " + c);
|
||||
debugPrintStackTrace(exp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -329,8 +437,8 @@ public class ObjectReader {
|
||||
arrayObj[ifd.getIndex()] = readObject(field.getValue(getObj()));
|
||||
} catch (Exception e) {
|
||||
if (DEBUG) {
|
||||
System.err.println("Array element set failed for " + ifd);
|
||||
e.printStackTrace();
|
||||
debugPrintln("Array element set failed for " + ifd);
|
||||
debugPrintStackTrace(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -348,8 +456,8 @@ public class ObjectReader {
|
||||
|
||||
private void printFieldSetError(java.lang.reflect.Field f, Exception ex) {
|
||||
if (DEBUG) {
|
||||
if (f != null) System.err.println("Field set failed for " + f);
|
||||
ex.printStackTrace();
|
||||
if (f != null) debugPrintln("Field set failed for " + f);
|
||||
debugPrintStackTrace(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -601,7 +709,7 @@ public class ObjectReader {
|
||||
return Class.forName(className, true, cl);
|
||||
} catch (Exception e) {
|
||||
if (DEBUG) {
|
||||
System.err.println("Can't load class " + className);
|
||||
debugPrintln("Can't load class " + className);
|
||||
}
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
@ -110,4 +110,5 @@ copy_debug_jdk::
|
||||
|
||||
.PHONY: universal_product universal_fastdebug universal_debug \
|
||||
all_product_universal all_fastdebug_universal all_debug_universal \
|
||||
universalize export_universal copy_universal
|
||||
universalize export_universal copy_universal \
|
||||
$(UNIVERSAL_LIPO_LIST) $(UNIVERSAL_COPY_LIST)
|
||||
|
@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2012
|
||||
|
||||
HS_MAJOR_VER=24
|
||||
HS_MINOR_VER=0
|
||||
HS_BUILD_NUMBER=14
|
||||
HS_BUILD_NUMBER=15
|
||||
|
||||
JDK_MAJOR_VER=1
|
||||
JDK_MINOR_VER=8
|
||||
|
@ -102,6 +102,11 @@ jprt.my.linux.armvfp.jdk7=linux_armvfp_2.6
|
||||
jprt.my.linux.armvfp.jdk7u6=${jprt.my.linux.armvfp.jdk7}
|
||||
jprt.my.linux.armvfp=${jprt.my.linux.armvfp.${jprt.tools.default.release}}
|
||||
|
||||
jprt.my.linux.armv6.jdk8=linux_armv6_2.6
|
||||
jprt.my.linux.armv6.jdk7=linux_armv6_2.6
|
||||
jprt.my.linux.armv6.jdk7u6=${jprt.my.linux.armv6.jdk7}
|
||||
jprt.my.linux.armv6=${jprt.my.linux.armv6.${jprt.tools.default.release}}
|
||||
|
||||
jprt.my.linux.armsflt.jdk8=linux_armsflt_2.6
|
||||
jprt.my.linux.armsflt.jdk7=linux_armsflt_2.6
|
||||
jprt.my.linux.armsflt.jdk7u6=${jprt.my.linux.armsflt.jdk7}
|
||||
@ -134,7 +139,7 @@ jprt.build.targets.standard= \
|
||||
${jprt.my.macosx.x64}-{product|fastdebug|debug}, \
|
||||
${jprt.my.windows.i586}-{product|fastdebug|debug}, \
|
||||
${jprt.my.windows.x64}-{product|fastdebug|debug}, \
|
||||
${jprt.my.linux.armvfp}-{product|fastdebug}
|
||||
${jprt.my.linux.armv6}-{product|fastdebug}
|
||||
|
||||
jprt.build.targets.open= \
|
||||
${jprt.my.solaris.i586}-{productOpen}, \
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2006, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2006, 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
|
||||
@ -30,6 +30,13 @@ include $(GAMMADIR)/make/scm.make
|
||||
|
||||
ifneq ($(OSNAME), windows)
|
||||
ifndef LP64
|
||||
PARTIAL_NONPIC=1
|
||||
endif
|
||||
PIC_ARCH = ppc
|
||||
ifneq ("$(filter $(PIC_ARCH),$(BUILDARCH))","")
|
||||
PARTIAL_NONPIC=0
|
||||
endif
|
||||
ifeq ($(PARTIAL_NONPIC),1)
|
||||
NONPIC_DIRS = memory oops gc_implementation gc_interface
|
||||
NONPIC_DIRS := $(foreach dir,$(NONPIC_DIRS), $(GAMMADIR)/src/share/vm/$(dir))
|
||||
# Look for source files under NONPIC_DIRS
|
||||
|
@ -24,8 +24,11 @@
|
||||
|
||||
# Rules to build add_gnu_debuglink, used by vm.make on Solaris
|
||||
|
||||
GENERATED = ../generated
|
||||
ADD_GNU_DEBUGLINK = $(GENERATED)/add_gnu_debuglink
|
||||
# Allow $(ADD_GNU_DEBUGLINK) to be called from any directory.
|
||||
# We don't set or use the GENERATED macro to avoid affecting
|
||||
# other HotSpot Makefiles.
|
||||
TOPDIR = $(shell echo `pwd`)
|
||||
ADD_GNU_DEBUGLINK = $(TOPDIR)/../generated/add_gnu_debuglink
|
||||
|
||||
ADD_GNU_DEBUGLINK_DIR = $(GAMMADIR)/src/os/solaris/add_gnu_debuglink
|
||||
ADD_GNU_DEBUGLINK_SRC = $(ADD_GNU_DEBUGLINK_DIR)/add_gnu_debuglink.c
|
||||
|
@ -203,10 +203,18 @@ ifeq ($(JVM_VARIANT_SERVER),true)
|
||||
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm.diz
|
||||
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm_db.diz
|
||||
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm_dtrace.diz
|
||||
ifeq ($(ARCH_DATA_MODEL),32)
|
||||
EXPORT_LIST += $(EXPORT_SERVER_DIR)/64/libjvm_db.diz
|
||||
EXPORT_LIST += $(EXPORT_SERVER_DIR)/64/libjvm_dtrace.diz
|
||||
endif
|
||||
else
|
||||
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm.debuginfo
|
||||
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm_db.debuginfo
|
||||
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm_dtrace.debuginfo
|
||||
ifeq ($(ARCH_DATA_MODEL),32)
|
||||
EXPORT_LIST += $(EXPORT_SERVER_DIR)/64/libjvm_db.debuginfo
|
||||
EXPORT_LIST += $(EXPORT_SERVER_DIR)/64/libjvm_dtrace.debuginfo
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
@ -94,23 +94,24 @@ ISA = $(subst i386,i486,$(shell isainfo -n))
|
||||
# Making 64/libjvm_db.so: 64-bit version of libjvm_db.so which handles 32-bit libjvm.so
|
||||
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)
|
||||
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 = 64/$(LIBJVM_DB_DEBUGINFO)
|
||||
XLIBJVM_DB_DIZ = 64/$(LIBJVM_DB_DIZ)
|
||||
XLIBJVM_DB_G_DEBUGINFO = 64/$(LIBJVM_DB_G_DEBUGINFO)
|
||||
XLIBJVM_DB_G_DIZ = 64/$(LIBJVM_DB_G_DIZ)
|
||||
XLIBJVM_DTRACE_DEBUGINFO = 64/$(LIBJVM_DTRACE_DEBUGINFO)
|
||||
XLIBJVM_DTRACE_DIZ = 64/$(LIBJVM_DTRACE_DIZ)
|
||||
XLIBJVM_DTRACE_G_DEBUGINFO = 64/$(LIBJVM_DTRACE_G_DEBUGINFO)
|
||||
XLIBJVM_DTRACE_G_DIZ = 64/$(LIBJVM_DTRACE_G_DIZ)
|
||||
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 64/ ; \
|
||||
$(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); }
|
||||
@ -124,8 +125,10 @@ ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
|
||||
$(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(XLIBJVM_DB_DEBUGINFO)
|
||||
# $(OBJCOPY) --add-gnu-debuglink=... corrupts SUNW_* sections.
|
||||
# Use $(ADD_GNU_DEBUGLINK) until a fixed $(OBJCOPY) is available.
|
||||
# $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(XLIBJVM_DB_DEBUGINFO) $@
|
||||
$(QUIETLY) $(ADD_GNU_DEBUGLINK) $(XLIBJVM_DB_DEBUGINFO) $@
|
||||
# $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB) ;
|
||||
# Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) is not
|
||||
# in the link name:
|
||||
( cd $(XLIBJVM_DIR) && $(ADD_GNU_DEBUGLINK) $(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB) )
|
||||
ifeq ($(STRIP_POLICY),all_strip)
|
||||
$(QUIETLY) $(STRIP) $@
|
||||
else
|
||||
@ -134,17 +137,19 @@ ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
|
||||
# implied else here is no stripping at all
|
||||
endif
|
||||
endif
|
||||
[ -f $(XLIBJVM_DB_G_DEBUGINFO) ] || { ln -s $(XLIBJVM_DB_DEBUGINFO) $(XLIBJVM_DB_G_DEBUGINFO); }
|
||||
[ -f $(XLIBJVM_DB_G_DEBUGINFO) ] || { cd $(XLIBJVM_DIR) && ln -s $(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB_G_DEBUGINFO); }
|
||||
ifeq ($(ZIP_DEBUGINFO_FILES),1)
|
||||
$(ZIPEXE) -q -y $(XLIBJVM_DB_DIZ) $(XLIBJVM_DB_DEBUGINFO) $(XLIBJVM_DB_G_DEBUGINFO)
|
||||
# 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) ] || { ln -s $(XLIBJVM_DB_DIZ) $(XLIBJVM_DB_G_DIZ); }
|
||||
[ -f $(XLIBJVM_DB_G_DIZ) ] || { cd $(XLIBJVM_DIR) && ln -s $(LIBJVM_DB_DIZ) $(LIBJVM_DB_G_DIZ); }
|
||||
endif
|
||||
endif
|
||||
|
||||
$(XLIBJVM_DTRACE): $(ADD_GNU_DEBUGLINK) $(FIX_EMPTY_SEC_HDR_FLAGS) $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE)
|
||||
@echo Making $@
|
||||
$(QUIETLY) mkdir -p 64/ ; \
|
||||
$(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); }
|
||||
@ -153,8 +158,10 @@ ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
|
||||
$(QUIETLY) $(FIX_EMPTY_SEC_HDR_FLAGS) $@
|
||||
$(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(XLIBJVM_DTRACE_DEBUGINFO)
|
||||
# $(OBJCOPY) --add-gnu-debuglink=... corrupts SUNW_* sections.
|
||||
# $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(XLIBJVM_DTRACE_DEBUGINFO) $@
|
||||
$(QUIETLY) $(ADD_GNU_DEBUGLINK) $(XLIBJVM_DTRACE_DEBUGINFO) $@
|
||||
# $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE) ;
|
||||
# Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) is not
|
||||
# in the link name:
|
||||
( cd $(XLIBJVM_DIR) && $(ADD_GNU_DEBUGLINK) $(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE) )
|
||||
ifeq ($(STRIP_POLICY),all_strip)
|
||||
$(QUIETLY) $(STRIP) $@
|
||||
else
|
||||
@ -163,11 +170,13 @@ ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
|
||||
# implied else here is no stripping at all
|
||||
endif
|
||||
endif
|
||||
[ -f $(XLIBJVM_DTRACE_G_DEBUGINFO) ] || { ln -s $(XLIBJVM_DTRACE_DEBUGINFO) $(XLIBJVM_DTRACE_G_DEBUGINFO); }
|
||||
[ -f $(XLIBJVM_DTRACE_G_DEBUGINFO) ] || { cd $(XLIBJVM_DIR) && ln -s $(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE_G_DEBUGINFO); }
|
||||
ifeq ($(ZIP_DEBUGINFO_FILES),1)
|
||||
$(ZIPEXE) -q -y $(XLIBJVM_DTRACE_DIZ) $(XLIBJVM_DTRACE_DEBUGINFO) $(XLIBJVM_DTRACE_G_DEBUGINFO)
|
||||
# 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) ] || { ln -s $(XLIBJVM_DTRACE_DIZ) $(XLIBJVM_DTRACE_G_DIZ); }
|
||||
[ -f $(XLIBJVM_DTRACE_G_DIZ) ] || { cd $(XLIBJVM_DIR) && ln -s $(LIBJVM_DTRACE_DIZ) $(LIBJVM_DTRACE_G_DIZ); }
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -24,8 +24,11 @@
|
||||
|
||||
# Rules to build fix_empty_sec_hdr_flags, used by vm.make on Solaris
|
||||
|
||||
GENERATED = ../generated
|
||||
FIX_EMPTY_SEC_HDR_FLAGS = $(GENERATED)/fix_empty_sec_hdr_flags
|
||||
# Allow $(FIX_EMPTY_SEC_HDR_FLAGS) to be called from any directory.
|
||||
# We don't set or use the GENERATED macro to avoid affecting
|
||||
# other HotSpot Makefiles.
|
||||
TOPDIR = $(shell echo `pwd`)
|
||||
FIX_EMPTY_SEC_HDR_FLAGS = $(TOPDIR)/../generated/fix_empty_sec_hdr_flags
|
||||
|
||||
FIX_EMPTY_SEC_HDR_FLAGS_DIR = $(GAMMADIR)/src/os/solaris/fix_empty_sec_hdr_flags
|
||||
FIX_EMPTY_SEC_HDR_FLAGS_SRC = $(FIX_EMPTY_SEC_HDR_FLAGS_DIR)/fix_empty_sec_hdr_flags.c
|
||||
|
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 1998, 2011, 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
|
||||
@ -678,18 +678,26 @@ intptr_t get_offset_from_base_2(const MachNode* n, const TypePtr* atype, int dis
|
||||
|
||||
static inline jdouble replicate_immI(int con, int count, int width) {
|
||||
// Load a constant replicated "count" times with width "width"
|
||||
assert(count*width == 8 && width <= 4, "sanity");
|
||||
int bit_width = width * 8;
|
||||
jlong elt_val = con;
|
||||
elt_val &= (((jlong) 1) << bit_width) - 1; // mask off sign bits
|
||||
jlong val = elt_val;
|
||||
jlong val = con;
|
||||
val &= (((jlong) 1) << bit_width) - 1; // mask off sign bits
|
||||
for (int i = 0; i < count - 1; i++) {
|
||||
val <<= bit_width;
|
||||
val |= elt_val;
|
||||
val |= (val << bit_width);
|
||||
}
|
||||
jdouble dval = *((jdouble*) &val); // coerce to double type
|
||||
return dval;
|
||||
}
|
||||
|
||||
static inline jdouble replicate_immF(float con) {
|
||||
// Replicate float con 2 times and pack into vector.
|
||||
int val = *((int*)&con);
|
||||
jlong lval = val;
|
||||
lval = (lval << 32) | (lval & 0xFFFFFFFFl);
|
||||
jdouble dval = *((jdouble*) &lval); // coerce to double type
|
||||
return dval;
|
||||
}
|
||||
|
||||
// Standard Sparc opcode form2 field breakdown
|
||||
static inline void emit2_19(CodeBuffer &cbuf, int f30, int f29, int f25, int f22, int f20, int f19, int f0 ) {
|
||||
f0 &= (1<<19)-1; // Mask displacement to 19 bits
|
||||
@ -791,6 +799,7 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, const MachNode* n, int primary, int te
|
||||
case Assembler::stdf_op3: st_op = Op_StoreD; break;
|
||||
|
||||
case Assembler::ldsb_op3: ld_op = Op_LoadB; break;
|
||||
case Assembler::ldub_op3: ld_op = Op_LoadUB; break;
|
||||
case Assembler::lduh_op3: ld_op = Op_LoadUS; break;
|
||||
case Assembler::ldsh_op3: ld_op = Op_LoadS; break;
|
||||
case Assembler::ldx_op3: // may become LoadP or stay LoadI
|
||||
@ -799,7 +808,6 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, const MachNode* n, int primary, int te
|
||||
case Assembler::ldd_op3: ld_op = Op_LoadL; break;
|
||||
case Assembler::ldf_op3: ld_op = Op_LoadF; break;
|
||||
case Assembler::lddf_op3: ld_op = Op_LoadD; break;
|
||||
case Assembler::ldub_op3: ld_op = Op_LoadB; break;
|
||||
case Assembler::prefetch_op3: ld_op = Op_LoadI; break;
|
||||
|
||||
default: ShouldNotReachHere();
|
||||
@ -840,10 +848,7 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, const MachNode* n, int primary, int te
|
||||
!(n->ideal_Opcode()==Op_PrefetchRead && ld_op==Op_LoadI) &&
|
||||
!(n->ideal_Opcode()==Op_PrefetchWrite && ld_op==Op_LoadI) &&
|
||||
!(n->ideal_Opcode()==Op_PrefetchAllocation && ld_op==Op_LoadI) &&
|
||||
!(n->ideal_Opcode()==Op_Load2I && ld_op==Op_LoadD) &&
|
||||
!(n->ideal_Opcode()==Op_Load4C && ld_op==Op_LoadD) &&
|
||||
!(n->ideal_Opcode()==Op_Load4S && ld_op==Op_LoadD) &&
|
||||
!(n->ideal_Opcode()==Op_Load8B && ld_op==Op_LoadD) &&
|
||||
!(n->ideal_Opcode()==Op_LoadVector && ld_op==Op_LoadD) &&
|
||||
!(n->rule() == loadUB_rule)) {
|
||||
verify_oops_warning(n, n->ideal_Opcode(), ld_op);
|
||||
}
|
||||
@ -855,9 +860,7 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, const MachNode* n, int primary, int te
|
||||
!(n->ideal_Opcode()==Op_StoreI && st_op==Op_StoreF) &&
|
||||
!(n->ideal_Opcode()==Op_StoreF && st_op==Op_StoreI) &&
|
||||
!(n->ideal_Opcode()==Op_StoreL && st_op==Op_StoreI) &&
|
||||
!(n->ideal_Opcode()==Op_Store2I && st_op==Op_StoreD) &&
|
||||
!(n->ideal_Opcode()==Op_Store4C && st_op==Op_StoreD) &&
|
||||
!(n->ideal_Opcode()==Op_Store8B && st_op==Op_StoreD) &&
|
||||
!(n->ideal_Opcode()==Op_StoreVector && st_op==Op_StoreD) &&
|
||||
!(n->ideal_Opcode()==Op_StoreD && st_op==Op_StoreI && n->rule() == storeD0_rule)) {
|
||||
verify_oops_warning(n, n->ideal_Opcode(), st_op);
|
||||
}
|
||||
@ -1849,16 +1852,45 @@ int Matcher::regnum_to_fpu_offset(int regnum) {
|
||||
address last_rethrow = NULL; // debugging aid for Rethrow encoding
|
||||
#endif
|
||||
|
||||
// Map Types to machine register types
|
||||
const int Matcher::base2reg[Type::lastype] = {
|
||||
Node::NotAMachineReg,0,0, Op_RegI, Op_RegL, 0, Op_RegN,
|
||||
Node::NotAMachineReg, Node::NotAMachineReg, /* tuple, array */
|
||||
0, Op_RegD, 0, 0, /* Vectors */
|
||||
Op_RegP, Op_RegP, Op_RegP, Op_RegP, Op_RegP, Op_RegP, /* the pointers */
|
||||
0, 0/*abio*/,
|
||||
Op_RegP /* Return address */, 0, /* the memories */
|
||||
Op_RegF, Op_RegF, Op_RegF, Op_RegD, Op_RegD, Op_RegD,
|
||||
0 /*bottom*/
|
||||
};
|
||||
|
||||
// Vector width in bytes
|
||||
const uint Matcher::vector_width_in_bytes(void) {
|
||||
const int Matcher::vector_width_in_bytes(BasicType bt) {
|
||||
assert(MaxVectorSize == 8, "");
|
||||
return 8;
|
||||
}
|
||||
|
||||
// Vector ideal reg
|
||||
const uint Matcher::vector_ideal_reg(void) {
|
||||
const int Matcher::vector_ideal_reg(int size) {
|
||||
assert(MaxVectorSize == 8, "");
|
||||
return Op_RegD;
|
||||
}
|
||||
|
||||
// Limits on vector size (number of elements) loaded into vector.
|
||||
const int Matcher::max_vector_size(const BasicType bt) {
|
||||
assert(is_java_primitive(bt), "only primitive type vectors");
|
||||
return vector_width_in_bytes(bt)/type2aelembytes(bt);
|
||||
}
|
||||
|
||||
const int Matcher::min_vector_size(const BasicType bt) {
|
||||
return max_vector_size(bt); // Same as max.
|
||||
}
|
||||
|
||||
// SPARC doesn't support misaligned vectors store/load.
|
||||
const bool Matcher::misaligned_vectors_ok() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// USII supports fxtof through the whole range of number, USIII doesn't
|
||||
const bool Matcher::convL2FSupported(void) {
|
||||
return VM_Version::has_fast_fxtof();
|
||||
@ -3125,50 +3157,6 @@ enc_class enc_Array_Equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, notemp_iRegI r
|
||||
__ membar( Assembler::Membar_mask_bits(Assembler::StoreLoad) );
|
||||
%}
|
||||
|
||||
enc_class enc_repl8b( iRegI src, iRegL dst ) %{
|
||||
MacroAssembler _masm(&cbuf);
|
||||
Register src_reg = reg_to_register_object($src$$reg);
|
||||
Register dst_reg = reg_to_register_object($dst$$reg);
|
||||
__ sllx(src_reg, 56, dst_reg);
|
||||
__ srlx(dst_reg, 8, O7);
|
||||
__ or3 (dst_reg, O7, dst_reg);
|
||||
__ srlx(dst_reg, 16, O7);
|
||||
__ or3 (dst_reg, O7, dst_reg);
|
||||
__ srlx(dst_reg, 32, O7);
|
||||
__ or3 (dst_reg, O7, dst_reg);
|
||||
%}
|
||||
|
||||
enc_class enc_repl4b( iRegI src, iRegL dst ) %{
|
||||
MacroAssembler _masm(&cbuf);
|
||||
Register src_reg = reg_to_register_object($src$$reg);
|
||||
Register dst_reg = reg_to_register_object($dst$$reg);
|
||||
__ sll(src_reg, 24, dst_reg);
|
||||
__ srl(dst_reg, 8, O7);
|
||||
__ or3(dst_reg, O7, dst_reg);
|
||||
__ srl(dst_reg, 16, O7);
|
||||
__ or3(dst_reg, O7, dst_reg);
|
||||
%}
|
||||
|
||||
enc_class enc_repl4s( iRegI src, iRegL dst ) %{
|
||||
MacroAssembler _masm(&cbuf);
|
||||
Register src_reg = reg_to_register_object($src$$reg);
|
||||
Register dst_reg = reg_to_register_object($dst$$reg);
|
||||
__ sllx(src_reg, 48, dst_reg);
|
||||
__ srlx(dst_reg, 16, O7);
|
||||
__ or3 (dst_reg, O7, dst_reg);
|
||||
__ srlx(dst_reg, 32, O7);
|
||||
__ or3 (dst_reg, O7, dst_reg);
|
||||
%}
|
||||
|
||||
enc_class enc_repl2i( iRegI src, iRegL dst ) %{
|
||||
MacroAssembler _masm(&cbuf);
|
||||
Register src_reg = reg_to_register_object($src$$reg);
|
||||
Register dst_reg = reg_to_register_object($dst$$reg);
|
||||
__ sllx(src_reg, 32, dst_reg);
|
||||
__ srlx(dst_reg, 32, O7);
|
||||
__ or3 (dst_reg, O7, dst_reg);
|
||||
%}
|
||||
|
||||
%}
|
||||
|
||||
//----------FRAME--------------------------------------------------------------
|
||||
@ -5932,50 +5920,6 @@ instruct loadL_unaligned(iRegL dst, memory mem, o7RegI tmp) %{
|
||||
ins_pipe(iload_mem);
|
||||
%}
|
||||
|
||||
// Load Aligned Packed Byte into a Double Register
|
||||
instruct loadA8B(regD dst, memory mem) %{
|
||||
match(Set dst (Load8B mem));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(4);
|
||||
format %{ "LDDF $mem,$dst\t! packed8B" %}
|
||||
opcode(Assembler::lddf_op3);
|
||||
ins_encode(simple_form3_mem_reg( mem, dst ) );
|
||||
ins_pipe(floadD_mem);
|
||||
%}
|
||||
|
||||
// Load Aligned Packed Char into a Double Register
|
||||
instruct loadA4C(regD dst, memory mem) %{
|
||||
match(Set dst (Load4C mem));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(4);
|
||||
format %{ "LDDF $mem,$dst\t! packed4C" %}
|
||||
opcode(Assembler::lddf_op3);
|
||||
ins_encode(simple_form3_mem_reg( mem, dst ) );
|
||||
ins_pipe(floadD_mem);
|
||||
%}
|
||||
|
||||
// Load Aligned Packed Short into a Double Register
|
||||
instruct loadA4S(regD dst, memory mem) %{
|
||||
match(Set dst (Load4S mem));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(4);
|
||||
format %{ "LDDF $mem,$dst\t! packed4S" %}
|
||||
opcode(Assembler::lddf_op3);
|
||||
ins_encode(simple_form3_mem_reg( mem, dst ) );
|
||||
ins_pipe(floadD_mem);
|
||||
%}
|
||||
|
||||
// Load Aligned Packed Int into a Double Register
|
||||
instruct loadA2I(regD dst, memory mem) %{
|
||||
match(Set dst (Load2I mem));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(4);
|
||||
format %{ "LDDF $mem,$dst\t! packed2I" %}
|
||||
opcode(Assembler::lddf_op3);
|
||||
ins_encode(simple_form3_mem_reg( mem, dst ) );
|
||||
ins_pipe(floadD_mem);
|
||||
%}
|
||||
|
||||
// Load Range
|
||||
instruct loadRange(iRegI dst, memory mem) %{
|
||||
match(Set dst (LoadRange mem));
|
||||
@ -6599,17 +6543,6 @@ instruct storeF0( memory mem, immF0 src) %{
|
||||
ins_pipe(fstoreF_mem_zero);
|
||||
%}
|
||||
|
||||
// Store Aligned Packed Bytes in Double register to memory
|
||||
instruct storeA8B(memory mem, regD src) %{
|
||||
match(Set mem (Store8B mem src));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(4);
|
||||
format %{ "STDF $src,$mem\t! packed8B" %}
|
||||
opcode(Assembler::stdf_op3);
|
||||
ins_encode(simple_form3_mem_reg( mem, src ) );
|
||||
ins_pipe(fstoreD_mem_reg);
|
||||
%}
|
||||
|
||||
// Convert oop pointer into compressed form
|
||||
instruct encodeHeapOop(iRegN dst, iRegP src) %{
|
||||
predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull);
|
||||
@ -6654,62 +6587,6 @@ instruct decodeHeapOop_not_null(iRegP dst, iRegN src) %{
|
||||
%}
|
||||
|
||||
|
||||
// Store Zero into Aligned Packed Bytes
|
||||
instruct storeA8B0(memory mem, immI0 zero) %{
|
||||
match(Set mem (Store8B mem zero));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(4);
|
||||
format %{ "STX $zero,$mem\t! packed8B" %}
|
||||
opcode(Assembler::stx_op3);
|
||||
ins_encode(simple_form3_mem_reg( mem, R_G0 ) );
|
||||
ins_pipe(fstoreD_mem_zero);
|
||||
%}
|
||||
|
||||
// Store Aligned Packed Chars/Shorts in Double register to memory
|
||||
instruct storeA4C(memory mem, regD src) %{
|
||||
match(Set mem (Store4C mem src));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(4);
|
||||
format %{ "STDF $src,$mem\t! packed4C" %}
|
||||
opcode(Assembler::stdf_op3);
|
||||
ins_encode(simple_form3_mem_reg( mem, src ) );
|
||||
ins_pipe(fstoreD_mem_reg);
|
||||
%}
|
||||
|
||||
// Store Zero into Aligned Packed Chars/Shorts
|
||||
instruct storeA4C0(memory mem, immI0 zero) %{
|
||||
match(Set mem (Store4C mem (Replicate4C zero)));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(4);
|
||||
format %{ "STX $zero,$mem\t! packed4C" %}
|
||||
opcode(Assembler::stx_op3);
|
||||
ins_encode(simple_form3_mem_reg( mem, R_G0 ) );
|
||||
ins_pipe(fstoreD_mem_zero);
|
||||
%}
|
||||
|
||||
// Store Aligned Packed Ints in Double register to memory
|
||||
instruct storeA2I(memory mem, regD src) %{
|
||||
match(Set mem (Store2I mem src));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(4);
|
||||
format %{ "STDF $src,$mem\t! packed2I" %}
|
||||
opcode(Assembler::stdf_op3);
|
||||
ins_encode(simple_form3_mem_reg( mem, src ) );
|
||||
ins_pipe(fstoreD_mem_reg);
|
||||
%}
|
||||
|
||||
// Store Zero into Aligned Packed Ints
|
||||
instruct storeA2I0(memory mem, immI0 zero) %{
|
||||
match(Set mem (Store2I mem zero));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(4);
|
||||
format %{ "STX $zero,$mem\t! packed2I" %}
|
||||
opcode(Assembler::stx_op3);
|
||||
ins_encode(simple_form3_mem_reg( mem, R_G0 ) );
|
||||
ins_pipe(fstoreD_mem_zero);
|
||||
%}
|
||||
|
||||
|
||||
//----------MemBar Instructions-----------------------------------------------
|
||||
// Memory barrier flavors
|
||||
|
||||
@ -8880,150 +8757,6 @@ instruct shrL_reg_imm6_L2I(iRegI dst, iRegL src, immI_32_63 cnt) %{
|
||||
ins_pipe(ialu_reg_imm);
|
||||
%}
|
||||
|
||||
// Replicate scalar to packed byte values in Double register
|
||||
instruct Repl8B_reg_helper(iRegL dst, iRegI src) %{
|
||||
effect(DEF dst, USE src);
|
||||
format %{ "SLLX $src,56,$dst\n\t"
|
||||
"SRLX $dst, 8,O7\n\t"
|
||||
"OR $dst,O7,$dst\n\t"
|
||||
"SRLX $dst,16,O7\n\t"
|
||||
"OR $dst,O7,$dst\n\t"
|
||||
"SRLX $dst,32,O7\n\t"
|
||||
"OR $dst,O7,$dst\t! replicate8B" %}
|
||||
ins_encode( enc_repl8b(src, dst));
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
// Replicate scalar to packed byte values in Double register
|
||||
instruct Repl8B_reg(stackSlotD dst, iRegI src) %{
|
||||
match(Set dst (Replicate8B src));
|
||||
expand %{
|
||||
iRegL tmp;
|
||||
Repl8B_reg_helper(tmp, src);
|
||||
regL_to_stkD(dst, tmp);
|
||||
%}
|
||||
%}
|
||||
|
||||
// Replicate scalar constant to packed byte values in Double register
|
||||
instruct Repl8B_immI(regD dst, immI13 con, o7RegI tmp) %{
|
||||
match(Set dst (Replicate8B con));
|
||||
effect(KILL tmp);
|
||||
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl8B($con)" %}
|
||||
ins_encode %{
|
||||
// XXX This is a quick fix for 6833573.
|
||||
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 8, 1)), $dst$$FloatRegister);
|
||||
RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 8, 1)), $tmp$$Register);
|
||||
__ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(loadConFD);
|
||||
%}
|
||||
|
||||
// Replicate scalar to packed char values into stack slot
|
||||
instruct Repl4C_reg_helper(iRegL dst, iRegI src) %{
|
||||
effect(DEF dst, USE src);
|
||||
format %{ "SLLX $src,48,$dst\n\t"
|
||||
"SRLX $dst,16,O7\n\t"
|
||||
"OR $dst,O7,$dst\n\t"
|
||||
"SRLX $dst,32,O7\n\t"
|
||||
"OR $dst,O7,$dst\t! replicate4C" %}
|
||||
ins_encode( enc_repl4s(src, dst) );
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
// Replicate scalar to packed char values into stack slot
|
||||
instruct Repl4C_reg(stackSlotD dst, iRegI src) %{
|
||||
match(Set dst (Replicate4C src));
|
||||
expand %{
|
||||
iRegL tmp;
|
||||
Repl4C_reg_helper(tmp, src);
|
||||
regL_to_stkD(dst, tmp);
|
||||
%}
|
||||
%}
|
||||
|
||||
// Replicate scalar constant to packed char values in Double register
|
||||
instruct Repl4C_immI(regD dst, immI con, o7RegI tmp) %{
|
||||
match(Set dst (Replicate4C con));
|
||||
effect(KILL tmp);
|
||||
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl4C($con)" %}
|
||||
ins_encode %{
|
||||
// XXX This is a quick fix for 6833573.
|
||||
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 4, 2)), $dst$$FloatRegister);
|
||||
RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 4, 2)), $tmp$$Register);
|
||||
__ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(loadConFD);
|
||||
%}
|
||||
|
||||
// Replicate scalar to packed short values into stack slot
|
||||
instruct Repl4S_reg_helper(iRegL dst, iRegI src) %{
|
||||
effect(DEF dst, USE src);
|
||||
format %{ "SLLX $src,48,$dst\n\t"
|
||||
"SRLX $dst,16,O7\n\t"
|
||||
"OR $dst,O7,$dst\n\t"
|
||||
"SRLX $dst,32,O7\n\t"
|
||||
"OR $dst,O7,$dst\t! replicate4S" %}
|
||||
ins_encode( enc_repl4s(src, dst) );
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
// Replicate scalar to packed short values into stack slot
|
||||
instruct Repl4S_reg(stackSlotD dst, iRegI src) %{
|
||||
match(Set dst (Replicate4S src));
|
||||
expand %{
|
||||
iRegL tmp;
|
||||
Repl4S_reg_helper(tmp, src);
|
||||
regL_to_stkD(dst, tmp);
|
||||
%}
|
||||
%}
|
||||
|
||||
// Replicate scalar constant to packed short values in Double register
|
||||
instruct Repl4S_immI(regD dst, immI con, o7RegI tmp) %{
|
||||
match(Set dst (Replicate4S con));
|
||||
effect(KILL tmp);
|
||||
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl4S($con)" %}
|
||||
ins_encode %{
|
||||
// XXX This is a quick fix for 6833573.
|
||||
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 4, 2)), $dst$$FloatRegister);
|
||||
RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 4, 2)), $tmp$$Register);
|
||||
__ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(loadConFD);
|
||||
%}
|
||||
|
||||
// Replicate scalar to packed int values in Double register
|
||||
instruct Repl2I_reg_helper(iRegL dst, iRegI src) %{
|
||||
effect(DEF dst, USE src);
|
||||
format %{ "SLLX $src,32,$dst\n\t"
|
||||
"SRLX $dst,32,O7\n\t"
|
||||
"OR $dst,O7,$dst\t! replicate2I" %}
|
||||
ins_encode( enc_repl2i(src, dst));
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
// Replicate scalar to packed int values in Double register
|
||||
instruct Repl2I_reg(stackSlotD dst, iRegI src) %{
|
||||
match(Set dst (Replicate2I src));
|
||||
expand %{
|
||||
iRegL tmp;
|
||||
Repl2I_reg_helper(tmp, src);
|
||||
regL_to_stkD(dst, tmp);
|
||||
%}
|
||||
%}
|
||||
|
||||
// Replicate scalar zero constant to packed int values in Double register
|
||||
instruct Repl2I_immI(regD dst, immI con, o7RegI tmp) %{
|
||||
match(Set dst (Replicate2I con));
|
||||
effect(KILL tmp);
|
||||
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl2I($con)" %}
|
||||
ins_encode %{
|
||||
// XXX This is a quick fix for 6833573.
|
||||
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 2, 4)), $dst$$FloatRegister);
|
||||
RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 2, 4)), $tmp$$Register);
|
||||
__ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(loadConFD);
|
||||
%}
|
||||
|
||||
//----------Control Flow Instructions------------------------------------------
|
||||
// Compare Instructions
|
||||
// Compare Integers
|
||||
@ -10742,6 +10475,308 @@ instruct storeS_reversed(indIndexMemory dst, iRegI src) %{
|
||||
ins_pipe(istore_mem_reg);
|
||||
%}
|
||||
|
||||
// ====================VECTOR INSTRUCTIONS=====================================
|
||||
|
||||
// Load Aligned Packed values into a Double Register
|
||||
instruct loadV8(regD dst, memory mem) %{
|
||||
predicate(n->as_LoadVector()->memory_size() == 8);
|
||||
match(Set dst (LoadVector mem));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(4);
|
||||
format %{ "LDDF $mem,$dst\t! load vector (8 bytes)" %}
|
||||
ins_encode %{
|
||||
__ ldf(FloatRegisterImpl::D, $mem$$Address, as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(floadD_mem);
|
||||
%}
|
||||
|
||||
// Store Vector in Double register to memory
|
||||
instruct storeV8(memory mem, regD src) %{
|
||||
predicate(n->as_StoreVector()->memory_size() == 8);
|
||||
match(Set mem (StoreVector mem src));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(4);
|
||||
format %{ "STDF $src,$mem\t! store vector (8 bytes)" %}
|
||||
ins_encode %{
|
||||
__ stf(FloatRegisterImpl::D, as_DoubleFloatRegister($src$$reg), $mem$$Address);
|
||||
%}
|
||||
ins_pipe(fstoreD_mem_reg);
|
||||
%}
|
||||
|
||||
// Store Zero into vector in memory
|
||||
instruct storeV8B_zero(memory mem, immI0 zero) %{
|
||||
predicate(n->as_StoreVector()->memory_size() == 8);
|
||||
match(Set mem (StoreVector mem (ReplicateB zero)));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(4);
|
||||
format %{ "STX $zero,$mem\t! store zero vector (8 bytes)" %}
|
||||
ins_encode %{
|
||||
__ stx(G0, $mem$$Address);
|
||||
%}
|
||||
ins_pipe(fstoreD_mem_zero);
|
||||
%}
|
||||
|
||||
instruct storeV4S_zero(memory mem, immI0 zero) %{
|
||||
predicate(n->as_StoreVector()->memory_size() == 8);
|
||||
match(Set mem (StoreVector mem (ReplicateS zero)));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(4);
|
||||
format %{ "STX $zero,$mem\t! store zero vector (4 shorts)" %}
|
||||
ins_encode %{
|
||||
__ stx(G0, $mem$$Address);
|
||||
%}
|
||||
ins_pipe(fstoreD_mem_zero);
|
||||
%}
|
||||
|
||||
instruct storeV2I_zero(memory mem, immI0 zero) %{
|
||||
predicate(n->as_StoreVector()->memory_size() == 8);
|
||||
match(Set mem (StoreVector mem (ReplicateI zero)));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(4);
|
||||
format %{ "STX $zero,$mem\t! store zero vector (2 ints)" %}
|
||||
ins_encode %{
|
||||
__ stx(G0, $mem$$Address);
|
||||
%}
|
||||
ins_pipe(fstoreD_mem_zero);
|
||||
%}
|
||||
|
||||
instruct storeV2F_zero(memory mem, immF0 zero) %{
|
||||
predicate(n->as_StoreVector()->memory_size() == 8);
|
||||
match(Set mem (StoreVector mem (ReplicateF zero)));
|
||||
ins_cost(MEMORY_REF_COST);
|
||||
size(4);
|
||||
format %{ "STX $zero,$mem\t! store zero vector (2 floats)" %}
|
||||
ins_encode %{
|
||||
__ stx(G0, $mem$$Address);
|
||||
%}
|
||||
ins_pipe(fstoreD_mem_zero);
|
||||
%}
|
||||
|
||||
// Replicate scalar to packed byte values into Double register
|
||||
instruct Repl8B_reg(regD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
|
||||
predicate(n->as_Vector()->length() == 8 && UseVIS >= 3);
|
||||
match(Set dst (ReplicateB src));
|
||||
effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
|
||||
format %{ "SLLX $src,56,$tmp\n\t"
|
||||
"SRLX $tmp, 8,$tmp2\n\t"
|
||||
"OR $tmp,$tmp2,$tmp\n\t"
|
||||
"SRLX $tmp,16,$tmp2\n\t"
|
||||
"OR $tmp,$tmp2,$tmp\n\t"
|
||||
"SRLX $tmp,32,$tmp2\n\t"
|
||||
"OR $tmp,$tmp2,$tmp\t! replicate8B\n\t"
|
||||
"MOVXTOD $tmp,$dst\t! MoveL2D" %}
|
||||
ins_encode %{
|
||||
Register Rsrc = $src$$Register;
|
||||
Register Rtmp = $tmp$$Register;
|
||||
Register Rtmp2 = $tmp2$$Register;
|
||||
__ sllx(Rsrc, 56, Rtmp);
|
||||
__ srlx(Rtmp, 8, Rtmp2);
|
||||
__ or3 (Rtmp, Rtmp2, Rtmp);
|
||||
__ srlx(Rtmp, 16, Rtmp2);
|
||||
__ or3 (Rtmp, Rtmp2, Rtmp);
|
||||
__ srlx(Rtmp, 32, Rtmp2);
|
||||
__ or3 (Rtmp, Rtmp2, Rtmp);
|
||||
__ movxtod(Rtmp, as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
// Replicate scalar to packed byte values into Double stack
|
||||
instruct Repl8B_stk(stackSlotD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
|
||||
predicate(n->as_Vector()->length() == 8 && UseVIS < 3);
|
||||
match(Set dst (ReplicateB src));
|
||||
effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
|
||||
format %{ "SLLX $src,56,$tmp\n\t"
|
||||
"SRLX $tmp, 8,$tmp2\n\t"
|
||||
"OR $tmp,$tmp2,$tmp\n\t"
|
||||
"SRLX $tmp,16,$tmp2\n\t"
|
||||
"OR $tmp,$tmp2,$tmp\n\t"
|
||||
"SRLX $tmp,32,$tmp2\n\t"
|
||||
"OR $tmp,$tmp2,$tmp\t! replicate8B\n\t"
|
||||
"STX $tmp,$dst\t! regL to stkD" %}
|
||||
ins_encode %{
|
||||
Register Rsrc = $src$$Register;
|
||||
Register Rtmp = $tmp$$Register;
|
||||
Register Rtmp2 = $tmp2$$Register;
|
||||
__ sllx(Rsrc, 56, Rtmp);
|
||||
__ srlx(Rtmp, 8, Rtmp2);
|
||||
__ or3 (Rtmp, Rtmp2, Rtmp);
|
||||
__ srlx(Rtmp, 16, Rtmp2);
|
||||
__ or3 (Rtmp, Rtmp2, Rtmp);
|
||||
__ srlx(Rtmp, 32, Rtmp2);
|
||||
__ or3 (Rtmp, Rtmp2, Rtmp);
|
||||
__ set ($dst$$disp + STACK_BIAS, Rtmp2);
|
||||
__ stx (Rtmp, Rtmp2, $dst$$base$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
// Replicate scalar constant to packed byte values in Double register
|
||||
instruct Repl8B_immI(regD dst, immI13 con, o7RegI tmp) %{
|
||||
predicate(n->as_Vector()->length() == 8);
|
||||
match(Set dst (ReplicateB con));
|
||||
effect(KILL tmp);
|
||||
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl8B($con)" %}
|
||||
ins_encode %{
|
||||
// XXX This is a quick fix for 6833573.
|
||||
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 8, 1)), $dst$$FloatRegister);
|
||||
RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 8, 1)), $tmp$$Register);
|
||||
__ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(loadConFD);
|
||||
%}
|
||||
|
||||
// Replicate scalar to packed char/short values into Double register
|
||||
instruct Repl4S_reg(regD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
|
||||
predicate(n->as_Vector()->length() == 4 && UseVIS >= 3);
|
||||
match(Set dst (ReplicateS src));
|
||||
effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
|
||||
format %{ "SLLX $src,48,$tmp\n\t"
|
||||
"SRLX $tmp,16,$tmp2\n\t"
|
||||
"OR $tmp,$tmp2,$tmp\n\t"
|
||||
"SRLX $tmp,32,$tmp2\n\t"
|
||||
"OR $tmp,$tmp2,$tmp\t! replicate4S\n\t"
|
||||
"MOVXTOD $tmp,$dst\t! MoveL2D" %}
|
||||
ins_encode %{
|
||||
Register Rsrc = $src$$Register;
|
||||
Register Rtmp = $tmp$$Register;
|
||||
Register Rtmp2 = $tmp2$$Register;
|
||||
__ sllx(Rsrc, 48, Rtmp);
|
||||
__ srlx(Rtmp, 16, Rtmp2);
|
||||
__ or3 (Rtmp, Rtmp2, Rtmp);
|
||||
__ srlx(Rtmp, 32, Rtmp2);
|
||||
__ or3 (Rtmp, Rtmp2, Rtmp);
|
||||
__ movxtod(Rtmp, as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
// Replicate scalar to packed char/short values into Double stack
|
||||
instruct Repl4S_stk(stackSlotD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
|
||||
predicate(n->as_Vector()->length() == 4 && UseVIS < 3);
|
||||
match(Set dst (ReplicateS src));
|
||||
effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
|
||||
format %{ "SLLX $src,48,$tmp\n\t"
|
||||
"SRLX $tmp,16,$tmp2\n\t"
|
||||
"OR $tmp,$tmp2,$tmp\n\t"
|
||||
"SRLX $tmp,32,$tmp2\n\t"
|
||||
"OR $tmp,$tmp2,$tmp\t! replicate4S\n\t"
|
||||
"STX $tmp,$dst\t! regL to stkD" %}
|
||||
ins_encode %{
|
||||
Register Rsrc = $src$$Register;
|
||||
Register Rtmp = $tmp$$Register;
|
||||
Register Rtmp2 = $tmp2$$Register;
|
||||
__ sllx(Rsrc, 48, Rtmp);
|
||||
__ srlx(Rtmp, 16, Rtmp2);
|
||||
__ or3 (Rtmp, Rtmp2, Rtmp);
|
||||
__ srlx(Rtmp, 32, Rtmp2);
|
||||
__ or3 (Rtmp, Rtmp2, Rtmp);
|
||||
__ set ($dst$$disp + STACK_BIAS, Rtmp2);
|
||||
__ stx (Rtmp, Rtmp2, $dst$$base$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
// Replicate scalar constant to packed char/short values in Double register
|
||||
instruct Repl4S_immI(regD dst, immI con, o7RegI tmp) %{
|
||||
predicate(n->as_Vector()->length() == 4);
|
||||
match(Set dst (ReplicateS con));
|
||||
effect(KILL tmp);
|
||||
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl4S($con)" %}
|
||||
ins_encode %{
|
||||
// XXX This is a quick fix for 6833573.
|
||||
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 4, 2)), $dst$$FloatRegister);
|
||||
RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 4, 2)), $tmp$$Register);
|
||||
__ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(loadConFD);
|
||||
%}
|
||||
|
||||
// Replicate scalar to packed int values into Double register
|
||||
instruct Repl2I_reg(regD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
|
||||
predicate(n->as_Vector()->length() == 2 && UseVIS >= 3);
|
||||
match(Set dst (ReplicateI src));
|
||||
effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
|
||||
format %{ "SLLX $src,32,$tmp\n\t"
|
||||
"SRLX $tmp,32,$tmp2\n\t"
|
||||
"OR $tmp,$tmp2,$tmp\t! replicate2I\n\t"
|
||||
"MOVXTOD $tmp,$dst\t! MoveL2D" %}
|
||||
ins_encode %{
|
||||
Register Rsrc = $src$$Register;
|
||||
Register Rtmp = $tmp$$Register;
|
||||
Register Rtmp2 = $tmp2$$Register;
|
||||
__ sllx(Rsrc, 32, Rtmp);
|
||||
__ srlx(Rtmp, 32, Rtmp2);
|
||||
__ or3 (Rtmp, Rtmp2, Rtmp);
|
||||
__ movxtod(Rtmp, as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
// Replicate scalar to packed int values into Double stack
|
||||
instruct Repl2I_stk(stackSlotD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
|
||||
predicate(n->as_Vector()->length() == 2 && UseVIS < 3);
|
||||
match(Set dst (ReplicateI src));
|
||||
effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
|
||||
format %{ "SLLX $src,32,$tmp\n\t"
|
||||
"SRLX $tmp,32,$tmp2\n\t"
|
||||
"OR $tmp,$tmp2,$tmp\t! replicate2I\n\t"
|
||||
"STX $tmp,$dst\t! regL to stkD" %}
|
||||
ins_encode %{
|
||||
Register Rsrc = $src$$Register;
|
||||
Register Rtmp = $tmp$$Register;
|
||||
Register Rtmp2 = $tmp2$$Register;
|
||||
__ sllx(Rsrc, 32, Rtmp);
|
||||
__ srlx(Rtmp, 32, Rtmp2);
|
||||
__ or3 (Rtmp, Rtmp2, Rtmp);
|
||||
__ set ($dst$$disp + STACK_BIAS, Rtmp2);
|
||||
__ stx (Rtmp, Rtmp2, $dst$$base$$Register);
|
||||
%}
|
||||
ins_pipe(ialu_reg);
|
||||
%}
|
||||
|
||||
// Replicate scalar zero constant to packed int values in Double register
|
||||
instruct Repl2I_immI(regD dst, immI con, o7RegI tmp) %{
|
||||
predicate(n->as_Vector()->length() == 2);
|
||||
match(Set dst (ReplicateI con));
|
||||
effect(KILL tmp);
|
||||
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl2I($con)" %}
|
||||
ins_encode %{
|
||||
// XXX This is a quick fix for 6833573.
|
||||
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 2, 4)), $dst$$FloatRegister);
|
||||
RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 2, 4)), $tmp$$Register);
|
||||
__ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(loadConFD);
|
||||
%}
|
||||
|
||||
// Replicate scalar to packed float values into Double stack
|
||||
instruct Repl2F_stk(stackSlotD dst, regF src) %{
|
||||
predicate(n->as_Vector()->length() == 2);
|
||||
match(Set dst (ReplicateF src));
|
||||
ins_cost(MEMORY_REF_COST*2);
|
||||
format %{ "STF $src,$dst.hi\t! packed2F\n\t"
|
||||
"STF $src,$dst.lo" %}
|
||||
opcode(Assembler::stf_op3);
|
||||
ins_encode(simple_form3_mem_reg(dst, src), form3_mem_plus_4_reg(dst, src));
|
||||
ins_pipe(fstoreF_stk_reg);
|
||||
%}
|
||||
|
||||
// Replicate scalar zero constant to packed float values in Double register
|
||||
instruct Repl2F_immF(regD dst, immF con, o7RegI tmp) %{
|
||||
predicate(n->as_Vector()->length() == 2);
|
||||
match(Set dst (ReplicateF con));
|
||||
effect(KILL tmp);
|
||||
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl2F($con)" %}
|
||||
ins_encode %{
|
||||
// XXX This is a quick fix for 6833573.
|
||||
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immF($con$$constant)), $dst$$FloatRegister);
|
||||
RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immF($con$$constant)), $tmp$$Register);
|
||||
__ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
|
||||
%}
|
||||
ins_pipe(loadConFD);
|
||||
%}
|
||||
|
||||
//----------PEEPHOLE RULES-----------------------------------------------------
|
||||
// These must follow all instruction definitions as they use the names
|
||||
// defined in the instructions definitions.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -217,6 +217,8 @@ void VM_Version::initialize() {
|
||||
// Currently not supported anywhere.
|
||||
FLAG_SET_DEFAULT(UseFPUForSpilling, false);
|
||||
|
||||
MaxVectorSize = 8;
|
||||
|
||||
assert((InteriorEntryAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size");
|
||||
#endif
|
||||
|
||||
|
@ -1637,6 +1637,13 @@ void Assembler::movaps(XMMRegister dst, XMMRegister src) {
|
||||
emit_byte(0xC0 | encode);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void Assembler::movb(Register dst, Address src) {
|
||||
NOT_LP64(assert(dst->has_byte_register(), "must have byte register"));
|
||||
InstructionMark im(this);
|
||||
@ -1686,6 +1693,14 @@ void Assembler::movdl(XMMRegister dst, Address src) {
|
||||
emit_operand(dst, src);
|
||||
}
|
||||
|
||||
void Assembler::movdl(Address dst, XMMRegister src) {
|
||||
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
|
||||
InstructionMark im(this);
|
||||
simd_prefix(dst, src, VEX_SIMD_66);
|
||||
emit_byte(0x7E);
|
||||
emit_operand(src, dst);
|
||||
}
|
||||
|
||||
void Assembler::movdqa(XMMRegister dst, XMMRegister src) {
|
||||
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
|
||||
int encode = simd_prefix_and_encode(dst, src, VEX_SIMD_66);
|
||||
@ -1716,6 +1731,35 @@ void Assembler::movdqu(Address dst, XMMRegister src) {
|
||||
emit_operand(src, dst);
|
||||
}
|
||||
|
||||
// Move Unaligned 256bit Vector
|
||||
void Assembler::vmovdqu(XMMRegister dst, XMMRegister src) {
|
||||
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);
|
||||
}
|
||||
|
||||
void Assembler::vmovdqu(XMMRegister dst, Address src) {
|
||||
assert(UseAVX, "");
|
||||
InstructionMark im(this);
|
||||
bool vector256 = true;
|
||||
vex_prefix(dst, xnoreg, src, VEX_SIMD_F3, vector256);
|
||||
emit_byte(0x6F);
|
||||
emit_operand(dst, src);
|
||||
}
|
||||
|
||||
void Assembler::vmovdqu(Address dst, XMMRegister src) {
|
||||
assert(UseAVX, "");
|
||||
InstructionMark im(this);
|
||||
bool vector256 = true;
|
||||
// swap src<->dst for encoding
|
||||
assert(src != xnoreg, "sanity");
|
||||
vex_prefix(src, xnoreg, dst, VEX_SIMD_F3, vector256);
|
||||
emit_byte(0x7F);
|
||||
emit_operand(src, dst);
|
||||
}
|
||||
|
||||
// Uses zero extension on 64bit
|
||||
|
||||
void Assembler::movl(Register dst, int32_t imm32) {
|
||||
@ -3112,6 +3156,13 @@ void Assembler::vxorpd(XMMRegister dst, XMMRegister nds, Address src) {
|
||||
emit_operand(dst, src);
|
||||
}
|
||||
|
||||
void Assembler::vxorpd(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) {
|
||||
assert(VM_Version::supports_avx(), "");
|
||||
int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector256);
|
||||
emit_byte(0x57);
|
||||
emit_byte(0xC0 | encode);
|
||||
}
|
||||
|
||||
void Assembler::vxorps(XMMRegister dst, XMMRegister nds, Address src) {
|
||||
assert(VM_Version::supports_avx(), "");
|
||||
InstructionMark im(this);
|
||||
@ -3120,6 +3171,30 @@ void Assembler::vxorps(XMMRegister dst, XMMRegister nds, Address src) {
|
||||
emit_operand(dst, src);
|
||||
}
|
||||
|
||||
void Assembler::vxorps(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) {
|
||||
assert(VM_Version::supports_avx(), "");
|
||||
int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_NONE, vector256);
|
||||
emit_byte(0x57);
|
||||
emit_byte(0xC0 | encode);
|
||||
}
|
||||
|
||||
void Assembler::vinsertf128h(XMMRegister dst, XMMRegister nds, XMMRegister src) {
|
||||
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);
|
||||
// 0x00 - insert into lower 128 bits
|
||||
// 0x01 - insert into upper 128 bits
|
||||
emit_byte(0x01);
|
||||
}
|
||||
|
||||
void Assembler::vzeroupper() {
|
||||
assert(VM_Version::supports_avx(), "");
|
||||
(void)vex_prefix_and_encode(xmm0, xmm0, xmm0, VEX_SIMD_NONE);
|
||||
emit_byte(0x77);
|
||||
}
|
||||
|
||||
|
||||
#ifndef _LP64
|
||||
// 32bit only pieces of the assembler
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -591,8 +591,9 @@ private:
|
||||
|
||||
void vex_prefix(XMMRegister dst, XMMRegister nds, Address src,
|
||||
VexSimdPrefix pre, bool vector256 = false) {
|
||||
vex_prefix(src, nds->encoding(), dst->encoding(),
|
||||
pre, VEX_OPCODE_0F, false, vector256);
|
||||
int dst_enc = dst->encoding();
|
||||
int nds_enc = nds->is_valid() ? nds->encoding() : 0;
|
||||
vex_prefix(src, nds_enc, dst_enc, pre, VEX_OPCODE_0F, false, vector256);
|
||||
}
|
||||
|
||||
int vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc,
|
||||
@ -600,9 +601,12 @@ private:
|
||||
bool vex_w, bool vector256);
|
||||
|
||||
int vex_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegister src,
|
||||
VexSimdPrefix pre, bool vector256 = false) {
|
||||
return vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(),
|
||||
pre, VEX_OPCODE_0F, false, vector256);
|
||||
VexSimdPrefix pre, bool vector256 = false,
|
||||
VexOpcode opc = VEX_OPCODE_0F) {
|
||||
int src_enc = src->encoding();
|
||||
int dst_enc = dst->encoding();
|
||||
int nds_enc = nds->is_valid() ? nds->encoding() : 0;
|
||||
return vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, opc, false, vector256);
|
||||
}
|
||||
|
||||
void simd_prefix(XMMRegister xreg, XMMRegister nds, Address adr,
|
||||
@ -1261,6 +1265,7 @@ private:
|
||||
void movdl(XMMRegister dst, Register src);
|
||||
void movdl(Register dst, XMMRegister src);
|
||||
void movdl(XMMRegister dst, Address src);
|
||||
void movdl(Address dst, XMMRegister src);
|
||||
|
||||
// Move Double Quadword
|
||||
void movdq(XMMRegister dst, Register src);
|
||||
@ -1274,6 +1279,14 @@ private:
|
||||
void movdqu(XMMRegister dst, Address src);
|
||||
void movdqu(XMMRegister dst, XMMRegister src);
|
||||
|
||||
// Move Unaligned 256bit Vector
|
||||
void vmovdqu(Address dst, XMMRegister src);
|
||||
void vmovdqu(XMMRegister dst, Address src);
|
||||
void vmovdqu(XMMRegister dst, XMMRegister src);
|
||||
|
||||
// Move lower 64bit to high 64bit in 128bit register
|
||||
void movlhps(XMMRegister dst, XMMRegister src);
|
||||
|
||||
void movl(Register dst, int32_t imm32);
|
||||
void movl(Address dst, int32_t imm32);
|
||||
void movl(Register dst, Register src);
|
||||
@ -1615,6 +1628,17 @@ private:
|
||||
void vxorpd(XMMRegister dst, XMMRegister nds, Address src);
|
||||
void vxorps(XMMRegister dst, XMMRegister nds, Address src);
|
||||
|
||||
// AVX Vector instrucitons.
|
||||
void vxorpd(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256);
|
||||
void vxorps(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256);
|
||||
void vinsertf128h(XMMRegister dst, XMMRegister nds, 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
|
||||
// they always clear upper 128 bits. It should be used before calling
|
||||
// runtime code and native libraries.
|
||||
void vzeroupper();
|
||||
|
||||
protected:
|
||||
// Next instructions require address alignment 16 bytes SSE mode.
|
||||
@ -2529,9 +2553,13 @@ public:
|
||||
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) { Assembler::vxorpd(dst, nds, src); }
|
||||
void vxorpd(XMMRegister dst, XMMRegister nds, AddressLiteral src);
|
||||
|
||||
void vxorps(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { Assembler::vxorps(dst, nds, src, vector256); }
|
||||
void vxorps(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vxorps(dst, nds, src); }
|
||||
void vxorps(XMMRegister dst, XMMRegister nds, AddressLiteral src);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 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
|
||||
@ -35,7 +35,7 @@ const int ConcreteRegisterImpl::max_gpr = RegisterImpl::number_of_registers << 1
|
||||
const int ConcreteRegisterImpl::max_fpr = ConcreteRegisterImpl::max_gpr +
|
||||
2 * FloatRegisterImpl::number_of_registers;
|
||||
const int ConcreteRegisterImpl::max_xmm = ConcreteRegisterImpl::max_fpr +
|
||||
2 * XMMRegisterImpl::number_of_registers;
|
||||
8 * XMMRegisterImpl::number_of_registers;
|
||||
const char* RegisterImpl::name() const {
|
||||
const char* names[number_of_registers] = {
|
||||
#ifndef AMD64
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 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
|
||||
@ -158,7 +158,7 @@ class XMMRegisterImpl: public AbstractRegisterImpl {
|
||||
XMMRegister successor() const { return as_XMMRegister(encoding() + 1); }
|
||||
|
||||
// accessors
|
||||
int encoding() const { assert(is_valid(), "invalid register"); return (intptr_t)this; }
|
||||
int encoding() const { assert(is_valid(), err_msg("invalid register (%d)", (int)(intptr_t)this )); return (intptr_t)this; }
|
||||
bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; }
|
||||
const char* name() const;
|
||||
};
|
||||
@ -216,7 +216,7 @@ class ConcreteRegisterImpl : public AbstractRegisterImpl {
|
||||
RegisterImpl::number_of_registers + // "H" half of a 64bit register
|
||||
#endif // AMD64
|
||||
2 * FloatRegisterImpl::number_of_registers +
|
||||
2 * XMMRegisterImpl::number_of_registers +
|
||||
8 * XMMRegisterImpl::number_of_registers +
|
||||
1 // eflags
|
||||
};
|
||||
|
||||
|
@ -467,6 +467,32 @@ void VM_Version::get_processor_features() {
|
||||
if (!supports_avx ()) // Drop to 0 if no AVX support
|
||||
UseAVX = 0;
|
||||
|
||||
#ifdef COMPILER2
|
||||
if (UseFPUForSpilling) {
|
||||
if (UseSSE < 2) {
|
||||
// Only supported with SSE2+
|
||||
FLAG_SET_DEFAULT(UseFPUForSpilling, false);
|
||||
}
|
||||
}
|
||||
if (MaxVectorSize > 0) {
|
||||
if (!is_power_of_2(MaxVectorSize)) {
|
||||
warning("MaxVectorSize must be a power of 2");
|
||||
FLAG_SET_DEFAULT(MaxVectorSize, 32);
|
||||
}
|
||||
if (MaxVectorSize > 32) {
|
||||
FLAG_SET_DEFAULT(MaxVectorSize, 32);
|
||||
}
|
||||
if (MaxVectorSize > 16 && UseAVX == 0) {
|
||||
// Only supported with AVX+
|
||||
FLAG_SET_DEFAULT(MaxVectorSize, 16);
|
||||
}
|
||||
if (UseSSE < 2) {
|
||||
// Only supported with SSE2+
|
||||
FLAG_SET_DEFAULT(MaxVectorSize, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// On new cpus instructions which update whole XMM register should be used
|
||||
// to prevent partial register stall due to dependencies on high half.
|
||||
//
|
||||
@ -544,6 +570,12 @@ void VM_Version::get_processor_features() {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef COMPILER2
|
||||
if (MaxVectorSize > 16) {
|
||||
// Limit vectors size to 16 bytes on current AMD cpus.
|
||||
FLAG_SET_DEFAULT(MaxVectorSize, 16);
|
||||
}
|
||||
#endif // COMPILER2
|
||||
}
|
||||
|
||||
if( is_intel() ) { // Intel cpus specific settings
|
||||
@ -606,15 +638,6 @@ void VM_Version::get_processor_features() {
|
||||
FLAG_SET_DEFAULT(UsePopCountInstruction, false);
|
||||
}
|
||||
|
||||
#ifdef COMPILER2
|
||||
if (UseFPUForSpilling) {
|
||||
if (UseSSE < 2) {
|
||||
// Only supported with SSE2+
|
||||
FLAG_SET_DEFAULT(UseFPUForSpilling, false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
assert(0 <= ReadPrefetchInstr && ReadPrefetchInstr <= 3, "invalid value");
|
||||
assert(0 <= AllocatePrefetchInstr && AllocatePrefetchInstr <= 3, "invalid value");
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 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
|
||||
@ -48,8 +48,9 @@ void VMRegImpl::set_regName() {
|
||||
|
||||
XMMRegister xreg = ::as_XMMRegister(0);
|
||||
for ( ; i < ConcreteRegisterImpl::max_xmm ; ) {
|
||||
regName[i++] = xreg->name();
|
||||
regName[i++] = xreg->name();
|
||||
for (int j = 0 ; j < 8 ; j++) {
|
||||
regName[i++] = xreg->name();
|
||||
}
|
||||
xreg = xreg->successor();
|
||||
}
|
||||
for ( ; i < ConcreteRegisterImpl::number_of_registers ; i ++ ) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 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
|
||||
@ -39,7 +39,7 @@ inline VMReg FloatRegisterImpl::as_VMReg() {
|
||||
}
|
||||
|
||||
inline VMReg XMMRegisterImpl::as_VMReg() {
|
||||
return VMRegImpl::as_VMReg((encoding() << 1) + ConcreteRegisterImpl::max_fpr);
|
||||
return VMRegImpl::as_VMReg((encoding() << 3) + ConcreteRegisterImpl::max_fpr);
|
||||
}
|
||||
|
||||
|
||||
@ -75,7 +75,7 @@ inline FloatRegister VMRegImpl::as_FloatRegister() {
|
||||
inline XMMRegister VMRegImpl::as_XMMRegister() {
|
||||
assert( is_XMMRegister() && is_even(value()), "must be" );
|
||||
// Yuk
|
||||
return ::as_XMMRegister((value() - ConcreteRegisterImpl::max_fpr) >> 1);
|
||||
return ::as_XMMRegister((value() - ConcreteRegisterImpl::max_fpr) >> 3);
|
||||
}
|
||||
|
||||
inline bool VMRegImpl::is_concrete() {
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -516,7 +516,12 @@ JVM_handle_bsd_signal(int sig,
|
||||
}
|
||||
}
|
||||
|
||||
if (thread->thread_state() == _thread_in_Java) {
|
||||
// We test if stub is already set (by the stack overflow code
|
||||
// above) so it is not overwritten by the code that follows. This
|
||||
// check is not required on other platforms, because on other
|
||||
// platforms we check for SIGSEGV only or SIGBUS only, where here
|
||||
// we have to check for both SIGSEGV and SIGBUS.
|
||||
if (thread->thread_state() == _thread_in_Java && stub == NULL) {
|
||||
// Java thread running in Java code => find exception handler if any
|
||||
// a fault inside compiled code, the interpreter, or a stub
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -115,6 +115,12 @@ void ADLParser::parse() {
|
||||
parse_err(SYNERR, "expected one of - instruct, operand, ins_attrib, op_attrib, source, register, pipeline, encode\n Found %s",ident);
|
||||
}
|
||||
}
|
||||
// Add reg_class spill_regs after parsing.
|
||||
RegisterForm *regBlock = _AD.get_registers();
|
||||
if (regBlock == NULL) {
|
||||
parse_err(SEMERR, "Did not declare 'register' definitions");
|
||||
}
|
||||
regBlock->addSpillRegClass();
|
||||
|
||||
// Done with parsing, check consistency.
|
||||
|
||||
@ -768,11 +774,12 @@ void ADLParser::source_hpp_parse(void) {
|
||||
|
||||
//------------------------------reg_parse--------------------------------------
|
||||
void ADLParser::reg_parse(void) {
|
||||
|
||||
// Create the RegisterForm for the architecture description.
|
||||
RegisterForm *regBlock = new RegisterForm(); // Build new Source object
|
||||
regBlock->_linenum = linenum();
|
||||
_AD.addForm(regBlock);
|
||||
RegisterForm *regBlock = _AD.get_registers(); // Information about registers encoding
|
||||
if (regBlock == NULL) {
|
||||
// Create the RegisterForm for the architecture description.
|
||||
regBlock = new RegisterForm(); // Build new Source object
|
||||
_AD.addForm(regBlock);
|
||||
}
|
||||
|
||||
skipws(); // Skip leading whitespace
|
||||
if (_curchar == '%' && *(_ptr+1) == '{') {
|
||||
@ -796,15 +803,11 @@ void ADLParser::reg_parse(void) {
|
||||
parse_err(SYNERR, "Missing %c{ ... %c} block after register keyword.\n",'%','%');
|
||||
return;
|
||||
}
|
||||
|
||||
// Add reg_class spill_regs
|
||||
regBlock->addSpillRegClass();
|
||||
}
|
||||
|
||||
//------------------------------encode_parse-----------------------------------
|
||||
void ADLParser::encode_parse(void) {
|
||||
EncodeForm *encBlock; // Information about instruction/operand encoding
|
||||
char *desc = NULL; // String representation of encode rule
|
||||
|
||||
_AD.getForm(&encBlock);
|
||||
if ( encBlock == NULL) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
//
|
||||
// Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
// 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
|
||||
@ -911,12 +911,24 @@ const char *ArchDesc::getIdealType(const char *idealOp) {
|
||||
// Find last character in idealOp, it specifies the type
|
||||
char last_char = 0;
|
||||
const char *ptr = idealOp;
|
||||
for( ; *ptr != '\0'; ++ptr) {
|
||||
for (; *ptr != '\0'; ++ptr) {
|
||||
last_char = *ptr;
|
||||
}
|
||||
|
||||
// Match Vector types.
|
||||
if (strncmp(idealOp, "Vec",3)==0) {
|
||||
switch(last_char) {
|
||||
case 'S': return "TypeVect::VECTS";
|
||||
case 'D': return "TypeVect::VECTD";
|
||||
case 'X': return "TypeVect::VECTX";
|
||||
case 'Y': return "TypeVect::VECTY";
|
||||
default:
|
||||
internal_err("Vector type %s with unrecognized type\n",idealOp);
|
||||
}
|
||||
}
|
||||
|
||||
// !!!!!
|
||||
switch( last_char ) {
|
||||
switch(last_char) {
|
||||
case 'I': return "TypeInt::INT";
|
||||
case 'P': return "TypePtr::BOTTOM";
|
||||
case 'N': return "TypeNarrowOop::BOTTOM";
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -265,47 +265,22 @@ Form::DataType Form::is_load_from_memory(const char *opType) const {
|
||||
if( strcmp(opType,"LoadN")==0 ) return Form::idealN;
|
||||
if( strcmp(opType,"LoadRange")==0 ) return Form::idealI;
|
||||
if( strcmp(opType,"LoadS")==0 ) return Form::idealS;
|
||||
if( strcmp(opType,"Load16B")==0 ) return Form::idealB;
|
||||
if( strcmp(opType,"Load8B")==0 ) return Form::idealB;
|
||||
if( strcmp(opType,"Load4B")==0 ) return Form::idealB;
|
||||
if( strcmp(opType,"Load8C")==0 ) return Form::idealC;
|
||||
if( strcmp(opType,"Load4C")==0 ) return Form::idealC;
|
||||
if( strcmp(opType,"Load2C")==0 ) return Form::idealC;
|
||||
if( strcmp(opType,"Load8S")==0 ) return Form::idealS;
|
||||
if( strcmp(opType,"Load4S")==0 ) return Form::idealS;
|
||||
if( strcmp(opType,"Load2S")==0 ) return Form::idealS;
|
||||
if( strcmp(opType,"Load2D")==0 ) return Form::idealD;
|
||||
if( strcmp(opType,"Load4F")==0 ) return Form::idealF;
|
||||
if( strcmp(opType,"Load2F")==0 ) return Form::idealF;
|
||||
if( strcmp(opType,"Load4I")==0 ) return Form::idealI;
|
||||
if( strcmp(opType,"Load2I")==0 ) return Form::idealI;
|
||||
if( strcmp(opType,"Load2L")==0 ) return Form::idealL;
|
||||
if( strcmp(opType,"LoadVector")==0 ) return Form::idealV;
|
||||
assert( strcmp(opType,"Load") != 0, "Must type Loads" );
|
||||
return Form::none;
|
||||
}
|
||||
|
||||
Form::DataType Form::is_store_to_memory(const char *opType) const {
|
||||
if( strcmp(opType,"StoreB")==0) return Form::idealB;
|
||||
if( strcmp(opType,"StoreCM")==0) return Form::idealB;
|
||||
if( strcmp(opType,"StoreCM")==0) return Form::idealB;
|
||||
if( strcmp(opType,"StoreC")==0) return Form::idealC;
|
||||
if( strcmp(opType,"StoreD")==0) return Form::idealD;
|
||||
if( strcmp(opType,"StoreF")==0) return Form::idealF;
|
||||
if( strcmp(opType,"StoreI")==0) return Form::idealI;
|
||||
if( strcmp(opType,"StoreL")==0) return Form::idealL;
|
||||
if( strcmp(opType,"StoreP")==0) return Form::idealP;
|
||||
if( strcmp(opType,"StoreN")==0) return Form::idealN;
|
||||
if( strcmp(opType,"Store16B")==0) return Form::idealB;
|
||||
if( strcmp(opType,"Store8B")==0) return Form::idealB;
|
||||
if( strcmp(opType,"Store4B")==0) return Form::idealB;
|
||||
if( strcmp(opType,"Store8C")==0) return Form::idealC;
|
||||
if( strcmp(opType,"Store4C")==0) return Form::idealC;
|
||||
if( strcmp(opType,"Store2C")==0) return Form::idealC;
|
||||
if( strcmp(opType,"Store2D")==0) return Form::idealD;
|
||||
if( strcmp(opType,"Store4F")==0) return Form::idealF;
|
||||
if( strcmp(opType,"Store2F")==0) return Form::idealF;
|
||||
if( strcmp(opType,"Store4I")==0) return Form::idealI;
|
||||
if( strcmp(opType,"Store2I")==0) return Form::idealI;
|
||||
if( strcmp(opType,"Store2L")==0) return Form::idealL;
|
||||
if( strcmp(opType,"StoreN")==0) return Form::idealN;
|
||||
if( strcmp(opType,"StoreVector")==0 ) return Form::idealV;
|
||||
assert( strcmp(opType,"Store") != 0, "Must type Stores" );
|
||||
return Form::none;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -172,7 +172,8 @@ public:
|
||||
idealB = 6, // Byte type
|
||||
idealC = 7, // Char type
|
||||
idealS = 8, // String type
|
||||
idealN = 9 // Narrow oop types
|
||||
idealN = 9, // Narrow oop types
|
||||
idealV = 10 // Vector type
|
||||
};
|
||||
// Convert ideal name to a DataType, return DataType::none if not a 'ConX'
|
||||
Form::DataType ideal_to_const_type(const char *ideal_type_name) const;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, 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
|
||||
@ -66,7 +66,7 @@ AllocClass *RegisterForm::addAllocClass(char *className) {
|
||||
// for spill-slots/regs.
|
||||
void RegisterForm::addSpillRegClass() {
|
||||
// Stack slots start at the next available even register number.
|
||||
_reg_ctr = (_reg_ctr+1) & ~1;
|
||||
_reg_ctr = (_reg_ctr+7) & ~7;
|
||||
const char *rc_name = "stack_slots";
|
||||
RegClass *reg_class = new RegClass(rc_name);
|
||||
reg_class->_stack_or_reg = true;
|
||||
@ -150,9 +150,14 @@ bool RegisterForm::verify() {
|
||||
int RegisterForm::RegMask_Size() {
|
||||
// Need at least this many words
|
||||
int words_for_regs = (_reg_ctr + 31)>>5;
|
||||
// Add a few for incoming & outgoing arguments to calls.
|
||||
// The array of Register Mask bits should be large enough to cover
|
||||
// all the machine registers and all parameters that need to be passed
|
||||
// on the stack (stack registers) up to some interesting limit. Methods
|
||||
// that need more parameters will NOT be compiled. On Intel, the limit
|
||||
// is something like 90+ parameters.
|
||||
// Add a few (3 words == 96 bits) for incoming & outgoing arguments to calls.
|
||||
// Round up to the next doubleword size.
|
||||
return (words_for_regs + 2 + 1) & ~1;
|
||||
return (words_for_regs + 3 + 1) & ~1;
|
||||
}
|
||||
|
||||
void RegisterForm::dump() { // Debug printer
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, 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
|
||||
@ -432,6 +432,14 @@ Form::DataType InstructForm::is_ideal_store() const {
|
||||
return _matrule->is_ideal_store();
|
||||
}
|
||||
|
||||
// Return 'true' if this instruction matches an ideal vector node
|
||||
bool InstructForm::is_vector() const {
|
||||
if( _matrule == NULL ) return false;
|
||||
|
||||
return _matrule->is_vector();
|
||||
}
|
||||
|
||||
|
||||
// Return the input register that must match the output register
|
||||
// If this is not required, return 0
|
||||
uint InstructForm::two_address(FormDict &globals) {
|
||||
@ -751,6 +759,9 @@ bool InstructForm::captures_bottom_type(FormDict &globals) const {
|
||||
|
||||
if (needs_base_oop_edge(globals)) return true;
|
||||
|
||||
if (is_vector()) return true;
|
||||
if (is_mach_constant()) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -3381,11 +3392,8 @@ int MatchNode::needs_ideal_memory_edge(FormDict &globals) const {
|
||||
"StoreI","StoreL","StoreP","StoreN","StoreD","StoreF" ,
|
||||
"StoreB","StoreC","Store" ,"StoreFP",
|
||||
"LoadI", "LoadUI2L", "LoadL", "LoadP" ,"LoadN", "LoadD" ,"LoadF" ,
|
||||
"LoadB" , "LoadUB", "LoadUS" ,"LoadS" ,"Load" ,
|
||||
"Store4I","Store2I","Store2L","Store2D","Store4F","Store2F","Store16B",
|
||||
"Store8B","Store4B","Store8C","Store4C","Store2C",
|
||||
"Load4I" ,"Load2I" ,"Load2L" ,"Load2D" ,"Load4F" ,"Load2F" ,"Load16B" ,
|
||||
"Load8B" ,"Load4B" ,"Load8C" ,"Load4C" ,"Load2C" ,"Load8S", "Load4S","Load2S",
|
||||
"LoadB" , "LoadUB", "LoadUS" ,"LoadS" ,"Load" ,
|
||||
"StoreVector", "LoadVector",
|
||||
"LoadRange", "LoadKlass", "LoadNKlass", "LoadL_unaligned", "LoadD_unaligned",
|
||||
"LoadPLocked",
|
||||
"StorePConditional", "StoreIConditional", "StoreLConditional",
|
||||
@ -3822,6 +3830,10 @@ bool MatchRule::is_base_register(FormDict &globals) const {
|
||||
strcmp(opType,"RegL")==0 ||
|
||||
strcmp(opType,"RegF")==0 ||
|
||||
strcmp(opType,"RegD")==0 ||
|
||||
strcmp(opType,"VecS")==0 ||
|
||||
strcmp(opType,"VecD")==0 ||
|
||||
strcmp(opType,"VecX")==0 ||
|
||||
strcmp(opType,"VecY")==0 ||
|
||||
strcmp(opType,"Reg" )==0) ) {
|
||||
return 1;
|
||||
}
|
||||
@ -3938,19 +3950,12 @@ int MatchRule::is_expensive() const {
|
||||
strcmp(opType,"ReverseBytesL")==0 ||
|
||||
strcmp(opType,"ReverseBytesUS")==0 ||
|
||||
strcmp(opType,"ReverseBytesS")==0 ||
|
||||
strcmp(opType,"Replicate16B")==0 ||
|
||||
strcmp(opType,"Replicate8B")==0 ||
|
||||
strcmp(opType,"Replicate4B")==0 ||
|
||||
strcmp(opType,"Replicate8C")==0 ||
|
||||
strcmp(opType,"Replicate4C")==0 ||
|
||||
strcmp(opType,"Replicate8S")==0 ||
|
||||
strcmp(opType,"Replicate4S")==0 ||
|
||||
strcmp(opType,"Replicate4I")==0 ||
|
||||
strcmp(opType,"Replicate2I")==0 ||
|
||||
strcmp(opType,"Replicate2L")==0 ||
|
||||
strcmp(opType,"Replicate4F")==0 ||
|
||||
strcmp(opType,"Replicate2F")==0 ||
|
||||
strcmp(opType,"Replicate2D")==0 ||
|
||||
strcmp(opType,"ReplicateB")==0 ||
|
||||
strcmp(opType,"ReplicateS")==0 ||
|
||||
strcmp(opType,"ReplicateI")==0 ||
|
||||
strcmp(opType,"ReplicateL")==0 ||
|
||||
strcmp(opType,"ReplicateF")==0 ||
|
||||
strcmp(opType,"ReplicateD")==0 ||
|
||||
0 /* 0 to line up columns nicely */ )
|
||||
return 1;
|
||||
}
|
||||
@ -4034,6 +4039,23 @@ Form::DataType MatchRule::is_ideal_load() const {
|
||||
return ideal_load;
|
||||
}
|
||||
|
||||
bool MatchRule::is_vector() const {
|
||||
if( _rChild ) {
|
||||
const char *opType = _rChild->_opType;
|
||||
if( strcmp(opType,"ReplicateB")==0 ||
|
||||
strcmp(opType,"ReplicateS")==0 ||
|
||||
strcmp(opType,"ReplicateI")==0 ||
|
||||
strcmp(opType,"ReplicateL")==0 ||
|
||||
strcmp(opType,"ReplicateF")==0 ||
|
||||
strcmp(opType,"ReplicateD")==0 ||
|
||||
strcmp(opType,"LoadVector")==0 ||
|
||||
strcmp(opType,"StoreVector")==0 ||
|
||||
0 /* 0 to line up columns nicely */ )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool MatchRule::skip_antidep_check() const {
|
||||
// Some loads operate on what is effectively immutable memory so we
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, 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
|
||||
@ -160,6 +160,7 @@ public:
|
||||
virtual bool is_ideal_safepoint() const; // node matches 'SafePoint'
|
||||
virtual bool is_ideal_nop() const; // node matches 'Nop'
|
||||
virtual bool is_ideal_control() const; // control node
|
||||
virtual bool is_vector() const; // vector instruction
|
||||
|
||||
virtual Form::CallType is_ideal_call() const; // matches ideal 'Call'
|
||||
virtual Form::DataType is_ideal_load() const; // node matches ideal 'LoadXNode'
|
||||
@ -1011,6 +1012,7 @@ public:
|
||||
bool is_ideal_goto() const; // node matches ideal 'Goto'
|
||||
bool is_ideal_loopEnd() const; // node matches ideal 'LoopEnd'
|
||||
bool is_ideal_bool() const; // node matches ideal 'Bool'
|
||||
bool is_vector() const; // vector instruction
|
||||
Form::DataType is_ideal_load() const;// node matches ideal 'LoadXNode'
|
||||
// Should antidep checks be disabled for this rule
|
||||
// See definition of MatchRule::skip_antidep_check
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -250,6 +250,7 @@ int main(int argc, char *argv[])
|
||||
AD.addInclude(AD._HPP_file, "opto/node.hpp");
|
||||
AD.addInclude(AD._HPP_file, "opto/regalloc.hpp");
|
||||
AD.addInclude(AD._HPP_file, "opto/subnode.hpp");
|
||||
AD.addInclude(AD._HPP_file, "opto/vectornode.hpp");
|
||||
AD.addInclude(AD._CPP_CLONE_file, "precompiled.hpp");
|
||||
AD.addInclude(AD._CPP_CLONE_file, "adfiles", get_basename(AD._HPP_file._name));
|
||||
AD.addInclude(AD._CPP_EXPAND_file, "precompiled.hpp");
|
||||
|
304
hotspot/src/share/vm/classfile/altHashing.cpp
Normal file
304
hotspot/src/share/vm/classfile/altHashing.cpp
Normal file
@ -0,0 +1,304 @@
|
||||
/*
|
||||
* 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/altHashing.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "oops/markOop.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
|
||||
// Get the hash code of the classes mirror if it exists, otherwise just
|
||||
// return a random number, which is one of the possible hash code used for
|
||||
// objects. We don't want to call the synchronizer hash code to install
|
||||
// this value because it may safepoint.
|
||||
intptr_t object_hash(klassOop k) {
|
||||
intptr_t hc = k->java_mirror()->mark()->hash();
|
||||
return hc != markOopDesc::no_hash ? hc : os::random();
|
||||
}
|
||||
|
||||
// Seed value used for each alternative hash calculated.
|
||||
jint AltHashing::compute_seed() {
|
||||
jlong nanos = os::javaTimeNanos();
|
||||
jlong now = os::javaTimeMillis();
|
||||
jint SEED_MATERIAL[8] = {
|
||||
(jint) object_hash(SystemDictionary::String_klass()),
|
||||
(jint) object_hash(SystemDictionary::System_klass()),
|
||||
(jint) os::random(), // current thread isn't a java thread
|
||||
(jint) (((julong)nanos) >> 32),
|
||||
(jint) nanos,
|
||||
(jint) (((julong)now) >> 32),
|
||||
(jint) now,
|
||||
(jint) (os::javaTimeNanos() >> 2)
|
||||
};
|
||||
|
||||
return murmur3_32(SEED_MATERIAL, 8);
|
||||
}
|
||||
|
||||
|
||||
// Murmur3 hashing for Symbol
|
||||
jint AltHashing::murmur3_32(jint seed, const jbyte* data, int len) {
|
||||
jint h1 = seed;
|
||||
int count = len;
|
||||
int offset = 0;
|
||||
|
||||
// body
|
||||
while (count >= 4) {
|
||||
jint k1 = (data[offset] & 0x0FF)
|
||||
| (data[offset + 1] & 0x0FF) << 8
|
||||
| (data[offset + 2] & 0x0FF) << 16
|
||||
| data[offset + 3] << 24;
|
||||
|
||||
count -= 4;
|
||||
offset += 4;
|
||||
|
||||
k1 *= 0xcc9e2d51;
|
||||
k1 = Integer_rotateLeft(k1, 15);
|
||||
k1 *= 0x1b873593;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = Integer_rotateLeft(h1, 13);
|
||||
h1 = h1 * 5 + 0xe6546b64;
|
||||
}
|
||||
|
||||
// tail
|
||||
|
||||
if (count > 0) {
|
||||
jint k1 = 0;
|
||||
|
||||
switch (count) {
|
||||
case 3:
|
||||
k1 ^= (data[offset + 2] & 0xff) << 16;
|
||||
// fall through
|
||||
case 2:
|
||||
k1 ^= (data[offset + 1] & 0xff) << 8;
|
||||
// fall through
|
||||
case 1:
|
||||
k1 ^= (data[offset] & 0xff);
|
||||
// fall through
|
||||
default:
|
||||
k1 *= 0xcc9e2d51;
|
||||
k1 = Integer_rotateLeft(k1, 15);
|
||||
k1 *= 0x1b873593;
|
||||
h1 ^= k1;
|
||||
}
|
||||
}
|
||||
|
||||
// finalization
|
||||
h1 ^= len;
|
||||
|
||||
// finalization mix force all bits of a hash block to avalanche
|
||||
h1 ^= ((unsigned int)h1) >> 16;
|
||||
h1 *= 0x85ebca6b;
|
||||
h1 ^= ((unsigned int)h1) >> 13;
|
||||
h1 *= 0xc2b2ae35;
|
||||
h1 ^= ((unsigned int)h1) >> 16;
|
||||
|
||||
return h1;
|
||||
}
|
||||
|
||||
// Murmur3 hashing for Strings
|
||||
jint AltHashing::murmur3_32(jint seed, const jchar* data, int len) {
|
||||
jint h1 = seed;
|
||||
|
||||
int off = 0;
|
||||
int count = len;
|
||||
|
||||
// body
|
||||
while (count >= 2) {
|
||||
jchar d1 = data[off++] & 0xFFFF;
|
||||
jchar d2 = data[off++];
|
||||
jint k1 = (d1 | d2 << 16);
|
||||
|
||||
count -= 2;
|
||||
|
||||
k1 *= 0xcc9e2d51;
|
||||
k1 = Integer_rotateLeft(k1, 15);
|
||||
k1 *= 0x1b873593;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = Integer_rotateLeft(h1, 13);
|
||||
h1 = h1 * 5 + 0xe6546b64;
|
||||
}
|
||||
|
||||
// tail
|
||||
|
||||
if (count > 0) {
|
||||
int k1 = data[off];
|
||||
|
||||
k1 *= 0xcc9e2d51;
|
||||
k1 = Integer_rotateLeft(k1, 15);
|
||||
k1 *= 0x1b873593;
|
||||
h1 ^= k1;
|
||||
}
|
||||
|
||||
// finalization
|
||||
h1 ^= len * 2; // (Character.SIZE / Byte.SIZE);
|
||||
|
||||
// finalization mix force all bits of a hash block to avalanche
|
||||
h1 ^= ((unsigned int)h1) >> 16;
|
||||
h1 *= 0x85ebca6b;
|
||||
h1 ^= ((unsigned int)h1) >> 13;
|
||||
h1 *= 0xc2b2ae35;
|
||||
h1 ^= ((unsigned int)h1) >> 16;
|
||||
|
||||
return h1;
|
||||
}
|
||||
|
||||
// Hash used for the seed.
|
||||
jint AltHashing::murmur3_32(jint seed, const int* data, int len) {
|
||||
jint h1 = seed;
|
||||
|
||||
int off = 0;
|
||||
int end = len;
|
||||
|
||||
// body
|
||||
while (off < end) {
|
||||
jint k1 = data[off++];
|
||||
|
||||
k1 *= 0xcc9e2d51;
|
||||
k1 = Integer_rotateLeft(k1, 15);
|
||||
k1 *= 0x1b873593;
|
||||
|
||||
h1 ^= k1;
|
||||
h1 = Integer_rotateLeft(h1, 13);
|
||||
h1 = h1 * 5 + 0xe6546b64;
|
||||
}
|
||||
|
||||
// tail (always empty, as body is always 32-bit chunks)
|
||||
|
||||
// finalization
|
||||
|
||||
h1 ^= len * 4; // (Integer.SIZE / Byte.SIZE);
|
||||
|
||||
// finalization mix force all bits of a hash block to avalanche
|
||||
h1 ^= ((juint)h1) >> 16;
|
||||
h1 *= 0x85ebca6b;
|
||||
h1 ^= ((juint)h1) >> 13;
|
||||
h1 *= 0xc2b2ae35;
|
||||
h1 ^= ((juint)h1) >> 16;
|
||||
|
||||
return h1;
|
||||
}
|
||||
|
||||
jint AltHashing::murmur3_32(const int* data, int len) {
|
||||
return murmur3_32(0, data, len);
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
// Overloaded versions for internal test.
|
||||
jint AltHashing::murmur3_32(const jbyte* data, int len) {
|
||||
return murmur3_32(0, data, len);
|
||||
}
|
||||
|
||||
jint AltHashing::murmur3_32(const jchar* data, int len) {
|
||||
return murmur3_32(0, data, len);
|
||||
}
|
||||
|
||||
// Internal test for alternate hashing. Translated from JDK version
|
||||
// test/sun/misc/Hashing.java
|
||||
static const jbyte ONE_BYTE[] = { (jbyte) 0x80};
|
||||
static const jbyte TWO_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81};
|
||||
static const jchar ONE_CHAR[] = { (jchar) 0x8180};
|
||||
static const jbyte THREE_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82};
|
||||
static const jbyte FOUR_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, (jbyte) 0x83};
|
||||
static const jchar TWO_CHAR[] = { (jchar) 0x8180, (jchar) 0x8382};
|
||||
static const jint ONE_INT[] = { 0x83828180};
|
||||
static const jbyte SIX_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, (jbyte) 0x83, (jbyte) 0x84, (jbyte) 0x85};
|
||||
static const jchar THREE_CHAR[] = { (jchar) 0x8180, (jchar) 0x8382, (jchar) 0x8584};
|
||||
static const jbyte EIGHT_BYTE[] = {
|
||||
(jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82,
|
||||
(jbyte) 0x83, (jbyte) 0x84, (jbyte) 0x85,
|
||||
(jbyte) 0x86, (jbyte) 0x87};
|
||||
static const jchar FOUR_CHAR[] = {
|
||||
(jchar) 0x8180, (jchar) 0x8382,
|
||||
(jchar) 0x8584, (jchar) 0x8786};
|
||||
|
||||
static const jint TWO_INT[] = { 0x83828180, 0x87868584};
|
||||
|
||||
static const juint MURMUR3_32_X86_CHECK_VALUE = 0xB0F57EE3;
|
||||
|
||||
void AltHashing::testMurmur3_32_ByteArray() {
|
||||
// printf("testMurmur3_32_ByteArray\n");
|
||||
|
||||
jbyte* vector = new jbyte[256];
|
||||
jbyte* hashes = new jbyte[4 * 256];
|
||||
|
||||
for (int i = 0; i < 256; i++) {
|
||||
vector[i] = (jbyte) i;
|
||||
}
|
||||
|
||||
// Hash subranges {}, {0}, {0,1}, {0,1,2}, ..., {0,...,255}
|
||||
for (int i = 0; i < 256; i++) {
|
||||
jint hash = murmur3_32(256 - i, vector, i);
|
||||
hashes[i * 4] = (jbyte) hash;
|
||||
hashes[i * 4 + 1] = (jbyte) (((juint)hash) >> 8);
|
||||
hashes[i * 4 + 2] = (jbyte) (((juint)hash) >> 16);
|
||||
hashes[i * 4 + 3] = (jbyte) (((juint)hash) >> 24);
|
||||
}
|
||||
|
||||
// hash to get const result.
|
||||
juint final_hash = murmur3_32(hashes, 4*256);
|
||||
|
||||
assert (MURMUR3_32_X86_CHECK_VALUE == final_hash,
|
||||
err_msg(
|
||||
"Calculated hash result not as expected. Expected %08X got %08X\n",
|
||||
MURMUR3_32_X86_CHECK_VALUE,
|
||||
final_hash));
|
||||
}
|
||||
|
||||
void AltHashing::testEquivalentHashes() {
|
||||
jint jbytes, jchars, ints;
|
||||
|
||||
// printf("testEquivalentHashes\n");
|
||||
|
||||
jbytes = murmur3_32(TWO_BYTE, 2);
|
||||
jchars = murmur3_32(ONE_CHAR, 1);
|
||||
assert (jbytes == jchars,
|
||||
err_msg("Hashes did not match. b:%08x != c:%08x\n", jbytes, jchars));
|
||||
|
||||
jbytes = murmur3_32(FOUR_BYTE, 4);
|
||||
jchars = murmur3_32(TWO_CHAR, 2);
|
||||
ints = murmur3_32(ONE_INT, 1);
|
||||
assert ((jbytes == jchars) && (jbytes == ints),
|
||||
err_msg("Hashes did not match. b:%08x != c:%08x != i:%08x\n", jbytes, jchars, ints));
|
||||
|
||||
jbytes = murmur3_32(SIX_BYTE, 6);
|
||||
jchars = murmur3_32(THREE_CHAR, 3);
|
||||
assert (jbytes == jchars,
|
||||
err_msg("Hashes did not match. b:%08x != c:%08x\n", jbytes, jchars));
|
||||
|
||||
jbytes = murmur3_32(EIGHT_BYTE, 8);
|
||||
jchars = murmur3_32(FOUR_CHAR, 4);
|
||||
ints = murmur3_32(TWO_INT, 2);
|
||||
assert ((jbytes == jchars) && (jbytes == ints),
|
||||
err_msg("Hashes did not match. b:%08x != c:%08x != i:%08x\n", jbytes, jchars, ints));
|
||||
}
|
||||
|
||||
// Returns true if the alternate hashcode is correct
|
||||
void AltHashing::test_alt_hash() {
|
||||
testMurmur3_32_ByteArray();
|
||||
testEquivalentHashes();
|
||||
}
|
||||
#endif // PRODUCT
|
62
hotspot/src/share/vm/classfile/altHashing.hpp
Normal file
62
hotspot/src/share/vm/classfile/altHashing.hpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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_ALTHASHING_HPP
|
||||
#define SHARE_VM_CLASSFILE_ALTHASHING_HPP
|
||||
|
||||
#include "prims/jni.h"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
|
||||
/**
|
||||
* Hashing utilities.
|
||||
*
|
||||
* Implementation of Murmur3 hashing.
|
||||
* This code was translated from src/share/classes/sun/misc/Hashing.java
|
||||
* code in the JDK.
|
||||
*/
|
||||
|
||||
class AltHashing : AllStatic {
|
||||
|
||||
// utility function copied from java/lang/Integer
|
||||
static jint Integer_rotateLeft(jint i, int distance) {
|
||||
return (i << distance) | (((juint)i) >> (32-distance));
|
||||
}
|
||||
static jint murmur3_32(const int* data, int len);
|
||||
static jint murmur3_32(jint seed, const int* data, int len);
|
||||
|
||||
#ifndef PRODUCT
|
||||
// Hashing functions used for internal testing
|
||||
static jint murmur3_32(const jbyte* data, int len);
|
||||
static jint murmur3_32(const jchar* data, int len);
|
||||
static void testMurmur3_32_ByteArray();
|
||||
static void testEquivalentHashes();
|
||||
#endif // PRODUCT
|
||||
|
||||
public:
|
||||
static jint compute_seed();
|
||||
static jint murmur3_32(jint seed, const jbyte* data, int len);
|
||||
static jint murmur3_32(jint seed, const jchar* data, int len);
|
||||
NOT_PRODUCT(static void test_alt_hash();)
|
||||
};
|
||||
#endif // SHARE_VM_CLASSFILE_ALTHASHING_HPP
|
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/altHashing.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
@ -347,13 +348,26 @@ jchar* java_lang_String::as_unicode_string(oop java_string, int& length) {
|
||||
return result;
|
||||
}
|
||||
|
||||
unsigned int java_lang_String::hash_string(oop java_string) {
|
||||
unsigned int java_lang_String::to_hash(oop java_string) {
|
||||
int length = java_lang_String::length(java_string);
|
||||
// Zero length string will hash to zero with String.toHash() function.
|
||||
if (length == 0) return 0;
|
||||
|
||||
typeArrayOop value = java_lang_String::value(java_string);
|
||||
int offset = java_lang_String::offset(java_string);
|
||||
int length = java_lang_String::length(java_string);
|
||||
return java_lang_String::to_hash(value->char_at_addr(offset), length);
|
||||
}
|
||||
|
||||
if (length == 0) return 0;
|
||||
return hash_string(value->char_at_addr(offset), length);
|
||||
unsigned int java_lang_String::hash_string(oop java_string) {
|
||||
int length = java_lang_String::length(java_string);
|
||||
// Zero length string doesn't hash necessarily hash to zero.
|
||||
if (length == 0) {
|
||||
return StringTable::hash_string(NULL, 0);
|
||||
}
|
||||
|
||||
typeArrayOop value = java_lang_String::value(java_string);
|
||||
int offset = java_lang_String::offset(java_string);
|
||||
return StringTable::hash_string(value->char_at_addr(offset), length);
|
||||
}
|
||||
|
||||
Symbol* java_lang_String::as_symbol(Handle java_string, TRAPS) {
|
||||
|
@ -158,20 +158,16 @@ class java_lang_String : AllStatic {
|
||||
static jchar* as_unicode_string(oop java_string, int& length);
|
||||
|
||||
// Compute the hash value for a java.lang.String object which would
|
||||
// contain the characters passed in. This hash value is used for at
|
||||
// least two purposes.
|
||||
// contain the characters passed in.
|
||||
//
|
||||
// (a) As the hash value used by the StringTable for bucket selection
|
||||
// and comparison (stored in the HashtableEntry structures). This
|
||||
// is used in the String.intern() method.
|
||||
// As the hash value used by the String object itself, in
|
||||
// String.hashCode(). This value is normally calculated in Java code
|
||||
// in the String.hashCode method(), but is precomputed for String
|
||||
// objects in the shared archive file.
|
||||
// hash P(31) from Kernighan & Ritchie
|
||||
//
|
||||
// (b) As the hash value used by the String object itself, in
|
||||
// String.hashCode(). This value is normally calculate in Java code
|
||||
// in the String.hashCode method(), but is precomputed for String
|
||||
// objects in the shared archive file.
|
||||
//
|
||||
// For this reason, THIS ALGORITHM MUST MATCH String.hashCode().
|
||||
static unsigned int hash_string(jchar* s, int len) {
|
||||
// For this reason, THIS ALGORITHM MUST MATCH String.toHash().
|
||||
template <typename T> static unsigned int to_hash(T* s, int len) {
|
||||
unsigned int h = 0;
|
||||
while (len-- > 0) {
|
||||
h = 31*h + (unsigned int) *s;
|
||||
@ -179,6 +175,10 @@ class java_lang_String : AllStatic {
|
||||
}
|
||||
return h;
|
||||
}
|
||||
static unsigned int to_hash(oop java_string);
|
||||
|
||||
// This is the string hash code used by the StringTable, which may be
|
||||
// the same as String.toHash or an alternate hash code.
|
||||
static unsigned int hash_string(oop java_string);
|
||||
|
||||
static bool equals(oop java_string, jchar* chars, int len);
|
||||
|
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/altHashing.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
@ -34,19 +35,19 @@
|
||||
#include "oops/oop.inline2.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "utilities/hashtable.inline.hpp"
|
||||
#include "utilities/numberSeq.hpp"
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
SymbolTable* SymbolTable::_the_table = NULL;
|
||||
// Static arena for symbols that are not deallocated
|
||||
Arena* SymbolTable::_arena = NULL;
|
||||
bool SymbolTable::_needs_rehashing = false;
|
||||
jint SymbolTable::_seed = 0;
|
||||
|
||||
Symbol* SymbolTable::allocate_symbol(const u1* name, int len, bool c_heap, TRAPS) {
|
||||
// Don't allow symbols to be created which cannot fit in a Symbol*.
|
||||
if (len > Symbol::max_length()) {
|
||||
THROW_MSG_0(vmSymbols::java_lang_InternalError(),
|
||||
"name is too long to represent");
|
||||
}
|
||||
assert (len <= Symbol::max_length(), "should be checked by caller");
|
||||
|
||||
Symbol* sym;
|
||||
// Allocate symbols in the C heap when dumping shared spaces in case there
|
||||
// are temporary symbols we can remove.
|
||||
@ -91,9 +92,14 @@ void SymbolTable::unlink() {
|
||||
int total = 0;
|
||||
size_t memory_total = 0;
|
||||
for (int i = 0; i < the_table()->table_size(); ++i) {
|
||||
for (HashtableEntry<Symbol*>** p = the_table()->bucket_addr(i); *p != NULL; ) {
|
||||
HashtableEntry<Symbol*>* entry = *p;
|
||||
if (entry->is_shared()) {
|
||||
HashtableEntry<Symbol*>** p = the_table()->bucket_addr(i);
|
||||
HashtableEntry<Symbol*>* entry = the_table()->bucket(i);
|
||||
while (entry != NULL) {
|
||||
// Shared entries are normally at the end of the bucket and if we run into
|
||||
// a shared entry, then there is nothing more to remove. However, if we
|
||||
// have rehashed the table, then the shared entries are no longer at the
|
||||
// end of the bucket.
|
||||
if (entry->is_shared() && !use_alternate_hashcode()) {
|
||||
break;
|
||||
}
|
||||
Symbol* s = entry->literal();
|
||||
@ -102,6 +108,7 @@ void SymbolTable::unlink() {
|
||||
assert(s != NULL, "just checking");
|
||||
// If reference count is zero, remove.
|
||||
if (s->refcount() == 0) {
|
||||
assert(!entry->is_shared(), "shared entries should be kept live");
|
||||
delete s;
|
||||
removed++;
|
||||
*p = entry->next();
|
||||
@ -109,6 +116,8 @@ void SymbolTable::unlink() {
|
||||
} else {
|
||||
p = entry->next_addr();
|
||||
}
|
||||
// get next entry
|
||||
entry = (HashtableEntry<Symbol*>*)HashtableEntry<Symbol*>::make_ptr(*p);
|
||||
}
|
||||
}
|
||||
symbols_removed += removed;
|
||||
@ -121,12 +130,42 @@ void SymbolTable::unlink() {
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int SymbolTable::new_hash(Symbol* sym) {
|
||||
ResourceMark rm;
|
||||
// Use alternate hashing algorithm on this symbol.
|
||||
return AltHashing::murmur3_32(seed(), (const jbyte*)sym->as_C_string(), sym->utf8_length());
|
||||
}
|
||||
|
||||
// Create a new table and using alternate hash code, populate the new table
|
||||
// with the existing strings. Set flag to use the alternate hash code afterwards.
|
||||
void SymbolTable::rehash_table() {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
||||
// This should never happen with -Xshare:dump but it might in testing mode.
|
||||
if (DumpSharedSpaces) return;
|
||||
// Create a new symbol table
|
||||
SymbolTable* new_table = new SymbolTable();
|
||||
|
||||
// Initialize the global seed for hashing.
|
||||
_seed = AltHashing::compute_seed();
|
||||
assert(seed() != 0, "shouldn't be zero");
|
||||
|
||||
the_table()->move_to(new_table);
|
||||
|
||||
// Delete the table and buckets (entries are reused in new table).
|
||||
delete _the_table;
|
||||
// Don't check if we need rehashing until the table gets unbalanced again.
|
||||
// Then rehash with a new global seed.
|
||||
_needs_rehashing = false;
|
||||
_the_table = new_table;
|
||||
}
|
||||
|
||||
// Lookup a symbol in a bucket.
|
||||
|
||||
Symbol* SymbolTable::lookup(int index, const char* name,
|
||||
int len, unsigned int hash) {
|
||||
int count = 0;
|
||||
for (HashtableEntry<Symbol*>* e = bucket(index); e != NULL; e = e->next()) {
|
||||
count++; // count all entries in this bucket, not just ones with same hash
|
||||
if (e->hash() == hash) {
|
||||
Symbol* sym = e->literal();
|
||||
if (sym->equals(name, len)) {
|
||||
@ -136,9 +175,20 @@ Symbol* SymbolTable::lookup(int index, const char* name,
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the bucket size is too deep check if this hash code is insufficient.
|
||||
if (count >= BasicHashtable::rehash_count && !needs_rehashing()) {
|
||||
_needs_rehashing = check_rehash_table(count);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Pick hashing algorithm.
|
||||
unsigned int SymbolTable::hash_symbol(const char* s, int len) {
|
||||
return use_alternate_hashcode() ?
|
||||
AltHashing::murmur3_32(seed(), (const jbyte*)s, len) :
|
||||
java_lang_String::to_hash(s, len);
|
||||
}
|
||||
|
||||
|
||||
// We take care not to be blocking while holding the
|
||||
// SymbolTable_lock. Otherwise, the system might deadlock, since the
|
||||
@ -156,6 +206,9 @@ Symbol* SymbolTable::lookup(const char* name, int len, TRAPS) {
|
||||
// Found
|
||||
if (s != NULL) return s;
|
||||
|
||||
// Grab SymbolTable_lock first.
|
||||
MutexLocker ml(SymbolTable_lock, THREAD);
|
||||
|
||||
// Otherwise, add to symbol to table
|
||||
return the_table()->basic_add(index, (u1*)name, len, hashValue, true, CHECK_NULL);
|
||||
}
|
||||
@ -193,6 +246,9 @@ Symbol* SymbolTable::lookup(const Symbol* sym, int begin, int end, TRAPS) {
|
||||
// We can't include the code in No_Safepoint_Verifier because of the
|
||||
// ResourceMark.
|
||||
|
||||
// Grab SymbolTable_lock first.
|
||||
MutexLocker ml(SymbolTable_lock, THREAD);
|
||||
|
||||
return the_table()->basic_add(index, (u1*)buffer, len, hashValue, true, CHECK_NULL);
|
||||
}
|
||||
|
||||
@ -261,6 +317,9 @@ void SymbolTable::add(Handle class_loader, constantPoolHandle cp,
|
||||
int names_count,
|
||||
const char** names, int* lengths, int* cp_indices,
|
||||
unsigned int* hashValues, TRAPS) {
|
||||
// Grab SymbolTable_lock first.
|
||||
MutexLocker ml(SymbolTable_lock, THREAD);
|
||||
|
||||
SymbolTable* table = the_table();
|
||||
bool added = table->basic_add(class_loader, cp, names_count, names, lengths,
|
||||
cp_indices, hashValues, CHECK);
|
||||
@ -281,18 +340,39 @@ Symbol* SymbolTable::new_permanent_symbol(const char* name, TRAPS) {
|
||||
if (result != NULL) {
|
||||
return result;
|
||||
}
|
||||
// Grab SymbolTable_lock first.
|
||||
MutexLocker ml(SymbolTable_lock, THREAD);
|
||||
|
||||
SymbolTable* table = the_table();
|
||||
int index = table->hash_to_index(hash);
|
||||
return table->basic_add(index, (u1*)name, (int)strlen(name), hash, false, THREAD);
|
||||
}
|
||||
|
||||
Symbol* SymbolTable::basic_add(int index, u1 *name, int len,
|
||||
unsigned int hashValue, bool c_heap, TRAPS) {
|
||||
Symbol* SymbolTable::basic_add(int index_arg, u1 *name, int len,
|
||||
unsigned int hashValue_arg, bool c_heap, TRAPS) {
|
||||
assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(),
|
||||
"proposed name of symbol must be stable");
|
||||
|
||||
// Grab SymbolTable_lock first.
|
||||
MutexLocker ml(SymbolTable_lock, THREAD);
|
||||
// Don't allow symbols to be created which cannot fit in a Symbol*.
|
||||
if (len > Symbol::max_length()) {
|
||||
THROW_MSG_0(vmSymbols::java_lang_InternalError(),
|
||||
"name is too long to represent");
|
||||
}
|
||||
|
||||
// Cannot hit a safepoint in this function because the "this" pointer can move.
|
||||
No_Safepoint_Verifier nsv;
|
||||
|
||||
// Check if the symbol table has been rehashed, if so, need to recalculate
|
||||
// the hash value and index.
|
||||
unsigned int hashValue;
|
||||
int index;
|
||||
if (use_alternate_hashcode()) {
|
||||
hashValue = hash_symbol((const char*)name, len);
|
||||
index = hash_to_index(hashValue);
|
||||
} else {
|
||||
hashValue = hashValue_arg;
|
||||
index = index_arg;
|
||||
}
|
||||
|
||||
// Since look-up was done lock-free, we need to check if another
|
||||
// thread beat us in the race to insert the symbol.
|
||||
@ -328,14 +408,22 @@ bool SymbolTable::basic_add(Handle class_loader, constantPoolHandle cp,
|
||||
}
|
||||
}
|
||||
|
||||
// Hold SymbolTable_lock through the symbol creation
|
||||
MutexLocker ml(SymbolTable_lock, THREAD);
|
||||
// Cannot hit a safepoint in this function because the "this" pointer can move.
|
||||
No_Safepoint_Verifier nsv;
|
||||
|
||||
for (int i=0; i<names_count; i++) {
|
||||
// Check if the symbol table has been rehashed, if so, need to recalculate
|
||||
// the hash value.
|
||||
unsigned int hashValue;
|
||||
if (use_alternate_hashcode()) {
|
||||
hashValue = hash_symbol(names[i], lengths[i]);
|
||||
} else {
|
||||
hashValue = hashValues[i];
|
||||
}
|
||||
// Since look-up was done lock-free, we need to check if another
|
||||
// thread beat us in the race to insert the symbol.
|
||||
int index = hash_to_index(hashValues[i]);
|
||||
Symbol* test = lookup(index, names[i], lengths[i], hashValues[i]);
|
||||
int index = hash_to_index(hashValue);
|
||||
Symbol* test = lookup(index, names[i], lengths[i], hashValue);
|
||||
if (test != NULL) {
|
||||
// A race occurred and another thread introduced the symbol, this one
|
||||
// will be dropped and collected. Use test instead.
|
||||
@ -347,7 +435,7 @@ bool SymbolTable::basic_add(Handle class_loader, constantPoolHandle cp,
|
||||
bool c_heap = class_loader() != NULL;
|
||||
Symbol* sym = allocate_symbol((const u1*)names[i], lengths[i], c_heap, CHECK_(false));
|
||||
assert(sym->equals(names[i], lengths[i]), "symbol must be properly initialized"); // why wouldn't it be???
|
||||
HashtableEntry<Symbol*>* entry = new_entry(hashValues[i], sym);
|
||||
HashtableEntry<Symbol*>* entry = new_entry(hashValue, sym);
|
||||
add_entry(index, entry);
|
||||
cp->symbol_at_put(cp_indices[i], sym);
|
||||
}
|
||||
@ -370,6 +458,24 @@ void SymbolTable::verify() {
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolTable::dump(outputStream* st) {
|
||||
NumberSeq summary;
|
||||
for (int i = 0; i < the_table()->table_size(); ++i) {
|
||||
int count = 0;
|
||||
for (HashtableEntry<Symbol*>* e = the_table()->bucket(i);
|
||||
e != NULL; e = e->next()) {
|
||||
count++;
|
||||
}
|
||||
summary.add((double)count);
|
||||
}
|
||||
st->print_cr("SymbolTable statistics:");
|
||||
st->print_cr("Number of buckets : %7d", summary.num());
|
||||
st->print_cr("Average bucket size : %7.0f", summary.avg());
|
||||
st->print_cr("Variance of bucket size : %7.0f", summary.variance());
|
||||
st->print_cr("Std. dev. of bucket size: %7.0f", summary.sd());
|
||||
st->print_cr("Maximum bucket size : %7.0f", summary.maximum());
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Non-product code
|
||||
@ -468,7 +574,6 @@ void SymbolTable::print() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // PRODUCT
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
@ -514,38 +619,53 @@ class StableMemoryChecker : public StackObj {
|
||||
// --------------------------------------------------------------------------
|
||||
StringTable* StringTable::_the_table = NULL;
|
||||
|
||||
bool StringTable::_needs_rehashing = false;
|
||||
jint StringTable::_seed = 0;
|
||||
|
||||
// Pick hashing algorithm
|
||||
unsigned int StringTable::hash_string(const jchar* s, int len) {
|
||||
return use_alternate_hashcode() ? AltHashing::murmur3_32(seed(), s, len) :
|
||||
java_lang_String::to_hash(s, len);
|
||||
}
|
||||
|
||||
oop StringTable::lookup(int index, jchar* name,
|
||||
int len, unsigned int hash) {
|
||||
int count = 0;
|
||||
for (HashtableEntry<oop>* l = bucket(index); l != NULL; l = l->next()) {
|
||||
count++;
|
||||
if (l->hash() == hash) {
|
||||
if (java_lang_String::equals(l->literal(), name, len)) {
|
||||
return l->literal();
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the bucket size is too deep check if this hash code is insufficient.
|
||||
if (count >= BasicHashtable::rehash_count && !needs_rehashing()) {
|
||||
_needs_rehashing = check_rehash_table(count);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
oop StringTable::basic_add(int index, Handle string_or_null, jchar* name,
|
||||
int len, unsigned int hashValue, TRAPS) {
|
||||
debug_only(StableMemoryChecker smc(name, len * sizeof(name[0])));
|
||||
assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(),
|
||||
"proposed name of symbol must be stable");
|
||||
|
||||
Handle string;
|
||||
// try to reuse the string if possible
|
||||
if (!string_or_null.is_null() && (!JavaObjectsInPerm || string_or_null()->is_perm())) {
|
||||
string = string_or_null;
|
||||
} else {
|
||||
string = java_lang_String::create_tenured_from_unicode(name, len, CHECK_NULL);
|
||||
}
|
||||
|
||||
// Allocation must be done before grapping the SymbolTable_lock lock
|
||||
MutexLocker ml(StringTable_lock, THREAD);
|
||||
oop StringTable::basic_add(int index_arg, Handle string, jchar* name,
|
||||
int len, unsigned int hashValue_arg, TRAPS) {
|
||||
|
||||
assert(java_lang_String::equals(string(), name, len),
|
||||
"string must be properly initialized");
|
||||
// Cannot hit a safepoint in this function because the "this" pointer can move.
|
||||
No_Safepoint_Verifier nsv;
|
||||
|
||||
// Check if the symbol table has been rehashed, if so, need to recalculate
|
||||
// the hash value and index before second lookup.
|
||||
unsigned int hashValue;
|
||||
int index;
|
||||
if (use_alternate_hashcode()) {
|
||||
hashValue = hash_string(name, len);
|
||||
index = hash_to_index(hashValue);
|
||||
} else {
|
||||
hashValue = hashValue_arg;
|
||||
index = index_arg;
|
||||
}
|
||||
|
||||
// Since look-up was done lock-free, we need to check if another
|
||||
// thread beat us in the race to insert the symbol.
|
||||
@ -566,7 +686,7 @@ oop StringTable::lookup(Symbol* symbol) {
|
||||
ResourceMark rm;
|
||||
int length;
|
||||
jchar* chars = symbol->as_unicode(length);
|
||||
unsigned int hashValue = java_lang_String::hash_string(chars, length);
|
||||
unsigned int hashValue = hash_string(chars, length);
|
||||
int index = the_table()->hash_to_index(hashValue);
|
||||
return the_table()->lookup(index, chars, length, hashValue);
|
||||
}
|
||||
@ -574,15 +694,31 @@ oop StringTable::lookup(Symbol* symbol) {
|
||||
|
||||
oop StringTable::intern(Handle string_or_null, jchar* name,
|
||||
int len, TRAPS) {
|
||||
unsigned int hashValue = java_lang_String::hash_string(name, len);
|
||||
unsigned int hashValue = hash_string(name, len);
|
||||
int index = the_table()->hash_to_index(hashValue);
|
||||
oop string = the_table()->lookup(index, name, len, hashValue);
|
||||
oop found_string = the_table()->lookup(index, name, len, hashValue);
|
||||
|
||||
// Found
|
||||
if (string != NULL) return string;
|
||||
if (found_string != NULL) return found_string;
|
||||
|
||||
debug_only(StableMemoryChecker smc(name, len * sizeof(name[0])));
|
||||
assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(),
|
||||
"proposed name of symbol must be stable");
|
||||
|
||||
Handle string;
|
||||
// try to reuse the string if possible
|
||||
if (!string_or_null.is_null() && (!JavaObjectsInPerm || string_or_null()->is_perm())) {
|
||||
string = string_or_null;
|
||||
} else {
|
||||
string = java_lang_String::create_tenured_from_unicode(name, len, CHECK_NULL);
|
||||
}
|
||||
|
||||
// Grab the StringTable_lock before getting the_table() because it could
|
||||
// change at safepoint.
|
||||
MutexLocker ml(StringTable_lock, THREAD);
|
||||
|
||||
// Otherwise, add to symbol to table
|
||||
return the_table()->basic_add(index, string_or_null, name, len,
|
||||
return the_table()->basic_add(index, string, name, len,
|
||||
hashValue, CHECK_NULL);
|
||||
}
|
||||
|
||||
@ -625,18 +761,24 @@ void StringTable::unlink(BoolObjectClosure* is_alive) {
|
||||
// entries at a safepoint.
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
||||
for (int i = 0; i < the_table()->table_size(); ++i) {
|
||||
for (HashtableEntry<oop>** p = the_table()->bucket_addr(i); *p != NULL; ) {
|
||||
HashtableEntry<oop>* entry = *p;
|
||||
if (entry->is_shared()) {
|
||||
HashtableEntry<oop>** p = the_table()->bucket_addr(i);
|
||||
HashtableEntry<oop>* entry = the_table()->bucket(i);
|
||||
while (entry != NULL) {
|
||||
// Shared entries are normally at the end of the bucket and if we run into
|
||||
// a shared entry, then there is nothing more to remove. However, if we
|
||||
// have rehashed the table, then the shared entries are no longer at the
|
||||
// end of the bucket.
|
||||
if (entry->is_shared() && !use_alternate_hashcode()) {
|
||||
break;
|
||||
}
|
||||
assert(entry->literal() != NULL, "just checking");
|
||||
if (is_alive->do_object_b(entry->literal())) {
|
||||
if (entry->is_shared() || is_alive->do_object_b(entry->literal())) {
|
||||
p = entry->next_addr();
|
||||
} else {
|
||||
*p = entry->next();
|
||||
the_table()->free_entry(entry);
|
||||
}
|
||||
entry = (HashtableEntry<oop>*)HashtableEntry<oop>::make_ptr(*p);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -675,3 +817,53 @@ void StringTable::verify() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StringTable::dump(outputStream* st) {
|
||||
NumberSeq summary;
|
||||
for (int i = 0; i < the_table()->table_size(); ++i) {
|
||||
HashtableEntry<oop>* p = the_table()->bucket(i);
|
||||
int count = 0;
|
||||
for ( ; p != NULL; p = p->next()) {
|
||||
count++;
|
||||
}
|
||||
summary.add((double)count);
|
||||
}
|
||||
st->print_cr("StringTable statistics:");
|
||||
st->print_cr("Number of buckets : %7d", summary.num());
|
||||
st->print_cr("Average bucket size : %7.0f", summary.avg());
|
||||
st->print_cr("Variance of bucket size : %7.0f", summary.variance());
|
||||
st->print_cr("Std. dev. of bucket size: %7.0f", summary.sd());
|
||||
st->print_cr("Maximum bucket size : %7.0f", summary.maximum());
|
||||
}
|
||||
|
||||
|
||||
unsigned int StringTable::new_hash(oop string) {
|
||||
ResourceMark rm;
|
||||
int length;
|
||||
jchar* chars = java_lang_String::as_unicode_string(string, length);
|
||||
// Use alternate hashing algorithm on the string
|
||||
return AltHashing::murmur3_32(seed(), chars, length);
|
||||
}
|
||||
|
||||
// Create a new table and using alternate hash code, populate the new table
|
||||
// with the existing strings. Set flag to use the alternate hash code afterwards.
|
||||
void StringTable::rehash_table() {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
||||
// This should never happen with -Xshare:dump but it might in testing mode.
|
||||
if (DumpSharedSpaces) return;
|
||||
StringTable* new_table = new StringTable();
|
||||
|
||||
// Initialize new global seed for hashing.
|
||||
_seed = AltHashing::compute_seed();
|
||||
assert(seed() != 0, "shouldn't be zero");
|
||||
|
||||
// Rehash the table
|
||||
the_table()->move_to(new_table);
|
||||
|
||||
// Delete the table and buckets (entries are reused in new table).
|
||||
delete _the_table;
|
||||
// Don't check if we need rehashing until the table gets unbalanced again.
|
||||
// Then rehash with a new global seed.
|
||||
_needs_rehashing = false;
|
||||
_the_table = new_table;
|
||||
}
|
||||
|
@ -40,6 +40,7 @@
|
||||
// - symbolTableEntrys are allocated in blocks to reduce the space overhead.
|
||||
|
||||
class BoolObjectClosure;
|
||||
class outputStream;
|
||||
|
||||
|
||||
// Class to hold a newly created or referenced Symbol* temporarily in scope.
|
||||
@ -78,6 +79,10 @@ private:
|
||||
// The symbol table
|
||||
static SymbolTable* _the_table;
|
||||
|
||||
// Set if one bucket is out of balance due to hash algorithm deficiency
|
||||
static bool _needs_rehashing;
|
||||
static jint _seed;
|
||||
|
||||
// For statistics
|
||||
static int symbols_removed;
|
||||
static int symbols_counted;
|
||||
@ -119,6 +124,11 @@ private:
|
||||
static Arena* arena() { return _arena; } // called for statistics
|
||||
|
||||
static void initialize_symbols(int arena_alloc_size = 0);
|
||||
|
||||
static bool use_alternate_hashcode() { return _seed != 0; }
|
||||
static jint seed() { return _seed; }
|
||||
|
||||
unsigned int new_hash(Symbol* sym);
|
||||
public:
|
||||
enum {
|
||||
symbol_alloc_batch_size = 8,
|
||||
@ -146,6 +156,8 @@ public:
|
||||
initialize_symbols();
|
||||
}
|
||||
|
||||
static unsigned int hash_symbol(const char* s, int len);
|
||||
|
||||
static Symbol* lookup(const char* name, int len, TRAPS);
|
||||
// lookup only, won't add. Also calculate hash.
|
||||
static Symbol* lookup_only(const char* name, int len, unsigned int& hash);
|
||||
@ -208,6 +220,7 @@ public:
|
||||
|
||||
// Debugging
|
||||
static void verify();
|
||||
static void dump(outputStream* st);
|
||||
|
||||
// Sharing
|
||||
static void copy_buckets(char** top, char*end) {
|
||||
@ -219,8 +232,13 @@ public:
|
||||
static void reverse(void* boundary = NULL) {
|
||||
the_table()->Hashtable<Symbol*>::reverse(boundary);
|
||||
}
|
||||
|
||||
// Rehash the symbol table if it gets out of balance
|
||||
static void rehash_table();
|
||||
static bool needs_rehashing() { return _needs_rehashing; }
|
||||
};
|
||||
|
||||
|
||||
class StringTable : public Hashtable<oop> {
|
||||
friend class VMStructs;
|
||||
|
||||
@ -228,6 +246,10 @@ private:
|
||||
// The string table
|
||||
static StringTable* _the_table;
|
||||
|
||||
// Set if one bucket is out of balance due to hash algorithm deficiency
|
||||
static bool _needs_rehashing;
|
||||
static jint _seed;
|
||||
|
||||
static oop intern(Handle string_or_null, jchar* chars, int length, TRAPS);
|
||||
oop basic_add(int index, Handle string_or_null, jchar* name, int len,
|
||||
unsigned int hashValue, TRAPS);
|
||||
@ -241,6 +263,10 @@ private:
|
||||
: Hashtable<oop>((int)StringTableSize, sizeof (HashtableEntry<oop>), t,
|
||||
number_of_entries) {}
|
||||
|
||||
static bool use_alternate_hashcode() { return _seed != 0; }
|
||||
static jint seed() { return _seed; }
|
||||
|
||||
unsigned int new_hash(oop s);
|
||||
public:
|
||||
// The string table
|
||||
static StringTable* the_table() { return _the_table; }
|
||||
@ -265,6 +291,14 @@ public:
|
||||
// Invoke "f->do_oop" on the locations of all oops in the table.
|
||||
static void oops_do(OopClosure* f);
|
||||
|
||||
// Hashing algorithm, used as the hash value used by the
|
||||
// StringTable for bucket selection and comparison (stored in the
|
||||
// HashtableEntry structures). This is used in the String.intern() method.
|
||||
static unsigned int hash_string(const jchar* s, int len);
|
||||
|
||||
// Internal test.
|
||||
static void test_alt_hash() PRODUCT_RETURN;
|
||||
|
||||
// Probing
|
||||
static oop lookup(Symbol* symbol);
|
||||
|
||||
@ -275,6 +309,7 @@ public:
|
||||
|
||||
// Debugging
|
||||
static void verify();
|
||||
static void dump(outputStream* st);
|
||||
|
||||
// Sharing
|
||||
static void copy_buckets(char** top, char*end) {
|
||||
@ -286,6 +321,9 @@ public:
|
||||
static void reverse() {
|
||||
the_table()->Hashtable<oop>::reverse();
|
||||
}
|
||||
};
|
||||
|
||||
// Rehash the symbol table if it gets out of balance
|
||||
static void rehash_table();
|
||||
static bool needs_rehashing() { return _needs_rehashing; }
|
||||
};
|
||||
#endif // SHARE_VM_CLASSFILE_SYMBOLTABLE_HPP
|
||||
|
@ -111,6 +111,10 @@
|
||||
template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \
|
||||
template(sun_misc_PostVMInitHook, "sun/misc/PostVMInitHook") \
|
||||
\
|
||||
/* Java runtime version access */ \
|
||||
template(sun_misc_Version, "sun/misc/Version") \
|
||||
template(java_runtime_name_name, "java_runtime_name") \
|
||||
\
|
||||
/* class file format tags */ \
|
||||
template(tag_source_file, "SourceFile") \
|
||||
template(tag_inner_classes, "InnerClasses") \
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, 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
|
||||
@ -27,7 +27,7 @@
|
||||
#include "code/vmreg.hpp"
|
||||
|
||||
// First VMReg value that could refer to a stack slot
|
||||
VMReg VMRegImpl::stack0 = (VMReg)(intptr_t)((ConcreteRegisterImpl::number_of_registers + 1) & ~1);
|
||||
VMReg VMRegImpl::stack0 = (VMReg)(intptr_t)((ConcreteRegisterImpl::number_of_registers + 7) & ~7);
|
||||
|
||||
// VMRegs are 4 bytes wide on all platforms
|
||||
const int VMRegImpl::stack_slot_size = 4;
|
||||
|
@ -4750,9 +4750,6 @@ public:
|
||||
_g1h->g1_policy()->record_thread_age_table(pss.age_table());
|
||||
_g1h->update_surviving_young_words(pss.surviving_young_words()+1);
|
||||
|
||||
// Clean up any par-expanded rem sets.
|
||||
HeapRegionRemSet::par_cleanup();
|
||||
|
||||
if (ParallelGCVerbose) {
|
||||
MutexLocker x(stats_lock());
|
||||
pss.print_termination_stats(worker_id);
|
||||
|
@ -53,6 +53,9 @@
|
||||
develop(bool, G1TraceMarkStackOverflow, false, \
|
||||
"If true, extra debugging code for CM restart for ovflw.") \
|
||||
\
|
||||
develop(bool, G1TraceHeapRegionRememberedSet, false, \
|
||||
"Enables heap region remembered set debug logs") \
|
||||
\
|
||||
diagnostic(bool, G1SummarizeConcMark, false, \
|
||||
"Summarize concurrent mark info") \
|
||||
\
|
||||
|
@ -30,13 +30,10 @@
|
||||
#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/space.inline.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "utilities/bitMap.inline.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
|
||||
#define HRRS_VERBOSE 0
|
||||
|
||||
#define PRT_COUNT_OCCUPIED 1
|
||||
|
||||
// OtherRegionsTable
|
||||
|
||||
class PerRegionTable: public CHeapObj {
|
||||
@ -45,14 +42,10 @@ class PerRegionTable: public CHeapObj {
|
||||
|
||||
HeapRegion* _hr;
|
||||
BitMap _bm;
|
||||
#if PRT_COUNT_OCCUPIED
|
||||
jint _occupied;
|
||||
#endif
|
||||
PerRegionTable* _next_free;
|
||||
|
||||
PerRegionTable* next_free() { return _next_free; }
|
||||
void set_next_free(PerRegionTable* prt) { _next_free = prt; }
|
||||
|
||||
// next pointer for free/allocated lis
|
||||
PerRegionTable* _next;
|
||||
|
||||
static PerRegionTable* _free_list;
|
||||
|
||||
@ -69,63 +62,25 @@ protected:
|
||||
// We need access in order to union things into the base table.
|
||||
BitMap* bm() { return &_bm; }
|
||||
|
||||
#if PRT_COUNT_OCCUPIED
|
||||
void recount_occupied() {
|
||||
_occupied = (jint) bm()->count_one_bits();
|
||||
}
|
||||
#endif
|
||||
|
||||
PerRegionTable(HeapRegion* hr) :
|
||||
_hr(hr),
|
||||
#if PRT_COUNT_OCCUPIED
|
||||
_occupied(0),
|
||||
#endif
|
||||
_bm(HeapRegion::CardsPerRegion, false /* in-resource-area */)
|
||||
{}
|
||||
|
||||
static void free(PerRegionTable* prt) {
|
||||
while (true) {
|
||||
PerRegionTable* fl = _free_list;
|
||||
prt->set_next_free(fl);
|
||||
PerRegionTable* res =
|
||||
(PerRegionTable*)
|
||||
Atomic::cmpxchg_ptr(prt, &_free_list, fl);
|
||||
if (res == fl) return;
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
static PerRegionTable* alloc(HeapRegion* hr) {
|
||||
PerRegionTable* fl = _free_list;
|
||||
while (fl != NULL) {
|
||||
PerRegionTable* nxt = fl->next_free();
|
||||
PerRegionTable* res =
|
||||
(PerRegionTable*)
|
||||
Atomic::cmpxchg_ptr(nxt, &_free_list, fl);
|
||||
if (res == fl) {
|
||||
fl->init(hr);
|
||||
return fl;
|
||||
} else {
|
||||
fl = _free_list;
|
||||
}
|
||||
}
|
||||
assert(fl == NULL, "Loop condition.");
|
||||
return new PerRegionTable(hr);
|
||||
}
|
||||
|
||||
void add_card_work(CardIdx_t from_card, bool par) {
|
||||
if (!_bm.at(from_card)) {
|
||||
if (par) {
|
||||
if (_bm.par_at_put(from_card, 1)) {
|
||||
#if PRT_COUNT_OCCUPIED
|
||||
Atomic::inc(&_occupied);
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
_bm.at_put(from_card, 1);
|
||||
#if PRT_COUNT_OCCUPIED
|
||||
_occupied++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -134,10 +89,13 @@ protected:
|
||||
// Must make this robust in case "from" is not in "_hr", because of
|
||||
// concurrency.
|
||||
|
||||
#if HRRS_VERBOSE
|
||||
gclog_or_tty->print_cr(" PRT::Add_reference_work(" PTR_FORMAT "->" PTR_FORMAT").",
|
||||
from, *from);
|
||||
#endif
|
||||
if (G1TraceHeapRegionRememberedSet) {
|
||||
gclog_or_tty->print_cr(" PRT::Add_reference_work(" PTR_FORMAT "->" PTR_FORMAT").",
|
||||
from,
|
||||
UseCompressedOops
|
||||
? oopDesc::load_decode_heap_oop((narrowOop*)from)
|
||||
: oopDesc::load_decode_heap_oop((oop*)from));
|
||||
}
|
||||
|
||||
HeapRegion* loc_hr = hr();
|
||||
// If the test below fails, then this table was reused concurrently
|
||||
@ -162,23 +120,16 @@ public:
|
||||
|
||||
HeapRegion* hr() const { return _hr; }
|
||||
|
||||
#if PRT_COUNT_OCCUPIED
|
||||
jint occupied() const {
|
||||
// Overkill, but if we ever need it...
|
||||
// guarantee(_occupied == _bm.count_one_bits(), "Check");
|
||||
return _occupied;
|
||||
}
|
||||
#else
|
||||
jint occupied() const {
|
||||
return _bm.count_one_bits();
|
||||
}
|
||||
#endif
|
||||
|
||||
void init(HeapRegion* hr) {
|
||||
_hr = hr;
|
||||
#if PRT_COUNT_OCCUPIED
|
||||
_next = NULL;
|
||||
_occupied = 0;
|
||||
#endif
|
||||
_bm.clear();
|
||||
}
|
||||
|
||||
@ -194,9 +145,7 @@ public:
|
||||
HeapWord* hr_bot = hr()->bottom();
|
||||
size_t hr_first_card_index = ctbs->index_for(hr_bot);
|
||||
bm()->set_intersection_at_offset(*card_bm, hr_first_card_index);
|
||||
#if PRT_COUNT_OCCUPIED
|
||||
recount_occupied();
|
||||
#endif
|
||||
}
|
||||
|
||||
void add_card(CardIdx_t from_card_index) {
|
||||
@ -218,16 +167,6 @@ public:
|
||||
return sizeof(this) + _bm.size_in_words() * HeapWordSize;
|
||||
}
|
||||
|
||||
static size_t fl_mem_size() {
|
||||
PerRegionTable* cur = _free_list;
|
||||
size_t res = 0;
|
||||
while (cur != NULL) {
|
||||
res += sizeof(PerRegionTable);
|
||||
cur = cur->next_free();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Requires "from" to be in "hr()".
|
||||
bool contains_reference(OopOrNarrowOopStar from) const {
|
||||
assert(hr()->is_in_reserved(from), "Precondition.");
|
||||
@ -235,122 +174,29 @@ public:
|
||||
CardTableModRefBS::card_size);
|
||||
return _bm.at(card_ind);
|
||||
}
|
||||
};
|
||||
|
||||
PerRegionTable* PerRegionTable::_free_list = NULL;
|
||||
PerRegionTable* next() const { return _next; }
|
||||
void set_next(PerRegionTable* nxt) { _next = nxt; }
|
||||
PerRegionTable** next_addr() { return &_next; }
|
||||
|
||||
|
||||
#define COUNT_PAR_EXPANDS 0
|
||||
|
||||
#if COUNT_PAR_EXPANDS
|
||||
static jint n_par_expands = 0;
|
||||
static jint n_par_contracts = 0;
|
||||
static jint par_expand_list_len = 0;
|
||||
static jint max_par_expand_list_len = 0;
|
||||
|
||||
static void print_par_expand() {
|
||||
Atomic::inc(&n_par_expands);
|
||||
Atomic::inc(&par_expand_list_len);
|
||||
if (par_expand_list_len > max_par_expand_list_len) {
|
||||
max_par_expand_list_len = par_expand_list_len;
|
||||
}
|
||||
if ((n_par_expands % 10) == 0) {
|
||||
gclog_or_tty->print_cr("\n\n%d par expands: %d contracts, "
|
||||
"len = %d, max_len = %d\n.",
|
||||
n_par_expands, n_par_contracts, par_expand_list_len,
|
||||
max_par_expand_list_len);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
class PosParPRT: public PerRegionTable {
|
||||
PerRegionTable** _par_tables;
|
||||
|
||||
enum SomePrivateConstants {
|
||||
ReserveParTableExpansion = 1
|
||||
};
|
||||
|
||||
void par_contract() {
|
||||
assert(_par_tables != NULL, "Precondition.");
|
||||
int n = HeapRegionRemSet::num_par_rem_sets()-1;
|
||||
for (int i = 0; i < n; i++) {
|
||||
_par_tables[i]->union_bitmap_into(bm());
|
||||
PerRegionTable::free(_par_tables[i]);
|
||||
_par_tables[i] = NULL;
|
||||
}
|
||||
#if PRT_COUNT_OCCUPIED
|
||||
// We must recount the "occupied."
|
||||
recount_occupied();
|
||||
#endif
|
||||
FREE_C_HEAP_ARRAY(PerRegionTable*, _par_tables);
|
||||
_par_tables = NULL;
|
||||
#if COUNT_PAR_EXPANDS
|
||||
Atomic::inc(&n_par_contracts);
|
||||
Atomic::dec(&par_expand_list_len);
|
||||
#endif
|
||||
}
|
||||
|
||||
static PerRegionTable** _par_table_fl;
|
||||
|
||||
PosParPRT* _next;
|
||||
|
||||
static PosParPRT* _free_list;
|
||||
|
||||
PerRegionTable** par_tables() const {
|
||||
assert(uintptr_t(NULL) == 0, "Assumption.");
|
||||
if (uintptr_t(_par_tables) <= ReserveParTableExpansion)
|
||||
return NULL;
|
||||
else
|
||||
return _par_tables;
|
||||
}
|
||||
|
||||
PosParPRT* _next_par_expanded;
|
||||
PosParPRT* next_par_expanded() { return _next_par_expanded; }
|
||||
void set_next_par_expanded(PosParPRT* ppprt) { _next_par_expanded = ppprt; }
|
||||
static PosParPRT* _par_expanded_list;
|
||||
|
||||
public:
|
||||
|
||||
PosParPRT(HeapRegion* hr) : PerRegionTable(hr), _par_tables(NULL) {}
|
||||
|
||||
jint occupied() const {
|
||||
jint res = PerRegionTable::occupied();
|
||||
if (par_tables() != NULL) {
|
||||
for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets()-1; i++) {
|
||||
res += par_tables()[i]->occupied();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void init(HeapRegion* hr) {
|
||||
PerRegionTable::init(hr);
|
||||
_next = NULL;
|
||||
if (par_tables() != NULL) {
|
||||
for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets()-1; i++) {
|
||||
par_tables()[i]->init(hr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void free(PosParPRT* prt) {
|
||||
static void free(PerRegionTable* prt) {
|
||||
while (true) {
|
||||
PosParPRT* fl = _free_list;
|
||||
PerRegionTable* fl = _free_list;
|
||||
prt->set_next(fl);
|
||||
PosParPRT* res =
|
||||
(PosParPRT*)
|
||||
PerRegionTable* res =
|
||||
(PerRegionTable*)
|
||||
Atomic::cmpxchg_ptr(prt, &_free_list, fl);
|
||||
if (res == fl) return;
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
static PosParPRT* alloc(HeapRegion* hr) {
|
||||
PosParPRT* fl = _free_list;
|
||||
static PerRegionTable* alloc(HeapRegion* hr) {
|
||||
PerRegionTable* fl = _free_list;
|
||||
while (fl != NULL) {
|
||||
PosParPRT* nxt = fl->next();
|
||||
PosParPRT* res =
|
||||
(PosParPRT*)
|
||||
PerRegionTable* nxt = fl->next();
|
||||
PerRegionTable* res =
|
||||
(PerRegionTable*)
|
||||
Atomic::cmpxchg_ptr(nxt, &_free_list, fl);
|
||||
if (res == fl) {
|
||||
fl->init(hr);
|
||||
@ -360,148 +206,26 @@ public:
|
||||
}
|
||||
}
|
||||
assert(fl == NULL, "Loop condition.");
|
||||
return new PosParPRT(hr);
|
||||
}
|
||||
|
||||
PosParPRT* next() const { return _next; }
|
||||
void set_next(PosParPRT* nxt) { _next = nxt; }
|
||||
PosParPRT** next_addr() { return &_next; }
|
||||
|
||||
bool should_expand(int tid) {
|
||||
// Given that we now defer RSet updates for after a GC we don't
|
||||
// really need to expand the tables any more. This code should be
|
||||
// cleaned up in the future (see CR 6921087).
|
||||
return false;
|
||||
}
|
||||
|
||||
void par_expand() {
|
||||
int n = HeapRegionRemSet::num_par_rem_sets()-1;
|
||||
if (n <= 0) return;
|
||||
if (_par_tables == NULL) {
|
||||
PerRegionTable* res =
|
||||
(PerRegionTable*)
|
||||
Atomic::cmpxchg_ptr((PerRegionTable*)ReserveParTableExpansion,
|
||||
&_par_tables, NULL);
|
||||
if (res != NULL) return;
|
||||
// Otherwise, we reserved the right to do the expansion.
|
||||
|
||||
PerRegionTable** ptables = NEW_C_HEAP_ARRAY(PerRegionTable*, n);
|
||||
for (int i = 0; i < n; i++) {
|
||||
PerRegionTable* ptable = PerRegionTable::alloc(hr());
|
||||
ptables[i] = ptable;
|
||||
}
|
||||
// Here we do not need an atomic.
|
||||
_par_tables = ptables;
|
||||
#if COUNT_PAR_EXPANDS
|
||||
print_par_expand();
|
||||
#endif
|
||||
// We must put this table on the expanded list.
|
||||
PosParPRT* exp_head = _par_expanded_list;
|
||||
while (true) {
|
||||
set_next_par_expanded(exp_head);
|
||||
PosParPRT* res =
|
||||
(PosParPRT*)
|
||||
Atomic::cmpxchg_ptr(this, &_par_expanded_list, exp_head);
|
||||
if (res == exp_head) return;
|
||||
// Otherwise.
|
||||
exp_head = res;
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
void add_reference(OopOrNarrowOopStar from, int tid) {
|
||||
// Expand if necessary.
|
||||
PerRegionTable** pt = par_tables();
|
||||
if (pt != NULL) {
|
||||
// We always have to assume that mods to table 0 are in parallel,
|
||||
// because of the claiming scheme in parallel expansion. A thread
|
||||
// with tid != 0 that finds the table to be NULL, but doesn't succeed
|
||||
// in claiming the right of expanding it, will end up in the else
|
||||
// clause of the above if test. That thread could be delayed, and a
|
||||
// thread 0 add reference could see the table expanded, and come
|
||||
// here. Both threads would be adding in parallel. But we get to
|
||||
// not use atomics for tids > 0.
|
||||
if (tid == 0) {
|
||||
PerRegionTable::add_reference(from);
|
||||
} else {
|
||||
pt[tid-1]->seq_add_reference(from);
|
||||
}
|
||||
} else {
|
||||
// Not expanded -- add to the base table.
|
||||
PerRegionTable::add_reference(from);
|
||||
}
|
||||
}
|
||||
|
||||
void scrub(CardTableModRefBS* ctbs, BitMap* card_bm) {
|
||||
assert(_par_tables == NULL, "Precondition");
|
||||
PerRegionTable::scrub(ctbs, card_bm);
|
||||
}
|
||||
|
||||
size_t mem_size() const {
|
||||
size_t res =
|
||||
PerRegionTable::mem_size() + sizeof(this) - sizeof(PerRegionTable);
|
||||
if (_par_tables != NULL) {
|
||||
for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets()-1; i++) {
|
||||
res += _par_tables[i]->mem_size();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
return new PerRegionTable(hr);
|
||||
}
|
||||
|
||||
static size_t fl_mem_size() {
|
||||
PosParPRT* cur = _free_list;
|
||||
PerRegionTable* cur = _free_list;
|
||||
size_t res = 0;
|
||||
while (cur != NULL) {
|
||||
res += sizeof(PosParPRT);
|
||||
res += sizeof(PerRegionTable);
|
||||
cur = cur->next();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool contains_reference(OopOrNarrowOopStar from) const {
|
||||
if (PerRegionTable::contains_reference(from)) return true;
|
||||
if (_par_tables != NULL) {
|
||||
for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets()-1; i++) {
|
||||
if (_par_tables[i]->contains_reference(from)) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void par_contract_all();
|
||||
};
|
||||
|
||||
void PosParPRT::par_contract_all() {
|
||||
PosParPRT* hd = _par_expanded_list;
|
||||
while (hd != NULL) {
|
||||
PosParPRT* nxt = hd->next_par_expanded();
|
||||
PosParPRT* res =
|
||||
(PosParPRT*)
|
||||
Atomic::cmpxchg_ptr(nxt, &_par_expanded_list, hd);
|
||||
if (res == hd) {
|
||||
// We claimed the right to contract this table.
|
||||
hd->set_next_par_expanded(NULL);
|
||||
hd->par_contract();
|
||||
hd = _par_expanded_list;
|
||||
} else {
|
||||
hd = res;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PosParPRT* PosParPRT::_free_list = NULL;
|
||||
PosParPRT* PosParPRT::_par_expanded_list = NULL;
|
||||
|
||||
jint OtherRegionsTable::_cache_probes = 0;
|
||||
jint OtherRegionsTable::_cache_hits = 0;
|
||||
PerRegionTable* PerRegionTable::_free_list = NULL;
|
||||
|
||||
size_t OtherRegionsTable::_max_fine_entries = 0;
|
||||
size_t OtherRegionsTable::_mod_max_fine_entries_mask = 0;
|
||||
#if SAMPLE_FOR_EVICTION
|
||||
size_t OtherRegionsTable::_fine_eviction_stride = 0;
|
||||
size_t OtherRegionsTable::_fine_eviction_sample_size = 0;
|
||||
#endif
|
||||
|
||||
OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) :
|
||||
_g1h(G1CollectedHeap::heap()),
|
||||
@ -511,34 +235,36 @@ OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) :
|
||||
false /* in-resource-area */),
|
||||
_fine_grain_regions(NULL),
|
||||
_n_fine_entries(0), _n_coarse_entries(0),
|
||||
#if SAMPLE_FOR_EVICTION
|
||||
_fine_eviction_start(0),
|
||||
#endif
|
||||
_sparse_table(hr)
|
||||
{
|
||||
typedef PosParPRT* PosParPRTPtr;
|
||||
typedef PerRegionTable* PerRegionTablePtr;
|
||||
|
||||
if (_max_fine_entries == 0) {
|
||||
assert(_mod_max_fine_entries_mask == 0, "Both or none.");
|
||||
size_t max_entries_log = (size_t)log2_long((jlong)G1RSetRegionEntries);
|
||||
_max_fine_entries = (size_t)(1 << max_entries_log);
|
||||
_mod_max_fine_entries_mask = _max_fine_entries - 1;
|
||||
#if SAMPLE_FOR_EVICTION
|
||||
|
||||
assert(_fine_eviction_sample_size == 0
|
||||
&& _fine_eviction_stride == 0, "All init at same time.");
|
||||
_fine_eviction_sample_size = MAX2((size_t)4, max_entries_log);
|
||||
_fine_eviction_stride = _max_fine_entries / _fine_eviction_sample_size;
|
||||
#endif
|
||||
}
|
||||
_fine_grain_regions = new PosParPRTPtr[_max_fine_entries];
|
||||
if (_fine_grain_regions == NULL)
|
||||
|
||||
_fine_grain_regions = new PerRegionTablePtr[_max_fine_entries];
|
||||
|
||||
if (_fine_grain_regions == NULL) {
|
||||
vm_exit_out_of_memory(sizeof(void*)*_max_fine_entries,
|
||||
"Failed to allocate _fine_grain_entries.");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < _max_fine_entries; i++) {
|
||||
_fine_grain_regions[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int** OtherRegionsTable::_from_card_cache = NULL;
|
||||
int** OtherRegionsTable::_from_card_cache = NULL;
|
||||
size_t OtherRegionsTable::_from_card_cache_max_regions = 0;
|
||||
size_t OtherRegionsTable::_from_card_cache_mem_size = 0;
|
||||
|
||||
@ -579,38 +305,26 @@ void OtherRegionsTable::print_from_card_cache() {
|
||||
void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
|
||||
size_t cur_hrs_ind = (size_t) hr()->hrs_index();
|
||||
|
||||
#if HRRS_VERBOSE
|
||||
gclog_or_tty->print_cr("ORT::add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").",
|
||||
from,
|
||||
UseCompressedOops
|
||||
? oopDesc::load_decode_heap_oop((narrowOop*)from)
|
||||
: oopDesc::load_decode_heap_oop((oop*)from));
|
||||
#endif
|
||||
if (G1TraceHeapRegionRememberedSet) {
|
||||
gclog_or_tty->print_cr("ORT::add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").",
|
||||
from,
|
||||
UseCompressedOops
|
||||
? oopDesc::load_decode_heap_oop((narrowOop*)from)
|
||||
: oopDesc::load_decode_heap_oop((oop*)from));
|
||||
}
|
||||
|
||||
int from_card = (int)(uintptr_t(from) >> CardTableModRefBS::card_shift);
|
||||
|
||||
#if HRRS_VERBOSE
|
||||
gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = %d)",
|
||||
hr()->bottom(), from_card,
|
||||
_from_card_cache[tid][cur_hrs_ind]);
|
||||
#endif
|
||||
|
||||
#define COUNT_CACHE 0
|
||||
#if COUNT_CACHE
|
||||
jint p = Atomic::add(1, &_cache_probes);
|
||||
if ((p % 10000) == 0) {
|
||||
jint hits = _cache_hits;
|
||||
gclog_or_tty->print_cr("%d/%d = %5.2f%% RS cache hits.",
|
||||
_cache_hits, p, 100.0* (float)hits/(float)p);
|
||||
if (G1TraceHeapRegionRememberedSet) {
|
||||
gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = %d)",
|
||||
hr()->bottom(), from_card,
|
||||
_from_card_cache[tid][cur_hrs_ind]);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (from_card == _from_card_cache[tid][cur_hrs_ind]) {
|
||||
#if HRRS_VERBOSE
|
||||
gclog_or_tty->print_cr(" from-card cache hit.");
|
||||
#endif
|
||||
#if COUNT_CACHE
|
||||
Atomic::inc(&_cache_hits);
|
||||
#endif
|
||||
if (G1TraceHeapRegionRememberedSet) {
|
||||
gclog_or_tty->print_cr(" from-card cache hit.");
|
||||
}
|
||||
assert(contains_reference(from), "We just added it!");
|
||||
return;
|
||||
} else {
|
||||
@ -623,16 +337,16 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
|
||||
|
||||
// If the region is already coarsened, return.
|
||||
if (_coarse_map.at(from_hrs_ind)) {
|
||||
#if HRRS_VERBOSE
|
||||
gclog_or_tty->print_cr(" coarse map hit.");
|
||||
#endif
|
||||
if (G1TraceHeapRegionRememberedSet) {
|
||||
gclog_or_tty->print_cr(" coarse map hit.");
|
||||
}
|
||||
assert(contains_reference(from), "We just added it!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise find a per-region table to add it to.
|
||||
size_t ind = from_hrs_ind & _mod_max_fine_entries_mask;
|
||||
PosParPRT* prt = find_region_table(ind, from_hr);
|
||||
PerRegionTable* prt = find_region_table(ind, from_hr);
|
||||
if (prt == NULL) {
|
||||
MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
|
||||
// Confirm that it's really not there...
|
||||
@ -649,35 +363,35 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
|
||||
_sparse_table.add_card(from_hrs_ind, card_index)) {
|
||||
if (G1RecordHRRSOops) {
|
||||
HeapRegionRemSet::record(hr(), from);
|
||||
#if HRRS_VERBOSE
|
||||
gclog_or_tty->print(" Added card " PTR_FORMAT " to region "
|
||||
"[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
|
||||
align_size_down(uintptr_t(from),
|
||||
CardTableModRefBS::card_size),
|
||||
hr()->bottom(), from);
|
||||
#endif
|
||||
if (G1TraceHeapRegionRememberedSet) {
|
||||
gclog_or_tty->print(" Added card " PTR_FORMAT " to region "
|
||||
"[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
|
||||
align_size_down(uintptr_t(from),
|
||||
CardTableModRefBS::card_size),
|
||||
hr()->bottom(), from);
|
||||
}
|
||||
}
|
||||
if (G1TraceHeapRegionRememberedSet) {
|
||||
gclog_or_tty->print_cr(" added card to sparse table.");
|
||||
}
|
||||
#if HRRS_VERBOSE
|
||||
gclog_or_tty->print_cr(" added card to sparse table.");
|
||||
#endif
|
||||
assert(contains_reference_locked(from), "We just added it!");
|
||||
return;
|
||||
} else {
|
||||
#if HRRS_VERBOSE
|
||||
gclog_or_tty->print_cr(" [tid %d] sparse table entry "
|
||||
"overflow(f: %d, t: %d)",
|
||||
tid, from_hrs_ind, cur_hrs_ind);
|
||||
#endif
|
||||
if (G1TraceHeapRegionRememberedSet) {
|
||||
gclog_or_tty->print_cr(" [tid %d] sparse table entry "
|
||||
"overflow(f: %d, t: %d)",
|
||||
tid, from_hrs_ind, cur_hrs_ind);
|
||||
}
|
||||
}
|
||||
|
||||
if (_n_fine_entries == _max_fine_entries) {
|
||||
prt = delete_region_table();
|
||||
} else {
|
||||
prt = PosParPRT::alloc(from_hr);
|
||||
prt = PerRegionTable::alloc(from_hr);
|
||||
}
|
||||
prt->init(from_hr);
|
||||
|
||||
PosParPRT* first_prt = _fine_grain_regions[ind];
|
||||
PerRegionTable* first_prt = _fine_grain_regions[ind];
|
||||
prt->set_next(first_prt); // XXX Maybe move to init?
|
||||
_fine_grain_regions[ind] = prt;
|
||||
_n_fine_entries++;
|
||||
@ -704,38 +418,25 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
|
||||
// OtherRegionsTable for why this is OK.
|
||||
assert(prt != NULL, "Inv");
|
||||
|
||||
if (prt->should_expand(tid)) {
|
||||
MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
|
||||
HeapRegion* prt_hr = prt->hr();
|
||||
if (prt_hr == from_hr) {
|
||||
// Make sure the table still corresponds to the same region
|
||||
prt->par_expand();
|
||||
prt->add_reference(from, tid);
|
||||
}
|
||||
// else: The table has been concurrently coarsened, evicted, and
|
||||
// the table data structure re-used for another table. So, we
|
||||
// don't need to add the reference any more given that the table
|
||||
// has been coarsened and the whole region will be scanned anyway.
|
||||
} else {
|
||||
prt->add_reference(from, tid);
|
||||
}
|
||||
prt->add_reference(from);
|
||||
|
||||
if (G1RecordHRRSOops) {
|
||||
HeapRegionRemSet::record(hr(), from);
|
||||
#if HRRS_VERBOSE
|
||||
gclog_or_tty->print("Added card " PTR_FORMAT " to region "
|
||||
"[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
|
||||
align_size_down(uintptr_t(from),
|
||||
CardTableModRefBS::card_size),
|
||||
hr()->bottom(), from);
|
||||
#endif
|
||||
if (G1TraceHeapRegionRememberedSet) {
|
||||
gclog_or_tty->print("Added card " PTR_FORMAT " to region "
|
||||
"[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
|
||||
align_size_down(uintptr_t(from),
|
||||
CardTableModRefBS::card_size),
|
||||
hr()->bottom(), from);
|
||||
}
|
||||
}
|
||||
assert(contains_reference(from), "We just added it!");
|
||||
}
|
||||
|
||||
PosParPRT*
|
||||
PerRegionTable*
|
||||
OtherRegionsTable::find_region_table(size_t ind, HeapRegion* hr) const {
|
||||
assert(0 <= ind && ind < _max_fine_entries, "Preconditions.");
|
||||
PosParPRT* prt = _fine_grain_regions[ind];
|
||||
PerRegionTable* prt = _fine_grain_regions[ind];
|
||||
while (prt != NULL && prt->hr() != hr) {
|
||||
prt = prt->next();
|
||||
}
|
||||
@ -743,32 +444,16 @@ OtherRegionsTable::find_region_table(size_t ind, HeapRegion* hr) const {
|
||||
return prt;
|
||||
}
|
||||
|
||||
|
||||
#define DRT_CENSUS 0
|
||||
|
||||
#if DRT_CENSUS
|
||||
static const int HistoSize = 6;
|
||||
static int global_histo[HistoSize] = { 0, 0, 0, 0, 0, 0 };
|
||||
static int coarsenings = 0;
|
||||
static int occ_sum = 0;
|
||||
#endif
|
||||
|
||||
jint OtherRegionsTable::_n_coarsenings = 0;
|
||||
|
||||
PosParPRT* OtherRegionsTable::delete_region_table() {
|
||||
#if DRT_CENSUS
|
||||
int histo[HistoSize] = { 0, 0, 0, 0, 0, 0 };
|
||||
const int histo_limits[] = { 1, 4, 16, 64, 256, 2048 };
|
||||
#endif
|
||||
|
||||
PerRegionTable* OtherRegionsTable::delete_region_table() {
|
||||
assert(_m.owned_by_self(), "Precondition");
|
||||
assert(_n_fine_entries == _max_fine_entries, "Precondition");
|
||||
PosParPRT* max = NULL;
|
||||
PerRegionTable* max = NULL;
|
||||
jint max_occ = 0;
|
||||
PosParPRT** max_prev;
|
||||
PerRegionTable** max_prev;
|
||||
size_t max_ind;
|
||||
|
||||
#if SAMPLE_FOR_EVICTION
|
||||
size_t i = _fine_eviction_start;
|
||||
for (size_t k = 0; k < _fine_eviction_sample_size; k++) {
|
||||
size_t ii = i;
|
||||
@ -778,8 +463,8 @@ PosParPRT* OtherRegionsTable::delete_region_table() {
|
||||
if (ii == _max_fine_entries) ii = 0;
|
||||
guarantee(ii != i, "We must find one.");
|
||||
}
|
||||
PosParPRT** prev = &_fine_grain_regions[ii];
|
||||
PosParPRT* cur = *prev;
|
||||
PerRegionTable** prev = &_fine_grain_regions[ii];
|
||||
PerRegionTable* cur = *prev;
|
||||
while (cur != NULL) {
|
||||
jint cur_occ = cur->occupied();
|
||||
if (max == NULL || cur_occ > max_occ) {
|
||||
@ -794,64 +479,27 @@ PosParPRT* OtherRegionsTable::delete_region_table() {
|
||||
i = i + _fine_eviction_stride;
|
||||
if (i >= _n_fine_entries) i = i - _n_fine_entries;
|
||||
}
|
||||
|
||||
_fine_eviction_start++;
|
||||
if (_fine_eviction_start >= _n_fine_entries)
|
||||
|
||||
if (_fine_eviction_start >= _n_fine_entries) {
|
||||
_fine_eviction_start -= _n_fine_entries;
|
||||
#else
|
||||
for (int i = 0; i < _max_fine_entries; i++) {
|
||||
PosParPRT** prev = &_fine_grain_regions[i];
|
||||
PosParPRT* cur = *prev;
|
||||
while (cur != NULL) {
|
||||
jint cur_occ = cur->occupied();
|
||||
#if DRT_CENSUS
|
||||
for (int k = 0; k < HistoSize; k++) {
|
||||
if (cur_occ <= histo_limits[k]) {
|
||||
histo[k]++; global_histo[k]++; break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (max == NULL || cur_occ > max_occ) {
|
||||
max = cur;
|
||||
max_prev = prev;
|
||||
max_ind = i;
|
||||
max_occ = cur_occ;
|
||||
}
|
||||
prev = cur->next_addr();
|
||||
cur = cur->next();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// XXX
|
||||
|
||||
guarantee(max != NULL, "Since _n_fine_entries > 0");
|
||||
#if DRT_CENSUS
|
||||
gclog_or_tty->print_cr("In a coarsening: histo of occs:");
|
||||
for (int k = 0; k < HistoSize; k++) {
|
||||
gclog_or_tty->print_cr(" <= %4d: %5d.", histo_limits[k], histo[k]);
|
||||
}
|
||||
coarsenings++;
|
||||
occ_sum += max_occ;
|
||||
if ((coarsenings % 100) == 0) {
|
||||
gclog_or_tty->print_cr("\ncoarsenings = %d; global summary:", coarsenings);
|
||||
for (int k = 0; k < HistoSize; k++) {
|
||||
gclog_or_tty->print_cr(" <= %4d: %5d.", histo_limits[k], global_histo[k]);
|
||||
}
|
||||
gclog_or_tty->print_cr("Avg occ of deleted region = %6.2f.",
|
||||
(float)occ_sum/(float)coarsenings);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Set the corresponding coarse bit.
|
||||
size_t max_hrs_index = (size_t) max->hr()->hrs_index();
|
||||
if (!_coarse_map.at(max_hrs_index)) {
|
||||
_coarse_map.at_put(max_hrs_index, true);
|
||||
_n_coarse_entries++;
|
||||
#if 0
|
||||
gclog_or_tty->print("Coarsened entry in region [" PTR_FORMAT "...] "
|
||||
"for region [" PTR_FORMAT "...] (%d coarse entries).\n",
|
||||
hr()->bottom(),
|
||||
max->hr()->bottom(),
|
||||
_n_coarse_entries);
|
||||
#endif
|
||||
if (G1TraceHeapRegionRememberedSet) {
|
||||
gclog_or_tty->print("Coarsened entry in region [" PTR_FORMAT "...] "
|
||||
"for region [" PTR_FORMAT "...] (%d coarse entries).\n",
|
||||
hr()->bottom(),
|
||||
max->hr()->bottom(),
|
||||
_n_coarse_entries);
|
||||
}
|
||||
}
|
||||
|
||||
// Unsplice.
|
||||
@ -883,10 +531,10 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
|
||||
|
||||
// Now do the fine-grained maps.
|
||||
for (size_t i = 0; i < _max_fine_entries; i++) {
|
||||
PosParPRT* cur = _fine_grain_regions[i];
|
||||
PosParPRT** prev = &_fine_grain_regions[i];
|
||||
PerRegionTable* cur = _fine_grain_regions[i];
|
||||
PerRegionTable** prev = &_fine_grain_regions[i];
|
||||
while (cur != NULL) {
|
||||
PosParPRT* nxt = cur->next();
|
||||
PerRegionTable* nxt = cur->next();
|
||||
// If the entire region is dead, eliminate.
|
||||
if (G1RSScrubVerbose) {
|
||||
gclog_or_tty->print_cr(" For other region %u:",
|
||||
@ -899,7 +547,7 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
|
||||
if (G1RSScrubVerbose) {
|
||||
gclog_or_tty->print_cr(" deleted via region map.");
|
||||
}
|
||||
PosParPRT::free(cur);
|
||||
PerRegionTable::free(cur);
|
||||
} else {
|
||||
// Do fine-grain elimination.
|
||||
if (G1RSScrubVerbose) {
|
||||
@ -914,7 +562,7 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
|
||||
*prev = nxt;
|
||||
cur->set_next(NULL);
|
||||
_n_fine_entries--;
|
||||
PosParPRT::free(cur);
|
||||
PerRegionTable::free(cur);
|
||||
} else {
|
||||
prev = cur->next_addr();
|
||||
}
|
||||
@ -940,7 +588,7 @@ size_t OtherRegionsTable::occupied() const {
|
||||
size_t OtherRegionsTable::occ_fine() const {
|
||||
size_t sum = 0;
|
||||
for (size_t i = 0; i < _max_fine_entries; i++) {
|
||||
PosParPRT* cur = _fine_grain_regions[i];
|
||||
PerRegionTable* cur = _fine_grain_regions[i];
|
||||
while (cur != NULL) {
|
||||
sum += cur->occupied();
|
||||
cur = cur->next();
|
||||
@ -962,13 +610,13 @@ size_t OtherRegionsTable::mem_size() const {
|
||||
MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag);
|
||||
size_t sum = 0;
|
||||
for (size_t i = 0; i < _max_fine_entries; i++) {
|
||||
PosParPRT* cur = _fine_grain_regions[i];
|
||||
PerRegionTable* cur = _fine_grain_regions[i];
|
||||
while (cur != NULL) {
|
||||
sum += cur->mem_size();
|
||||
cur = cur->next();
|
||||
}
|
||||
}
|
||||
sum += (sizeof(PosParPRT*) * _max_fine_entries);
|
||||
sum += (sizeof(PerRegionTable*) * _max_fine_entries);
|
||||
sum += (_coarse_map.size_in_words() * HeapWordSize);
|
||||
sum += (_sparse_table.mem_size());
|
||||
sum += sizeof(*this) - sizeof(_sparse_table); // Avoid double counting above.
|
||||
@ -980,7 +628,7 @@ size_t OtherRegionsTable::static_mem_size() {
|
||||
}
|
||||
|
||||
size_t OtherRegionsTable::fl_mem_size() {
|
||||
return PerRegionTable::fl_mem_size() + PosParPRT::fl_mem_size();
|
||||
return PerRegionTable::fl_mem_size();
|
||||
}
|
||||
|
||||
void OtherRegionsTable::clear_fcc() {
|
||||
@ -992,10 +640,10 @@ void OtherRegionsTable::clear_fcc() {
|
||||
void OtherRegionsTable::clear() {
|
||||
MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
|
||||
for (size_t i = 0; i < _max_fine_entries; i++) {
|
||||
PosParPRT* cur = _fine_grain_regions[i];
|
||||
PerRegionTable* cur = _fine_grain_regions[i];
|
||||
while (cur != NULL) {
|
||||
PosParPRT* nxt = cur->next();
|
||||
PosParPRT::free(cur);
|
||||
PerRegionTable* nxt = cur->next();
|
||||
PerRegionTable::free(cur);
|
||||
cur = nxt;
|
||||
}
|
||||
_fine_grain_regions[i] = NULL;
|
||||
@ -1035,8 +683,8 @@ void OtherRegionsTable::clear_incoming_entry(HeapRegion* from_hr) {
|
||||
bool OtherRegionsTable::del_single_region_table(size_t ind,
|
||||
HeapRegion* hr) {
|
||||
assert(0 <= ind && ind < _max_fine_entries, "Preconditions.");
|
||||
PosParPRT** prev_addr = &_fine_grain_regions[ind];
|
||||
PosParPRT* prt = *prev_addr;
|
||||
PerRegionTable** prev_addr = &_fine_grain_regions[ind];
|
||||
PerRegionTable* prt = *prev_addr;
|
||||
while (prt != NULL && prt->hr() != hr) {
|
||||
prev_addr = prt->next_addr();
|
||||
prt = prt->next();
|
||||
@ -1044,7 +692,7 @@ bool OtherRegionsTable::del_single_region_table(size_t ind,
|
||||
if (prt != NULL) {
|
||||
assert(prt->hr() == hr, "Loop postcondition.");
|
||||
*prev_addr = prt->next();
|
||||
PosParPRT::free(prt);
|
||||
PerRegionTable::free(prt);
|
||||
_n_fine_entries--;
|
||||
return true;
|
||||
} else {
|
||||
@ -1065,7 +713,7 @@ bool OtherRegionsTable::contains_reference_locked(OopOrNarrowOopStar from) const
|
||||
// Is this region in the coarse map?
|
||||
if (_coarse_map.at(hr_ind)) return true;
|
||||
|
||||
PosParPRT* prt = find_region_table(hr_ind & _mod_max_fine_entries_mask,
|
||||
PerRegionTable* prt = find_region_table(hr_ind & _mod_max_fine_entries_mask,
|
||||
hr);
|
||||
if (prt != NULL) {
|
||||
return prt->contains_reference(from);
|
||||
@ -1145,7 +793,7 @@ void HeapRegionRemSet::print() const {
|
||||
G1CollectedHeap::heap()->bot_shared()->address_for_index(card_index);
|
||||
gclog_or_tty->print_cr(" Card " PTR_FORMAT, card_start);
|
||||
}
|
||||
// XXX
|
||||
|
||||
if (iter.n_yielded() != occupied()) {
|
||||
gclog_or_tty->print_cr("Yielded disagrees with occupied:");
|
||||
gclog_or_tty->print_cr(" %6d yielded (%6d coarse, %6d fine).",
|
||||
@ -1163,10 +811,6 @@ void HeapRegionRemSet::cleanup() {
|
||||
SparsePRT::cleanup_all();
|
||||
}
|
||||
|
||||
void HeapRegionRemSet::par_cleanup() {
|
||||
PosParPRT::par_contract_all();
|
||||
}
|
||||
|
||||
void HeapRegionRemSet::clear() {
|
||||
_other_regions.clear();
|
||||
assert(occupied() == 0, "Should be clear.");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 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
|
||||
@ -35,7 +35,7 @@ class G1CollectedHeap;
|
||||
class G1BlockOffsetSharedArray;
|
||||
class HeapRegion;
|
||||
class HeapRegionRemSetIterator;
|
||||
class PosParPRT;
|
||||
class PerRegionTable;
|
||||
class SparsePRT;
|
||||
|
||||
// Essentially a wrapper around SparsePRTCleanupTask. See
|
||||
@ -79,15 +79,14 @@ class OtherRegionsTable VALUE_OBJ_CLASS_SPEC {
|
||||
size_t _n_coarse_entries;
|
||||
static jint _n_coarsenings;
|
||||
|
||||
PosParPRT** _fine_grain_regions;
|
||||
size_t _n_fine_entries;
|
||||
PerRegionTable** _fine_grain_regions;
|
||||
size_t _n_fine_entries;
|
||||
|
||||
#define SAMPLE_FOR_EVICTION 1
|
||||
#if SAMPLE_FOR_EVICTION
|
||||
// Used to sample a subset of the fine grain PRTs to determine which
|
||||
// PRT to evict and coarsen.
|
||||
size_t _fine_eviction_start;
|
||||
static size_t _fine_eviction_stride;
|
||||
static size_t _fine_eviction_sample_size;
|
||||
#endif
|
||||
|
||||
SparsePRT _sparse_table;
|
||||
|
||||
@ -98,21 +97,18 @@ class OtherRegionsTable VALUE_OBJ_CLASS_SPEC {
|
||||
// Requires "prt" to be the first element of the bucket list appropriate
|
||||
// for "hr". If this list contains an entry for "hr", return it,
|
||||
// otherwise return "NULL".
|
||||
PosParPRT* find_region_table(size_t ind, HeapRegion* hr) const;
|
||||
PerRegionTable* find_region_table(size_t ind, HeapRegion* hr) const;
|
||||
|
||||
// Find, delete, and return a candidate PosParPRT, if any exists,
|
||||
// Find, delete, and return a candidate PerRegionTable, if any exists,
|
||||
// adding the deleted region to the coarse bitmap. Requires the caller
|
||||
// to hold _m, and the fine-grain table to be full.
|
||||
PosParPRT* delete_region_table();
|
||||
PerRegionTable* delete_region_table();
|
||||
|
||||
// If a PRT for "hr" is in the bucket list indicated by "ind" (which must
|
||||
// be the correct index for "hr"), delete it and return true; else return
|
||||
// false.
|
||||
bool del_single_region_table(size_t ind, HeapRegion* hr);
|
||||
|
||||
static jint _cache_probes;
|
||||
static jint _cache_hits;
|
||||
|
||||
// Indexed by thread X heap region, to minimize thread contention.
|
||||
static int** _from_card_cache;
|
||||
static size_t _from_card_cache_max_regions;
|
||||
@ -127,10 +123,6 @@ public:
|
||||
// sense.
|
||||
void add_reference(OopOrNarrowOopStar from, int tid);
|
||||
|
||||
void add_reference(OopOrNarrowOopStar from) {
|
||||
return add_reference(from, 0);
|
||||
}
|
||||
|
||||
// Removes any entries shown by the given bitmaps to contain only dead
|
||||
// objects.
|
||||
void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm);
|
||||
@ -233,14 +225,12 @@ public:
|
||||
|
||||
static jint n_coarsenings() { return OtherRegionsTable::n_coarsenings(); }
|
||||
|
||||
/* Used in the sequential case. Returns "true" iff this addition causes
|
||||
the size limit to be reached. */
|
||||
// Used in the sequential case.
|
||||
void add_reference(OopOrNarrowOopStar from) {
|
||||
_other_regions.add_reference(from);
|
||||
_other_regions.add_reference(from, 0);
|
||||
}
|
||||
|
||||
/* Used in the parallel case. Returns "true" iff this addition causes
|
||||
the size limit to be reached. */
|
||||
// Used in the parallel case.
|
||||
void add_reference(OopOrNarrowOopStar from, int tid) {
|
||||
_other_regions.add_reference(from, tid);
|
||||
}
|
||||
@ -253,15 +243,6 @@ public:
|
||||
// entries for this region in other remsets.
|
||||
void clear();
|
||||
|
||||
// Forget any entries due to pointers from "from_hr".
|
||||
void clear_incoming_entry(HeapRegion* from_hr) {
|
||||
_other_regions.clear_incoming_entry(from_hr);
|
||||
}
|
||||
|
||||
#if 0
|
||||
virtual void cleanup() = 0;
|
||||
#endif
|
||||
|
||||
// Attempt to claim the region. Returns true iff this call caused an
|
||||
// atomic transition from Unclaimed to Claimed.
|
||||
bool claim_iter();
|
||||
@ -290,12 +271,6 @@ public:
|
||||
// Initialize the given iterator to iterate over this rem set.
|
||||
void init_iterator(HeapRegionRemSetIterator* iter) const;
|
||||
|
||||
#if 0
|
||||
// Apply the "do_card" method to the start address of every card in the
|
||||
// rem set. Returns false if some application of the closure aborted.
|
||||
virtual bool card_iterate(CardClosure* iter) = 0;
|
||||
#endif
|
||||
|
||||
// The actual # of bytes this hr_remset takes up.
|
||||
size_t mem_size() {
|
||||
return _other_regions.mem_size()
|
||||
@ -322,10 +297,7 @@ public:
|
||||
void print() const;
|
||||
|
||||
// Called during a stop-world phase to perform any deferred cleanups.
|
||||
// The second version may be called by parallel threads after then finish
|
||||
// collection work.
|
||||
static void cleanup();
|
||||
static void par_cleanup();
|
||||
|
||||
// Declare the heap size (in # of regions) to the HeapRegionRemSet(s).
|
||||
// (Uses it to initialize from_card_cache).
|
||||
@ -367,7 +339,7 @@ class HeapRegionRemSetIterator : public CHeapObj {
|
||||
|
||||
// Local caching of HRRS fields.
|
||||
const BitMap* _coarse_map;
|
||||
PosParPRT** _fine_grain_regions;
|
||||
PerRegionTable** _fine_grain_regions;
|
||||
|
||||
G1BlockOffsetSharedArray* _bosa;
|
||||
G1CollectedHeap* _g1h;
|
||||
@ -404,8 +376,9 @@ class HeapRegionRemSetIterator : public CHeapObj {
|
||||
|
||||
// Index of bucket-list we're working on.
|
||||
int _fine_array_index;
|
||||
|
||||
// Per Region Table we're doing within current bucket list.
|
||||
PosParPRT* _fine_cur_prt;
|
||||
PerRegionTable* _fine_cur_prt;
|
||||
|
||||
/* SparsePRT::*/ SparsePRTIter _sparse_iter;
|
||||
|
||||
@ -435,12 +408,4 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
class CardClosure: public Closure {
|
||||
public:
|
||||
virtual void do_card(HeapWord* card_start) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONREMSET_HPP
|
||||
|
@ -62,8 +62,8 @@ public:
|
||||
// written later, increasing the likelihood that the shared page contain
|
||||
// the hash can be shared.
|
||||
//
|
||||
// NOTE THAT the algorithm in StringTable::hash_string() MUST MATCH the
|
||||
// algorithm in java.lang.String.hashCode().
|
||||
// NOTE THAT we have to call java_lang_String::to_hash() to match the
|
||||
// algorithm in java.lang.String.toHash().
|
||||
|
||||
class StringHashCodeClosure: public OopClosure {
|
||||
private:
|
||||
@ -80,7 +80,7 @@ public:
|
||||
oop obj = *p;
|
||||
if (obj->klass() == SystemDictionary::String_klass() &&
|
||||
java_lang_String::has_hash_field()) {
|
||||
int hash = java_lang_String::hash_string(obj);
|
||||
int hash = java_lang_String::to_hash(obj);
|
||||
obj->int_field_put(hash_offset, hash);
|
||||
}
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ class Universe: AllStatic {
|
||||
}
|
||||
|
||||
static klassOop typeArrayKlassObj(BasicType t) {
|
||||
assert((uint)t < T_VOID+1, "range check");
|
||||
assert((uint)t < T_VOID+1, err_msg("range check for type: %s", type2name(t)));
|
||||
assert(_typeArrayKlassObjs[t] != NULL, "domain check");
|
||||
return _typeArrayKlassObjs[t];
|
||||
}
|
||||
|
@ -81,6 +81,13 @@
|
||||
product(intx, MaxLoopPad, (OptoLoopAlignment-1), \
|
||||
"Align a loop if padding size in bytes is less or equal to this value") \
|
||||
\
|
||||
product(intx, MaxVectorSize, 32, \
|
||||
"Max vector size in bytes, " \
|
||||
"actual size could be less depending on elements type") \
|
||||
\
|
||||
product(bool, AlignVector, false, \
|
||||
"Perform vector store/load alignment in loop") \
|
||||
\
|
||||
product(intx, NumberOfLoopInstrToAlign, 4, \
|
||||
"Number of first instructions in a loop to align") \
|
||||
\
|
||||
@ -292,9 +299,12 @@
|
||||
develop(bool, SuperWordRTDepCheck, false, \
|
||||
"Enable runtime dependency checks.") \
|
||||
\
|
||||
product(bool, TraceSuperWord, false, \
|
||||
notproduct(bool, TraceSuperWord, false, \
|
||||
"Trace superword transforms") \
|
||||
\
|
||||
notproduct(bool, TraceNewVectors, false, \
|
||||
"Trace creation of Vector nodes") \
|
||||
\
|
||||
product_pd(bool, OptoBundling, \
|
||||
"Generate nops to fill i-cache lines") \
|
||||
\
|
||||
|
@ -172,9 +172,11 @@ public:
|
||||
|
||||
JVMState* DynamicCallGenerator::generate(JVMState* jvms) {
|
||||
GraphKit kit(jvms);
|
||||
Compile* C = kit.C;
|
||||
PhaseGVN& gvn = kit.gvn();
|
||||
|
||||
if (kit.C->log() != NULL) {
|
||||
kit.C->log()->elem("dynamic_call bci='%d'", jvms->bci());
|
||||
if (C->log() != NULL) {
|
||||
C->log()->elem("dynamic_call bci='%d'", jvms->bci());
|
||||
}
|
||||
|
||||
// Get the constant pool cache from the caller class.
|
||||
@ -190,18 +192,21 @@ JVMState* DynamicCallGenerator::generate(JVMState* jvms) {
|
||||
size_t call_site_offset = cpcache->get_f1_offset(index);
|
||||
|
||||
// Load the CallSite object from the constant pool cache.
|
||||
const TypeOopPtr* cpcache_ptr = TypeOopPtr::make_from_constant(cpcache);
|
||||
Node* cpcache_adr = kit.makecon(cpcache_ptr);
|
||||
Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, cpcache_adr, call_site_offset);
|
||||
Node* call_site = kit.make_load(kit.control(), call_site_adr, TypeInstPtr::BOTTOM, T_OBJECT, Compile::AliasIdxRaw);
|
||||
const TypeOopPtr* cpcache_type = TypeOopPtr::make_from_constant(cpcache); // returns TypeAryPtr of type T_OBJECT
|
||||
const TypeOopPtr* call_site_type = TypeOopPtr::make_from_klass(C->env()->CallSite_klass());
|
||||
Node* cpcache_adr = kit.makecon(cpcache_type);
|
||||
Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, call_site_offset);
|
||||
// The oops in the constant pool cache are not compressed; load then as raw pointers.
|
||||
Node* call_site = kit.make_load(kit.control(), call_site_adr, call_site_type, T_ADDRESS, Compile::AliasIdxRaw);
|
||||
|
||||
// Load the target MethodHandle from the CallSite object.
|
||||
Node* target_mh_adr = kit.basic_plus_adr(call_site, call_site, java_lang_invoke_CallSite::target_offset_in_bytes());
|
||||
Node* target_mh = kit.make_load(kit.control(), target_mh_adr, TypeInstPtr::BOTTOM, T_OBJECT);
|
||||
const TypeOopPtr* target_type = TypeOopPtr::make_from_klass(C->env()->MethodHandle_klass());
|
||||
Node* target_mh_adr = kit.basic_plus_adr(call_site, java_lang_invoke_CallSite::target_offset_in_bytes());
|
||||
Node* target_mh = kit.make_load(kit.control(), target_mh_adr, target_type, T_OBJECT);
|
||||
|
||||
address resolve_stub = SharedRuntime::get_resolve_opt_virtual_call_stub();
|
||||
|
||||
CallStaticJavaNode *call = new (kit.C, tf()->domain()->cnt()) CallStaticJavaNode(tf(), resolve_stub, method(), kit.bci());
|
||||
CallStaticJavaNode* call = new (C, tf()->domain()->cnt()) CallStaticJavaNode(tf(), resolve_stub, method(), kit.bci());
|
||||
// invokedynamic is treated as an optimized invokevirtual.
|
||||
call->set_optimized_virtual(true);
|
||||
// Take extra care (in the presence of argument motion) not to trash the SP:
|
||||
@ -785,9 +790,10 @@ CallGenerator* CallGenerator::for_invokedynamic_inline(ciCallSite* call_site, JV
|
||||
|
||||
JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) {
|
||||
GraphKit kit(jvms);
|
||||
Compile* C = kit.C;
|
||||
PhaseGVN& gvn = kit.gvn();
|
||||
|
||||
CompileLog* log = kit.C->log();
|
||||
CompileLog* log = C->log();
|
||||
if (log != NULL) {
|
||||
log->elem("predicted_dynamic_call bci='%d'", jvms->bci());
|
||||
}
|
||||
@ -803,8 +809,8 @@ JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) {
|
||||
Node* receiver = kit.argument(0);
|
||||
|
||||
// Check if the MethodHandle is the expected one
|
||||
Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(receiver, predicted_mh));
|
||||
bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) );
|
||||
Node* cmp = gvn.transform(new (C, 3) CmpPNode(receiver, predicted_mh));
|
||||
bol = gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::eq) );
|
||||
} else {
|
||||
// Get the constant pool cache from the caller class.
|
||||
ciMethod* caller_method = jvms->method();
|
||||
@ -818,22 +824,25 @@ JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) {
|
||||
size_t call_site_offset = cpcache->get_f1_offset(index);
|
||||
|
||||
// Load the CallSite object from the constant pool cache.
|
||||
const TypeOopPtr* cpcache_ptr = TypeOopPtr::make_from_constant(cpcache);
|
||||
Node* cpcache_adr = kit.makecon(cpcache_ptr);
|
||||
Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, cpcache_adr, call_site_offset);
|
||||
Node* call_site = kit.make_load(kit.control(), call_site_adr, TypeInstPtr::BOTTOM, T_OBJECT, Compile::AliasIdxRaw);
|
||||
const TypeOopPtr* cpcache_type = TypeOopPtr::make_from_constant(cpcache); // returns TypeAryPtr of type T_OBJECT
|
||||
const TypeOopPtr* call_site_type = TypeOopPtr::make_from_klass(C->env()->CallSite_klass());
|
||||
Node* cpcache_adr = kit.makecon(cpcache_type);
|
||||
Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, call_site_offset);
|
||||
// The oops in the constant pool cache are not compressed; load then as raw pointers.
|
||||
Node* call_site = kit.make_load(kit.control(), call_site_adr, call_site_type, T_ADDRESS, Compile::AliasIdxRaw);
|
||||
|
||||
// Load the target MethodHandle from the CallSite object.
|
||||
const TypeOopPtr* target_type = TypeOopPtr::make_from_klass(C->env()->MethodHandle_klass());
|
||||
Node* target_adr = kit.basic_plus_adr(call_site, call_site, java_lang_invoke_CallSite::target_offset_in_bytes());
|
||||
Node* target_mh = kit.make_load(kit.control(), target_adr, TypeInstPtr::BOTTOM, T_OBJECT);
|
||||
Node* target_mh = kit.make_load(kit.control(), target_adr, target_type, T_OBJECT);
|
||||
|
||||
// Check if the MethodHandle is still the same.
|
||||
Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(target_mh, predicted_mh));
|
||||
bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) );
|
||||
Node* cmp = gvn.transform(new (C, 3) CmpPNode(target_mh, predicted_mh));
|
||||
bol = gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::eq) );
|
||||
}
|
||||
IfNode* iff = kit.create_and_xform_if(kit.control(), bol, _hit_prob, COUNT_UNKNOWN);
|
||||
kit.set_control( gvn.transform(new(kit.C, 1) IfTrueNode (iff)));
|
||||
Node* slow_ctl = gvn.transform(new(kit.C, 1) IfFalseNode(iff));
|
||||
kit.set_control( gvn.transform(new (C, 1) IfTrueNode (iff)));
|
||||
Node* slow_ctl = gvn.transform(new (C, 1) IfFalseNode(iff));
|
||||
|
||||
SafePointNode* slow_map = NULL;
|
||||
JVMState* slow_jvms;
|
||||
@ -882,7 +891,7 @@ JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) {
|
||||
|
||||
// Finish the diamond.
|
||||
kit.C->set_has_split_ifs(true); // Has chance for split-if optimization
|
||||
RegionNode* region = new (kit.C, 3) RegionNode(3);
|
||||
RegionNode* region = new (C, 3) RegionNode(3);
|
||||
region->init_req(1, kit.control());
|
||||
region->init_req(2, slow_map->control());
|
||||
kit.set_control(gvn.transform(region));
|
||||
|
@ -75,6 +75,7 @@ void LRG::dump( ) const {
|
||||
// Flags
|
||||
if( _is_oop ) tty->print("Oop ");
|
||||
if( _is_float ) tty->print("Float ");
|
||||
if( _is_vector ) tty->print("Vector ");
|
||||
if( _was_spilled1 ) tty->print("Spilled ");
|
||||
if( _was_spilled2 ) tty->print("Spilled2 ");
|
||||
if( _direct_conflict ) tty->print("Direct_conflict ");
|
||||
@ -479,16 +480,18 @@ void PhaseChaitin::Register_Allocate() {
|
||||
|
||||
// Move important info out of the live_arena to longer lasting storage.
|
||||
alloc_node_regs(_names.Size());
|
||||
for( uint i=0; i < _names.Size(); i++ ) {
|
||||
if( _names[i] ) { // Live range associated with Node?
|
||||
LRG &lrg = lrgs( _names[i] );
|
||||
if( lrg.num_regs() == 1 ) {
|
||||
_node_regs[i].set1( lrg.reg() );
|
||||
for (uint i=0; i < _names.Size(); i++) {
|
||||
if (_names[i]) { // Live range associated with Node?
|
||||
LRG &lrg = lrgs(_names[i]);
|
||||
if (!lrg.alive()) {
|
||||
_node_regs[i].set_bad();
|
||||
} else if (lrg.num_regs() == 1) {
|
||||
_node_regs[i].set1(lrg.reg());
|
||||
} else { // Must be a register-pair
|
||||
if( !lrg._fat_proj ) { // Must be aligned adjacent register pair
|
||||
if (!lrg._fat_proj) { // Must be aligned adjacent register pair
|
||||
// Live ranges record the highest register in their mask.
|
||||
// We want the low register for the AD file writer's convenience.
|
||||
_node_regs[i].set2( OptoReg::add(lrg.reg(),-1) );
|
||||
_node_regs[i].set2( OptoReg::add(lrg.reg(),(1-lrg.num_regs())) );
|
||||
} else { // Misaligned; extract 2 bits
|
||||
OptoReg::Name hi = lrg.reg(); // Get hi register
|
||||
lrg.Remove(hi); // Yank from mask
|
||||
@ -568,7 +571,7 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) {
|
||||
// Check for float-vs-int live range (used in register-pressure
|
||||
// calculations)
|
||||
const Type *n_type = n->bottom_type();
|
||||
if( n_type->is_floatingpoint() )
|
||||
if (n_type->is_floatingpoint())
|
||||
lrg._is_float = 1;
|
||||
|
||||
// Check for twice prior spilling. Once prior spilling might have
|
||||
@ -599,18 +602,28 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) {
|
||||
// Limit result register mask to acceptable registers
|
||||
const RegMask &rm = n->out_RegMask();
|
||||
lrg.AND( rm );
|
||||
// Check for bound register masks
|
||||
const RegMask &lrgmask = lrg.mask();
|
||||
if( lrgmask.is_bound1() || lrgmask.is_bound2() )
|
||||
lrg._is_bound = 1;
|
||||
|
||||
// Check for maximum frequency value
|
||||
if( lrg._maxfreq < b->_freq )
|
||||
lrg._maxfreq = b->_freq;
|
||||
|
||||
int ireg = n->ideal_reg();
|
||||
assert( !n->bottom_type()->isa_oop_ptr() || ireg == Op_RegP,
|
||||
"oops must be in Op_RegP's" );
|
||||
|
||||
// Check for vector live range (only if vector register is used).
|
||||
// On SPARC vector uses RegD which could be misaligned so it is not
|
||||
// processes as vector in RA.
|
||||
if (RegMask::is_vector(ireg))
|
||||
lrg._is_vector = 1;
|
||||
assert(n_type->isa_vect() == NULL || lrg._is_vector || ireg == Op_RegD,
|
||||
"vector must be in vector registers");
|
||||
|
||||
// Check for bound register masks
|
||||
const RegMask &lrgmask = lrg.mask();
|
||||
if (lrgmask.is_bound(ireg))
|
||||
lrg._is_bound = 1;
|
||||
|
||||
// Check for maximum frequency value
|
||||
if (lrg._maxfreq < b->_freq)
|
||||
lrg._maxfreq = b->_freq;
|
||||
|
||||
// Check for oop-iness, or long/double
|
||||
// Check for multi-kill projection
|
||||
switch( ireg ) {
|
||||
@ -689,7 +702,7 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) {
|
||||
// AND changes how we count interferences. A mis-aligned
|
||||
// double can interfere with TWO aligned pairs, or effectively
|
||||
// FOUR registers!
|
||||
if( rm.is_misaligned_Pair() ) {
|
||||
if (rm.is_misaligned_pair()) {
|
||||
lrg._fat_proj = 1;
|
||||
lrg._is_bound = 1;
|
||||
}
|
||||
@ -706,6 +719,33 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) {
|
||||
lrg.set_reg_pressure(1);
|
||||
#endif
|
||||
break;
|
||||
case Op_VecS:
|
||||
assert(Matcher::vector_size_supported(T_BYTE,4), "sanity");
|
||||
assert(RegMask::num_registers(Op_VecS) == RegMask::SlotsPerVecS, "sanity");
|
||||
lrg.set_num_regs(RegMask::SlotsPerVecS);
|
||||
lrg.set_reg_pressure(1);
|
||||
break;
|
||||
case Op_VecD:
|
||||
assert(Matcher::vector_size_supported(T_FLOAT,RegMask::SlotsPerVecD), "sanity");
|
||||
assert(RegMask::num_registers(Op_VecD) == RegMask::SlotsPerVecD, "sanity");
|
||||
assert(lrgmask.is_aligned_sets(RegMask::SlotsPerVecD), "vector should be aligned");
|
||||
lrg.set_num_regs(RegMask::SlotsPerVecD);
|
||||
lrg.set_reg_pressure(1);
|
||||
break;
|
||||
case Op_VecX:
|
||||
assert(Matcher::vector_size_supported(T_FLOAT,RegMask::SlotsPerVecX), "sanity");
|
||||
assert(RegMask::num_registers(Op_VecX) == RegMask::SlotsPerVecX, "sanity");
|
||||
assert(lrgmask.is_aligned_sets(RegMask::SlotsPerVecX), "vector should be aligned");
|
||||
lrg.set_num_regs(RegMask::SlotsPerVecX);
|
||||
lrg.set_reg_pressure(1);
|
||||
break;
|
||||
case Op_VecY:
|
||||
assert(Matcher::vector_size_supported(T_FLOAT,RegMask::SlotsPerVecY), "sanity");
|
||||
assert(RegMask::num_registers(Op_VecY) == RegMask::SlotsPerVecY, "sanity");
|
||||
assert(lrgmask.is_aligned_sets(RegMask::SlotsPerVecY), "vector should be aligned");
|
||||
lrg.set_num_regs(RegMask::SlotsPerVecY);
|
||||
lrg.set_reg_pressure(1);
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
@ -763,24 +803,38 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) {
|
||||
} else {
|
||||
lrg.AND( rm );
|
||||
}
|
||||
|
||||
// Check for bound register masks
|
||||
const RegMask &lrgmask = lrg.mask();
|
||||
if( lrgmask.is_bound1() || lrgmask.is_bound2() )
|
||||
int kreg = n->in(k)->ideal_reg();
|
||||
bool is_vect = RegMask::is_vector(kreg);
|
||||
assert(n->in(k)->bottom_type()->isa_vect() == NULL ||
|
||||
is_vect || kreg == Op_RegD,
|
||||
"vector must be in vector registers");
|
||||
if (lrgmask.is_bound(kreg))
|
||||
lrg._is_bound = 1;
|
||||
|
||||
// If this use of a double forces a mis-aligned double,
|
||||
// flag as '_fat_proj' - really flag as allowing misalignment
|
||||
// AND changes how we count interferences. A mis-aligned
|
||||
// double can interfere with TWO aligned pairs, or effectively
|
||||
// FOUR registers!
|
||||
if( lrg.num_regs() == 2 && !lrg._fat_proj && rm.is_misaligned_Pair() ) {
|
||||
#ifdef ASSERT
|
||||
if (is_vect) {
|
||||
assert(lrgmask.is_aligned_sets(lrg.num_regs()), "vector should be aligned");
|
||||
assert(!lrg._fat_proj, "sanity");
|
||||
assert(RegMask::num_registers(kreg) == lrg.num_regs(), "sanity");
|
||||
}
|
||||
#endif
|
||||
if (!is_vect && lrg.num_regs() == 2 && !lrg._fat_proj && rm.is_misaligned_pair()) {
|
||||
lrg._fat_proj = 1;
|
||||
lrg._is_bound = 1;
|
||||
}
|
||||
// if the LRG is an unaligned pair, we will have to spill
|
||||
// so clear the LRG's register mask if it is not already spilled
|
||||
if ( !n->is_SpillCopy() &&
|
||||
(lrg._def == NULL || lrg.is_multidef() || !lrg._def->is_SpillCopy()) &&
|
||||
lrgmask.is_misaligned_Pair()) {
|
||||
if (!is_vect && !n->is_SpillCopy() &&
|
||||
(lrg._def == NULL || lrg.is_multidef() || !lrg._def->is_SpillCopy()) &&
|
||||
lrgmask.is_misaligned_pair()) {
|
||||
lrg.Clear();
|
||||
}
|
||||
|
||||
@ -793,12 +847,14 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) {
|
||||
} // end for all blocks
|
||||
|
||||
// Final per-liverange setup
|
||||
for( uint i2=0; i2<_maxlrg; i2++ ) {
|
||||
for (uint i2=0; i2<_maxlrg; i2++) {
|
||||
LRG &lrg = lrgs(i2);
|
||||
if( lrg.num_regs() == 2 && !lrg._fat_proj )
|
||||
lrg.ClearToPairs();
|
||||
assert(!lrg._is_vector || !lrg._fat_proj, "sanity");
|
||||
if (lrg.num_regs() > 1 && !lrg._fat_proj) {
|
||||
lrg.clear_to_sets();
|
||||
}
|
||||
lrg.compute_set_mask_size();
|
||||
if( lrg.not_free() ) { // Handle case where we lose from the start
|
||||
if (lrg.not_free()) { // Handle case where we lose from the start
|
||||
lrg.set_reg(OptoReg::Name(LRG::SPILL_REG));
|
||||
lrg._direct_conflict = 1;
|
||||
}
|
||||
@ -1104,22 +1160,17 @@ OptoReg::Name PhaseChaitin::bias_color( LRG &lrg, int chunk ) {
|
||||
// Choose a color which is legal for him
|
||||
RegMask tempmask = lrg.mask();
|
||||
tempmask.AND(lrgs(copy_lrg).mask());
|
||||
OptoReg::Name reg;
|
||||
if( lrg.num_regs() == 1 ) {
|
||||
reg = tempmask.find_first_elem();
|
||||
} else {
|
||||
tempmask.ClearToPairs();
|
||||
reg = tempmask.find_first_pair();
|
||||
}
|
||||
if( OptoReg::is_valid(reg) )
|
||||
tempmask.clear_to_sets(lrg.num_regs());
|
||||
OptoReg::Name reg = tempmask.find_first_set(lrg.num_regs());
|
||||
if (OptoReg::is_valid(reg))
|
||||
return reg;
|
||||
}
|
||||
}
|
||||
|
||||
// If no bias info exists, just go with the register selection ordering
|
||||
if( lrg.num_regs() == 2 ) {
|
||||
// Find an aligned pair
|
||||
return OptoReg::add(lrg.mask().find_first_pair(),chunk);
|
||||
if (lrg._is_vector || lrg.num_regs() == 2) {
|
||||
// Find an aligned set
|
||||
return OptoReg::add(lrg.mask().find_first_set(lrg.num_regs()),chunk);
|
||||
}
|
||||
|
||||
// CNC - Fun hack. Alternate 1st and 2nd selection. Enables post-allocate
|
||||
@ -1149,6 +1200,7 @@ OptoReg::Name PhaseChaitin::choose_color( LRG &lrg, int chunk ) {
|
||||
// Use a heuristic to "bias" the color choice
|
||||
return bias_color(lrg, chunk);
|
||||
|
||||
assert(!lrg._is_vector, "should be not vector here" );
|
||||
assert( lrg.num_regs() >= 2, "dead live ranges do not color" );
|
||||
|
||||
// Fat-proj case or misaligned double argument.
|
||||
@ -1238,14 +1290,16 @@ uint PhaseChaitin::Select( ) {
|
||||
}
|
||||
//assert(is_allstack == lrg->mask().is_AllStack(), "nbrs must not change AllStackedness");
|
||||
// Aligned pairs need aligned masks
|
||||
if( lrg->num_regs() == 2 && !lrg->_fat_proj )
|
||||
lrg->ClearToPairs();
|
||||
assert(!lrg->_is_vector || !lrg->_fat_proj, "sanity");
|
||||
if (lrg->num_regs() > 1 && !lrg->_fat_proj) {
|
||||
lrg->clear_to_sets();
|
||||
}
|
||||
|
||||
// Check if a color is available and if so pick the color
|
||||
OptoReg::Name reg = choose_color( *lrg, chunk );
|
||||
#ifdef SPARC
|
||||
debug_only(lrg->compute_set_mask_size());
|
||||
assert(lrg->num_regs() != 2 || lrg->is_bound() || is_even(reg-1), "allocate all doubles aligned");
|
||||
assert(lrg->num_regs() < 2 || lrg->is_bound() || is_even(reg-1), "allocate all doubles aligned");
|
||||
#endif
|
||||
|
||||
//---------------
|
||||
@ -1277,17 +1331,16 @@ uint PhaseChaitin::Select( ) {
|
||||
// If the live range is not bound, then we actually had some choices
|
||||
// to make. In this case, the mask has more bits in it than the colors
|
||||
// chosen. Restrict the mask to just what was picked.
|
||||
if( lrg->num_regs() == 1 ) { // Size 1 live range
|
||||
int n_regs = lrg->num_regs();
|
||||
assert(!lrg->_is_vector || !lrg->_fat_proj, "sanity");
|
||||
if (n_regs == 1 || !lrg->_fat_proj) {
|
||||
assert(!lrg->_is_vector || n_regs <= RegMask::SlotsPerVecY, "sanity");
|
||||
lrg->Clear(); // Clear the mask
|
||||
lrg->Insert(reg); // Set regmask to match selected reg
|
||||
lrg->set_mask_size(1);
|
||||
} else if( !lrg->_fat_proj ) {
|
||||
// For pairs, also insert the low bit of the pair
|
||||
assert( lrg->num_regs() == 2, "unbound fatproj???" );
|
||||
lrg->Clear(); // Clear the mask
|
||||
lrg->Insert(reg); // Set regmask to match selected reg
|
||||
lrg->Insert(OptoReg::add(reg,-1));
|
||||
lrg->set_mask_size(2);
|
||||
// For vectors and pairs, also insert the low bit of the pair
|
||||
for (int i = 1; i < n_regs; i++)
|
||||
lrg->Insert(OptoReg::add(reg,-i));
|
||||
lrg->set_mask_size(n_regs);
|
||||
} else { // Else fatproj
|
||||
// mask must be equal to fatproj bits, by definition
|
||||
}
|
||||
@ -1483,7 +1536,7 @@ Node *PhaseChaitin::find_base_for_derived( Node **derived_base_map, Node *derive
|
||||
|
||||
// Check for AddP-related opcodes
|
||||
if( !derived->is_Phi() ) {
|
||||
assert( derived->as_Mach()->ideal_Opcode() == Op_AddP, "" );
|
||||
assert(derived->as_Mach()->ideal_Opcode() == Op_AddP, err_msg("but is: %s", derived->Name()));
|
||||
Node *base = derived->in(AddPNode::Base);
|
||||
derived_base_map[derived->_idx] = base;
|
||||
return base;
|
||||
@ -1860,12 +1913,20 @@ char *PhaseChaitin::dump_register( const Node *n, char *buf ) const {
|
||||
sprintf(buf,"L%d",lidx); // No register binding yet
|
||||
} else if( !lidx ) { // Special, not allocated value
|
||||
strcpy(buf,"Special");
|
||||
} else if( (lrgs(lidx).num_regs() == 1)
|
||||
? !lrgs(lidx).mask().is_bound1()
|
||||
: !lrgs(lidx).mask().is_bound2() ) {
|
||||
sprintf(buf,"L%d",lidx); // No register binding yet
|
||||
} else { // Hah! We have a bound machine register
|
||||
print_reg( lrgs(lidx).reg(), this, buf );
|
||||
} else {
|
||||
if (lrgs(lidx)._is_vector) {
|
||||
if (lrgs(lidx).mask().is_bound_set(lrgs(lidx).num_regs()))
|
||||
print_reg( lrgs(lidx).reg(), this, buf ); // a bound machine register
|
||||
else
|
||||
sprintf(buf,"L%d",lidx); // No register binding yet
|
||||
} else if( (lrgs(lidx).num_regs() == 1)
|
||||
? lrgs(lidx).mask().is_bound1()
|
||||
: lrgs(lidx).mask().is_bound_pair() ) {
|
||||
// Hah! We have a bound machine register
|
||||
print_reg( lrgs(lidx).reg(), this, buf );
|
||||
} else {
|
||||
sprintf(buf,"L%d",lidx); // No register binding yet
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf+strlen(buf);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -99,8 +99,15 @@ public:
|
||||
void set_mask_size( int size ) {
|
||||
assert((size == 65535) || (size == (int)_mask.Size()), "");
|
||||
_mask_size = size;
|
||||
debug_only(_msize_valid=1;)
|
||||
debug_only( if( _num_regs == 2 && !_fat_proj ) _mask.VerifyPairs(); )
|
||||
#ifdef ASSERT
|
||||
_msize_valid=1;
|
||||
if (_is_vector) {
|
||||
assert(!_fat_proj, "sanity");
|
||||
_mask.verify_sets(_num_regs);
|
||||
} else if (_num_regs == 2 && !_fat_proj) {
|
||||
_mask.verify_pairs();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
void compute_set_mask_size() { set_mask_size(compute_mask_size()); }
|
||||
int mask_size() const { assert( _msize_valid, "mask size not valid" );
|
||||
@ -116,7 +123,8 @@ public:
|
||||
void Set_All() { _mask.Set_All(); debug_only(_msize_valid=1); _mask_size = RegMask::CHUNK_SIZE; }
|
||||
void Insert( OptoReg::Name reg ) { _mask.Insert(reg); debug_only(_msize_valid=0;) }
|
||||
void Remove( OptoReg::Name reg ) { _mask.Remove(reg); debug_only(_msize_valid=0;) }
|
||||
void ClearToPairs() { _mask.ClearToPairs(); debug_only(_msize_valid=0;) }
|
||||
void clear_to_pairs() { _mask.clear_to_pairs(); debug_only(_msize_valid=0;) }
|
||||
void clear_to_sets() { _mask.clear_to_sets(_num_regs); debug_only(_msize_valid=0;) }
|
||||
|
||||
// Number of registers this live range uses when it colors
|
||||
private:
|
||||
@ -150,6 +158,7 @@ public:
|
||||
|
||||
uint _is_oop:1, // Live-range holds an oop
|
||||
_is_float:1, // True if in float registers
|
||||
_is_vector:1, // True if in vector registers
|
||||
_was_spilled1:1, // True if prior spilling on def
|
||||
_was_spilled2:1, // True if twice prior spilling on def
|
||||
_is_bound:1, // live range starts life with no
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -245,14 +245,12 @@ macro(XorI)
|
||||
macro(XorL)
|
||||
macro(Vector)
|
||||
macro(AddVB)
|
||||
macro(AddVC)
|
||||
macro(AddVS)
|
||||
macro(AddVI)
|
||||
macro(AddVL)
|
||||
macro(AddVF)
|
||||
macro(AddVD)
|
||||
macro(SubVB)
|
||||
macro(SubVC)
|
||||
macro(SubVS)
|
||||
macro(SubVI)
|
||||
macro(SubVL)
|
||||
@ -263,74 +261,36 @@ macro(MulVD)
|
||||
macro(DivVF)
|
||||
macro(DivVD)
|
||||
macro(LShiftVB)
|
||||
macro(LShiftVC)
|
||||
macro(LShiftVS)
|
||||
macro(LShiftVI)
|
||||
macro(URShiftVB)
|
||||
macro(URShiftVC)
|
||||
macro(URShiftVS)
|
||||
macro(URShiftVI)
|
||||
macro(RShiftVB)
|
||||
macro(RShiftVS)
|
||||
macro(RShiftVI)
|
||||
macro(AndV)
|
||||
macro(OrV)
|
||||
macro(XorV)
|
||||
macro(VectorLoad)
|
||||
macro(Load16B)
|
||||
macro(Load8B)
|
||||
macro(Load4B)
|
||||
macro(Load8C)
|
||||
macro(Load4C)
|
||||
macro(Load2C)
|
||||
macro(Load8S)
|
||||
macro(Load4S)
|
||||
macro(Load2S)
|
||||
macro(Load4I)
|
||||
macro(Load2I)
|
||||
macro(Load2L)
|
||||
macro(Load4F)
|
||||
macro(Load2F)
|
||||
macro(Load2D)
|
||||
macro(VectorStore)
|
||||
macro(Store16B)
|
||||
macro(Store8B)
|
||||
macro(Store4B)
|
||||
macro(Store8C)
|
||||
macro(Store4C)
|
||||
macro(Store2C)
|
||||
macro(Store4I)
|
||||
macro(Store2I)
|
||||
macro(Store2L)
|
||||
macro(Store4F)
|
||||
macro(Store2F)
|
||||
macro(Store2D)
|
||||
macro(LoadVector)
|
||||
macro(StoreVector)
|
||||
macro(Pack)
|
||||
macro(PackB)
|
||||
macro(PackS)
|
||||
macro(PackC)
|
||||
macro(PackI)
|
||||
macro(PackL)
|
||||
macro(PackF)
|
||||
macro(PackD)
|
||||
macro(Pack2x1B)
|
||||
macro(Pack2x2B)
|
||||
macro(Replicate16B)
|
||||
macro(Replicate8B)
|
||||
macro(Replicate4B)
|
||||
macro(Replicate8S)
|
||||
macro(Replicate4S)
|
||||
macro(Replicate2S)
|
||||
macro(Replicate8C)
|
||||
macro(Replicate4C)
|
||||
macro(Replicate2C)
|
||||
macro(Replicate4I)
|
||||
macro(Replicate2I)
|
||||
macro(Replicate2L)
|
||||
macro(Replicate4F)
|
||||
macro(Replicate2F)
|
||||
macro(Replicate2D)
|
||||
macro(Pack2L)
|
||||
macro(Pack2D)
|
||||
macro(ReplicateB)
|
||||
macro(ReplicateS)
|
||||
macro(ReplicateI)
|
||||
macro(ReplicateL)
|
||||
macro(ReplicateF)
|
||||
macro(ReplicateD)
|
||||
macro(Extract)
|
||||
macro(ExtractB)
|
||||
macro(ExtractS)
|
||||
macro(ExtractUB)
|
||||
macro(ExtractC)
|
||||
macro(ExtractS)
|
||||
macro(ExtractI)
|
||||
macro(ExtractL)
|
||||
macro(ExtractF)
|
||||
|
@ -2591,38 +2591,12 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc ) {
|
||||
}
|
||||
break;
|
||||
|
||||
case Op_Load16B:
|
||||
case Op_Load8B:
|
||||
case Op_Load4B:
|
||||
case Op_Load8S:
|
||||
case Op_Load4S:
|
||||
case Op_Load2S:
|
||||
case Op_Load8C:
|
||||
case Op_Load4C:
|
||||
case Op_Load2C:
|
||||
case Op_Load4I:
|
||||
case Op_Load2I:
|
||||
case Op_Load2L:
|
||||
case Op_Load4F:
|
||||
case Op_Load2F:
|
||||
case Op_Load2D:
|
||||
case Op_Store16B:
|
||||
case Op_Store8B:
|
||||
case Op_Store4B:
|
||||
case Op_Store8C:
|
||||
case Op_Store4C:
|
||||
case Op_Store2C:
|
||||
case Op_Store4I:
|
||||
case Op_Store2I:
|
||||
case Op_Store2L:
|
||||
case Op_Store4F:
|
||||
case Op_Store2F:
|
||||
case Op_Store2D:
|
||||
case Op_LoadVector:
|
||||
case Op_StoreVector:
|
||||
break;
|
||||
|
||||
case Op_PackB:
|
||||
case Op_PackS:
|
||||
case Op_PackC:
|
||||
case Op_PackI:
|
||||
case Op_PackF:
|
||||
case Op_PackL:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, 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
|
||||
@ -416,6 +416,7 @@ uint PhaseChaitin::count_int_pressure( IndexSet *liveout ) {
|
||||
if( lrgs(lidx).mask().is_UP() &&
|
||||
lrgs(lidx).mask_size() &&
|
||||
!lrgs(lidx)._is_float &&
|
||||
!lrgs(lidx)._is_vector &&
|
||||
lrgs(lidx).mask().overlap(*Matcher::idealreg2regmask[Op_RegI]) )
|
||||
cnt += lrgs(lidx).reg_pressure();
|
||||
}
|
||||
@ -430,7 +431,7 @@ uint PhaseChaitin::count_float_pressure( IndexSet *liveout ) {
|
||||
while ((lidx = elements.next()) != 0) {
|
||||
if( lrgs(lidx).mask().is_UP() &&
|
||||
lrgs(lidx).mask_size() &&
|
||||
lrgs(lidx)._is_float )
|
||||
(lrgs(lidx)._is_float || lrgs(lidx)._is_vector))
|
||||
cnt += lrgs(lidx).reg_pressure();
|
||||
}
|
||||
return cnt;
|
||||
@ -439,8 +440,8 @@ uint PhaseChaitin::count_float_pressure( IndexSet *liveout ) {
|
||||
//------------------------------lower_pressure---------------------------------
|
||||
// Adjust register pressure down by 1. Capture last hi-to-low transition,
|
||||
static void lower_pressure( LRG *lrg, uint where, Block *b, uint *pressure, uint *hrp_index ) {
|
||||
if( lrg->mask().is_UP() && lrg->mask_size() ) {
|
||||
if( lrg->_is_float ) {
|
||||
if (lrg->mask().is_UP() && lrg->mask_size()) {
|
||||
if (lrg->_is_float || lrg->_is_vector) {
|
||||
pressure[1] -= lrg->reg_pressure();
|
||||
if( pressure[1] == (uint)FLOATPRESSURE ) {
|
||||
hrp_index[1] = where;
|
||||
@ -522,8 +523,8 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) {
|
||||
LRG &lrg = lrgs(lidx);
|
||||
lrg._area += cost;
|
||||
// Compute initial register pressure
|
||||
if( lrg.mask().is_UP() && lrg.mask_size() ) {
|
||||
if( lrg._is_float ) { // Count float pressure
|
||||
if (lrg.mask().is_UP() && lrg.mask_size()) {
|
||||
if (lrg._is_float || lrg._is_vector) { // Count float pressure
|
||||
pressure[1] += lrg.reg_pressure();
|
||||
#ifdef EXACT_PRESSURE
|
||||
if( pressure[1] > b->_freg_pressure )
|
||||
@ -681,13 +682,10 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) {
|
||||
// according to its bindings.
|
||||
const RegMask &rmask = lrgs(r).mask();
|
||||
if( lrgs(r).is_bound() && !(n->rematerialize()) && rmask.is_NotEmpty() ) {
|
||||
// Smear odd bits; leave only aligned pairs of bits.
|
||||
RegMask r2mask = rmask;
|
||||
r2mask.SmearToPairs();
|
||||
// Check for common case
|
||||
int r_size = lrgs(r).num_regs();
|
||||
OptoReg::Name r_reg = (r_size == 1) ? rmask.find_first_elem() : OptoReg::Physical;
|
||||
|
||||
// Smear odd bits
|
||||
IndexSetIterator elements(&liveout);
|
||||
uint l;
|
||||
while ((l = elements.next()) != 0) {
|
||||
@ -701,10 +699,15 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) {
|
||||
// Remove the bits from LRG 'r' from LRG 'l' so 'l' no
|
||||
// longer interferes with 'r'. If 'l' requires aligned
|
||||
// adjacent pairs, subtract out bit pairs.
|
||||
if( lrg.num_regs() == 2 && !lrg._fat_proj ) {
|
||||
assert(!lrg._is_vector || !lrg._fat_proj, "sanity");
|
||||
if (lrg.num_regs() > 1 && !lrg._fat_proj) {
|
||||
RegMask r2mask = rmask;
|
||||
// Leave only aligned set of bits.
|
||||
r2mask.smear_to_sets(lrg.num_regs());
|
||||
// It includes vector case.
|
||||
lrg.SUBTRACT( r2mask );
|
||||
lrg.compute_set_mask_size();
|
||||
} else if( r_size != 1 ) {
|
||||
} else if( r_size != 1 ) { // fat proj
|
||||
lrg.SUBTRACT( rmask );
|
||||
lrg.compute_set_mask_size();
|
||||
} else { // Common case: size 1 bound removal
|
||||
@ -763,8 +766,8 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) {
|
||||
// Newly live things assumed live from here to top of block
|
||||
lrg._area += cost;
|
||||
// Adjust register pressure
|
||||
if( lrg.mask().is_UP() && lrg.mask_size() ) {
|
||||
if( lrg._is_float ) {
|
||||
if (lrg.mask().is_UP() && lrg.mask_size()) {
|
||||
if (lrg._is_float || lrg._is_vector) {
|
||||
pressure[1] += lrg.reg_pressure();
|
||||
#ifdef EXACT_PRESSURE
|
||||
if( pressure[1] > b->_freg_pressure )
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2011, 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
|
||||
@ -139,6 +139,7 @@ void Block::implicit_null_check(PhaseCFG *cfg, Node *proj, Node *val, int allowe
|
||||
int iop = mach->ideal_Opcode();
|
||||
switch( iop ) {
|
||||
case Op_LoadB:
|
||||
case Op_LoadUB:
|
||||
case Op_LoadUS:
|
||||
case Op_LoadD:
|
||||
case Op_LoadF:
|
||||
@ -445,6 +446,11 @@ Node *Block::select(PhaseCFG *cfg, Node_List &worklist, GrowableArray<int> &read
|
||||
if( e->is_MachNullCheck() && e->in(1) == n )
|
||||
continue;
|
||||
|
||||
// Schedule IV increment last.
|
||||
if (e->is_Mach() && e->as_Mach()->ideal_Opcode() == Op_CountedLoopEnd &&
|
||||
e->in(1)->in(1) == n && n->is_iteratively_computed())
|
||||
continue;
|
||||
|
||||
uint n_choice = 2;
|
||||
|
||||
// See if this instruction is consumed by a branch. If so, then (as the
|
||||
|
@ -3592,8 +3592,10 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) {
|
||||
}
|
||||
|
||||
// Bail out if length is negative.
|
||||
// ...Not needed, since the new_array will throw the right exception.
|
||||
//generate_negative_guard(length, bailout, &length);
|
||||
// Without this the new_array would throw
|
||||
// NegativeArraySizeException but IllegalArgumentException is what
|
||||
// should be thrown
|
||||
generate_negative_guard(length, bailout, &length);
|
||||
|
||||
if (bailout->req() > 1) {
|
||||
PreserveJVMState pjvms(this);
|
||||
@ -3617,7 +3619,9 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) {
|
||||
// Extreme case: Arrays.copyOf((Integer[])x, 10, String[].class).
|
||||
// This will fail a store-check if x contains any non-nulls.
|
||||
bool disjoint_bases = true;
|
||||
bool length_never_negative = true;
|
||||
// if start > orig_length then the length of the copy may be
|
||||
// negative.
|
||||
bool length_never_negative = !is_copyOfRange;
|
||||
generate_arraycopy(TypeAryPtr::OOPS, T_OBJECT,
|
||||
original, start, newcopy, intcon(0), moved,
|
||||
disjoint_bases, length_never_negative);
|
||||
|
@ -2751,7 +2751,8 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
|
||||
// Do not count uncommon calls
|
||||
if( !n->is_CallStaticJava() || !n->as_CallStaticJava()->_name ) {
|
||||
Node *iff = n->in(0)->in(0);
|
||||
if( !iff->is_If() ||
|
||||
// No any calls for vectorized loops.
|
||||
if( UseSuperWord || !iff->is_If() ||
|
||||
(n->in(0)->Opcode() == Op_IfFalse &&
|
||||
(1.0 - iff->as_If()->_prob) >= 0.01) ||
|
||||
(iff->as_If()->_prob >= 0.01) )
|
||||
@ -3216,7 +3217,8 @@ void PhaseIdealLoop::build_loop_late_post( Node *n ) {
|
||||
case Op_ModF:
|
||||
case Op_ModD:
|
||||
case Op_LoadB: // Same with Loads; they can sink
|
||||
case Op_LoadUS: // during loop optimizations.
|
||||
case Op_LoadUB: // during loop optimizations.
|
||||
case Op_LoadUS:
|
||||
case Op_LoadD:
|
||||
case Op_LoadF:
|
||||
case Op_LoadI:
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -439,9 +439,9 @@ bool MachNode::rematerialize() const {
|
||||
// Don't remateralize somebody with bound inputs - it stretches a
|
||||
// fixed register lifetime.
|
||||
uint idx = oper_input_base();
|
||||
if( req() > idx ) {
|
||||
if (req() > idx) {
|
||||
const RegMask &rm = in_RegMask(idx);
|
||||
if( rm.is_bound1() || rm.is_bound2() )
|
||||
if (rm.is_bound(ideal_reg()))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -319,6 +319,7 @@ public:
|
||||
class MachTypeNode : public MachNode {
|
||||
virtual uint size_of() const { return sizeof(*this); } // Size is bigger
|
||||
public:
|
||||
MachTypeNode( ) {}
|
||||
const Type *_bottom_type;
|
||||
|
||||
virtual const class Type *bottom_type() const { return _bottom_type; }
|
||||
@ -370,12 +371,12 @@ public:
|
||||
|
||||
//------------------------------MachConstantNode-------------------------------
|
||||
// Machine node that holds a constant which is stored in the constant table.
|
||||
class MachConstantNode : public MachNode {
|
||||
class MachConstantNode : public MachTypeNode {
|
||||
protected:
|
||||
Compile::Constant _constant; // This node's constant.
|
||||
|
||||
public:
|
||||
MachConstantNode() : MachNode() {
|
||||
MachConstantNode() : MachTypeNode() {
|
||||
init_class_id(Class_MachConstant);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -35,6 +35,7 @@
|
||||
#include "opto/rootnode.hpp"
|
||||
#include "opto/runtime.hpp"
|
||||
#include "opto/type.hpp"
|
||||
#include "opto/vectornode.hpp"
|
||||
#include "runtime/atomic.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#ifdef TARGET_ARCH_MODEL_x86_32
|
||||
@ -58,18 +59,6 @@
|
||||
|
||||
OptoReg::Name OptoReg::c_frame_pointer;
|
||||
|
||||
|
||||
|
||||
const int Matcher::base2reg[Type::lastype] = {
|
||||
Node::NotAMachineReg,0,0, Op_RegI, Op_RegL, 0, Op_RegN,
|
||||
Node::NotAMachineReg, Node::NotAMachineReg, /* tuple, array */
|
||||
Op_RegP, Op_RegP, Op_RegP, Op_RegP, Op_RegP, Op_RegP, /* the pointers */
|
||||
0, 0/*abio*/,
|
||||
Op_RegP /* Return address */, 0, /* the memories */
|
||||
Op_RegF, Op_RegF, Op_RegF, Op_RegD, Op_RegD, Op_RegD,
|
||||
0 /*bottom*/
|
||||
};
|
||||
|
||||
const RegMask *Matcher::idealreg2regmask[_last_machine_leaf];
|
||||
RegMask Matcher::mreg2regmask[_last_Mach_Reg];
|
||||
RegMask Matcher::STACK_ONLY_mask;
|
||||
@ -107,6 +96,10 @@ Matcher::Matcher( Node_List &proj_list ) :
|
||||
idealreg2spillmask [Op_RegF] = NULL;
|
||||
idealreg2spillmask [Op_RegD] = NULL;
|
||||
idealreg2spillmask [Op_RegP] = NULL;
|
||||
idealreg2spillmask [Op_VecS] = NULL;
|
||||
idealreg2spillmask [Op_VecD] = NULL;
|
||||
idealreg2spillmask [Op_VecX] = NULL;
|
||||
idealreg2spillmask [Op_VecY] = NULL;
|
||||
|
||||
idealreg2debugmask [Op_RegI] = NULL;
|
||||
idealreg2debugmask [Op_RegN] = NULL;
|
||||
@ -114,6 +107,10 @@ Matcher::Matcher( Node_List &proj_list ) :
|
||||
idealreg2debugmask [Op_RegF] = NULL;
|
||||
idealreg2debugmask [Op_RegD] = NULL;
|
||||
idealreg2debugmask [Op_RegP] = NULL;
|
||||
idealreg2debugmask [Op_VecS] = NULL;
|
||||
idealreg2debugmask [Op_VecD] = NULL;
|
||||
idealreg2debugmask [Op_VecX] = NULL;
|
||||
idealreg2debugmask [Op_VecY] = NULL;
|
||||
|
||||
idealreg2mhdebugmask[Op_RegI] = NULL;
|
||||
idealreg2mhdebugmask[Op_RegN] = NULL;
|
||||
@ -121,6 +118,10 @@ Matcher::Matcher( Node_List &proj_list ) :
|
||||
idealreg2mhdebugmask[Op_RegF] = NULL;
|
||||
idealreg2mhdebugmask[Op_RegD] = NULL;
|
||||
idealreg2mhdebugmask[Op_RegP] = NULL;
|
||||
idealreg2mhdebugmask[Op_VecS] = NULL;
|
||||
idealreg2mhdebugmask[Op_VecD] = NULL;
|
||||
idealreg2mhdebugmask[Op_VecX] = NULL;
|
||||
idealreg2mhdebugmask[Op_VecY] = NULL;
|
||||
|
||||
debug_only(_mem_node = NULL;) // Ideal memory node consumed by mach node
|
||||
}
|
||||
@ -134,7 +135,7 @@ OptoReg::Name Matcher::warp_incoming_stk_arg( VMReg reg ) {
|
||||
warped = OptoReg::add(warped, C->out_preserve_stack_slots());
|
||||
if( warped >= _in_arg_limit )
|
||||
_in_arg_limit = OptoReg::add(warped, 1); // Bump max stack slot seen
|
||||
if (!RegMask::can_represent(warped)) {
|
||||
if (!RegMask::can_represent_arg(warped)) {
|
||||
// the compiler cannot represent this method's calling sequence
|
||||
C->record_method_not_compilable_all_tiers("unsupported incoming calling sequence");
|
||||
return OptoReg::Bad;
|
||||
@ -302,7 +303,7 @@ void Matcher::match( ) {
|
||||
_out_arg_limit = OptoReg::add(_new_SP, C->out_preserve_stack_slots());
|
||||
assert( is_even(_out_arg_limit), "out_preserve must be even" );
|
||||
|
||||
if (!RegMask::can_represent(OptoReg::add(_out_arg_limit,-1))) {
|
||||
if (!RegMask::can_represent_arg(OptoReg::add(_out_arg_limit,-1))) {
|
||||
// the compiler cannot represent this method's calling sequence
|
||||
C->record_method_not_compilable("must be able to represent all call arguments in reg mask");
|
||||
}
|
||||
@ -428,7 +429,7 @@ static RegMask *init_input_masks( uint size, RegMask &ret_adr, RegMask &fp ) {
|
||||
void Matcher::init_first_stack_mask() {
|
||||
|
||||
// Allocate storage for spill masks as masks for the appropriate load type.
|
||||
RegMask *rms = (RegMask*)C->comp_arena()->Amalloc_D(sizeof(RegMask) * 3*6);
|
||||
RegMask *rms = (RegMask*)C->comp_arena()->Amalloc_D(sizeof(RegMask) * (3*6+4));
|
||||
|
||||
idealreg2spillmask [Op_RegN] = &rms[0];
|
||||
idealreg2spillmask [Op_RegI] = &rms[1];
|
||||
@ -451,6 +452,11 @@ void Matcher::init_first_stack_mask() {
|
||||
idealreg2mhdebugmask[Op_RegD] = &rms[16];
|
||||
idealreg2mhdebugmask[Op_RegP] = &rms[17];
|
||||
|
||||
idealreg2spillmask [Op_VecS] = &rms[18];
|
||||
idealreg2spillmask [Op_VecD] = &rms[19];
|
||||
idealreg2spillmask [Op_VecX] = &rms[20];
|
||||
idealreg2spillmask [Op_VecY] = &rms[21];
|
||||
|
||||
OptoReg::Name i;
|
||||
|
||||
// At first, start with the empty mask
|
||||
@ -462,7 +468,7 @@ void Matcher::init_first_stack_mask() {
|
||||
C->FIRST_STACK_mask().Insert(i);
|
||||
|
||||
// Add in all bits past the outgoing argument area
|
||||
guarantee(RegMask::can_represent(OptoReg::add(_out_arg_limit,-1)),
|
||||
guarantee(RegMask::can_represent_arg(OptoReg::add(_out_arg_limit,-1)),
|
||||
"must be able to represent all call arguments in reg mask");
|
||||
init = _out_arg_limit;
|
||||
for (i = init; RegMask::can_represent(i); i = OptoReg::add(i,1))
|
||||
@ -472,21 +478,48 @@ void Matcher::init_first_stack_mask() {
|
||||
C->FIRST_STACK_mask().set_AllStack();
|
||||
|
||||
// Make spill masks. Registers for their class, plus FIRST_STACK_mask.
|
||||
RegMask aligned_stack_mask = C->FIRST_STACK_mask();
|
||||
// Keep spill masks aligned.
|
||||
aligned_stack_mask.clear_to_pairs();
|
||||
assert(aligned_stack_mask.is_AllStack(), "should be infinite stack");
|
||||
|
||||
*idealreg2spillmask[Op_RegP] = *idealreg2regmask[Op_RegP];
|
||||
#ifdef _LP64
|
||||
*idealreg2spillmask[Op_RegN] = *idealreg2regmask[Op_RegN];
|
||||
idealreg2spillmask[Op_RegN]->OR(C->FIRST_STACK_mask());
|
||||
idealreg2spillmask[Op_RegP]->OR(aligned_stack_mask);
|
||||
#else
|
||||
idealreg2spillmask[Op_RegP]->OR(C->FIRST_STACK_mask());
|
||||
#endif
|
||||
*idealreg2spillmask[Op_RegI] = *idealreg2regmask[Op_RegI];
|
||||
idealreg2spillmask[Op_RegI]->OR(C->FIRST_STACK_mask());
|
||||
*idealreg2spillmask[Op_RegL] = *idealreg2regmask[Op_RegL];
|
||||
idealreg2spillmask[Op_RegL]->OR(C->FIRST_STACK_mask());
|
||||
idealreg2spillmask[Op_RegL]->OR(aligned_stack_mask);
|
||||
*idealreg2spillmask[Op_RegF] = *idealreg2regmask[Op_RegF];
|
||||
idealreg2spillmask[Op_RegF]->OR(C->FIRST_STACK_mask());
|
||||
*idealreg2spillmask[Op_RegD] = *idealreg2regmask[Op_RegD];
|
||||
idealreg2spillmask[Op_RegD]->OR(C->FIRST_STACK_mask());
|
||||
*idealreg2spillmask[Op_RegP] = *idealreg2regmask[Op_RegP];
|
||||
idealreg2spillmask[Op_RegP]->OR(C->FIRST_STACK_mask());
|
||||
idealreg2spillmask[Op_RegD]->OR(aligned_stack_mask);
|
||||
|
||||
if (Matcher::vector_size_supported(T_BYTE,4)) {
|
||||
*idealreg2spillmask[Op_VecS] = *idealreg2regmask[Op_VecS];
|
||||
idealreg2spillmask[Op_VecS]->OR(C->FIRST_STACK_mask());
|
||||
}
|
||||
if (Matcher::vector_size_supported(T_FLOAT,2)) {
|
||||
*idealreg2spillmask[Op_VecD] = *idealreg2regmask[Op_VecD];
|
||||
idealreg2spillmask[Op_VecD]->OR(aligned_stack_mask);
|
||||
}
|
||||
if (Matcher::vector_size_supported(T_FLOAT,4)) {
|
||||
aligned_stack_mask.clear_to_sets(RegMask::SlotsPerVecX);
|
||||
assert(aligned_stack_mask.is_AllStack(), "should be infinite stack");
|
||||
*idealreg2spillmask[Op_VecX] = *idealreg2regmask[Op_VecX];
|
||||
idealreg2spillmask[Op_VecX]->OR(aligned_stack_mask);
|
||||
}
|
||||
if (Matcher::vector_size_supported(T_FLOAT,8)) {
|
||||
aligned_stack_mask.clear_to_sets(RegMask::SlotsPerVecY);
|
||||
assert(aligned_stack_mask.is_AllStack(), "should be infinite stack");
|
||||
*idealreg2spillmask[Op_VecY] = *idealreg2regmask[Op_VecY];
|
||||
idealreg2spillmask[Op_VecY]->OR(aligned_stack_mask);
|
||||
}
|
||||
if (UseFPUForSpilling) {
|
||||
// This mask logic assumes that the spill operations are
|
||||
// symmetric and that the registers involved are the same size.
|
||||
@ -807,6 +840,25 @@ void Matcher::init_spill_mask( Node *ret ) {
|
||||
idealreg2regmask[Op_RegF] = &spillF->out_RegMask();
|
||||
idealreg2regmask[Op_RegD] = &spillD->out_RegMask();
|
||||
idealreg2regmask[Op_RegP] = &spillP->out_RegMask();
|
||||
|
||||
// Vector regmasks.
|
||||
if (Matcher::vector_size_supported(T_BYTE,4)) {
|
||||
TypeVect::VECTS = TypeVect::make(T_BYTE, 4);
|
||||
MachNode *spillVectS = match_tree(new (C, 3) LoadVectorNode(NULL,mem,fp,atp,TypeVect::VECTS));
|
||||
idealreg2regmask[Op_VecS] = &spillVectS->out_RegMask();
|
||||
}
|
||||
if (Matcher::vector_size_supported(T_FLOAT,2)) {
|
||||
MachNode *spillVectD = match_tree(new (C, 3) LoadVectorNode(NULL,mem,fp,atp,TypeVect::VECTD));
|
||||
idealreg2regmask[Op_VecD] = &spillVectD->out_RegMask();
|
||||
}
|
||||
if (Matcher::vector_size_supported(T_FLOAT,4)) {
|
||||
MachNode *spillVectX = match_tree(new (C, 3) LoadVectorNode(NULL,mem,fp,atp,TypeVect::VECTX));
|
||||
idealreg2regmask[Op_VecX] = &spillVectX->out_RegMask();
|
||||
}
|
||||
if (Matcher::vector_size_supported(T_FLOAT,8)) {
|
||||
MachNode *spillVectY = match_tree(new (C, 3) LoadVectorNode(NULL,mem,fp,atp,TypeVect::VECTY));
|
||||
idealreg2regmask[Op_VecY] = &spillVectY->out_RegMask();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ASSERT
|
||||
@ -1063,7 +1115,7 @@ OptoReg::Name Matcher::warp_outgoing_stk_arg( VMReg reg, OptoReg::Name begin_out
|
||||
// that is killed by the call.
|
||||
if( warped >= out_arg_limit_per_call )
|
||||
out_arg_limit_per_call = OptoReg::add(warped,1);
|
||||
if (!RegMask::can_represent(warped)) {
|
||||
if (!RegMask::can_represent_arg(warped)) {
|
||||
C->record_method_not_compilable_all_tiers("unsupported calling sequence");
|
||||
return OptoReg::Bad;
|
||||
}
|
||||
@ -1251,7 +1303,7 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) {
|
||||
// this killed area.
|
||||
uint r_cnt = mcall->tf()->range()->cnt();
|
||||
MachProjNode *proj = new (C, 1) MachProjNode( mcall, r_cnt+10000, RegMask::Empty, MachProjNode::fat_proj );
|
||||
if (!RegMask::can_represent(OptoReg::Name(out_arg_limit_per_call-1))) {
|
||||
if (!RegMask::can_represent_arg(OptoReg::Name(out_arg_limit_per_call-1))) {
|
||||
C->record_method_not_compilable_all_tiers("unsupported outgoing calling sequence");
|
||||
} else {
|
||||
for (int i = begin_out_arg_area; i < out_arg_limit_per_call; i++)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -250,10 +250,21 @@ public:
|
||||
static const bool convL2FSupported(void);
|
||||
|
||||
// Vector width in bytes
|
||||
static const uint vector_width_in_bytes(void);
|
||||
static const int vector_width_in_bytes(BasicType bt);
|
||||
|
||||
// Limits on vector size (number of elements).
|
||||
static const int max_vector_size(const BasicType bt);
|
||||
static const int min_vector_size(const BasicType bt);
|
||||
static const bool vector_size_supported(const BasicType bt, int size) {
|
||||
return (Matcher::max_vector_size(bt) >= size &&
|
||||
Matcher::min_vector_size(bt) <= size);
|
||||
}
|
||||
|
||||
// Vector ideal reg
|
||||
static const uint vector_ideal_reg(void);
|
||||
static const int vector_ideal_reg(int len);
|
||||
|
||||
// CPU supports misaligned vectors store/load.
|
||||
static const bool misaligned_vectors_ok();
|
||||
|
||||
// Used to determine a "low complexity" 64-bit constant. (Zero is simple.)
|
||||
// The standard of comparison is one (StoreL ConL) vs. two (StoreI ConI).
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -1543,6 +1543,7 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const {
|
||||
// had an original form like p1:(AddP x x (LShiftL quux 3)), where the
|
||||
// expression (LShiftL quux 3) independently optimized to the constant 8.
|
||||
if ((t->isa_int() == NULL) && (t->isa_long() == NULL)
|
||||
&& (_type->isa_vect() == NULL)
|
||||
&& Opcode() != Op_LoadKlass && Opcode() != Op_LoadNKlass) {
|
||||
// t might actually be lower than _type, if _type is a unique
|
||||
// concrete subclass of abstract class t.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -41,7 +41,9 @@ class PhaseTransform;
|
||||
class MulNode : public Node {
|
||||
virtual uint hash() const;
|
||||
public:
|
||||
MulNode( Node *in1, Node *in2 ): Node(0,in1,in2) {}
|
||||
MulNode( Node *in1, Node *in2 ): Node(0,in1,in2) {
|
||||
init_class_id(Class_Mul);
|
||||
}
|
||||
|
||||
// Handle algebraic identities here. If we have an identity, return the Node
|
||||
// we are equivalent to. We look for "add of zero" as an identity.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -1576,6 +1576,9 @@ void Node::dump() const {
|
||||
} else {
|
||||
tty->print("no type");
|
||||
}
|
||||
} else if (t->isa_vect() && this->is_MachSpillCopy()) {
|
||||
// Dump MachSpillcopy vector type.
|
||||
t->dump();
|
||||
}
|
||||
if (is_new) {
|
||||
debug_only(dump_orig(debug_orig()));
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -100,6 +100,7 @@ class MemBarNode;
|
||||
class MemBarStoreStoreNode;
|
||||
class MemNode;
|
||||
class MergeMemNode;
|
||||
class MulNode;
|
||||
class MultiNode;
|
||||
class MultiBranchNode;
|
||||
class NeverBranchNode;
|
||||
@ -133,8 +134,8 @@ class Type;
|
||||
class TypeNode;
|
||||
class UnlockNode;
|
||||
class VectorNode;
|
||||
class VectorLoadNode;
|
||||
class VectorStoreNode;
|
||||
class LoadVectorNode;
|
||||
class StoreVectorNode;
|
||||
class VectorSet;
|
||||
typedef void (*NFunc)(Node&,void*);
|
||||
extern "C" {
|
||||
@ -609,9 +610,9 @@ public:
|
||||
|
||||
DEFINE_CLASS_ID(Mem, Node, 4)
|
||||
DEFINE_CLASS_ID(Load, Mem, 0)
|
||||
DEFINE_CLASS_ID(VectorLoad, Load, 0)
|
||||
DEFINE_CLASS_ID(LoadVector, Load, 0)
|
||||
DEFINE_CLASS_ID(Store, Mem, 1)
|
||||
DEFINE_CLASS_ID(VectorStore, Store, 0)
|
||||
DEFINE_CLASS_ID(StoreVector, Store, 0)
|
||||
DEFINE_CLASS_ID(LoadStore, Mem, 2)
|
||||
|
||||
DEFINE_CLASS_ID(Region, Node, 5)
|
||||
@ -629,8 +630,9 @@ public:
|
||||
DEFINE_CLASS_ID(AddP, Node, 9)
|
||||
DEFINE_CLASS_ID(BoxLock, Node, 10)
|
||||
DEFINE_CLASS_ID(Add, Node, 11)
|
||||
DEFINE_CLASS_ID(Vector, Node, 12)
|
||||
DEFINE_CLASS_ID(ClearArray, Node, 13)
|
||||
DEFINE_CLASS_ID(Mul, Node, 12)
|
||||
DEFINE_CLASS_ID(Vector, Node, 13)
|
||||
DEFINE_CLASS_ID(ClearArray, Node, 14)
|
||||
|
||||
_max_classes = ClassMask_ClearArray
|
||||
};
|
||||
@ -752,6 +754,7 @@ public:
|
||||
DEFINE_CLASS_QUERY(MemBar)
|
||||
DEFINE_CLASS_QUERY(MemBarStoreStore)
|
||||
DEFINE_CLASS_QUERY(MergeMem)
|
||||
DEFINE_CLASS_QUERY(Mul)
|
||||
DEFINE_CLASS_QUERY(Multi)
|
||||
DEFINE_CLASS_QUERY(MultiBranch)
|
||||
DEFINE_CLASS_QUERY(Parm)
|
||||
@ -767,8 +770,8 @@ public:
|
||||
DEFINE_CLASS_QUERY(Sub)
|
||||
DEFINE_CLASS_QUERY(Type)
|
||||
DEFINE_CLASS_QUERY(Vector)
|
||||
DEFINE_CLASS_QUERY(VectorLoad)
|
||||
DEFINE_CLASS_QUERY(VectorStore)
|
||||
DEFINE_CLASS_QUERY(LoadVector)
|
||||
DEFINE_CLASS_QUERY(StoreVector)
|
||||
DEFINE_CLASS_QUERY(Unlock)
|
||||
|
||||
#undef DEFINE_CLASS_QUERY
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, 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
|
||||
@ -38,6 +38,10 @@ const char *NodeClassNames[] = {
|
||||
"RegD",
|
||||
"RegL",
|
||||
"RegFlags",
|
||||
"VecS",
|
||||
"VecD",
|
||||
"VecX",
|
||||
"VecY",
|
||||
"_last_machine_leaf",
|
||||
#include "classes.hpp"
|
||||
"_last_class_name",
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -36,6 +36,10 @@ enum Opcodes {
|
||||
macro(RegF) // Machine float register
|
||||
macro(RegD) // Machine double register
|
||||
macro(RegL) // Machine long register
|
||||
macro(VecS) // Machine vectors register
|
||||
macro(VecD) // Machine vectord register
|
||||
macro(VecX) // Machine vectorx register
|
||||
macro(VecY) // Machine vectory register
|
||||
macro(RegFlags) // Machine flags register
|
||||
_last_machine_leaf, // Split between regular opcodes and machine
|
||||
#include "classes.hpp"
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2010, 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
|
||||
@ -27,13 +27,15 @@
|
||||
#include "opto/chaitin.hpp"
|
||||
#include "opto/machnode.hpp"
|
||||
|
||||
// see if this register kind does not requires two registers
|
||||
static bool is_single_register(uint x) {
|
||||
#ifdef _LP64
|
||||
return (x != Op_RegD && x != Op_RegL && x != Op_RegP);
|
||||
#else
|
||||
return (x != Op_RegD && x != Op_RegL);
|
||||
#endif
|
||||
// See if this register (or pairs, or vector) already contains the value.
|
||||
static bool register_contains_value(Node* val, OptoReg::Name reg, int n_regs,
|
||||
Node_List& value) {
|
||||
for (int i = 0; i < n_regs; i++) {
|
||||
OptoReg::Name nreg = OptoReg::add(reg,-i);
|
||||
if (value[nreg] != val)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------may_be_copy_of_callee-----------------------------
|
||||
@ -167,9 +169,11 @@ int PhaseChaitin::use_prior_register( Node *n, uint idx, Node *def, Block *curre
|
||||
const RegMask &use_mask = n->in_RegMask(idx);
|
||||
bool can_use = ( RegMask::can_represent(def_reg) ? (use_mask.Member(def_reg) != 0)
|
||||
: (use_mask.is_AllStack() != 0));
|
||||
// Check for a copy to or from a misaligned pair.
|
||||
can_use = can_use && !use_mask.is_misaligned_Pair() && !def_lrg.mask().is_misaligned_Pair();
|
||||
|
||||
if (!RegMask::is_vector(def->ideal_reg())) {
|
||||
// Check for a copy to or from a misaligned pair.
|
||||
// It is workaround for a sparc with misaligned pairs.
|
||||
can_use = can_use && !use_mask.is_misaligned_pair() && !def_lrg.mask().is_misaligned_pair();
|
||||
}
|
||||
if (!can_use)
|
||||
return 0;
|
||||
|
||||
@ -263,18 +267,16 @@ int PhaseChaitin::elide_copy( Node *n, int k, Block *current_block, Node_List &v
|
||||
val = skip_copies(n->in(k));
|
||||
}
|
||||
|
||||
if( val == x ) return blk_adjust; // No progress?
|
||||
if (val == x) return blk_adjust; // No progress?
|
||||
|
||||
bool single = is_single_register(val->ideal_reg());
|
||||
int n_regs = RegMask::num_registers(val->ideal_reg());
|
||||
uint val_idx = n2lidx(val);
|
||||
OptoReg::Name val_reg = lrgs(val_idx).reg();
|
||||
|
||||
// See if it happens to already be in the correct register!
|
||||
// (either Phi's direct register, or the common case of the name
|
||||
// never-clobbered original-def register)
|
||||
if( value[val_reg] == val &&
|
||||
// Doubles check both halves
|
||||
( single || value[val_reg-1] == val ) ) {
|
||||
if (register_contains_value(val, val_reg, n_regs, value)) {
|
||||
blk_adjust += use_prior_register(n,k,regnd[val_reg],current_block,value,regnd);
|
||||
if( n->in(k) == regnd[val_reg] ) // Success! Quit trying
|
||||
return blk_adjust;
|
||||
@ -306,9 +308,10 @@ int PhaseChaitin::elide_copy( Node *n, int k, Block *current_block, Node_List &v
|
||||
}
|
||||
|
||||
Node *vv = value[reg];
|
||||
if( !single ) { // Doubles check for aligned-adjacent pair
|
||||
if( (reg&1)==0 ) continue; // Wrong half of a pair
|
||||
if( vv != value[reg-1] ) continue; // Not a complete pair
|
||||
if (n_regs > 1) { // Doubles and vectors check for aligned-adjacent set
|
||||
uint last = (n_regs-1); // Looking for the last part of a set
|
||||
if ((reg&last) != last) continue; // Wrong part of a set
|
||||
if (!register_contains_value(vv, reg, n_regs, value)) continue; // Different value
|
||||
}
|
||||
if( vv == val || // Got a direct hit?
|
||||
(t && vv && vv->bottom_type() == t && vv->is_Mach() &&
|
||||
@ -526,8 +529,9 @@ void PhaseChaitin::post_allocate_copy_removal() {
|
||||
if( pidx ) {
|
||||
value.map(preg,phi);
|
||||
regnd.map(preg,phi);
|
||||
OptoReg::Name preg_lo = OptoReg::add(preg,-1);
|
||||
if( !is_single_register(phi->ideal_reg()) ) {
|
||||
int n_regs = RegMask::num_registers(phi->ideal_reg());
|
||||
for (int l = 1; l < n_regs; l++) {
|
||||
OptoReg::Name preg_lo = OptoReg::add(preg,-l);
|
||||
value.map(preg_lo,phi);
|
||||
regnd.map(preg_lo,phi);
|
||||
}
|
||||
@ -568,13 +572,16 @@ void PhaseChaitin::post_allocate_copy_removal() {
|
||||
value.map(ureg,valdef); // record improved reaching-def info
|
||||
regnd.map(ureg, def);
|
||||
// Record other half of doubles
|
||||
OptoReg::Name ureg_lo = OptoReg::add(ureg,-1);
|
||||
if( !is_single_register(def->ideal_reg()) &&
|
||||
( !RegMask::can_represent(ureg_lo) ||
|
||||
lrgs(useidx).mask().Member(ureg_lo) ) && // Nearly always adjacent
|
||||
!value[ureg_lo] ) {
|
||||
value.map(ureg_lo,valdef); // record improved reaching-def info
|
||||
regnd.map(ureg_lo, def);
|
||||
uint def_ideal_reg = def->ideal_reg();
|
||||
int n_regs = RegMask::num_registers(def_ideal_reg);
|
||||
for (int l = 1; l < n_regs; l++) {
|
||||
OptoReg::Name ureg_lo = OptoReg::add(ureg,-l);
|
||||
if (!value[ureg_lo] &&
|
||||
(!RegMask::can_represent(ureg_lo) ||
|
||||
lrgs(useidx).mask().Member(ureg_lo))) { // Nearly always adjacent
|
||||
value.map(ureg_lo,valdef); // record improved reaching-def info
|
||||
regnd.map(ureg_lo, def);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -607,7 +614,8 @@ void PhaseChaitin::post_allocate_copy_removal() {
|
||||
}
|
||||
|
||||
uint n_ideal_reg = n->ideal_reg();
|
||||
if( is_single_register(n_ideal_reg) ) {
|
||||
int n_regs = RegMask::num_registers(n_ideal_reg);
|
||||
if (n_regs == 1) {
|
||||
// If Node 'n' does not change the value mapped by the register,
|
||||
// then 'n' is a useless copy. Do not update the register->node
|
||||
// mapping so 'n' will go dead.
|
||||
@ -625,6 +633,25 @@ void PhaseChaitin::post_allocate_copy_removal() {
|
||||
assert( n->is_Copy(), "" );
|
||||
j -= replace_and_yank_if_dead(n, nreg, b, value, regnd);
|
||||
}
|
||||
} else if (RegMask::is_vector(n_ideal_reg)) {
|
||||
// If Node 'n' does not change the value mapped by the register,
|
||||
// then 'n' is a useless copy. Do not update the register->node
|
||||
// mapping so 'n' will go dead.
|
||||
if (!register_contains_value(val, nreg, n_regs, value)) {
|
||||
// Update the mapping: record new Node defined by the register
|
||||
regnd.map(nreg,n);
|
||||
// Update mapping for defined *value*, which is the defined
|
||||
// Node after skipping all copies.
|
||||
value.map(nreg,val);
|
||||
for (int l = 1; l < n_regs; l++) {
|
||||
OptoReg::Name nreg_lo = OptoReg::add(nreg,-l);
|
||||
regnd.map(nreg_lo, n );
|
||||
value.map(nreg_lo,val);
|
||||
}
|
||||
} else if (n->is_Copy()) {
|
||||
// Note: vector can't be constant and can't be copy of calee.
|
||||
j -= replace_and_yank_if_dead(n, nreg, b, value, regnd);
|
||||
}
|
||||
} else {
|
||||
// If the value occupies a register pair, record same info
|
||||
// in both registers.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 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
|
||||
@ -74,12 +74,13 @@ Node *PhaseChaitin::get_spillcopy_wide( Node *def, Node *use, uint uidx ) {
|
||||
const RegMask *w_i_mask = w_mask->overlap( *i_mask ) ? w_mask : i_mask;
|
||||
const RegMask *w_o_mask;
|
||||
|
||||
int num_regs = RegMask::num_registers(ireg);
|
||||
bool is_vect = RegMask::is_vector(ireg);
|
||||
if( w_mask->overlap( *o_mask ) && // Overlap AND
|
||||
((ireg != Op_RegL && ireg != Op_RegD // Single use or aligned
|
||||
#ifdef _LP64
|
||||
&& ireg != Op_RegP
|
||||
#endif
|
||||
) || o_mask->is_aligned_Pairs()) ) {
|
||||
((num_regs == 1) // Single use or aligned
|
||||
|| is_vect // or vector
|
||||
|| !is_vect && o_mask->is_aligned_pairs()) ) {
|
||||
assert(!is_vect || o_mask->is_aligned_sets(num_regs), "vectors are aligned");
|
||||
// Don't come here for mis-aligned doubles
|
||||
w_o_mask = w_mask;
|
||||
} else { // wide ideal mask does not overlap with o_mask
|
||||
@ -400,15 +401,17 @@ bool PhaseChaitin::is_high_pressure( Block *b, LRG *lrg, uint insidx ) {
|
||||
// CNC - Turned off 7/8/99, causes too much spilling
|
||||
// if( lrg->_is_bound ) return false;
|
||||
|
||||
// Use float pressure numbers for vectors.
|
||||
bool is_float_or_vector = lrg->_is_float || lrg->_is_vector;
|
||||
// Not yet reached the high-pressure cutoff point, so low pressure
|
||||
uint hrp_idx = lrg->_is_float ? b->_fhrp_index : b->_ihrp_index;
|
||||
uint hrp_idx = is_float_or_vector ? b->_fhrp_index : b->_ihrp_index;
|
||||
if( insidx < hrp_idx ) return false;
|
||||
// Register pressure for the block as a whole depends on reg class
|
||||
int block_pres = lrg->_is_float ? b->_freg_pressure : b->_reg_pressure;
|
||||
int block_pres = is_float_or_vector ? b->_freg_pressure : b->_reg_pressure;
|
||||
// Bound live ranges will split at the binding points first;
|
||||
// Intermediate splits should assume the live range's register set
|
||||
// got "freed up" and that num_regs will become INT_PRESSURE.
|
||||
int bound_pres = lrg->_is_float ? FLOATPRESSURE : INTPRESSURE;
|
||||
int bound_pres = is_float_or_vector ? FLOATPRESSURE : INTPRESSURE;
|
||||
// Effective register pressure limit.
|
||||
int lrg_pres = (lrg->get_invalid_mask_size() > lrg->num_regs())
|
||||
? (lrg->get_invalid_mask_size() >> (lrg->num_regs()-1)) : bound_pres;
|
||||
@ -794,12 +797,15 @@ uint PhaseChaitin::Split( uint maxlrg ) {
|
||||
if( i < n->req() ) break;
|
||||
insert_point--;
|
||||
}
|
||||
uint orig_eidx = b->end_idx();
|
||||
maxlrg = split_DEF( n1, b, insert_point, maxlrg, Reachblock, debug_defs, splits, slidx);
|
||||
// If it wasn't split bail
|
||||
if (!maxlrg) {
|
||||
return 0;
|
||||
}
|
||||
insidx++;
|
||||
// Spill of NULL check mem op goes into the following block.
|
||||
if (b->end_idx() > orig_eidx)
|
||||
insidx++;
|
||||
}
|
||||
// This is a new DEF, so update UP
|
||||
UPblock[slidx] = false;
|
||||
@ -960,7 +966,7 @@ uint PhaseChaitin::Split( uint maxlrg ) {
|
||||
// Grab register mask info
|
||||
const RegMask &dmask = def->out_RegMask();
|
||||
const RegMask &umask = n->in_RegMask(inpidx);
|
||||
|
||||
bool is_vect = RegMask::is_vector(def->ideal_reg());
|
||||
assert(inpidx < oopoff, "cannot use-split oop map info");
|
||||
|
||||
bool dup = UPblock[slidx];
|
||||
@ -972,7 +978,7 @@ uint PhaseChaitin::Split( uint maxlrg ) {
|
||||
if( !umask.is_AllStack() &&
|
||||
(int)umask.Size() <= lrgs(useidx).num_regs() &&
|
||||
(!def->rematerialize() ||
|
||||
umask.is_misaligned_Pair())) {
|
||||
!is_vect && umask.is_misaligned_pair())) {
|
||||
// These need a Split regardless of overlap or pressure
|
||||
// SPLIT - NO DEF - NO CISC SPILL
|
||||
maxlrg = split_USE(def,b,n,inpidx,maxlrg,dup,false, splits,slidx);
|
||||
@ -1123,10 +1129,12 @@ uint PhaseChaitin::Split( uint maxlrg ) {
|
||||
// Grab UP info for DEF
|
||||
const RegMask &dmask = n->out_RegMask();
|
||||
bool defup = dmask.is_UP();
|
||||
int ireg = n->ideal_reg();
|
||||
bool is_vect = RegMask::is_vector(ireg);
|
||||
// Only split at Def if this is a HRP block or bound (and spilled once)
|
||||
if( !n->rematerialize() &&
|
||||
(((dmask.is_bound1() || dmask.is_bound2() || dmask.is_misaligned_Pair()) &&
|
||||
(deflrg._direct_conflict || deflrg._must_spill)) ||
|
||||
(((dmask.is_bound(ireg) || !is_vect && dmask.is_misaligned_pair()) &&
|
||||
(deflrg._direct_conflict || deflrg._must_spill)) ||
|
||||
// Check for LRG being up in a register and we are inside a high
|
||||
// pressure area. Spill it down immediately.
|
||||
(defup && is_high_pressure(b,&deflrg,insidx))) ) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -129,11 +129,34 @@ const RegMask RegMask::Empty(
|
||||
0
|
||||
);
|
||||
|
||||
//=============================================================================
|
||||
bool RegMask::is_vector(uint ireg) {
|
||||
return (ireg == Op_VecS || ireg == Op_VecD || ireg == Op_VecX || ireg == Op_VecY);
|
||||
}
|
||||
|
||||
int RegMask::num_registers(uint ireg) {
|
||||
switch(ireg) {
|
||||
case Op_VecY:
|
||||
return 8;
|
||||
case Op_VecX:
|
||||
return 4;
|
||||
case Op_VecD:
|
||||
case Op_RegD:
|
||||
case Op_RegL:
|
||||
#ifdef _LP64
|
||||
case Op_RegP:
|
||||
#endif
|
||||
return 2;
|
||||
}
|
||||
// Op_VecS and the rest ideal registers.
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------find_first_pair--------------------------------
|
||||
// Find the lowest-numbered register pair in the mask. Return the
|
||||
// HIGHEST register number in the pair, or BAD if no pairs.
|
||||
OptoReg::Name RegMask::find_first_pair() const {
|
||||
VerifyPairs();
|
||||
verify_pairs();
|
||||
for( int i = 0; i < RM_SIZE; i++ ) {
|
||||
if( _A[i] ) { // Found some bits
|
||||
int bit = _A[i] & -_A[i]; // Extract low bit
|
||||
@ -146,30 +169,30 @@ OptoReg::Name RegMask::find_first_pair() const {
|
||||
|
||||
//------------------------------ClearToPairs-----------------------------------
|
||||
// Clear out partial bits; leave only bit pairs
|
||||
void RegMask::ClearToPairs() {
|
||||
void RegMask::clear_to_pairs() {
|
||||
for( int i = 0; i < RM_SIZE; i++ ) {
|
||||
int bits = _A[i];
|
||||
bits &= ((bits & 0x55555555)<<1); // 1 hi-bit set for each pair
|
||||
bits |= (bits>>1); // Smear 1 hi-bit into a pair
|
||||
_A[i] = bits;
|
||||
}
|
||||
VerifyPairs();
|
||||
verify_pairs();
|
||||
}
|
||||
|
||||
//------------------------------SmearToPairs-----------------------------------
|
||||
// Smear out partial bits; leave only bit pairs
|
||||
void RegMask::SmearToPairs() {
|
||||
void RegMask::smear_to_pairs() {
|
||||
for( int i = 0; i < RM_SIZE; i++ ) {
|
||||
int bits = _A[i];
|
||||
bits |= ((bits & 0x55555555)<<1); // Smear lo bit hi per pair
|
||||
bits |= ((bits & 0xAAAAAAAA)>>1); // Smear hi bit lo per pair
|
||||
_A[i] = bits;
|
||||
}
|
||||
VerifyPairs();
|
||||
verify_pairs();
|
||||
}
|
||||
|
||||
//------------------------------is_aligned_pairs-------------------------------
|
||||
bool RegMask::is_aligned_Pairs() const {
|
||||
bool RegMask::is_aligned_pairs() const {
|
||||
// Assert that the register mask contains only bit pairs.
|
||||
for( int i = 0; i < RM_SIZE; i++ ) {
|
||||
int bits = _A[i];
|
||||
@ -204,7 +227,7 @@ int RegMask::is_bound1() const {
|
||||
|
||||
//------------------------------is_bound2--------------------------------------
|
||||
// Return TRUE if the mask contains an adjacent pair of bits and no other bits.
|
||||
int RegMask::is_bound2() const {
|
||||
int RegMask::is_bound_pair() const {
|
||||
if( is_AllStack() ) return false;
|
||||
|
||||
int bit = -1; // Set to hold the one bit allowed
|
||||
@ -226,6 +249,132 @@ int RegMask::is_bound2() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
static int low_bits[3] = { 0x55555555, 0x11111111, 0x01010101 };
|
||||
//------------------------------find_first_set---------------------------------
|
||||
// Find the lowest-numbered register set in the mask. Return the
|
||||
// HIGHEST register number in the set, or BAD if no sets.
|
||||
// Works also for size 1.
|
||||
OptoReg::Name RegMask::find_first_set(int size) const {
|
||||
verify_sets(size);
|
||||
for (int i = 0; i < RM_SIZE; i++) {
|
||||
if (_A[i]) { // Found some bits
|
||||
int bit = _A[i] & -_A[i]; // Extract low bit
|
||||
// Convert to bit number, return hi bit in pair
|
||||
return OptoReg::Name((i<<_LogWordBits)+find_lowest_bit(bit)+(size-1));
|
||||
}
|
||||
}
|
||||
return OptoReg::Bad;
|
||||
}
|
||||
|
||||
//------------------------------clear_to_sets----------------------------------
|
||||
// Clear out partial bits; leave only aligned adjacent bit pairs
|
||||
void RegMask::clear_to_sets(int size) {
|
||||
if (size == 1) return;
|
||||
assert(2 <= size && size <= 8, "update low bits table");
|
||||
assert(is_power_of_2(size), "sanity");
|
||||
int low_bits_mask = low_bits[size>>2];
|
||||
for (int i = 0; i < RM_SIZE; i++) {
|
||||
int bits = _A[i];
|
||||
int sets = (bits & low_bits_mask);
|
||||
for (int j = 1; j < size; j++) {
|
||||
sets = (bits & (sets<<1)); // filter bits which produce whole sets
|
||||
}
|
||||
sets |= (sets>>1); // Smear 1 hi-bit into a set
|
||||
if (size > 2) {
|
||||
sets |= (sets>>2); // Smear 2 hi-bits into a set
|
||||
if (size > 4) {
|
||||
sets |= (sets>>4); // Smear 4 hi-bits into a set
|
||||
}
|
||||
}
|
||||
_A[i] = sets;
|
||||
}
|
||||
verify_sets(size);
|
||||
}
|
||||
|
||||
//------------------------------smear_to_sets----------------------------------
|
||||
// Smear out partial bits to aligned adjacent bit sets
|
||||
void RegMask::smear_to_sets(int size) {
|
||||
if (size == 1) return;
|
||||
assert(2 <= size && size <= 8, "update low bits table");
|
||||
assert(is_power_of_2(size), "sanity");
|
||||
int low_bits_mask = low_bits[size>>2];
|
||||
for (int i = 0; i < RM_SIZE; i++) {
|
||||
int bits = _A[i];
|
||||
int sets = 0;
|
||||
for (int j = 0; j < size; j++) {
|
||||
sets |= (bits & low_bits_mask); // collect partial bits
|
||||
bits = bits>>1;
|
||||
}
|
||||
sets |= (sets<<1); // Smear 1 lo-bit into a set
|
||||
if (size > 2) {
|
||||
sets |= (sets<<2); // Smear 2 lo-bits into a set
|
||||
if (size > 4) {
|
||||
sets |= (sets<<4); // Smear 4 lo-bits into a set
|
||||
}
|
||||
}
|
||||
_A[i] = sets;
|
||||
}
|
||||
verify_sets(size);
|
||||
}
|
||||
|
||||
//------------------------------is_aligned_set--------------------------------
|
||||
bool RegMask::is_aligned_sets(int size) const {
|
||||
if (size == 1) return true;
|
||||
assert(2 <= size && size <= 8, "update low bits table");
|
||||
assert(is_power_of_2(size), "sanity");
|
||||
int low_bits_mask = low_bits[size>>2];
|
||||
// Assert that the register mask contains only bit sets.
|
||||
for (int i = 0; i < RM_SIZE; i++) {
|
||||
int bits = _A[i];
|
||||
while (bits) { // Check bits for pairing
|
||||
int bit = bits & -bits; // Extract low bit
|
||||
// Low bit is not odd means its mis-aligned.
|
||||
if ((bit & low_bits_mask) == 0) return false;
|
||||
// Do extra work since (bit << size) may overflow.
|
||||
int hi_bit = bit << (size-1); // high bit
|
||||
int set = hi_bit + ((hi_bit-1) & ~(bit-1));
|
||||
// Check for aligned adjacent bits in this set
|
||||
if ((bits & set) != set) return false;
|
||||
bits -= set; // Remove this set
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------is_bound_set-----------------------------------
|
||||
// Return TRUE if the mask contains one adjacent set of bits and no other bits.
|
||||
// Works also for size 1.
|
||||
int RegMask::is_bound_set(int size) const {
|
||||
if( is_AllStack() ) return false;
|
||||
assert(1 <= size && size <= 8, "update low bits table");
|
||||
int bit = -1; // Set to hold the one bit allowed
|
||||
for (int i = 0; i < RM_SIZE; i++) {
|
||||
if (_A[i] ) { // Found some bits
|
||||
if (bit != -1)
|
||||
return false; // Already had bits, so fail
|
||||
bit = _A[i] & -_A[i]; // Extract 1 bit from mask
|
||||
int hi_bit = bit << (size-1); // high bit
|
||||
if (hi_bit != 0) { // Bit set stays in same word?
|
||||
int set = hi_bit + ((hi_bit-1) & ~(bit-1));
|
||||
if (set != _A[i])
|
||||
return false; // Require adjacent bit set and no more bits
|
||||
} else { // Else its a split-set case
|
||||
if (((-1) & ~(bit-1)) != _A[i])
|
||||
return false; // Found many bits, so fail
|
||||
i++; // Skip iteration forward and check high part
|
||||
assert(size <= 8, "update next code");
|
||||
// The lower 24 bits should be 0 since it is split case and size <= 8.
|
||||
int set = bit>>24;
|
||||
set = set & -set; // Remove sign extension.
|
||||
set = (((set << size) - 1) >> 8);
|
||||
if (_A[i] != set) return false; // Require 1 lo bit in next word
|
||||
}
|
||||
}
|
||||
}
|
||||
// True for both the empty mask and for a bit set
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------is_UP------------------------------------------
|
||||
// UP means register only, Register plus stack, or stack only is DOWN
|
||||
bool RegMask::is_UP() const {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -113,7 +113,11 @@ public:
|
||||
// the controlling alignment constraint. Note that this alignment
|
||||
// requirement is internal to the allocator, and independent of any
|
||||
// particular platform.
|
||||
enum { SlotsPerLong = 2 };
|
||||
enum { SlotsPerLong = 2,
|
||||
SlotsPerVecS = 1,
|
||||
SlotsPerVecD = 2,
|
||||
SlotsPerVecX = 4,
|
||||
SlotsPerVecY = 8 };
|
||||
|
||||
// A constructor only used by the ADLC output. All mask fields are filled
|
||||
// in directly. Calls to this look something like RM(1,2,3,4);
|
||||
@ -193,20 +197,53 @@ public:
|
||||
OptoReg::Name find_first_pair() const;
|
||||
|
||||
// Clear out partial bits; leave only aligned adjacent bit pairs.
|
||||
void ClearToPairs();
|
||||
void clear_to_pairs();
|
||||
// Smear out partial bits; leave only aligned adjacent bit pairs.
|
||||
void SmearToPairs();
|
||||
void smear_to_pairs();
|
||||
// Verify that the mask contains only aligned adjacent bit pairs
|
||||
void VerifyPairs() const { assert( is_aligned_Pairs(), "mask is not aligned, adjacent pairs" ); }
|
||||
void verify_pairs() const { assert( is_aligned_pairs(), "mask is not aligned, adjacent pairs" ); }
|
||||
// Test that the mask contains only aligned adjacent bit pairs
|
||||
bool is_aligned_Pairs() const;
|
||||
bool is_aligned_pairs() const;
|
||||
|
||||
// mask is a pair of misaligned registers
|
||||
bool is_misaligned_Pair() const { return Size()==2 && !is_aligned_Pairs();}
|
||||
bool is_misaligned_pair() const { return Size()==2 && !is_aligned_pairs(); }
|
||||
// Test for single register
|
||||
int is_bound1() const;
|
||||
// Test for a single adjacent pair
|
||||
int is_bound2() const;
|
||||
int is_bound_pair() const;
|
||||
// Test for a single adjacent set of ideal register's size.
|
||||
int is_bound(uint ireg) const {
|
||||
if (is_vector(ireg)) {
|
||||
if (is_bound_set(num_registers(ireg)))
|
||||
return true;
|
||||
} else if (is_bound1() || is_bound_pair()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the lowest-numbered register set in the mask. Return the
|
||||
// HIGHEST register number in the set, or BAD if no sets.
|
||||
// Assert that the mask contains only bit sets.
|
||||
OptoReg::Name find_first_set(int size) const;
|
||||
|
||||
// Clear out partial bits; leave only aligned adjacent bit sets of size.
|
||||
void clear_to_sets(int size);
|
||||
// Smear out partial bits to aligned adjacent bit sets.
|
||||
void smear_to_sets(int size);
|
||||
// Verify that the mask contains only aligned adjacent bit sets
|
||||
void verify_sets(int size) const { assert(is_aligned_sets(size), "mask is not aligned, adjacent sets"); }
|
||||
// Test that the mask contains only aligned adjacent bit sets
|
||||
bool is_aligned_sets(int size) const;
|
||||
|
||||
// mask is a set of misaligned registers
|
||||
bool is_misaligned_set(int size) const { return (int)Size()==size && !is_aligned_sets(size);}
|
||||
|
||||
// Test for a single adjacent set
|
||||
int is_bound_set(int size) const;
|
||||
|
||||
static bool is_vector(uint ireg);
|
||||
static int num_registers(uint ireg);
|
||||
|
||||
// Fast overlap test. Non-zero if any registers in common.
|
||||
int overlap( const RegMask &rm ) const {
|
||||
@ -280,9 +317,15 @@ public:
|
||||
|
||||
static bool can_represent(OptoReg::Name reg) {
|
||||
// NOTE: -1 in computation reflects the usage of the last
|
||||
// bit of the regmask as an infinite stack flag.
|
||||
// bit of the regmask as an infinite stack flag and
|
||||
// -7 is to keep mask aligned for largest value (VecY).
|
||||
return (int)reg < (int)(CHUNK_SIZE-1);
|
||||
}
|
||||
static bool can_represent_arg(OptoReg::Name reg) {
|
||||
// NOTE: -SlotsPerVecY in computation reflects the need
|
||||
// to keep mask aligned for largest value (VecY).
|
||||
return (int)reg < (int)(CHUNK_SIZE-SlotsPerVecY);
|
||||
}
|
||||
};
|
||||
|
||||
// Do not use this constant directly in client code!
|
||||
|
@ -112,6 +112,7 @@ class StringConcat : public ResourceObj {
|
||||
_arguments->ins_req(0, value);
|
||||
_mode.insert_before(0, mode);
|
||||
}
|
||||
|
||||
void push_string(Node* value) {
|
||||
push(value, StringMode);
|
||||
}
|
||||
@ -125,9 +126,56 @@ class StringConcat : public ResourceObj {
|
||||
push(value, CharMode);
|
||||
}
|
||||
|
||||
static bool is_SB_toString(Node* call) {
|
||||
if (call->is_CallStaticJava()) {
|
||||
CallStaticJavaNode* csj = call->as_CallStaticJava();
|
||||
ciMethod* m = csj->method();
|
||||
if (m != NULL &&
|
||||
(m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString ||
|
||||
m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static Node* skip_string_null_check(Node* value) {
|
||||
// Look for a diamond shaped Null check of toString() result
|
||||
// (could be code from String.valueOf()):
|
||||
// (Proj == NULL) ? "null":"CastPP(Proj)#NotNULL
|
||||
if (value->is_Phi()) {
|
||||
int true_path = value->as_Phi()->is_diamond_phi();
|
||||
if (true_path != 0) {
|
||||
// phi->region->if_proj->ifnode->bool
|
||||
BoolNode* b = value->in(0)->in(1)->in(0)->in(1)->as_Bool();
|
||||
Node* cmp = b->in(1);
|
||||
Node* v1 = cmp->in(1);
|
||||
Node* v2 = cmp->in(2);
|
||||
// Null check of the return of toString which can simply be skipped.
|
||||
if (b->_test._test == BoolTest::ne &&
|
||||
v2->bottom_type() == TypePtr::NULL_PTR &&
|
||||
value->in(true_path)->Opcode() == Op_CastPP &&
|
||||
value->in(true_path)->in(1) == v1 &&
|
||||
v1->is_Proj() && is_SB_toString(v1->in(0))) {
|
||||
return v1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
Node* argument(int i) {
|
||||
return _arguments->in(i);
|
||||
}
|
||||
Node* argument_uncast(int i) {
|
||||
Node* arg = argument(i);
|
||||
int amode = mode(i);
|
||||
if (amode == StringConcat::StringMode ||
|
||||
amode == StringConcat::StringNullCheckMode) {
|
||||
arg = skip_string_null_check(arg);
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
void set_argument(int i, Node* value) {
|
||||
_arguments->set_req(i, value);
|
||||
}
|
||||
@ -206,9 +254,11 @@ class StringConcat : public ResourceObj {
|
||||
|
||||
|
||||
void StringConcat::eliminate_unneeded_control() {
|
||||
eliminate_initialize(begin()->initialization());
|
||||
for (uint i = 0; i < _control.size(); i++) {
|
||||
Node* n = _control.at(i);
|
||||
if (n->is_Allocate()) {
|
||||
eliminate_initialize(n->as_Allocate()->initialization());
|
||||
}
|
||||
if (n->is_Call()) {
|
||||
if (n != _end) {
|
||||
eliminate_call(n->as_Call());
|
||||
@ -239,14 +289,15 @@ StringConcat* StringConcat::merge(StringConcat* other, Node* arg) {
|
||||
assert(result->_control.contains(other->_end), "what?");
|
||||
assert(result->_control.contains(_begin), "what?");
|
||||
for (int x = 0; x < num_arguments(); x++) {
|
||||
if (argument(x) == arg) {
|
||||
Node* argx = argument_uncast(x);
|
||||
if (argx == arg) {
|
||||
// replace the toString result with the all the arguments that
|
||||
// made up the other StringConcat
|
||||
for (int y = 0; y < other->num_arguments(); y++) {
|
||||
result->append(other->argument(y), other->mode(y));
|
||||
}
|
||||
} else {
|
||||
result->append(argument(x), mode(x));
|
||||
result->append(argx, mode(x));
|
||||
}
|
||||
}
|
||||
result->set_allocation(other->_begin);
|
||||
@ -327,14 +378,9 @@ Node_List PhaseStringOpts::collect_toString_calls() {
|
||||
|
||||
while (worklist.size() > 0) {
|
||||
Node* ctrl = worklist.pop();
|
||||
if (ctrl->is_CallStaticJava()) {
|
||||
if (StringConcat::is_SB_toString(ctrl)) {
|
||||
CallStaticJavaNode* csj = ctrl->as_CallStaticJava();
|
||||
ciMethod* m = csj->method();
|
||||
if (m != NULL &&
|
||||
(m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString ||
|
||||
m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString)) {
|
||||
string_calls.push(csj);
|
||||
}
|
||||
string_calls.push(csj);
|
||||
}
|
||||
if (ctrl->in(0) != NULL && !_visited.test_set(ctrl->in(0)->_idx)) {
|
||||
worklist.push(ctrl->in(0));
|
||||
@ -550,44 +596,40 @@ PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List*):
|
||||
for (int c = 0; c < concats.length(); c++) {
|
||||
StringConcat* sc = concats.at(c);
|
||||
for (int i = 0; i < sc->num_arguments(); i++) {
|
||||
Node* arg = sc->argument(i);
|
||||
if (arg->is_Proj() && arg->in(0)->is_CallStaticJava()) {
|
||||
Node* arg = sc->argument_uncast(i);
|
||||
if (arg->is_Proj() && StringConcat::is_SB_toString(arg->in(0))) {
|
||||
CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava();
|
||||
if (csj->method() != NULL &&
|
||||
(csj->method()->intrinsic_id() == vmIntrinsics::_StringBuilder_toString ||
|
||||
csj->method()->intrinsic_id() == vmIntrinsics::_StringBuffer_toString)) {
|
||||
for (int o = 0; o < concats.length(); o++) {
|
||||
if (c == o) continue;
|
||||
StringConcat* other = concats.at(o);
|
||||
if (other->end() == csj) {
|
||||
for (int o = 0; o < concats.length(); o++) {
|
||||
if (c == o) continue;
|
||||
StringConcat* other = concats.at(o);
|
||||
if (other->end() == csj) {
|
||||
#ifndef PRODUCT
|
||||
if (PrintOptimizeStringConcat) {
|
||||
tty->print_cr("considering stacked concats");
|
||||
}
|
||||
if (PrintOptimizeStringConcat) {
|
||||
tty->print_cr("considering stacked concats");
|
||||
}
|
||||
#endif
|
||||
|
||||
StringConcat* merged = sc->merge(other, arg);
|
||||
if (merged->validate_control_flow()) {
|
||||
StringConcat* merged = sc->merge(other, arg);
|
||||
if (merged->validate_control_flow()) {
|
||||
#ifndef PRODUCT
|
||||
if (PrintOptimizeStringConcat) {
|
||||
tty->print_cr("stacking would succeed");
|
||||
}
|
||||
#endif
|
||||
if (c < o) {
|
||||
concats.remove_at(o);
|
||||
concats.at_put(c, merged);
|
||||
} else {
|
||||
concats.remove_at(c);
|
||||
concats.at_put(o, merged);
|
||||
}
|
||||
goto restart;
|
||||
} else {
|
||||
#ifndef PRODUCT
|
||||
if (PrintOptimizeStringConcat) {
|
||||
tty->print_cr("stacking would fail");
|
||||
}
|
||||
#endif
|
||||
if (PrintOptimizeStringConcat) {
|
||||
tty->print_cr("stacking would succeed");
|
||||
}
|
||||
#endif
|
||||
if (c < o) {
|
||||
concats.remove_at(o);
|
||||
concats.at_put(c, merged);
|
||||
} else {
|
||||
concats.remove_at(c);
|
||||
concats.at_put(o, merged);
|
||||
}
|
||||
goto restart;
|
||||
} else {
|
||||
#ifndef PRODUCT
|
||||
if (PrintOptimizeStringConcat) {
|
||||
tty->print_cr("stacking would fail");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 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
|
||||
@ -67,6 +67,10 @@ SuperWord::SuperWord(PhaseIdealLoop* phase) :
|
||||
|
||||
//------------------------------transform_loop---------------------------
|
||||
void SuperWord::transform_loop(IdealLoopTree* lpt) {
|
||||
assert(UseSuperWord, "should be");
|
||||
// Do vectors exist on this architecture?
|
||||
if (Matcher::vector_width_in_bytes(T_BYTE) < 2) return;
|
||||
|
||||
assert(lpt->_head->is_CountedLoop(), "must be");
|
||||
CountedLoopNode *cl = lpt->_head->as_CountedLoop();
|
||||
|
||||
@ -89,15 +93,12 @@ void SuperWord::transform_loop(IdealLoopTree* lpt) {
|
||||
Node *pre_opaq1 = pre_end->limit();
|
||||
if (pre_opaq1->Opcode() != Op_Opaque1) return;
|
||||
|
||||
// Do vectors exist on this architecture?
|
||||
if (vector_width_in_bytes() == 0) return;
|
||||
|
||||
init(); // initialize data structures
|
||||
|
||||
set_lpt(lpt);
|
||||
set_lp(cl);
|
||||
|
||||
// For now, define one block which is the entire loop body
|
||||
// For now, define one block which is the entire loop body
|
||||
set_bb(cl);
|
||||
|
||||
assert(_packset.length() == 0, "packset must be empty");
|
||||
@ -177,7 +178,7 @@ void SuperWord::find_adjacent_refs() {
|
||||
Node_List memops;
|
||||
for (int i = 0; i < _block.length(); i++) {
|
||||
Node* n = _block.at(i);
|
||||
if (n->is_Mem() && in_bb(n) &&
|
||||
if (n->is_Mem() && !n->is_LoadStore() && in_bb(n) &&
|
||||
is_java_primitive(n->as_Mem()->memory_type())) {
|
||||
int align = memory_alignment(n->as_Mem(), 0);
|
||||
if (align != bottom_align) {
|
||||
@ -185,54 +186,141 @@ void SuperWord::find_adjacent_refs() {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (memops.size() == 0) return;
|
||||
|
||||
// Find a memory reference to align to. The pre-loop trip count
|
||||
// is modified to align this reference to a vector-aligned address
|
||||
find_align_to_ref(memops);
|
||||
if (align_to_ref() == NULL) return;
|
||||
Node_List align_to_refs;
|
||||
int best_iv_adjustment = 0;
|
||||
MemNode* best_align_to_mem_ref = NULL;
|
||||
|
||||
SWPointer align_to_ref_p(align_to_ref(), this);
|
||||
int offset = align_to_ref_p.offset_in_bytes();
|
||||
int scale = align_to_ref_p.scale_in_bytes();
|
||||
int vw = vector_width_in_bytes();
|
||||
int stride_sign = (scale * iv_stride()) > 0 ? 1 : -1;
|
||||
int iv_adjustment = (stride_sign * vw - (offset % vw)) % vw;
|
||||
while (memops.size() != 0) {
|
||||
// Find a memory reference to align to.
|
||||
MemNode* mem_ref = find_align_to_ref(memops);
|
||||
if (mem_ref == NULL) break;
|
||||
align_to_refs.push(mem_ref);
|
||||
int iv_adjustment = get_iv_adjustment(mem_ref);
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (TraceSuperWord)
|
||||
tty->print_cr("\noffset = %d iv_adjustment = %d elt_align = %d scale = %d iv_stride = %d",
|
||||
offset, iv_adjustment, align_to_ref_p.memory_size(), align_to_ref_p.scale_in_bytes(), iv_stride());
|
||||
#endif
|
||||
|
||||
// Set alignment relative to "align_to_ref"
|
||||
for (int i = memops.size() - 1; i >= 0; i--) {
|
||||
MemNode* s = memops.at(i)->as_Mem();
|
||||
SWPointer p2(s, this);
|
||||
if (p2.comparable(align_to_ref_p)) {
|
||||
int align = memory_alignment(s, iv_adjustment);
|
||||
set_alignment(s, align);
|
||||
} else {
|
||||
memops.remove(i);
|
||||
if (best_align_to_mem_ref == NULL) {
|
||||
// Set memory reference which is the best from all memory operations
|
||||
// to be used for alignment. The pre-loop trip count is modified to align
|
||||
// this reference to a vector-aligned address.
|
||||
best_align_to_mem_ref = mem_ref;
|
||||
best_iv_adjustment = iv_adjustment;
|
||||
}
|
||||
}
|
||||
|
||||
// Create initial pack pairs of memory operations
|
||||
for (uint i = 0; i < memops.size(); i++) {
|
||||
Node* s1 = memops.at(i);
|
||||
for (uint j = 0; j < memops.size(); j++) {
|
||||
Node* s2 = memops.at(j);
|
||||
if (s1 != s2 && are_adjacent_refs(s1, s2)) {
|
||||
int align = alignment(s1);
|
||||
if (stmts_can_pack(s1, s2, align)) {
|
||||
Node_List* pair = new Node_List();
|
||||
pair->push(s1);
|
||||
pair->push(s2);
|
||||
_packset.append(pair);
|
||||
SWPointer align_to_ref_p(mem_ref, this);
|
||||
// Set alignment relative to "align_to_ref" for all related memory operations.
|
||||
for (int i = memops.size() - 1; i >= 0; i--) {
|
||||
MemNode* s = memops.at(i)->as_Mem();
|
||||
if (isomorphic(s, mem_ref)) {
|
||||
SWPointer p2(s, this);
|
||||
if (p2.comparable(align_to_ref_p)) {
|
||||
int align = memory_alignment(s, iv_adjustment);
|
||||
set_alignment(s, align);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create initial pack pairs of memory operations for which
|
||||
// alignment is set and vectors will be aligned.
|
||||
bool create_pack = true;
|
||||
if (memory_alignment(mem_ref, best_iv_adjustment) == 0) {
|
||||
if (!Matcher::misaligned_vectors_ok()) {
|
||||
int vw = vector_width(mem_ref);
|
||||
int vw_best = vector_width(best_align_to_mem_ref);
|
||||
if (vw > vw_best) {
|
||||
// Do not vectorize a memory access with more elements per vector
|
||||
// if unaligned memory access is not allowed because number of
|
||||
// iterations in pre-loop will be not enough to align it.
|
||||
create_pack = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (same_velt_type(mem_ref, best_align_to_mem_ref)) {
|
||||
// Can't allow vectorization of unaligned memory accesses with the
|
||||
// same type since it could be overlapped accesses to the same array.
|
||||
create_pack = false;
|
||||
} else {
|
||||
// Allow independent (different type) unaligned memory operations
|
||||
// if HW supports them.
|
||||
if (!Matcher::misaligned_vectors_ok()) {
|
||||
create_pack = false;
|
||||
} else {
|
||||
// Check if packs of the same memory type but
|
||||
// with a different alignment were created before.
|
||||
for (uint i = 0; i < align_to_refs.size(); i++) {
|
||||
MemNode* mr = align_to_refs.at(i)->as_Mem();
|
||||
if (same_velt_type(mr, mem_ref) &&
|
||||
memory_alignment(mr, iv_adjustment) != 0)
|
||||
create_pack = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (create_pack) {
|
||||
for (uint i = 0; i < memops.size(); i++) {
|
||||
Node* s1 = memops.at(i);
|
||||
int align = alignment(s1);
|
||||
if (align == top_align) continue;
|
||||
for (uint j = 0; j < memops.size(); j++) {
|
||||
Node* s2 = memops.at(j);
|
||||
if (alignment(s2) == top_align) continue;
|
||||
if (s1 != s2 && are_adjacent_refs(s1, s2)) {
|
||||
if (stmts_can_pack(s1, s2, align)) {
|
||||
Node_List* pair = new Node_List();
|
||||
pair->push(s1);
|
||||
pair->push(s2);
|
||||
_packset.append(pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else { // Don't create unaligned pack
|
||||
// First, remove remaining memory ops of the same type from the list.
|
||||
for (int i = memops.size() - 1; i >= 0; i--) {
|
||||
MemNode* s = memops.at(i)->as_Mem();
|
||||
if (same_velt_type(s, mem_ref)) {
|
||||
memops.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Second, remove already constructed packs of the same type.
|
||||
for (int i = _packset.length() - 1; i >= 0; i--) {
|
||||
Node_List* p = _packset.at(i);
|
||||
MemNode* s = p->at(0)->as_Mem();
|
||||
if (same_velt_type(s, mem_ref)) {
|
||||
remove_pack_at(i);
|
||||
}
|
||||
}
|
||||
|
||||
// If needed find the best memory reference for loop alignment again.
|
||||
if (same_velt_type(mem_ref, best_align_to_mem_ref)) {
|
||||
// Put memory ops from remaining packs back on memops list for
|
||||
// the best alignment search.
|
||||
uint orig_msize = memops.size();
|
||||
for (int i = 0; i < _packset.length(); i++) {
|
||||
Node_List* p = _packset.at(i);
|
||||
MemNode* s = p->at(0)->as_Mem();
|
||||
assert(!same_velt_type(s, mem_ref), "sanity");
|
||||
memops.push(s);
|
||||
}
|
||||
MemNode* best_align_to_mem_ref = find_align_to_ref(memops);
|
||||
if (best_align_to_mem_ref == NULL) break;
|
||||
best_iv_adjustment = get_iv_adjustment(best_align_to_mem_ref);
|
||||
// Restore list.
|
||||
while (memops.size() > orig_msize)
|
||||
(void)memops.pop();
|
||||
}
|
||||
} // unaligned memory accesses
|
||||
|
||||
// Remove used mem nodes.
|
||||
for (int i = memops.size() - 1; i >= 0; i--) {
|
||||
MemNode* m = memops.at(i)->as_Mem();
|
||||
if (alignment(m) != top_align) {
|
||||
memops.remove(i);
|
||||
}
|
||||
}
|
||||
|
||||
} // while (memops.size() != 0
|
||||
set_align_to_ref(best_align_to_mem_ref);
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (TraceSuperWord) {
|
||||
@ -246,7 +334,7 @@ void SuperWord::find_adjacent_refs() {
|
||||
// Find a memory reference to align the loop induction variable to.
|
||||
// Looks first at stores then at loads, looking for a memory reference
|
||||
// with the largest number of references similar to it.
|
||||
void SuperWord::find_align_to_ref(Node_List &memops) {
|
||||
MemNode* SuperWord::find_align_to_ref(Node_List &memops) {
|
||||
GrowableArray<int> cmp_ct(arena(), memops.size(), memops.size(), 0);
|
||||
|
||||
// Count number of comparable memory ops
|
||||
@ -270,20 +358,28 @@ void SuperWord::find_align_to_ref(Node_List &memops) {
|
||||
}
|
||||
}
|
||||
|
||||
// Find Store (or Load) with the greatest number of "comparable" references
|
||||
// Find Store (or Load) with the greatest number of "comparable" references,
|
||||
// biggest vector size, smallest data size and smallest iv offset.
|
||||
int max_ct = 0;
|
||||
int max_vw = 0;
|
||||
int max_idx = -1;
|
||||
int min_size = max_jint;
|
||||
int min_iv_offset = max_jint;
|
||||
for (uint j = 0; j < memops.size(); j++) {
|
||||
MemNode* s = memops.at(j)->as_Mem();
|
||||
if (s->is_Store()) {
|
||||
int vw = vector_width_in_bytes(s);
|
||||
assert(vw > 1, "sanity");
|
||||
SWPointer p(s, this);
|
||||
if (cmp_ct.at(j) > max_ct ||
|
||||
cmp_ct.at(j) == max_ct && (data_size(s) < min_size ||
|
||||
data_size(s) == min_size &&
|
||||
p.offset_in_bytes() < min_iv_offset)) {
|
||||
if (cmp_ct.at(j) > max_ct ||
|
||||
cmp_ct.at(j) == max_ct &&
|
||||
(vw > max_vw ||
|
||||
vw == max_vw &&
|
||||
(data_size(s) < min_size ||
|
||||
data_size(s) == min_size &&
|
||||
(p.offset_in_bytes() < min_iv_offset)))) {
|
||||
max_ct = cmp_ct.at(j);
|
||||
max_vw = vw;
|
||||
max_idx = j;
|
||||
min_size = data_size(s);
|
||||
min_iv_offset = p.offset_in_bytes();
|
||||
@ -295,12 +391,18 @@ void SuperWord::find_align_to_ref(Node_List &memops) {
|
||||
for (uint j = 0; j < memops.size(); j++) {
|
||||
MemNode* s = memops.at(j)->as_Mem();
|
||||
if (s->is_Load()) {
|
||||
int vw = vector_width_in_bytes(s);
|
||||
assert(vw > 1, "sanity");
|
||||
SWPointer p(s, this);
|
||||
if (cmp_ct.at(j) > max_ct ||
|
||||
cmp_ct.at(j) == max_ct && (data_size(s) < min_size ||
|
||||
data_size(s) == min_size &&
|
||||
p.offset_in_bytes() < min_iv_offset)) {
|
||||
if (cmp_ct.at(j) > max_ct ||
|
||||
cmp_ct.at(j) == max_ct &&
|
||||
(vw > max_vw ||
|
||||
vw == max_vw &&
|
||||
(data_size(s) < min_size ||
|
||||
data_size(s) == min_size &&
|
||||
(p.offset_in_bytes() < min_iv_offset)))) {
|
||||
max_ct = cmp_ct.at(j);
|
||||
max_vw = vw;
|
||||
max_idx = j;
|
||||
min_size = data_size(s);
|
||||
min_iv_offset = p.offset_in_bytes();
|
||||
@ -309,10 +411,7 @@ void SuperWord::find_align_to_ref(Node_List &memops) {
|
||||
}
|
||||
}
|
||||
|
||||
if (max_ct > 0)
|
||||
set_align_to_ref(memops.at(max_idx)->as_Mem());
|
||||
|
||||
#ifndef PRODUCT
|
||||
#ifdef ASSERT
|
||||
if (TraceSuperWord && Verbose) {
|
||||
tty->print_cr("\nVector memops after find_align_to_refs");
|
||||
for (uint i = 0; i < memops.size(); i++) {
|
||||
@ -321,6 +420,17 @@ void SuperWord::find_align_to_ref(Node_List &memops) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (max_ct > 0) {
|
||||
#ifdef ASSERT
|
||||
if (TraceSuperWord) {
|
||||
tty->print("\nVector align to node: ");
|
||||
memops.at(max_idx)->as_Mem()->dump();
|
||||
}
|
||||
#endif
|
||||
return memops.at(max_idx)->as_Mem();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//------------------------------ref_is_alignable---------------------------
|
||||
@ -341,7 +451,8 @@ bool SuperWord::ref_is_alignable(SWPointer& p) {
|
||||
|
||||
// If initial offset from start of object is computable,
|
||||
// compute alignment within the vector.
|
||||
int vw = vector_width_in_bytes();
|
||||
int vw = vector_width_in_bytes(p.mem());
|
||||
assert(vw > 1, "sanity");
|
||||
if (vw % span == 0) {
|
||||
Node* init_nd = pre_end->init_trip();
|
||||
if (init_nd->is_Con() && p.invar() == NULL) {
|
||||
@ -361,6 +472,25 @@ bool SuperWord::ref_is_alignable(SWPointer& p) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//---------------------------get_iv_adjustment---------------------------
|
||||
// Calculate loop's iv adjustment for this memory ops.
|
||||
int SuperWord::get_iv_adjustment(MemNode* mem_ref) {
|
||||
SWPointer align_to_ref_p(mem_ref, this);
|
||||
int offset = align_to_ref_p.offset_in_bytes();
|
||||
int scale = align_to_ref_p.scale_in_bytes();
|
||||
int vw = vector_width_in_bytes(mem_ref);
|
||||
assert(vw > 1, "sanity");
|
||||
int stride_sign = (scale * iv_stride()) > 0 ? 1 : -1;
|
||||
int iv_adjustment = (stride_sign * vw - (offset % vw)) % vw;
|
||||
|
||||
#ifndef PRODUCT
|
||||
if (TraceSuperWord)
|
||||
tty->print_cr("\noffset = %d iv_adjust = %d elt_size = %d scale = %d iv_stride = %d vect_size %d",
|
||||
offset, iv_adjustment, align_to_ref_p.memory_size(), scale, iv_stride(), vw);
|
||||
#endif
|
||||
return iv_adjustment;
|
||||
}
|
||||
|
||||
//---------------------------dependence_graph---------------------------
|
||||
// Construct dependency graph.
|
||||
// Add dependence edges to load/store nodes for memory dependence
|
||||
@ -488,9 +618,13 @@ void SuperWord::mem_slice_preds(Node* start, Node* stop, GrowableArray<Node*> &p
|
||||
bool SuperWord::stmts_can_pack(Node* s1, Node* s2, int align) {
|
||||
|
||||
// Do not use superword for non-primitives
|
||||
if((s1->is_Mem() && !is_java_primitive(s1->as_Mem()->memory_type())) ||
|
||||
(s2->is_Mem() && !is_java_primitive(s2->as_Mem()->memory_type())))
|
||||
BasicType bt1 = velt_basic_type(s1);
|
||||
BasicType bt2 = velt_basic_type(s2);
|
||||
if(!is_java_primitive(bt1) || !is_java_primitive(bt2))
|
||||
return false;
|
||||
if (Matcher::max_vector_size(bt1) < 2) {
|
||||
return false; // No vectors for this type
|
||||
}
|
||||
|
||||
if (isomorphic(s1, s2)) {
|
||||
if (independent(s1, s2)) {
|
||||
@ -552,7 +686,7 @@ bool SuperWord::isomorphic(Node* s1, Node* s2) {
|
||||
if (s1->Opcode() != s2->Opcode()) return false;
|
||||
if (s1->req() != s2->req()) return false;
|
||||
if (s1->in(0) != s2->in(0)) return false;
|
||||
if (velt_type(s1) != velt_type(s2)) return false;
|
||||
if (!same_velt_type(s1, s2)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -595,14 +729,16 @@ bool SuperWord::independent_path(Node* shallow, Node* deep, uint dp) {
|
||||
//------------------------------set_alignment---------------------------
|
||||
void SuperWord::set_alignment(Node* s1, Node* s2, int align) {
|
||||
set_alignment(s1, align);
|
||||
set_alignment(s2, align + data_size(s1));
|
||||
if (align == top_align || align == bottom_align) {
|
||||
set_alignment(s2, align);
|
||||
} else {
|
||||
set_alignment(s2, align + data_size(s1));
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------data_size---------------------------
|
||||
int SuperWord::data_size(Node* s) {
|
||||
const Type* t = velt_type(s);
|
||||
BasicType bt = t->array_element_basic_type();
|
||||
int bsize = type2aelembytes(bt);
|
||||
int bsize = type2aelembytes(velt_basic_type(s));
|
||||
assert(bsize != 0, "valid size");
|
||||
return bsize;
|
||||
}
|
||||
@ -631,9 +767,9 @@ void SuperWord::extend_packlist() {
|
||||
//------------------------------follow_use_defs---------------------------
|
||||
// Extend the packset by visiting operand definitions of nodes in pack p
|
||||
bool SuperWord::follow_use_defs(Node_List* p) {
|
||||
assert(p->size() == 2, "just checking");
|
||||
Node* s1 = p->at(0);
|
||||
Node* s2 = p->at(1);
|
||||
assert(p->size() == 2, "just checking");
|
||||
assert(s1->req() == s2->req(), "just checking");
|
||||
assert(alignment(s1) + data_size(s1) == alignment(s2), "just checking");
|
||||
|
||||
@ -718,7 +854,12 @@ bool SuperWord::opnd_positions_match(Node* d1, Node* u1, Node* d2, Node* u2) {
|
||||
for (i1++; i1 < ct; i1++) if (u1->in(i1) == d1) break;
|
||||
for (i2++; i2 < ct; i2++) if (u2->in(i2) == d2) break;
|
||||
if (i1 != i2) {
|
||||
return false;
|
||||
if ((i1 == (3-i2)) && (u2->is_Add() || u2->is_Mul())) {
|
||||
// Further analysis relies on operands position matching.
|
||||
u2->swap_edges(i1, i2);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (i1 < ct);
|
||||
return true;
|
||||
@ -727,7 +868,7 @@ bool SuperWord::opnd_positions_match(Node* d1, Node* u1, Node* d2, Node* u2) {
|
||||
//------------------------------est_savings---------------------------
|
||||
// Estimate the savings from executing s1 and s2 as a pack
|
||||
int SuperWord::est_savings(Node* s1, Node* s2) {
|
||||
int save = 2 - 1; // 2 operations per instruction in packed form
|
||||
int save_in = 2 - 1; // 2 operations per instruction in packed form
|
||||
|
||||
// inputs
|
||||
for (uint i = 1; i < s1->req(); i++) {
|
||||
@ -735,17 +876,18 @@ int SuperWord::est_savings(Node* s1, Node* s2) {
|
||||
Node* x2 = s2->in(i);
|
||||
if (x1 != x2) {
|
||||
if (are_adjacent_refs(x1, x2)) {
|
||||
save += adjacent_profit(x1, x2);
|
||||
save_in += adjacent_profit(x1, x2);
|
||||
} else if (!in_packset(x1, x2)) {
|
||||
save -= pack_cost(2);
|
||||
save_in -= pack_cost(2);
|
||||
} else {
|
||||
save += unpack_cost(2);
|
||||
save_in += unpack_cost(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// uses of result
|
||||
uint ct = 0;
|
||||
int save_use = 0;
|
||||
for (DUIterator_Fast imax, i = s1->fast_outs(imax); i < imax; i++) {
|
||||
Node* s1_use = s1->fast_out(i);
|
||||
for (int j = 0; j < _packset.length(); j++) {
|
||||
@ -756,7 +898,7 @@ int SuperWord::est_savings(Node* s1, Node* s2) {
|
||||
if (p->at(p->size()-1) == s2_use) {
|
||||
ct++;
|
||||
if (are_adjacent_refs(s1_use, s2_use)) {
|
||||
save += adjacent_profit(s1_use, s2_use);
|
||||
save_use += adjacent_profit(s1_use, s2_use);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -764,10 +906,10 @@ int SuperWord::est_savings(Node* s1, Node* s2) {
|
||||
}
|
||||
}
|
||||
|
||||
if (ct < s1->outcnt()) save += unpack_cost(1);
|
||||
if (ct < s2->outcnt()) save += unpack_cost(1);
|
||||
if (ct < s1->outcnt()) save_use += unpack_cost(1);
|
||||
if (ct < s2->outcnt()) save_use += unpack_cost(1);
|
||||
|
||||
return save;
|
||||
return MAX2(save_in, save_use);
|
||||
}
|
||||
|
||||
//------------------------------costs---------------------------
|
||||
@ -778,8 +920,9 @@ int SuperWord::unpack_cost(int ct) { return ct; }
|
||||
//------------------------------combine_packs---------------------------
|
||||
// Combine packs A and B with A.last == B.first into A.first..,A.last,B.second,..B.last
|
||||
void SuperWord::combine_packs() {
|
||||
bool changed;
|
||||
do {
|
||||
bool changed = true;
|
||||
// Combine packs regardless max vector size.
|
||||
while (changed) {
|
||||
changed = false;
|
||||
for (int i = 0; i < _packset.length(); i++) {
|
||||
Node_List* p1 = _packset.at(i);
|
||||
@ -787,6 +930,7 @@ void SuperWord::combine_packs() {
|
||||
for (int j = 0; j < _packset.length(); j++) {
|
||||
Node_List* p2 = _packset.at(j);
|
||||
if (p2 == NULL) continue;
|
||||
if (i == j) continue;
|
||||
if (p1->at(p1->size()-1) == p2->at(0)) {
|
||||
for (uint k = 1; k < p2->size(); k++) {
|
||||
p1->push(p2->at(k));
|
||||
@ -796,8 +940,39 @@ void SuperWord::combine_packs() {
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (changed);
|
||||
}
|
||||
|
||||
// Split packs which have size greater then max vector size.
|
||||
for (int i = 0; i < _packset.length(); i++) {
|
||||
Node_List* p1 = _packset.at(i);
|
||||
if (p1 != NULL) {
|
||||
BasicType bt = velt_basic_type(p1->at(0));
|
||||
uint max_vlen = Matcher::max_vector_size(bt); // Max elements in vector
|
||||
assert(is_power_of_2(max_vlen), "sanity");
|
||||
uint psize = p1->size();
|
||||
if (!is_power_of_2(psize)) {
|
||||
// Skip pack which can't be vector.
|
||||
// case1: for(...) { a[i] = i; } elements values are different (i+x)
|
||||
// case2: for(...) { a[i] = b[i+1]; } can't align both, load and store
|
||||
_packset.at_put(i, NULL);
|
||||
continue;
|
||||
}
|
||||
if (psize > max_vlen) {
|
||||
Node_List* pack = new Node_List();
|
||||
for (uint j = 0; j < psize; j++) {
|
||||
pack->push(p1->at(j));
|
||||
if (pack->size() >= max_vlen) {
|
||||
assert(is_power_of_2(pack->size()), "sanity");
|
||||
_packset.append(pack);
|
||||
pack = new Node_List();
|
||||
}
|
||||
}
|
||||
_packset.at_put(i, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compress list.
|
||||
for (int i = _packset.length() - 1; i >= 0; i--) {
|
||||
Node_List* p1 = _packset.at(i);
|
||||
if (p1 == NULL) {
|
||||
@ -880,8 +1055,7 @@ void SuperWord::filter_packs() {
|
||||
// Can code be generated for pack p?
|
||||
bool SuperWord::implemented(Node_List* p) {
|
||||
Node* p0 = p->at(0);
|
||||
int vopc = VectorNode::opcode(p0->Opcode(), p->size(), velt_type(p0));
|
||||
return vopc > 0 && Matcher::has_match_rule(vopc);
|
||||
return VectorNode::implemented(p0->Opcode(), p->size(), velt_basic_type(p0));
|
||||
}
|
||||
|
||||
//------------------------------profitable---------------------------
|
||||
@ -939,36 +1113,36 @@ void SuperWord::schedule() {
|
||||
}
|
||||
|
||||
//-------------------------------remove_and_insert-------------------
|
||||
//remove "current" from its current position in the memory graph and insert
|
||||
//it after the appropriate insertion point (lip or uip)
|
||||
// Remove "current" from its current position in the memory graph and insert
|
||||
// it after the appropriate insertion point (lip or uip).
|
||||
void SuperWord::remove_and_insert(MemNode *current, MemNode *prev, MemNode *lip,
|
||||
Node *uip, Unique_Node_List &sched_before) {
|
||||
Node* my_mem = current->in(MemNode::Memory);
|
||||
_igvn.rehash_node_delayed(current);
|
||||
_igvn.hash_delete(my_mem);
|
||||
bool sched_up = sched_before.member(current);
|
||||
|
||||
//remove current_store from its current position in the memmory graph
|
||||
// remove current_store from its current position in the memmory graph
|
||||
for (DUIterator i = current->outs(); current->has_out(i); i++) {
|
||||
Node* use = current->out(i);
|
||||
if (use->is_Mem()) {
|
||||
assert(use->in(MemNode::Memory) == current, "must be");
|
||||
_igvn.rehash_node_delayed(use);
|
||||
if (use == prev) { // connect prev to my_mem
|
||||
use->set_req(MemNode::Memory, my_mem);
|
||||
_igvn.replace_input_of(use, MemNode::Memory, my_mem);
|
||||
--i; //deleted this edge; rescan position
|
||||
} else if (sched_before.member(use)) {
|
||||
_igvn.hash_delete(uip);
|
||||
use->set_req(MemNode::Memory, uip);
|
||||
if (!sched_up) { // Will be moved together with current
|
||||
_igvn.replace_input_of(use, MemNode::Memory, uip);
|
||||
--i; //deleted this edge; rescan position
|
||||
}
|
||||
} else {
|
||||
_igvn.hash_delete(lip);
|
||||
use->set_req(MemNode::Memory, lip);
|
||||
if (sched_up) { // Will be moved together with current
|
||||
_igvn.replace_input_of(use, MemNode::Memory, lip);
|
||||
--i; //deleted this edge; rescan position
|
||||
}
|
||||
}
|
||||
--i; //deleted this edge; rescan position
|
||||
}
|
||||
}
|
||||
|
||||
bool sched_up = sched_before.member(current);
|
||||
Node *insert_pt = sched_up ? uip : lip;
|
||||
_igvn.hash_delete(insert_pt);
|
||||
|
||||
// all uses of insert_pt's memory state should use current's instead
|
||||
for (DUIterator i = insert_pt->outs(); insert_pt->has_out(i); i++) {
|
||||
@ -988,7 +1162,7 @@ void SuperWord::remove_and_insert(MemNode *current, MemNode *prev, MemNode *lip,
|
||||
}
|
||||
|
||||
//connect current to insert_pt
|
||||
current->set_req(MemNode::Memory, insert_pt);
|
||||
_igvn.replace_input_of(current, MemNode::Memory, insert_pt);
|
||||
}
|
||||
|
||||
//------------------------------co_locate_pack----------------------------------
|
||||
@ -1025,7 +1199,7 @@ void SuperWord::co_locate_pack(Node_List* pk) {
|
||||
if (use->is_Mem() && use != previous)
|
||||
memops.push(use);
|
||||
}
|
||||
if(current == first) break;
|
||||
if (current == first) break;
|
||||
previous = current;
|
||||
current = current->in(MemNode::Memory)->as_Mem();
|
||||
}
|
||||
@ -1038,27 +1212,37 @@ void SuperWord::co_locate_pack(Node_List* pk) {
|
||||
Node *s2 = memops.at(j);
|
||||
if (!independent(s1, s2)) {
|
||||
if (in_pack(s2, pk) || schedule_before_pack.member(s2)) {
|
||||
schedule_before_pack.push(s1); //s1 must be scheduled before
|
||||
schedule_before_pack.push(s1); // s1 must be scheduled before
|
||||
Node_List* mem_pk = my_pack(s1);
|
||||
if (mem_pk != NULL) {
|
||||
for (uint ii = 0; ii < mem_pk->size(); ii++) {
|
||||
Node* s = mem_pk->at(ii); // follow partner
|
||||
Node* s = mem_pk->at(ii); // follow partner
|
||||
if (memops.member(s) && !schedule_before_pack.member(s))
|
||||
schedule_before_pack.push(s);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemNode* lower_insert_pt = last;
|
||||
Node* upper_insert_pt = first->in(MemNode::Memory);
|
||||
// Following code moves loads connected to upper_insert_pt below aliased stores.
|
||||
// Collect such loads here and reconnect them back to upper_insert_pt later.
|
||||
memops.clear();
|
||||
for (DUIterator i = upper_insert_pt->outs(); upper_insert_pt->has_out(i); i++) {
|
||||
Node* use = upper_insert_pt->out(i);
|
||||
if (!use->is_Store())
|
||||
memops.push(use);
|
||||
}
|
||||
|
||||
MemNode* lower_insert_pt = last;
|
||||
previous = last; //previous store in pk
|
||||
current = last->in(MemNode::Memory)->as_Mem();
|
||||
|
||||
//start scheduling from "last" to "first"
|
||||
// start scheduling from "last" to "first"
|
||||
while (true) {
|
||||
assert(in_bb(current), "stay in block");
|
||||
assert(in_pack(previous, pk), "previous stays in pack");
|
||||
@ -1066,16 +1250,13 @@ void SuperWord::co_locate_pack(Node_List* pk) {
|
||||
|
||||
if (in_pack(current, pk)) {
|
||||
// Forward users of my memory state (except "previous) to my input memory state
|
||||
_igvn.hash_delete(current);
|
||||
for (DUIterator i = current->outs(); current->has_out(i); i++) {
|
||||
Node* use = current->out(i);
|
||||
if (use->is_Mem() && use != previous) {
|
||||
assert(use->in(MemNode::Memory) == current, "must be");
|
||||
if (schedule_before_pack.member(use)) {
|
||||
_igvn.hash_delete(upper_insert_pt);
|
||||
_igvn.replace_input_of(use, MemNode::Memory, upper_insert_pt);
|
||||
} else {
|
||||
_igvn.hash_delete(lower_insert_pt);
|
||||
_igvn.replace_input_of(use, MemNode::Memory, lower_insert_pt);
|
||||
}
|
||||
--i; // deleted this edge; rescan position
|
||||
@ -1089,6 +1270,14 @@ void SuperWord::co_locate_pack(Node_List* pk) {
|
||||
if (current == first) break;
|
||||
current = my_mem->as_Mem();
|
||||
} // end while
|
||||
|
||||
// Reconnect loads back to upper_insert_pt.
|
||||
for (uint i = 0; i < memops.size(); i++) {
|
||||
Node *ld = memops.at(i);
|
||||
if (ld->in(MemNode::Memory) != upper_insert_pt) {
|
||||
_igvn.replace_input_of(ld, MemNode::Memory, upper_insert_pt);
|
||||
}
|
||||
}
|
||||
} else if (pk->at(0)->is_Load()) { //load
|
||||
// all loads in the pack should have the same memory state. By default,
|
||||
// we use the memory state of the last load. However, if any load could
|
||||
@ -1149,35 +1338,30 @@ void SuperWord::output() {
|
||||
Node* vn = NULL;
|
||||
Node* low_adr = p->at(0);
|
||||
Node* first = executed_first(p);
|
||||
int opc = n->Opcode();
|
||||
if (n->is_Load()) {
|
||||
int opc = n->Opcode();
|
||||
Node* ctl = n->in(MemNode::Control);
|
||||
Node* mem = first->in(MemNode::Memory);
|
||||
Node* adr = low_adr->in(MemNode::Address);
|
||||
const TypePtr* atyp = n->adr_type();
|
||||
vn = VectorLoadNode::make(_phase->C, opc, ctl, mem, adr, atyp, vlen);
|
||||
|
||||
vn = LoadVectorNode::make(_phase->C, opc, ctl, mem, adr, atyp, vlen, velt_basic_type(n));
|
||||
} else if (n->is_Store()) {
|
||||
// Promote value to be stored to vector
|
||||
Node* val = vector_opd(p, MemNode::ValueIn);
|
||||
|
||||
int opc = n->Opcode();
|
||||
Node* ctl = n->in(MemNode::Control);
|
||||
Node* mem = first->in(MemNode::Memory);
|
||||
Node* adr = low_adr->in(MemNode::Address);
|
||||
const TypePtr* atyp = n->adr_type();
|
||||
vn = VectorStoreNode::make(_phase->C, opc, ctl, mem, adr, atyp, val, vlen);
|
||||
|
||||
vn = StoreVectorNode::make(_phase->C, opc, ctl, mem, adr, atyp, val, vlen);
|
||||
} else if (n->req() == 3) {
|
||||
// Promote operands to vector
|
||||
Node* in1 = vector_opd(p, 1);
|
||||
Node* in2 = vector_opd(p, 2);
|
||||
vn = VectorNode::make(_phase->C, n->Opcode(), in1, in2, vlen, velt_type(n));
|
||||
|
||||
vn = VectorNode::make(_phase->C, opc, in1, in2, vlen, velt_basic_type(n));
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
assert(vn != NULL, "sanity");
|
||||
_phase->_igvn.register_new_node_with_optimizer(vn);
|
||||
_phase->set_ctrl(vn, _phase->get_ctrl(p->at(0)));
|
||||
for (uint j = 0; j < p->size(); j++) {
|
||||
@ -1185,6 +1369,12 @@ void SuperWord::output() {
|
||||
_igvn.replace_node(pm, vn);
|
||||
}
|
||||
_igvn._worklist.push(vn);
|
||||
#ifdef ASSERT
|
||||
if (TraceNewVectors) {
|
||||
tty->print("new Vector node: ");
|
||||
vn->dump();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1207,10 +1397,10 @@ Node* SuperWord::vector_opd(Node_List* p, int opd_idx) {
|
||||
}
|
||||
|
||||
if (same_opd) {
|
||||
if (opd->is_Vector() || opd->is_VectorLoad()) {
|
||||
if (opd->is_Vector() || opd->is_LoadVector()) {
|
||||
return opd; // input is matching vector
|
||||
}
|
||||
assert(!opd->is_VectorStore(), "such vector is not expected here");
|
||||
assert(!opd->is_StoreVector(), "such vector is not expected here");
|
||||
// Convert scalar input to vector with the same number of elements as
|
||||
// p0's vector. Use p0's type because size of operand's container in
|
||||
// vector should match p0's size regardless operand's size.
|
||||
@ -1219,12 +1409,18 @@ Node* SuperWord::vector_opd(Node_List* p, int opd_idx) {
|
||||
|
||||
_phase->_igvn.register_new_node_with_optimizer(vn);
|
||||
_phase->set_ctrl(vn, _phase->get_ctrl(opd));
|
||||
#ifdef ASSERT
|
||||
if (TraceNewVectors) {
|
||||
tty->print("new Vector node: ");
|
||||
vn->dump();
|
||||
}
|
||||
#endif
|
||||
return vn;
|
||||
}
|
||||
|
||||
// Insert pack operation
|
||||
const Type* p0_t = velt_type(p0);
|
||||
PackNode* pk = PackNode::make(_phase->C, opd, p0_t);
|
||||
BasicType bt = velt_basic_type(p0);
|
||||
PackNode* pk = PackNode::make(_phase->C, opd, vlen, bt);
|
||||
DEBUG_ONLY( const BasicType opd_bt = opd->bottom_type()->basic_type(); )
|
||||
|
||||
for (uint i = 1; i < vlen; i++) {
|
||||
@ -1232,10 +1428,16 @@ Node* SuperWord::vector_opd(Node_List* p, int opd_idx) {
|
||||
Node* in = pi->in(opd_idx);
|
||||
assert(my_pack(in) == NULL, "Should already have been unpacked");
|
||||
assert(opd_bt == in->bottom_type()->basic_type(), "all same type");
|
||||
pk->add_opd(in);
|
||||
pk->add_opd(i, in);
|
||||
}
|
||||
_phase->_igvn.register_new_node_with_optimizer(pk);
|
||||
_phase->set_ctrl(pk, _phase->get_ctrl(opd));
|
||||
#ifdef ASSERT
|
||||
if (TraceNewVectors) {
|
||||
tty->print("new Vector node: ");
|
||||
pk->dump();
|
||||
}
|
||||
#endif
|
||||
return pk;
|
||||
}
|
||||
|
||||
@ -1273,16 +1475,15 @@ void SuperWord::insert_extracts(Node_List* p) {
|
||||
// Insert extract operation
|
||||
_igvn.hash_delete(def);
|
||||
int def_pos = alignment(def) / data_size(def);
|
||||
const Type* def_t = velt_type(def);
|
||||
|
||||
Node* ex = ExtractNode::make(_phase->C, def, def_pos, def_t);
|
||||
Node* ex = ExtractNode::make(_phase->C, def, def_pos, velt_basic_type(def));
|
||||
_phase->_igvn.register_new_node_with_optimizer(ex);
|
||||
_phase->set_ctrl(ex, _phase->get_ctrl(def));
|
||||
_igvn.replace_input_of(use, idx, ex);
|
||||
_igvn._worklist.push(def);
|
||||
|
||||
bb_insert_after(ex, bb_idx(def));
|
||||
set_velt_type(ex, def_t);
|
||||
set_velt_type(ex, velt_type(def));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1509,10 +1710,7 @@ void SuperWord::compute_vector_element_type() {
|
||||
// Initial type
|
||||
for (int i = 0; i < _block.length(); i++) {
|
||||
Node* n = _block.at(i);
|
||||
const Type* t = n->is_Mem() ? Type::get_const_basic_type(n->as_Mem()->memory_type())
|
||||
: _igvn.type(n);
|
||||
const Type* vt = container_type(t);
|
||||
set_velt_type(n, vt);
|
||||
set_velt_type(n, container_type(n));
|
||||
}
|
||||
|
||||
// Propagate narrowed type backwards through operations
|
||||
@ -1543,7 +1741,7 @@ void SuperWord::compute_vector_element_type() {
|
||||
bool same_type = true;
|
||||
for (DUIterator_Fast kmax, k = in->fast_outs(kmax); k < kmax; k++) {
|
||||
Node *use = in->fast_out(k);
|
||||
if (!in_bb(use) || velt_type(use) != vt) {
|
||||
if (!in_bb(use) || !same_velt_type(use, n)) {
|
||||
same_type = false;
|
||||
break;
|
||||
}
|
||||
@ -1575,20 +1773,24 @@ int SuperWord::memory_alignment(MemNode* s, int iv_adjust_in_bytes) {
|
||||
if (!p.valid()) {
|
||||
return bottom_align;
|
||||
}
|
||||
int vw = vector_width_in_bytes(s);
|
||||
if (vw < 2) {
|
||||
return bottom_align; // No vectors for this type
|
||||
}
|
||||
int offset = p.offset_in_bytes();
|
||||
offset += iv_adjust_in_bytes;
|
||||
int off_rem = offset % vector_width_in_bytes();
|
||||
int off_mod = off_rem >= 0 ? off_rem : off_rem + vector_width_in_bytes();
|
||||
int off_rem = offset % vw;
|
||||
int off_mod = off_rem >= 0 ? off_rem : off_rem + vw;
|
||||
return off_mod;
|
||||
}
|
||||
|
||||
//---------------------------container_type---------------------------
|
||||
// Smallest type containing range of values
|
||||
const Type* SuperWord::container_type(const Type* t) {
|
||||
const Type* tp = t->make_ptr();
|
||||
if (tp && tp->isa_aryptr()) {
|
||||
t = tp->is_aryptr()->elem();
|
||||
const Type* SuperWord::container_type(Node* n) {
|
||||
if (n->is_Mem()) {
|
||||
return Type::get_const_basic_type(n->as_Mem()->memory_type());
|
||||
}
|
||||
const Type* t = _igvn.type(n);
|
||||
if (t->basic_type() == T_INT) {
|
||||
if (t->higher_equal(TypeInt::BOOL)) return TypeInt::BOOL;
|
||||
if (t->higher_equal(TypeInt::BYTE)) return TypeInt::BYTE;
|
||||
@ -1599,11 +1801,22 @@ const Type* SuperWord::container_type(const Type* t) {
|
||||
return t;
|
||||
}
|
||||
|
||||
bool SuperWord::same_velt_type(Node* n1, Node* n2) {
|
||||
const Type* vt1 = velt_type(n1);
|
||||
const Type* vt2 = velt_type(n1);
|
||||
if (vt1->basic_type() == T_INT && vt2->basic_type() == T_INT) {
|
||||
// Compare vectors element sizes for integer types.
|
||||
return data_size(n1) == data_size(n2);
|
||||
}
|
||||
return vt1 == vt2;
|
||||
}
|
||||
|
||||
//-------------------------vector_opd_range-----------------------
|
||||
// (Start, end] half-open range defining which operands are vector
|
||||
void SuperWord::vector_opd_range(Node* n, uint* start, uint* end) {
|
||||
switch (n->Opcode()) {
|
||||
case Op_LoadB: case Op_LoadUS:
|
||||
case Op_LoadB: case Op_LoadUB:
|
||||
case Op_LoadS: case Op_LoadUS:
|
||||
case Op_LoadI: case Op_LoadL:
|
||||
case Op_LoadF: case Op_LoadD:
|
||||
case Op_LoadP:
|
||||
@ -1721,6 +1934,7 @@ void SuperWord::align_initial_loop_index(MemNode* align_to_ref) {
|
||||
assert(orig_limit != NULL && _igvn.type(orig_limit) != Type::TOP, "");
|
||||
|
||||
SWPointer align_to_ref_p(align_to_ref, this);
|
||||
assert(align_to_ref_p.valid(), "sanity");
|
||||
|
||||
// Given:
|
||||
// lim0 == original pre loop limit
|
||||
@ -1773,10 +1987,12 @@ void SuperWord::align_initial_loop_index(MemNode* align_to_ref) {
|
||||
// N = (V - (e - lim0)) % V
|
||||
// lim = lim0 - (V - (e - lim0)) % V
|
||||
|
||||
int vw = vector_width_in_bytes(align_to_ref);
|
||||
int stride = iv_stride();
|
||||
int scale = align_to_ref_p.scale_in_bytes();
|
||||
int elt_size = align_to_ref_p.memory_size();
|
||||
int v_align = vector_width_in_bytes() / elt_size;
|
||||
int v_align = vw / elt_size;
|
||||
assert(v_align > 1, "sanity");
|
||||
int k = align_to_ref_p.offset_in_bytes() / elt_size;
|
||||
|
||||
Node *kn = _igvn.intcon(k);
|
||||
@ -1796,6 +2012,25 @@ void SuperWord::align_initial_loop_index(MemNode* align_to_ref) {
|
||||
_phase->_igvn.register_new_node_with_optimizer(e);
|
||||
_phase->set_ctrl(e, pre_ctrl);
|
||||
}
|
||||
if (vw > ObjectAlignmentInBytes) {
|
||||
// incorporate base e +/- base && Mask >>> log2(elt)
|
||||
Node* mask = _igvn.MakeConX(~(-1 << exact_log2(vw)));
|
||||
Node* xbase = new(_phase->C, 2) CastP2XNode(NULL, align_to_ref_p.base());
|
||||
_phase->_igvn.register_new_node_with_optimizer(xbase);
|
||||
Node* masked_xbase = new (_phase->C, 3) AndXNode(xbase, mask);
|
||||
_phase->_igvn.register_new_node_with_optimizer(masked_xbase);
|
||||
#ifdef _LP64
|
||||
masked_xbase = new (_phase->C, 2) ConvL2INode(masked_xbase);
|
||||
_phase->_igvn.register_new_node_with_optimizer(masked_xbase);
|
||||
#endif
|
||||
Node* log2_elt = _igvn.intcon(exact_log2(elt_size));
|
||||
Node* bref = new (_phase->C, 3) URShiftINode(masked_xbase, log2_elt);
|
||||
_phase->_igvn.register_new_node_with_optimizer(bref);
|
||||
_phase->set_ctrl(bref, pre_ctrl);
|
||||
e = new (_phase->C, 3) AddINode(e, bref);
|
||||
_phase->_igvn.register_new_node_with_optimizer(e);
|
||||
_phase->set_ctrl(e, pre_ctrl);
|
||||
}
|
||||
|
||||
// compute e +/- lim0
|
||||
if (scale < 0) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 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
|
||||
@ -264,8 +264,14 @@ class SuperWord : public ResourceObj {
|
||||
_iv = lp->as_CountedLoop()->phi()->as_Phi(); }
|
||||
int iv_stride() { return lp()->as_CountedLoop()->stride_con(); }
|
||||
|
||||
int vector_width_in_bytes() { return Matcher::vector_width_in_bytes(); }
|
||||
|
||||
int vector_width(Node* n) {
|
||||
BasicType bt = velt_basic_type(n);
|
||||
return MIN2(ABS(iv_stride()), Matcher::max_vector_size(bt));
|
||||
}
|
||||
int vector_width_in_bytes(Node* n) {
|
||||
BasicType bt = velt_basic_type(n);
|
||||
return vector_width(n)*type2aelembytes(bt);
|
||||
}
|
||||
MemNode* align_to_ref() { return _align_to_ref; }
|
||||
void set_align_to_ref(MemNode* m) { _align_to_ref = m; }
|
||||
|
||||
@ -298,7 +304,9 @@ class SuperWord : public ResourceObj {
|
||||
|
||||
// vector element type
|
||||
const Type* velt_type(Node* n) { return _node_info.adr_at(bb_idx(n))->_velt_type; }
|
||||
BasicType velt_basic_type(Node* n) { return velt_type(n)->array_element_basic_type(); }
|
||||
void set_velt_type(Node* n, const Type* t) { int i = bb_idx(n); grow_node_info(i); _node_info.adr_at(i)->_velt_type = t; }
|
||||
bool same_velt_type(Node* n1, Node* n2);
|
||||
|
||||
// my_pack
|
||||
Node_List* my_pack(Node* n) { return !in_bb(n) ? NULL : _node_info.adr_at(bb_idx(n))->_my_pack; }
|
||||
@ -311,7 +319,9 @@ class SuperWord : public ResourceObj {
|
||||
// Find the adjacent memory references and create pack pairs for them.
|
||||
void find_adjacent_refs();
|
||||
// Find a memory reference to align the loop induction variable to.
|
||||
void find_align_to_ref(Node_List &memops);
|
||||
MemNode* find_align_to_ref(Node_List &memops);
|
||||
// Calculate loop's iv adjustment for this memory ops.
|
||||
int get_iv_adjustment(MemNode* mem);
|
||||
// Can the preloop align the reference to position zero in the vector?
|
||||
bool ref_is_alignable(SWPointer& p);
|
||||
// Construct dependency graph.
|
||||
@ -394,7 +404,7 @@ class SuperWord : public ResourceObj {
|
||||
// (Start, end] half-open range defining which operands are vector
|
||||
void vector_opd_range(Node* n, uint* start, uint* end);
|
||||
// Smallest type containing range of values
|
||||
static const Type* container_type(const Type* t);
|
||||
const Type* container_type(Node* n);
|
||||
// Adjust pre-loop limit so that in main loop, a load/store reference
|
||||
// to align_to_ref will be a position zero in the vector.
|
||||
void align_initial_loop_index(MemNode* align_to_ref);
|
||||
@ -462,6 +472,7 @@ class SWPointer VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
Node* base() { return _base; }
|
||||
Node* adr() { return _adr; }
|
||||
MemNode* mem() { return _mem; }
|
||||
int scale_in_bytes() { return _scale; }
|
||||
Node* invar() { return _invar; }
|
||||
bool negate_invar() { return _negate_invar; }
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -60,6 +60,10 @@ const BasicType Type::_basic_type[Type::lastype] = {
|
||||
|
||||
T_ILLEGAL, // Tuple
|
||||
T_ARRAY, // Array
|
||||
T_ILLEGAL, // VectorS
|
||||
T_ILLEGAL, // VectorD
|
||||
T_ILLEGAL, // VectorX
|
||||
T_ILLEGAL, // VectorY
|
||||
|
||||
T_ADDRESS, // AnyPtr // shows up in factory methods for NULL_PTR
|
||||
T_ADDRESS, // RawPtr
|
||||
@ -414,6 +418,24 @@ void Type::Initialize_shared(Compile* current) {
|
||||
// get_zero_type() should not happen for T_CONFLICT
|
||||
_zero_type[T_CONFLICT]= NULL;
|
||||
|
||||
// Vector predefined types, it needs initialized _const_basic_type[].
|
||||
if (Matcher::vector_size_supported(T_BYTE,4)) {
|
||||
TypeVect::VECTS = TypeVect::make(T_BYTE,4);
|
||||
}
|
||||
if (Matcher::vector_size_supported(T_FLOAT,2)) {
|
||||
TypeVect::VECTD = TypeVect::make(T_FLOAT,2);
|
||||
}
|
||||
if (Matcher::vector_size_supported(T_FLOAT,4)) {
|
||||
TypeVect::VECTX = TypeVect::make(T_FLOAT,4);
|
||||
}
|
||||
if (Matcher::vector_size_supported(T_FLOAT,8)) {
|
||||
TypeVect::VECTY = TypeVect::make(T_FLOAT,8);
|
||||
}
|
||||
mreg2type[Op_VecS] = TypeVect::VECTS;
|
||||
mreg2type[Op_VecD] = TypeVect::VECTD;
|
||||
mreg2type[Op_VecX] = TypeVect::VECTX;
|
||||
mreg2type[Op_VecY] = TypeVect::VECTY;
|
||||
|
||||
// Restore working type arena.
|
||||
current->set_type_arena(save);
|
||||
current->set_type_dict(NULL);
|
||||
@ -668,6 +690,10 @@ const Type::TYPES Type::dual_type[Type::lastype] = {
|
||||
|
||||
Bad, // Tuple - handled in v-call
|
||||
Bad, // Array - handled in v-call
|
||||
Bad, // VectorS - handled in v-call
|
||||
Bad, // VectorD - handled in v-call
|
||||
Bad, // VectorX - handled in v-call
|
||||
Bad, // VectorY - handled in v-call
|
||||
|
||||
Bad, // AnyPtr - handled in v-call
|
||||
Bad, // RawPtr - handled in v-call
|
||||
@ -728,8 +754,8 @@ void Type::dump_on(outputStream *st) const {
|
||||
//------------------------------data-------------------------------------------
|
||||
const char * const Type::msg[Type::lastype] = {
|
||||
"bad","control","top","int:","long:","half", "narrowoop:",
|
||||
"tuple:", "aryptr",
|
||||
"anyptr:", "rawptr:", "java:", "inst:", "ary:", "klass:",
|
||||
"tuple:", "array:", "vectors:", "vectord:", "vectorx:", "vectory:",
|
||||
"anyptr:", "rawptr:", "java:", "inst:", "aryptr:", "klass:",
|
||||
"func", "abIO", "return_address", "memory",
|
||||
"float_top", "ftcon:", "float",
|
||||
"double_top", "dblcon:", "double",
|
||||
@ -790,7 +816,7 @@ void Type::typerr( const Type *t ) const {
|
||||
//------------------------------isa_oop_ptr------------------------------------
|
||||
// Return true if type is an oop pointer type. False for raw pointers.
|
||||
static char isa_oop_ptr_tbl[Type::lastype] = {
|
||||
0,0,0,0,0,0,0/*narrowoop*/,0/*tuple*/, 0/*ary*/,
|
||||
0,0,0,0,0,0,0/*narrowoop*/,0/*tuple*/, 0/*array*/, 0, 0, 0, 0/*vector*/,
|
||||
0/*anyptr*/,0/*rawptr*/,1/*OopPtr*/,1/*InstPtr*/,1/*AryPtr*/,1/*KlassPtr*/,
|
||||
0/*func*/,0,0/*return_address*/,0,
|
||||
/*floats*/0,0,0, /*doubles*/0,0,0,
|
||||
@ -1926,6 +1952,121 @@ bool TypeAry::ary_must_be_exact() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
//==============================TypeVect=======================================
|
||||
// Convenience common pre-built types.
|
||||
const TypeVect *TypeVect::VECTS = NULL; // 32-bit vectors
|
||||
const TypeVect *TypeVect::VECTD = NULL; // 64-bit vectors
|
||||
const TypeVect *TypeVect::VECTX = NULL; // 128-bit vectors
|
||||
const TypeVect *TypeVect::VECTY = NULL; // 256-bit vectors
|
||||
|
||||
//------------------------------make-------------------------------------------
|
||||
const TypeVect* TypeVect::make(const Type *elem, uint length) {
|
||||
BasicType elem_bt = elem->array_element_basic_type();
|
||||
assert(is_java_primitive(elem_bt), "only primitive types in vector");
|
||||
assert(length > 1 && is_power_of_2(length), "vector length is power of 2");
|
||||
assert(Matcher::vector_size_supported(elem_bt, length), "length in range");
|
||||
int size = length * type2aelembytes(elem_bt);
|
||||
switch (Matcher::vector_ideal_reg(size)) {
|
||||
case Op_VecS:
|
||||
return (TypeVect*)(new TypeVectS(elem, length))->hashcons();
|
||||
case Op_VecD:
|
||||
case Op_RegD:
|
||||
return (TypeVect*)(new TypeVectD(elem, length))->hashcons();
|
||||
case Op_VecX:
|
||||
return (TypeVect*)(new TypeVectX(elem, length))->hashcons();
|
||||
case Op_VecY:
|
||||
return (TypeVect*)(new TypeVectY(elem, length))->hashcons();
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//------------------------------meet-------------------------------------------
|
||||
// Compute the MEET of two types. It returns a new Type object.
|
||||
const Type *TypeVect::xmeet( const Type *t ) const {
|
||||
// Perform a fast test for common case; meeting the same types together.
|
||||
if( this == t ) return this; // Meeting same type-rep?
|
||||
|
||||
// Current "this->_base" is Vector
|
||||
switch (t->base()) { // switch on original type
|
||||
|
||||
case Bottom: // Ye Olde Default
|
||||
return t;
|
||||
|
||||
default: // All else is a mistake
|
||||
typerr(t);
|
||||
|
||||
case VectorS:
|
||||
case VectorD:
|
||||
case VectorX:
|
||||
case VectorY: { // Meeting 2 vectors?
|
||||
const TypeVect* v = t->is_vect();
|
||||
assert( base() == v->base(), "");
|
||||
assert(length() == v->length(), "");
|
||||
assert(element_basic_type() == v->element_basic_type(), "");
|
||||
return TypeVect::make(_elem->xmeet(v->_elem), _length);
|
||||
}
|
||||
case Top:
|
||||
break;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
//------------------------------xdual------------------------------------------
|
||||
// Dual: compute field-by-field dual
|
||||
const Type *TypeVect::xdual() const {
|
||||
return new TypeVect(base(), _elem->dual(), _length);
|
||||
}
|
||||
|
||||
//------------------------------eq---------------------------------------------
|
||||
// Structural equality check for Type representations
|
||||
bool TypeVect::eq(const Type *t) const {
|
||||
const TypeVect *v = t->is_vect();
|
||||
return (_elem == v->_elem) && (_length == v->_length);
|
||||
}
|
||||
|
||||
//------------------------------hash-------------------------------------------
|
||||
// Type-specific hashing function.
|
||||
int TypeVect::hash(void) const {
|
||||
return (intptr_t)_elem + (intptr_t)_length;
|
||||
}
|
||||
|
||||
//------------------------------singleton--------------------------------------
|
||||
// TRUE if Type is a singleton type, FALSE otherwise. Singletons are simple
|
||||
// constants (Ldi nodes). Vector is singleton if all elements are the same
|
||||
// constant value (when vector is created with Replicate code).
|
||||
bool TypeVect::singleton(void) const {
|
||||
// There is no Con node for vectors yet.
|
||||
// return _elem->singleton();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TypeVect::empty(void) const {
|
||||
return _elem->empty();
|
||||
}
|
||||
|
||||
//------------------------------dump2------------------------------------------
|
||||
#ifndef PRODUCT
|
||||
void TypeVect::dump2(Dict &d, uint depth, outputStream *st) const {
|
||||
switch (base()) {
|
||||
case VectorS:
|
||||
st->print("vectors["); break;
|
||||
case VectorD:
|
||||
st->print("vectord["); break;
|
||||
case VectorX:
|
||||
st->print("vectorx["); break;
|
||||
case VectorY:
|
||||
st->print("vectory["); break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
st->print("%d]:{", _length);
|
||||
_elem->dump2(d, depth, st);
|
||||
st->print("}");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//=============================================================================
|
||||
// Convenience common pre-built types.
|
||||
const TypePtr *TypePtr::NULL_PTR;
|
||||
@ -2472,18 +2613,26 @@ const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_
|
||||
//------------------------------make_from_constant-----------------------------
|
||||
// Make a java pointer from an oop constant
|
||||
const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_constant) {
|
||||
if (o->is_method_data() || o->is_method() || o->is_cpcache()) {
|
||||
if (o->is_method_data() || o->is_method()) {
|
||||
// Treat much like a typeArray of bytes, like below, but fake the type...
|
||||
const Type* etype = (Type*)get_const_basic_type(T_BYTE);
|
||||
const BasicType bt = T_BYTE;
|
||||
const Type* etype = get_const_basic_type(bt);
|
||||
const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS);
|
||||
ciKlass *klass = ciTypeArrayKlass::make((BasicType) T_BYTE);
|
||||
assert(o->can_be_constant(), "method data oops should be tenured");
|
||||
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
|
||||
return arr;
|
||||
ciKlass* klass = ciArrayKlass::make(ciType::make(bt));
|
||||
assert(o->can_be_constant(), "should be tenured");
|
||||
return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
|
||||
} else if (o->is_cpcache()) {
|
||||
// Treat much like a objArray, like below, but fake the type...
|
||||
const BasicType bt = T_OBJECT;
|
||||
const Type* etype = get_const_basic_type(bt);
|
||||
const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS);
|
||||
ciKlass* klass = ciArrayKlass::make(ciType::make(bt));
|
||||
assert(o->can_be_constant(), "should be tenured");
|
||||
return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
|
||||
} else {
|
||||
assert(o->is_java_object(), "must be java language object");
|
||||
assert(!o->is_null_object(), "null object not yet handled here.");
|
||||
ciKlass *klass = o->klass();
|
||||
ciKlass* klass = o->klass();
|
||||
if (klass->is_instance_klass()) {
|
||||
// Element is an instance
|
||||
if (require_constant) {
|
||||
@ -2494,8 +2643,7 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_const
|
||||
return TypeInstPtr::make(o);
|
||||
} else if (klass->is_obj_array_klass()) {
|
||||
// Element is an object array. Recursively call ourself.
|
||||
const Type *etype =
|
||||
TypeOopPtr::make_from_klass_raw(klass->as_obj_array_klass()->element_klass());
|
||||
const Type *etype = make_from_klass_raw(klass->as_obj_array_klass()->element_klass());
|
||||
const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
|
||||
// We used to pass NotNull in here, asserting that the sub-arrays
|
||||
// are all not-null. This is not true in generally, as code can
|
||||
@ -2505,12 +2653,10 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_const
|
||||
} else if (!o->should_be_constant()) {
|
||||
return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
|
||||
}
|
||||
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
|
||||
return arr;
|
||||
return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
|
||||
} else if (klass->is_type_array_klass()) {
|
||||
// Element is an typeArray
|
||||
const Type* etype =
|
||||
(Type*)get_const_basic_type(klass->as_type_array_klass()->element_type());
|
||||
const Type* etype = get_const_basic_type(klass->as_type_array_klass()->element_type());
|
||||
const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
|
||||
// We used to pass NotNull in here, asserting that the array pointer
|
||||
// is not-null. That was not true in general.
|
||||
@ -2519,12 +2665,11 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_const
|
||||
} else if (!o->should_be_constant()) {
|
||||
return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
|
||||
}
|
||||
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
|
||||
return arr;
|
||||
return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
|
||||
}
|
||||
}
|
||||
|
||||
ShouldNotReachHere();
|
||||
fatal("unhandled object type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -4140,7 +4285,7 @@ void TypeFunc::dump2( Dict &d, uint depth, outputStream *st ) const {
|
||||
// Print a 'flattened' signature
|
||||
static const char * const flat_type_msg[Type::lastype] = {
|
||||
"bad","control","top","int","long","_", "narrowoop",
|
||||
"tuple:", "array:",
|
||||
"tuple:", "array:", "vectors:", "vectord:", "vectorx:", "vectory:",
|
||||
"ptr", "rawptr", "ptr", "ptr", "ptr", "ptr",
|
||||
"func", "abIO", "return_address", "mem",
|
||||
"float_top", "ftcon:", "flt",
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* 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
|
||||
@ -51,6 +51,11 @@ class TypeLong;
|
||||
class TypeNarrowOop;
|
||||
class TypeAry;
|
||||
class TypeTuple;
|
||||
class TypeVect;
|
||||
class TypeVectS;
|
||||
class TypeVectD;
|
||||
class TypeVectX;
|
||||
class TypeVectY;
|
||||
class TypePtr;
|
||||
class TypeRawPtr;
|
||||
class TypeOopPtr;
|
||||
@ -78,6 +83,10 @@ public:
|
||||
|
||||
Tuple, // Method signature or object layout
|
||||
Array, // Array types
|
||||
VectorS, // 32bit Vector types
|
||||
VectorD, // 64bit Vector types
|
||||
VectorX, // 128bit Vector types
|
||||
VectorY, // 256bit Vector types
|
||||
|
||||
AnyPtr, // Any old raw, klass, inst, or array pointer
|
||||
RawPtr, // Raw (non-oop) pointers
|
||||
@ -222,6 +231,8 @@ public:
|
||||
const TypeF *isa_float_constant() const; // Returns NULL if not a FloatCon
|
||||
const TypeTuple *is_tuple() const; // Collection of fields, NOT a pointer
|
||||
const TypeAry *is_ary() const; // Array, NOT array pointer
|
||||
const TypeVect *is_vect() const; // Vector
|
||||
const TypeVect *isa_vect() const; // Returns NULL if not a Vector
|
||||
const TypePtr *is_ptr() const; // Asserts it is a ptr type
|
||||
const TypePtr *isa_ptr() const; // Returns NULL if not ptr type
|
||||
const TypeRawPtr *isa_rawptr() const; // NOT Java oop
|
||||
@ -574,6 +585,69 @@ public:
|
||||
#endif
|
||||
};
|
||||
|
||||
//------------------------------TypeVect---------------------------------------
|
||||
// Class of Vector Types
|
||||
class TypeVect : public Type {
|
||||
const Type* _elem; // Vector's element type
|
||||
const uint _length; // Elements in vector (power of 2)
|
||||
|
||||
protected:
|
||||
TypeVect(TYPES t, const Type* elem, uint length) : Type(t),
|
||||
_elem(elem), _length(length) {}
|
||||
|
||||
public:
|
||||
const Type* element_type() const { return _elem; }
|
||||
BasicType element_basic_type() const { return _elem->array_element_basic_type(); }
|
||||
uint length() const { return _length; }
|
||||
uint length_in_bytes() const {
|
||||
return _length * type2aelembytes(element_basic_type());
|
||||
}
|
||||
|
||||
virtual bool eq(const Type *t) const;
|
||||
virtual int hash() const; // Type specific hashing
|
||||
virtual bool singleton(void) const; // TRUE if type is a singleton
|
||||
virtual bool empty(void) const; // TRUE if type is vacuous
|
||||
|
||||
static const TypeVect *make(const BasicType elem_bt, uint length) {
|
||||
// Use bottom primitive type.
|
||||
return make(get_const_basic_type(elem_bt), length);
|
||||
}
|
||||
// Used directly by Replicate nodes to construct singleton vector.
|
||||
static const TypeVect *make(const Type* elem, uint length);
|
||||
|
||||
virtual const Type *xmeet( const Type *t) const;
|
||||
virtual const Type *xdual() const; // Compute dual right now.
|
||||
|
||||
static const TypeVect *VECTS;
|
||||
static const TypeVect *VECTD;
|
||||
static const TypeVect *VECTX;
|
||||
static const TypeVect *VECTY;
|
||||
|
||||
#ifndef PRODUCT
|
||||
virtual void dump2(Dict &d, uint, outputStream *st) const; // Specialized per-Type dumping
|
||||
#endif
|
||||
};
|
||||
|
||||
class TypeVectS : public TypeVect {
|
||||
friend class TypeVect;
|
||||
TypeVectS(const Type* elem, uint length) : TypeVect(VectorS, elem, length) {}
|
||||
};
|
||||
|
||||
class TypeVectD : public TypeVect {
|
||||
friend class TypeVect;
|
||||
TypeVectD(const Type* elem, uint length) : TypeVect(VectorD, elem, length) {}
|
||||
};
|
||||
|
||||
class TypeVectX : public TypeVect {
|
||||
friend class TypeVect;
|
||||
TypeVectX(const Type* elem, uint length) : TypeVect(VectorX, elem, length) {}
|
||||
};
|
||||
|
||||
class TypeVectY : public TypeVect {
|
||||
friend class TypeVect;
|
||||
TypeVectY(const Type* elem, uint length) : TypeVect(VectorY, elem, length) {}
|
||||
};
|
||||
|
||||
//------------------------------TypePtr----------------------------------------
|
||||
// Class of machine Pointer Types: raw data, instances or arrays.
|
||||
// If the _base enum is AnyPtr, then this refers to all of the above.
|
||||
@ -1113,6 +1187,15 @@ inline const TypeAry *Type::is_ary() const {
|
||||
return (TypeAry*)this;
|
||||
}
|
||||
|
||||
inline const TypeVect *Type::is_vect() const {
|
||||
assert( _base >= VectorS && _base <= VectorY, "Not a Vector" );
|
||||
return (TypeVect*)this;
|
||||
}
|
||||
|
||||
inline const TypeVect *Type::isa_vect() const {
|
||||
return (_base >= VectorS && _base <= VectorY) ? (TypeVect*)this : NULL;
|
||||
}
|
||||
|
||||
inline const TypePtr *Type::is_ptr() const {
|
||||
// AnyPtr is the first Ptr and KlassPtr the last, with no non-ptrs between.
|
||||
assert(_base >= AnyPtr && _base <= KlassPtr, "Not a pointer");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2007, 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
|
||||
@ -28,147 +28,16 @@
|
||||
|
||||
//------------------------------VectorNode--------------------------------------
|
||||
|
||||
// Return vector type for an element type and vector length.
|
||||
const Type* VectorNode::vect_type(BasicType elt_bt, uint len) {
|
||||
assert(len <= VectorNode::max_vlen(elt_bt), "len in range");
|
||||
switch(elt_bt) {
|
||||
case T_BOOLEAN:
|
||||
case T_BYTE:
|
||||
switch(len) {
|
||||
case 2: return TypeInt::CHAR;
|
||||
case 4: return TypeInt::INT;
|
||||
case 8: return TypeLong::LONG;
|
||||
}
|
||||
break;
|
||||
case T_CHAR:
|
||||
case T_SHORT:
|
||||
switch(len) {
|
||||
case 2: return TypeInt::INT;
|
||||
case 4: return TypeLong::LONG;
|
||||
}
|
||||
break;
|
||||
case T_INT:
|
||||
switch(len) {
|
||||
case 2: return TypeLong::LONG;
|
||||
}
|
||||
break;
|
||||
case T_LONG:
|
||||
break;
|
||||
case T_FLOAT:
|
||||
switch(len) {
|
||||
case 2: return Type::DOUBLE;
|
||||
}
|
||||
break;
|
||||
case T_DOUBLE:
|
||||
break;
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Scalar promotion
|
||||
VectorNode* VectorNode::scalar2vector(Compile* C, Node* s, uint vlen, const Type* opd_t) {
|
||||
BasicType bt = opd_t->array_element_basic_type();
|
||||
assert(vlen <= VectorNode::max_vlen(bt), "vlen in range");
|
||||
switch (bt) {
|
||||
case T_BOOLEAN:
|
||||
case T_BYTE:
|
||||
if (vlen == 16) return new (C, 2) Replicate16BNode(s);
|
||||
if (vlen == 8) return new (C, 2) Replicate8BNode(s);
|
||||
if (vlen == 4) return new (C, 2) Replicate4BNode(s);
|
||||
break;
|
||||
case T_CHAR:
|
||||
if (vlen == 8) return new (C, 2) Replicate8CNode(s);
|
||||
if (vlen == 4) return new (C, 2) Replicate4CNode(s);
|
||||
if (vlen == 2) return new (C, 2) Replicate2CNode(s);
|
||||
break;
|
||||
case T_SHORT:
|
||||
if (vlen == 8) return new (C, 2) Replicate8SNode(s);
|
||||
if (vlen == 4) return new (C, 2) Replicate4SNode(s);
|
||||
if (vlen == 2) return new (C, 2) Replicate2SNode(s);
|
||||
break;
|
||||
case T_INT:
|
||||
if (vlen == 4) return new (C, 2) Replicate4INode(s);
|
||||
if (vlen == 2) return new (C, 2) Replicate2INode(s);
|
||||
break;
|
||||
case T_LONG:
|
||||
if (vlen == 2) return new (C, 2) Replicate2LNode(s);
|
||||
break;
|
||||
case T_FLOAT:
|
||||
if (vlen == 4) return new (C, 2) Replicate4FNode(s);
|
||||
if (vlen == 2) return new (C, 2) Replicate2FNode(s);
|
||||
break;
|
||||
case T_DOUBLE:
|
||||
if (vlen == 2) return new (C, 2) Replicate2DNode(s);
|
||||
break;
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return initial Pack node. Additional operands added with add_opd() calls.
|
||||
PackNode* PackNode::make(Compile* C, Node* s, const Type* opd_t) {
|
||||
BasicType bt = opd_t->array_element_basic_type();
|
||||
switch (bt) {
|
||||
case T_BOOLEAN:
|
||||
case T_BYTE:
|
||||
return new (C, 2) PackBNode(s);
|
||||
case T_CHAR:
|
||||
return new (C, 2) PackCNode(s);
|
||||
case T_SHORT:
|
||||
return new (C, 2) PackSNode(s);
|
||||
case T_INT:
|
||||
return new (C, 2) PackINode(s);
|
||||
case T_LONG:
|
||||
return new (C, 2) PackLNode(s);
|
||||
case T_FLOAT:
|
||||
return new (C, 2) PackFNode(s);
|
||||
case T_DOUBLE:
|
||||
return new (C, 2) PackDNode(s);
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create a binary tree form for Packs. [lo, hi) (half-open) range
|
||||
Node* PackNode::binaryTreePack(Compile* C, int lo, int hi) {
|
||||
int ct = hi - lo;
|
||||
assert(is_power_of_2(ct), "power of 2");
|
||||
int mid = lo + ct/2;
|
||||
Node* n1 = ct == 2 ? in(lo) : binaryTreePack(C, lo, mid);
|
||||
Node* n2 = ct == 2 ? in(lo+1) : binaryTreePack(C, mid, hi );
|
||||
int rslt_bsize = ct * type2aelembytes(elt_basic_type());
|
||||
if (bottom_type()->is_floatingpoint()) {
|
||||
switch (rslt_bsize) {
|
||||
case 8: return new (C, 3) PackFNode(n1, n2);
|
||||
case 16: return new (C, 3) PackDNode(n1, n2);
|
||||
}
|
||||
} else {
|
||||
assert(bottom_type()->isa_int() || bottom_type()->isa_long(), "int or long");
|
||||
switch (rslt_bsize) {
|
||||
case 2: return new (C, 3) Pack2x1BNode(n1, n2);
|
||||
case 4: return new (C, 3) Pack2x2BNode(n1, n2);
|
||||
case 8: return new (C, 3) PackINode(n1, n2);
|
||||
case 16: return new (C, 3) PackLNode(n1, n2);
|
||||
}
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return the vector operator for the specified scalar operation
|
||||
// and vector length. One use is to check if the code generator
|
||||
// and vector length. Also used to check if the code generator
|
||||
// supports the vector operation.
|
||||
int VectorNode::opcode(int sopc, uint vlen, const Type* opd_t) {
|
||||
BasicType bt = opd_t->array_element_basic_type();
|
||||
if (!(is_power_of_2(vlen) && vlen <= max_vlen(bt)))
|
||||
return 0; // unimplemented
|
||||
int VectorNode::opcode(int sopc, uint vlen, BasicType bt) {
|
||||
switch (sopc) {
|
||||
case Op_AddI:
|
||||
switch (bt) {
|
||||
case T_BOOLEAN:
|
||||
case T_BYTE: return Op_AddVB;
|
||||
case T_CHAR: return Op_AddVC;
|
||||
case T_CHAR:
|
||||
case T_SHORT: return Op_AddVS;
|
||||
case T_INT: return Op_AddVI;
|
||||
}
|
||||
@ -186,7 +55,7 @@ int VectorNode::opcode(int sopc, uint vlen, const Type* opd_t) {
|
||||
switch (bt) {
|
||||
case T_BOOLEAN:
|
||||
case T_BYTE: return Op_SubVB;
|
||||
case T_CHAR: return Op_SubVC;
|
||||
case T_CHAR:
|
||||
case T_SHORT: return Op_SubVS;
|
||||
case T_INT: return Op_SubVI;
|
||||
}
|
||||
@ -216,18 +85,18 @@ int VectorNode::opcode(int sopc, uint vlen, const Type* opd_t) {
|
||||
switch (bt) {
|
||||
case T_BOOLEAN:
|
||||
case T_BYTE: return Op_LShiftVB;
|
||||
case T_CHAR: return Op_LShiftVC;
|
||||
case T_CHAR:
|
||||
case T_SHORT: return Op_LShiftVS;
|
||||
case T_INT: return Op_LShiftVI;
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
case Op_URShiftI:
|
||||
case Op_RShiftI:
|
||||
switch (bt) {
|
||||
case T_BOOLEAN:
|
||||
case T_BYTE: return Op_URShiftVB;
|
||||
case T_CHAR: return Op_URShiftVC;
|
||||
case T_SHORT: return Op_URShiftVS;
|
||||
case T_INT: return Op_URShiftVI;
|
||||
case T_BYTE: return Op_RShiftVB;
|
||||
case T_CHAR:
|
||||
case T_SHORT: return Op_RShiftVS;
|
||||
case T_INT: return Op_RShiftVI;
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
case Op_AndI:
|
||||
@ -241,13 +110,14 @@ int VectorNode::opcode(int sopc, uint vlen, const Type* opd_t) {
|
||||
return Op_XorV;
|
||||
|
||||
case Op_LoadB:
|
||||
case Op_LoadUB:
|
||||
case Op_LoadUS:
|
||||
case Op_LoadS:
|
||||
case Op_LoadI:
|
||||
case Op_LoadL:
|
||||
case Op_LoadF:
|
||||
case Op_LoadD:
|
||||
return VectorLoadNode::opcode(sopc, vlen);
|
||||
return Op_LoadVector;
|
||||
|
||||
case Op_StoreB:
|
||||
case Op_StoreC:
|
||||
@ -255,211 +125,170 @@ int VectorNode::opcode(int sopc, uint vlen, const Type* opd_t) {
|
||||
case Op_StoreL:
|
||||
case Op_StoreF:
|
||||
case Op_StoreD:
|
||||
return VectorStoreNode::opcode(sopc, vlen);
|
||||
return Op_StoreVector;
|
||||
}
|
||||
return 0; // Unimplemented
|
||||
}
|
||||
|
||||
// Helper for above.
|
||||
int VectorLoadNode::opcode(int sopc, uint vlen) {
|
||||
switch (sopc) {
|
||||
case Op_LoadB:
|
||||
switch (vlen) {
|
||||
case 2: return 0; // Unimplemented
|
||||
case 4: return Op_Load4B;
|
||||
case 8: return Op_Load8B;
|
||||
case 16: return Op_Load16B;
|
||||
}
|
||||
break;
|
||||
case Op_LoadUS:
|
||||
switch (vlen) {
|
||||
case 2: return Op_Load2C;
|
||||
case 4: return Op_Load4C;
|
||||
case 8: return Op_Load8C;
|
||||
}
|
||||
break;
|
||||
case Op_LoadS:
|
||||
switch (vlen) {
|
||||
case 2: return Op_Load2S;
|
||||
case 4: return Op_Load4S;
|
||||
case 8: return Op_Load8S;
|
||||
}
|
||||
break;
|
||||
case Op_LoadI:
|
||||
switch (vlen) {
|
||||
case 2: return Op_Load2I;
|
||||
case 4: return Op_Load4I;
|
||||
}
|
||||
break;
|
||||
case Op_LoadL:
|
||||
if (vlen == 2) return Op_Load2L;
|
||||
break;
|
||||
case Op_LoadF:
|
||||
switch (vlen) {
|
||||
case 2: return Op_Load2F;
|
||||
case 4: return Op_Load4F;
|
||||
}
|
||||
break;
|
||||
case Op_LoadD:
|
||||
if (vlen == 2) return Op_Load2D;
|
||||
break;
|
||||
bool VectorNode::implemented(int opc, uint vlen, BasicType bt) {
|
||||
if (is_java_primitive(bt) &&
|
||||
(vlen > 1) && is_power_of_2(vlen) &&
|
||||
Matcher::vector_size_supported(bt, vlen)) {
|
||||
int vopc = VectorNode::opcode(opc, vlen, bt);
|
||||
return vopc > 0 && Matcher::has_match_rule(vopc);
|
||||
}
|
||||
return 0; // Unimplemented
|
||||
}
|
||||
|
||||
// Helper for above
|
||||
int VectorStoreNode::opcode(int sopc, uint vlen) {
|
||||
switch (sopc) {
|
||||
case Op_StoreB:
|
||||
switch (vlen) {
|
||||
case 2: return 0; // Unimplemented
|
||||
case 4: return Op_Store4B;
|
||||
case 8: return Op_Store8B;
|
||||
case 16: return Op_Store16B;
|
||||
}
|
||||
break;
|
||||
case Op_StoreC:
|
||||
switch (vlen) {
|
||||
case 2: return Op_Store2C;
|
||||
case 4: return Op_Store4C;
|
||||
case 8: return Op_Store8C;
|
||||
}
|
||||
break;
|
||||
case Op_StoreI:
|
||||
switch (vlen) {
|
||||
case 2: return Op_Store2I;
|
||||
case 4: return Op_Store4I;
|
||||
}
|
||||
break;
|
||||
case Op_StoreL:
|
||||
if (vlen == 2) return Op_Store2L;
|
||||
break;
|
||||
case Op_StoreF:
|
||||
switch (vlen) {
|
||||
case 2: return Op_Store2F;
|
||||
case 4: return Op_Store4F;
|
||||
}
|
||||
break;
|
||||
case Op_StoreD:
|
||||
if (vlen == 2) return Op_Store2D;
|
||||
break;
|
||||
}
|
||||
return 0; // Unimplemented
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return the vector version of a scalar operation node.
|
||||
VectorNode* VectorNode::make(Compile* C, int sopc, Node* n1, Node* n2, uint vlen, const Type* opd_t) {
|
||||
int vopc = opcode(sopc, vlen, opd_t);
|
||||
VectorNode* VectorNode::make(Compile* C, int opc, Node* n1, Node* n2, uint vlen, BasicType bt) {
|
||||
const TypeVect* vt = TypeVect::make(bt, vlen);
|
||||
int vopc = VectorNode::opcode(opc, vlen, bt);
|
||||
|
||||
switch (vopc) {
|
||||
case Op_AddVB: return new (C, 3) AddVBNode(n1, n2, vlen);
|
||||
case Op_AddVC: return new (C, 3) AddVCNode(n1, n2, vlen);
|
||||
case Op_AddVS: return new (C, 3) AddVSNode(n1, n2, vlen);
|
||||
case Op_AddVI: return new (C, 3) AddVINode(n1, n2, vlen);
|
||||
case Op_AddVL: return new (C, 3) AddVLNode(n1, n2, vlen);
|
||||
case Op_AddVF: return new (C, 3) AddVFNode(n1, n2, vlen);
|
||||
case Op_AddVD: return new (C, 3) AddVDNode(n1, n2, vlen);
|
||||
case Op_AddVB: return new (C, 3) AddVBNode(n1, n2, vt);
|
||||
case Op_AddVS: return new (C, 3) AddVSNode(n1, n2, vt);
|
||||
case Op_AddVI: return new (C, 3) AddVINode(n1, n2, vt);
|
||||
case Op_AddVL: return new (C, 3) AddVLNode(n1, n2, vt);
|
||||
case Op_AddVF: return new (C, 3) AddVFNode(n1, n2, vt);
|
||||
case Op_AddVD: return new (C, 3) AddVDNode(n1, n2, vt);
|
||||
|
||||
case Op_SubVB: return new (C, 3) SubVBNode(n1, n2, vlen);
|
||||
case Op_SubVC: return new (C, 3) SubVCNode(n1, n2, vlen);
|
||||
case Op_SubVS: return new (C, 3) SubVSNode(n1, n2, vlen);
|
||||
case Op_SubVI: return new (C, 3) SubVINode(n1, n2, vlen);
|
||||
case Op_SubVL: return new (C, 3) SubVLNode(n1, n2, vlen);
|
||||
case Op_SubVF: return new (C, 3) SubVFNode(n1, n2, vlen);
|
||||
case Op_SubVD: return new (C, 3) SubVDNode(n1, n2, vlen);
|
||||
case Op_SubVB: return new (C, 3) SubVBNode(n1, n2, vt);
|
||||
case Op_SubVS: return new (C, 3) SubVSNode(n1, n2, vt);
|
||||
case Op_SubVI: return new (C, 3) SubVINode(n1, n2, vt);
|
||||
case Op_SubVL: return new (C, 3) SubVLNode(n1, n2, vt);
|
||||
case Op_SubVF: return new (C, 3) SubVFNode(n1, n2, vt);
|
||||
case Op_SubVD: return new (C, 3) SubVDNode(n1, n2, vt);
|
||||
|
||||
case Op_MulVF: return new (C, 3) MulVFNode(n1, n2, vlen);
|
||||
case Op_MulVD: return new (C, 3) MulVDNode(n1, n2, vlen);
|
||||
case Op_MulVF: return new (C, 3) MulVFNode(n1, n2, vt);
|
||||
case Op_MulVD: return new (C, 3) MulVDNode(n1, n2, vt);
|
||||
|
||||
case Op_DivVF: return new (C, 3) DivVFNode(n1, n2, vlen);
|
||||
case Op_DivVD: return new (C, 3) DivVDNode(n1, n2, vlen);
|
||||
case Op_DivVF: return new (C, 3) DivVFNode(n1, n2, vt);
|
||||
case Op_DivVD: return new (C, 3) DivVDNode(n1, n2, vt);
|
||||
|
||||
case Op_LShiftVB: return new (C, 3) LShiftVBNode(n1, n2, vlen);
|
||||
case Op_LShiftVC: return new (C, 3) LShiftVCNode(n1, n2, vlen);
|
||||
case Op_LShiftVS: return new (C, 3) LShiftVSNode(n1, n2, vlen);
|
||||
case Op_LShiftVI: return new (C, 3) LShiftVINode(n1, n2, vlen);
|
||||
case Op_LShiftVB: return new (C, 3) LShiftVBNode(n1, n2, vt);
|
||||
case Op_LShiftVS: return new (C, 3) LShiftVSNode(n1, n2, vt);
|
||||
case Op_LShiftVI: return new (C, 3) LShiftVINode(n1, n2, vt);
|
||||
|
||||
case Op_URShiftVB: return new (C, 3) URShiftVBNode(n1, n2, vlen);
|
||||
case Op_URShiftVC: return new (C, 3) URShiftVCNode(n1, n2, vlen);
|
||||
case Op_URShiftVS: return new (C, 3) URShiftVSNode(n1, n2, vlen);
|
||||
case Op_URShiftVI: return new (C, 3) URShiftVINode(n1, n2, vlen);
|
||||
case Op_RShiftVB: return new (C, 3) RShiftVBNode(n1, n2, vt);
|
||||
case Op_RShiftVS: return new (C, 3) RShiftVSNode(n1, n2, vt);
|
||||
case Op_RShiftVI: return new (C, 3) RShiftVINode(n1, n2, vt);
|
||||
|
||||
case Op_AndV: return new (C, 3) AndVNode(n1, n2, vlen, opd_t->array_element_basic_type());
|
||||
case Op_OrV: return new (C, 3) OrVNode (n1, n2, vlen, opd_t->array_element_basic_type());
|
||||
case Op_XorV: return new (C, 3) XorVNode(n1, n2, vlen, opd_t->array_element_basic_type());
|
||||
case Op_AndV: return new (C, 3) AndVNode(n1, n2, vt);
|
||||
case Op_OrV: return new (C, 3) OrVNode (n1, n2, vt);
|
||||
case Op_XorV: return new (C, 3) XorVNode(n1, n2, vt);
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
||||
// Scalar promotion
|
||||
VectorNode* VectorNode::scalar2vector(Compile* C, Node* s, uint vlen, const Type* opd_t) {
|
||||
BasicType bt = opd_t->array_element_basic_type();
|
||||
const TypeVect* vt = opd_t->singleton() ? TypeVect::make(opd_t, vlen)
|
||||
: TypeVect::make(bt, vlen);
|
||||
switch (bt) {
|
||||
case T_BOOLEAN:
|
||||
case T_BYTE:
|
||||
return new (C, 2) ReplicateBNode(s, vt);
|
||||
case T_CHAR:
|
||||
case T_SHORT:
|
||||
return new (C, 2) ReplicateSNode(s, vt);
|
||||
case T_INT:
|
||||
return new (C, 2) ReplicateINode(s, vt);
|
||||
case T_LONG:
|
||||
return new (C, 2) ReplicateLNode(s, vt);
|
||||
case T_FLOAT:
|
||||
return new (C, 2) ReplicateFNode(s, vt);
|
||||
case T_DOUBLE:
|
||||
return new (C, 2) ReplicateDNode(s, vt);
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return initial Pack node. Additional operands added with add_opd() calls.
|
||||
PackNode* PackNode::make(Compile* C, Node* s, uint vlen, BasicType bt) {
|
||||
const TypeVect* vt = TypeVect::make(bt, vlen);
|
||||
switch (bt) {
|
||||
case T_BOOLEAN:
|
||||
case T_BYTE:
|
||||
return new (C, vlen+1) PackBNode(s, vt);
|
||||
case T_CHAR:
|
||||
case T_SHORT:
|
||||
return new (C, vlen+1) PackSNode(s, vt);
|
||||
case T_INT:
|
||||
return new (C, vlen+1) PackINode(s, vt);
|
||||
case T_LONG:
|
||||
return new (C, vlen+1) PackLNode(s, vt);
|
||||
case T_FLOAT:
|
||||
return new (C, vlen+1) PackFNode(s, vt);
|
||||
case T_DOUBLE:
|
||||
return new (C, vlen+1) PackDNode(s, vt);
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create a binary tree form for Packs. [lo, hi) (half-open) range
|
||||
Node* PackNode::binaryTreePack(Compile* C, int lo, int hi) {
|
||||
int ct = hi - lo;
|
||||
assert(is_power_of_2(ct), "power of 2");
|
||||
if (ct == 2) {
|
||||
PackNode* pk = PackNode::make(C, in(lo), 2, vect_type()->element_basic_type());
|
||||
pk->add_opd(1, in(lo+1));
|
||||
return pk;
|
||||
|
||||
} else {
|
||||
int mid = lo + ct/2;
|
||||
Node* n1 = binaryTreePack(C, lo, mid);
|
||||
Node* n2 = binaryTreePack(C, mid, hi );
|
||||
|
||||
BasicType bt = vect_type()->element_basic_type();
|
||||
switch (bt) {
|
||||
case T_BOOLEAN:
|
||||
case T_BYTE:
|
||||
return new (C, 3) PackSNode(n1, n2, TypeVect::make(T_SHORT, 2));
|
||||
case T_CHAR:
|
||||
case T_SHORT:
|
||||
return new (C, 3) PackINode(n1, n2, TypeVect::make(T_INT, 2));
|
||||
case T_INT:
|
||||
return new (C, 3) PackLNode(n1, n2, TypeVect::make(T_LONG, 2));
|
||||
case T_LONG:
|
||||
return new (C, 3) Pack2LNode(n1, n2, TypeVect::make(T_LONG, 2));
|
||||
case T_FLOAT:
|
||||
return new (C, 3) PackDNode(n1, n2, TypeVect::make(T_DOUBLE, 2));
|
||||
case T_DOUBLE:
|
||||
return new (C, 3) Pack2DNode(n1, n2, TypeVect::make(T_DOUBLE, 2));
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return the vector version of a scalar load node.
|
||||
VectorLoadNode* VectorLoadNode::make(Compile* C, int opc, Node* ctl, Node* mem,
|
||||
Node* adr, const TypePtr* atyp, uint vlen) {
|
||||
int vopc = opcode(opc, vlen);
|
||||
|
||||
switch(vopc) {
|
||||
case Op_Load16B: return new (C, 3) Load16BNode(ctl, mem, adr, atyp);
|
||||
case Op_Load8B: return new (C, 3) Load8BNode(ctl, mem, adr, atyp);
|
||||
case Op_Load4B: return new (C, 3) Load4BNode(ctl, mem, adr, atyp);
|
||||
|
||||
case Op_Load8C: return new (C, 3) Load8CNode(ctl, mem, adr, atyp);
|
||||
case Op_Load4C: return new (C, 3) Load4CNode(ctl, mem, adr, atyp);
|
||||
case Op_Load2C: return new (C, 3) Load2CNode(ctl, mem, adr, atyp);
|
||||
|
||||
case Op_Load8S: return new (C, 3) Load8SNode(ctl, mem, adr, atyp);
|
||||
case Op_Load4S: return new (C, 3) Load4SNode(ctl, mem, adr, atyp);
|
||||
case Op_Load2S: return new (C, 3) Load2SNode(ctl, mem, adr, atyp);
|
||||
|
||||
case Op_Load4I: return new (C, 3) Load4INode(ctl, mem, adr, atyp);
|
||||
case Op_Load2I: return new (C, 3) Load2INode(ctl, mem, adr, atyp);
|
||||
|
||||
case Op_Load2L: return new (C, 3) Load2LNode(ctl, mem, adr, atyp);
|
||||
|
||||
case Op_Load4F: return new (C, 3) Load4FNode(ctl, mem, adr, atyp);
|
||||
case Op_Load2F: return new (C, 3) Load2FNode(ctl, mem, adr, atyp);
|
||||
|
||||
case Op_Load2D: return new (C, 3) Load2DNode(ctl, mem, adr, atyp);
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
LoadVectorNode* LoadVectorNode::make(Compile* C, int opc, Node* ctl, Node* mem,
|
||||
Node* adr, const TypePtr* atyp, uint vlen, BasicType bt) {
|
||||
const TypeVect* vt = TypeVect::make(bt, vlen);
|
||||
return new (C, 3) LoadVectorNode(ctl, mem, adr, atyp, vt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Return the vector version of a scalar store node.
|
||||
VectorStoreNode* VectorStoreNode::make(Compile* C, int opc, Node* ctl, Node* mem,
|
||||
StoreVectorNode* StoreVectorNode::make(Compile* C, int opc, Node* ctl, Node* mem,
|
||||
Node* adr, const TypePtr* atyp, Node* val,
|
||||
uint vlen) {
|
||||
int vopc = opcode(opc, vlen);
|
||||
|
||||
switch(vopc) {
|
||||
case Op_Store16B: return new (C, 4) Store16BNode(ctl, mem, adr, atyp, val);
|
||||
case Op_Store8B: return new (C, 4) Store8BNode(ctl, mem, adr, atyp, val);
|
||||
case Op_Store4B: return new (C, 4) Store4BNode(ctl, mem, adr, atyp, val);
|
||||
|
||||
case Op_Store8C: return new (C, 4) Store8CNode(ctl, mem, adr, atyp, val);
|
||||
case Op_Store4C: return new (C, 4) Store4CNode(ctl, mem, adr, atyp, val);
|
||||
case Op_Store2C: return new (C, 4) Store2CNode(ctl, mem, adr, atyp, val);
|
||||
|
||||
case Op_Store4I: return new (C, 4) Store4INode(ctl, mem, adr, atyp, val);
|
||||
case Op_Store2I: return new (C, 4) Store2INode(ctl, mem, adr, atyp, val);
|
||||
|
||||
case Op_Store2L: return new (C, 4) Store2LNode(ctl, mem, adr, atyp, val);
|
||||
|
||||
case Op_Store4F: return new (C, 4) Store4FNode(ctl, mem, adr, atyp, val);
|
||||
case Op_Store2F: return new (C, 4) Store2FNode(ctl, mem, adr, atyp, val);
|
||||
|
||||
case Op_Store2D: return new (C, 4) Store2DNode(ctl, mem, adr, atyp, val);
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
return new (C, 4) StoreVectorNode(ctl, mem, adr, atyp, val);
|
||||
}
|
||||
|
||||
// Extract a scalar element of vector.
|
||||
Node* ExtractNode::make(Compile* C, Node* v, uint position, const Type* opd_t) {
|
||||
BasicType bt = opd_t->array_element_basic_type();
|
||||
assert(position < VectorNode::max_vlen(bt), "pos in range");
|
||||
Node* ExtractNode::make(Compile* C, Node* v, uint position, BasicType bt) {
|
||||
assert((int)position < Matcher::max_vector_size(bt), "pos in range");
|
||||
ConINode* pos = ConINode::make(C, (int)position);
|
||||
switch (bt) {
|
||||
case T_BOOLEAN:
|
||||
return new (C, 3) ExtractUBNode(v, pos);
|
||||
case T_BYTE:
|
||||
return new (C, 3) ExtractBNode(v, pos);
|
||||
case T_CHAR:
|
||||
@ -478,3 +307,4 @@ Node* ExtractNode::make(Compile* C, Node* v, uint position, const Type* opd_t) {
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/altHashing.hpp"
|
||||
#include "classfile/classLoader.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
@ -5053,6 +5054,7 @@ void execute_internal_vm_tests() {
|
||||
run_unit_test(arrayOopDesc::test_max_array_length());
|
||||
run_unit_test(CollectedHeap::test_is_in());
|
||||
run_unit_test(QuickSort::test_quick_sort());
|
||||
run_unit_test(AltHashing::test_alt_hash());
|
||||
tty->print_cr("All internal VM tests passed");
|
||||
}
|
||||
}
|
||||
|
@ -585,7 +585,7 @@ class CallbackWrapper : public StackObj {
|
||||
_o = klassOop_if_java_lang_Class(o);
|
||||
|
||||
// object size
|
||||
_obj_size = _o->size() * wordSize;
|
||||
_obj_size = (jlong)_o->size() * wordSize;
|
||||
|
||||
// record the context
|
||||
_tag_map = tag_map;
|
||||
|
@ -39,6 +39,10 @@ oop fieldDescriptor::loader() const {
|
||||
}
|
||||
|
||||
Symbol* fieldDescriptor::generic_signature() const {
|
||||
if (!has_generic_signature()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int idx = 0;
|
||||
instanceKlass* ik = instanceKlass::cast(field_holder());
|
||||
for (AllFieldStream fs(ik); !fs.done(); fs.next()) {
|
||||
|
@ -100,6 +100,7 @@ class fieldDescriptor VALUE_OBJ_CLASS_SPEC {
|
||||
bool is_field_access_watched() const { return access_flags().is_field_access_watched(); }
|
||||
bool is_field_modification_watched() const
|
||||
{ return access_flags().is_field_modification_watched(); }
|
||||
bool has_generic_signature() const { return access_flags().field_has_generic_signature(); }
|
||||
|
||||
void set_is_field_access_watched(const bool value) {
|
||||
_access_flags.set_is_field_access_watched(value);
|
||||
|
@ -2659,6 +2659,9 @@ class CommandLineFlags {
|
||||
product(bool, UseHeavyMonitors, false, \
|
||||
"use heavyweight instead of lightweight Java monitors") \
|
||||
\
|
||||
product(bool, PrintStringTableStatistics, false, \
|
||||
"print statistics about the StringTable and SymbolTable") \
|
||||
\
|
||||
notproduct(bool, PrintSymbolTableSizeHistogram, false, \
|
||||
"print histogram of the symbol table") \
|
||||
\
|
||||
|
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "code/icBuffer.hpp"
|
||||
#include "gc_interface/collectedHeap.hpp"
|
||||
#include "interpreter/bytecodes.hpp"
|
||||
@ -157,6 +158,10 @@ void exit_globals() {
|
||||
// Print the collected safepoint statistics.
|
||||
SafepointSynchronize::print_stat_on_exit();
|
||||
}
|
||||
if (PrintStringTableStatistics) {
|
||||
SymbolTable::dump(tty);
|
||||
StringTable::dump(tty);
|
||||
}
|
||||
ostream_exit();
|
||||
}
|
||||
}
|
||||
|
@ -660,6 +660,7 @@ void vm_shutdown_during_initialization(const char* error, const char* message) {
|
||||
}
|
||||
|
||||
JDK_Version JDK_Version::_current;
|
||||
const char* JDK_Version::_runtime_name;
|
||||
|
||||
void JDK_Version::initialize() {
|
||||
jdk_version_info info;
|
||||
|
@ -74,6 +74,7 @@ class JDK_Version VALUE_OBJ_CLASS_SPEC {
|
||||
private:
|
||||
|
||||
static JDK_Version _current;
|
||||
static const char* _runtime_name;
|
||||
|
||||
// In this class, we promote the minor version of release to be the
|
||||
// major version for releases >= 5 in anticipation of the JDK doing the
|
||||
@ -181,6 +182,13 @@ class JDK_Version VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
void to_string(char* buffer, size_t buflen) const;
|
||||
|
||||
static const char* runtime_name() {
|
||||
return _runtime_name;
|
||||
}
|
||||
static void set_runtime_name(const char* name) {
|
||||
_runtime_name = name;
|
||||
}
|
||||
|
||||
// Convenience methods for queries on the current major/minor version
|
||||
static bool is_jdk12x_version() {
|
||||
return current().compare_major(2) == 0;
|
||||
|
@ -829,7 +829,7 @@ oop Reflection::new_field(fieldDescriptor* fd, bool intern_name, TRAPS) {
|
||||
java_lang_reflect_Field::set_modifiers(rh(), fd->access_flags().as_int() & JVM_RECOGNIZED_FIELD_MODIFIERS);
|
||||
java_lang_reflect_Field::set_override(rh(), false);
|
||||
if (java_lang_reflect_Field::has_signature_field() &&
|
||||
fd->generic_signature() != NULL) {
|
||||
fd->has_generic_signature()) {
|
||||
Symbol* gs = fd->generic_signature();
|
||||
Handle sig = java_lang_String::create_from_symbol(gs, CHECK_NULL);
|
||||
java_lang_reflect_Field::set_signature(rh(), sig());
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user