This commit is contained in:
Lana Steuck 2012-07-03 18:24:03 -07:00
commit 4bdc9c4528
142 changed files with 53965 additions and 3987 deletions

View File

@ -166,3 +166,4 @@ c029c972396cea042a0dc67c0f7ccf2fe68007d4 jdk8-b41
5c5a64ec0839df5affe9394b99ff338c363acbca jdk8-b42 5c5a64ec0839df5affe9394b99ff338c363acbca jdk8-b42
69d8a827cdf9236be9694a46d75c710d71dac7d7 jdk8-b43 69d8a827cdf9236be9694a46d75c710d71dac7d7 jdk8-b43
7e981cb0ad6a194f1fa859f9ad47586db461f269 jdk8-b44 7e981cb0ad6a194f1fa859f9ad47586db461f269 jdk8-b44
9b19b2302c28f4da6d4078f66234abecfed5688a jdk8-b45

View File

@ -166,3 +166,4 @@ a2b2d435f1d275fa8010774c653197c64e326d3a jdk8-b40
1ce5dc16416611c58b7480ca67a2eee5153498a6 jdk8-b42 1ce5dc16416611c58b7480ca67a2eee5153498a6 jdk8-b42
661c9aae602bbd9766d12590800c90f1edd1d8dd jdk8-b43 661c9aae602bbd9766d12590800c90f1edd1d8dd jdk8-b43
e4f81a817447c3a4f6868f083c81c2fb1b15d44c jdk8-b44 e4f81a817447c3a4f6868f083c81c2fb1b15d44c jdk8-b44
633f2378c904c92bb922a6e19e9f62fe8eac14af jdk8-b45

View File

@ -166,3 +166,4 @@ b8cbfb31139f820e5e094ba71449e58159fbe22e jdk8-b38
79cc42c9c71bbd6630ede681642e98f5e4a841fa jdk8-b42 79cc42c9c71bbd6630ede681642e98f5e4a841fa jdk8-b42
cd879aff5d3cc1f58829aab3116880aa19525b78 jdk8-b43 cd879aff5d3cc1f58829aab3116880aa19525b78 jdk8-b43
439d9bf8e4ff204cc89c9974c1515a508b2cc6ff jdk8-b44 439d9bf8e4ff204cc89c9974c1515a508b2cc6ff jdk8-b44
747dad9e9d37d244a5c765a1afe9194f7ddae118 jdk8-b45

View File

@ -256,3 +256,5 @@ bd568544be7fcd12a9327e6c448592198d57b043 hs24-b13
e77b8e0ed1f84e3e268239e276c7ab64fa573baa jdk8-b43 e77b8e0ed1f84e3e268239e276c7ab64fa573baa jdk8-b43
5ba29a1db46ecb80a321ca873adb56a3fe6ad320 hs24-b14 5ba29a1db46ecb80a321ca873adb56a3fe6ad320 hs24-b14
831e5c76a20af18f3c08c5a95ed31be0e128a010 jdk8-b44 831e5c76a20af18f3c08c5a95ed31be0e128a010 jdk8-b44
9d5f20961bc5846fa8d098d534effafbbdae0a58 jdk8-b45
40e5a3f2907ed02b335c7caa8ecf068cc801380d hs24-b15

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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) { while (fr != null) {
trace.add(new StackTraceEntry(fr, getCDebugger())); trace.add(new StackTraceEntry(fr, getCDebugger()));
try { try {
fr = fr.sender(); fr = fr.sender(t);
} catch (AddressException e) { } catch (AddressException e) {
e.printStackTrace(); e.printStackTrace();
showMessageDialog("Error while walking stack; stack trace will be truncated\n(see console for details)", showMessageDialog("Error while walking stack; stack trace will be truncated\n(see console for details)",

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,7 @@
package sun.jvm.hotspot.debugger.bsd.amd64; package sun.jvm.hotspot.debugger.bsd.amd64;
import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.amd64.*;
import sun.jvm.hotspot.debugger.bsd.*; import sun.jvm.hotspot.debugger.bsd.*;
import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.cdbg.basic.*; import sun.jvm.hotspot.debugger.cdbg.basic.*;
@ -51,8 +52,11 @@ final public class BsdAMD64CFrame extends BasicCFrame {
return rbp; return rbp;
} }
public CFrame sender() { public CFrame sender(ThreadProxy thread) {
if (rbp == null) { AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext();
Address rsp = context.getRegisterAsAddress(AMD64ThreadContext.RSP);
if ( (rbp == null) || rbp.lessThan(rsp) ) {
return null; return null;
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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.bsd.*;
import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.cdbg.basic.*; import sun.jvm.hotspot.debugger.cdbg.basic.*;
import sun.jvm.hotspot.debugger.x86.*;
final public class BsdX86CFrame extends BasicCFrame { final public class BsdX86CFrame extends BasicCFrame {
// package/class internals only // package/class internals only
@ -52,8 +53,11 @@ final public class BsdX86CFrame extends BasicCFrame {
return ebp; return ebp;
} }
public CFrame sender() { public CFrame sender(ThreadProxy thread) {
if (ebp == null) { X86ThreadContext context = (X86ThreadContext) thread.getContext();
Address esp = context.getRegisterAsAddress(X86ThreadContext.ESP);
if ( (ebp == null) || ebp.lessThan(esp) ) {
return null; return null;
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 { public interface CFrame {
/** Returns null when no more frames on stack */ /** Returns null when no more frames on stack */
public CFrame sender(); public CFrame sender(ThreadProxy th);
/** Get the program counter of this frame */ /** Get the program counter of this frame */
public Address pc(); public Address pc();

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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; package sun.jvm.hotspot.debugger.cdbg.basic.amd64;
import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.amd64.*;
import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.cdbg.basic.*; import sun.jvm.hotspot.debugger.cdbg.basic.*;
@ -43,8 +44,11 @@ public class AMD64CFrame extends BasicCFrame {
this.pc = pc; this.pc = pc;
} }
public CFrame sender() { public CFrame sender(ThreadProxy thread) {
if (rbp == null) { AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext();
Address rsp = context.getRegisterAsAddress(AMD64ThreadContext.RSP);
if ( (rbp == null) || rbp.lessThan(rsp) ) {
return null; return null;
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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; package sun.jvm.hotspot.debugger.cdbg.basic.x86;
import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.x86.*;
import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.cdbg.basic.*; import sun.jvm.hotspot.debugger.cdbg.basic.*;
@ -43,8 +44,11 @@ public class X86CFrame extends BasicCFrame {
this.pc = pc; this.pc = pc;
} }
public CFrame sender() { public CFrame sender(ThreadProxy thread) {
if (ebp == null) { X86ThreadContext context = (X86ThreadContext) thread.getContext();
Address esp = context.getRegisterAsAddress(X86ThreadContext.ESP);
if ( (ebp == null) || ebp.lessThan(esp) ) {
return null; return null;
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,7 @@
package sun.jvm.hotspot.debugger.linux.amd64; package sun.jvm.hotspot.debugger.linux.amd64;
import sun.jvm.hotspot.debugger.*; import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.amd64.*;
import sun.jvm.hotspot.debugger.linux.*; import sun.jvm.hotspot.debugger.linux.*;
import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.cdbg.basic.*; import sun.jvm.hotspot.debugger.cdbg.basic.*;
@ -51,8 +52,11 @@ final public class LinuxAMD64CFrame extends BasicCFrame {
return rbp; return rbp;
} }
public CFrame sender() { public CFrame sender(ThreadProxy thread) {
if (rbp == null) { AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext();
Address rsp = context.getRegisterAsAddress(AMD64ThreadContext.RSP);
if ( (rbp == null) || rbp.lessThan(rsp) ) {
return null; return null;
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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; return sp;
} }
public CFrame sender() { public CFrame sender(ThreadProxy thread) {
if (sp == null) { if (sp == null) {
return null; return null;
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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.linux.*;
import sun.jvm.hotspot.debugger.cdbg.*; import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.cdbg.basic.*; import sun.jvm.hotspot.debugger.cdbg.basic.*;
import sun.jvm.hotspot.debugger.x86.*;
final public class LinuxX86CFrame extends BasicCFrame { final public class LinuxX86CFrame extends BasicCFrame {
// package/class internals only // package/class internals only
@ -52,8 +53,11 @@ final public class LinuxX86CFrame extends BasicCFrame {
return ebp; return ebp;
} }
public CFrame sender() { public CFrame sender(ThreadProxy thread) {
if (ebp == null) { X86ThreadContext context = (X86ThreadContext) thread.getContext();
Address esp = context.getRegisterAsAddress(X86ThreadContext.ESP);
if ( (ebp == null) || ebp.lessThan(esp) ) {
return null; return null;
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -37,7 +37,7 @@ final class ProcCFrame extends BasicCFrame {
return fp; return fp;
} }
public CFrame sender() { public CFrame sender(ThreadProxy t) {
return sender; return sender;
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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) { public static String stringOopToString(Oop stringOop) {
if (offsetField == null) { if (offsetField == null) {
InstanceKlass k = (InstanceKlass) stringOop.getKlass(); InstanceKlass k = (InstanceKlass) stringOop.getKlass();
offsetField = (IntField) k.findField("offset", "I"); offsetField = (IntField) k.findField("offset", "I"); // optional
countField = (IntField) k.findField("count", "I"); countField = (IntField) k.findField("count", "I"); // optional
valueField = (OopField) k.findField("value", "[C"); valueField = (OopField) k.findField("value", "[C");
if (Assert.ASSERTS_ENABLED) { if (Assert.ASSERTS_ENABLED) {
Assert.that(offsetField != null && Assert.that(valueField != null, "Field \'value\' of java.lang.String not found");
countField != null &&
valueField != null, "must find all java.lang.String fields");
} }
} }
return charArrayToString((TypeArray) valueField.getValue(stringOop), if (offsetField != null && countField != null) {
offsetField.getValue(stringOop), return charArrayToString((TypeArray) valueField.getValue(stringOop),
countField.getValue(stringOop)); offsetField.getValue(stringOop),
countField.getValue(stringOop));
}
return charArrayToString((TypeArray) valueField.getValue(stringOop));
} }
public static String stringOopToEscapedString(Oop stringOop) { public static String stringOopToEscapedString(Oop stringOop) {

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -158,7 +158,7 @@ public class PStack extends Tool {
printUnknown(out); printUnknown(out);
} }
} }
f = f.sender(); f = f.sender(th);
} }
} catch (Exception exp) { } catch (Exception exp) {
exp.printStackTrace(); exp.printStackTrace();

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -85,6 +85,21 @@ public class ObjectReader {
this(new ProcImageClassLoader()); 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 { public Object readObject(Oop oop) throws ClassNotFoundException {
if (oop instanceof Instance) { if (oop instanceof Instance) {
return readInstance((Instance) oop); return readInstance((Instance) oop);
@ -120,13 +135,96 @@ public class ObjectReader {
} }
protected Symbol javaLangString; 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() { protected Symbol javaLangString() {
if (javaLangString == null) { if (javaLangString == null) {
javaLangString = VM.getVM().getSymbolTable().probe("java/lang/String"); javaLangString = getVMSymbol("java/lang/String");
} }
return javaLangString; 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 { public Object readInstance(Instance oop) throws ClassNotFoundException {
Object result = getFromObjTable(oop); Object result = getFromObjTable(oop);
if (result == null) { if (result == null) {
@ -134,11 +232,21 @@ public class ObjectReader {
// Handle java.lang.String instances differently. As part of JSR-133, fields of immutable // 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 // 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 // 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())) { if (kls.getName().equals(javaLangString())) {
return OopUtilities.stringOopToString(oop); 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); Class clz = readClass(kls);
try { try {
result = clz.newInstance(); result = clz.newInstance();
@ -164,8 +272,8 @@ public class ObjectReader {
break; break;
} catch (Exception exp) { } catch (Exception exp) {
if (DEBUG) { if (DEBUG) {
System.err.println("Can't create object using " + c); debugPrintln("Can't create object using " + c);
exp.printStackTrace(); debugPrintStackTrace(exp);
} }
} }
} }
@ -329,8 +437,8 @@ public class ObjectReader {
arrayObj[ifd.getIndex()] = readObject(field.getValue(getObj())); arrayObj[ifd.getIndex()] = readObject(field.getValue(getObj()));
} catch (Exception e) { } catch (Exception e) {
if (DEBUG) { if (DEBUG) {
System.err.println("Array element set failed for " + ifd); debugPrintln("Array element set failed for " + ifd);
e.printStackTrace(); debugPrintStackTrace(e);
} }
} }
} }
@ -348,8 +456,8 @@ public class ObjectReader {
private void printFieldSetError(java.lang.reflect.Field f, Exception ex) { private void printFieldSetError(java.lang.reflect.Field f, Exception ex) {
if (DEBUG) { if (DEBUG) {
if (f != null) System.err.println("Field set failed for " + f); if (f != null) debugPrintln("Field set failed for " + f);
ex.printStackTrace(); debugPrintStackTrace(ex);
} }
} }
@ -601,7 +709,7 @@ public class ObjectReader {
return Class.forName(className, true, cl); return Class.forName(className, true, cl);
} catch (Exception e) { } catch (Exception e) {
if (DEBUG) { if (DEBUG) {
System.err.println("Can't load class " + className); debugPrintln("Can't load class " + className);
} }
throw new RuntimeException(e); throw new RuntimeException(e);
} }

View File

@ -110,4 +110,5 @@ copy_debug_jdk::
.PHONY: universal_product universal_fastdebug universal_debug \ .PHONY: universal_product universal_fastdebug universal_debug \
all_product_universal all_fastdebug_universal all_debug_universal \ 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)

View File

@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2012
HS_MAJOR_VER=24 HS_MAJOR_VER=24
HS_MINOR_VER=0 HS_MINOR_VER=0
HS_BUILD_NUMBER=14 HS_BUILD_NUMBER=15
JDK_MAJOR_VER=1 JDK_MAJOR_VER=1
JDK_MINOR_VER=8 JDK_MINOR_VER=8

View File

@ -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.jdk7u6=${jprt.my.linux.armvfp.jdk7}
jprt.my.linux.armvfp=${jprt.my.linux.armvfp.${jprt.tools.default.release}} 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.jdk8=linux_armsflt_2.6
jprt.my.linux.armsflt.jdk7=linux_armsflt_2.6 jprt.my.linux.armsflt.jdk7=linux_armsflt_2.6
jprt.my.linux.armsflt.jdk7u6=${jprt.my.linux.armsflt.jdk7} 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.macosx.x64}-{product|fastdebug|debug}, \
${jprt.my.windows.i586}-{product|fastdebug|debug}, \ ${jprt.my.windows.i586}-{product|fastdebug|debug}, \
${jprt.my.windows.x64}-{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.build.targets.open= \
${jprt.my.solaris.i586}-{productOpen}, \ ${jprt.my.solaris.i586}-{productOpen}, \

View File

@ -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. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
# #
# This code is free software; you can redistribute it and/or modify it # 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) ifneq ($(OSNAME), windows)
ifndef LP64 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 = memory oops gc_implementation gc_interface
NONPIC_DIRS := $(foreach dir,$(NONPIC_DIRS), $(GAMMADIR)/src/share/vm/$(dir)) NONPIC_DIRS := $(foreach dir,$(NONPIC_DIRS), $(GAMMADIR)/src/share/vm/$(dir))
# Look for source files under NONPIC_DIRS # Look for source files under NONPIC_DIRS

View File

@ -24,8 +24,11 @@
# Rules to build add_gnu_debuglink, used by vm.make on Solaris # Rules to build add_gnu_debuglink, used by vm.make on Solaris
GENERATED = ../generated # Allow $(ADD_GNU_DEBUGLINK) to be called from any directory.
ADD_GNU_DEBUGLINK = $(GENERATED)/add_gnu_debuglink # 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_DIR = $(GAMMADIR)/src/os/solaris/add_gnu_debuglink
ADD_GNU_DEBUGLINK_SRC = $(ADD_GNU_DEBUGLINK_DIR)/add_gnu_debuglink.c ADD_GNU_DEBUGLINK_SRC = $(ADD_GNU_DEBUGLINK_DIR)/add_gnu_debuglink.c

View File

@ -203,10 +203,18 @@ ifeq ($(JVM_VARIANT_SERVER),true)
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm.diz EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm.diz
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm_db.diz EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm_db.diz
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm_dtrace.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 else
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm.debuginfo EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm.debuginfo
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm_db.debuginfo EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm_db.debuginfo
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm_dtrace.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 endif
endif endif

View File

@ -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 # Making 64/libjvm_db.so: 64-bit version of libjvm_db.so which handles 32-bit libjvm.so
ifneq ("${ISA}","${BUILDARCH}") ifneq ("${ISA}","${BUILDARCH}")
XLIBJVM_DB = 64/$(LIBJVM_DB) XLIBJVM_DIR = 64
XLIBJVM_DB_G = 64/$(LIBJVM_DB_G) XLIBJVM_DB = $(XLIBJVM_DIR)/$(LIBJVM_DB)
XLIBJVM_DTRACE = 64/$(LIBJVM_DTRACE) XLIBJVM_DB_G = $(XLIBJVM_DIR)/$(LIBJVM_DB_G)
XLIBJVM_DTRACE_G = 64/$(LIBJVM_DTRACE_G) XLIBJVM_DTRACE = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE)
XLIBJVM_DTRACE_G = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_G)
XLIBJVM_DB_DEBUGINFO = 64/$(LIBJVM_DB_DEBUGINFO) XLIBJVM_DB_DEBUGINFO = $(XLIBJVM_DIR)/$(LIBJVM_DB_DEBUGINFO)
XLIBJVM_DB_DIZ = 64/$(LIBJVM_DB_DIZ) XLIBJVM_DB_DIZ = $(XLIBJVM_DIR)/$(LIBJVM_DB_DIZ)
XLIBJVM_DB_G_DEBUGINFO = 64/$(LIBJVM_DB_G_DEBUGINFO) XLIBJVM_DB_G_DEBUGINFO = $(XLIBJVM_DIR)/$(LIBJVM_DB_G_DEBUGINFO)
XLIBJVM_DB_G_DIZ = 64/$(LIBJVM_DB_G_DIZ) XLIBJVM_DB_G_DIZ = $(XLIBJVM_DIR)/$(LIBJVM_DB_G_DIZ)
XLIBJVM_DTRACE_DEBUGINFO = 64/$(LIBJVM_DTRACE_DEBUGINFO) XLIBJVM_DTRACE_DEBUGINFO = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_DEBUGINFO)
XLIBJVM_DTRACE_DIZ = 64/$(LIBJVM_DTRACE_DIZ) XLIBJVM_DTRACE_DIZ = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_DIZ)
XLIBJVM_DTRACE_G_DEBUGINFO = 64/$(LIBJVM_DTRACE_G_DEBUGINFO) XLIBJVM_DTRACE_G_DEBUGINFO = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_G_DEBUGINFO)
XLIBJVM_DTRACE_G_DIZ = 64/$(LIBJVM_DTRACE_G_DIZ) 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) $(XLIBJVM_DB): $(ADD_GNU_DEBUGLINK) $(FIX_EMPTY_SEC_HDR_FLAGS) $(DTRACE_SRCDIR)/$(JVM_DB).c $(JVMOFFS).h $(LIBJVM_DB_MAPFILE)
@echo Making $@ @echo Making $@
$(QUIETLY) mkdir -p 64/ ; \ $(QUIETLY) mkdir -p $(XLIBJVM_DIR) ; \
$(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. -I$(GENERATED) \ $(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. -I$(GENERATED) \
$(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c -lc $(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c -lc
[ -f $(XLIBJVM_DB_G) ] || { ln -s $(LIBJVM_DB) $(XLIBJVM_DB_G); } [ -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) $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(XLIBJVM_DB_DEBUGINFO)
# $(OBJCOPY) --add-gnu-debuglink=... corrupts SUNW_* sections. # $(OBJCOPY) --add-gnu-debuglink=... corrupts SUNW_* sections.
# Use $(ADD_GNU_DEBUGLINK) until a fixed $(OBJCOPY) is available. # Use $(ADD_GNU_DEBUGLINK) until a fixed $(OBJCOPY) is available.
# $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(XLIBJVM_DB_DEBUGINFO) $@ # $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB) ;
$(QUIETLY) $(ADD_GNU_DEBUGLINK) $(XLIBJVM_DB_DEBUGINFO) $@ # 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) ifeq ($(STRIP_POLICY),all_strip)
$(QUIETLY) $(STRIP) $@ $(QUIETLY) $(STRIP) $@
else else
@ -134,17 +137,19 @@ ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
# implied else here is no stripping at all # implied else here is no stripping at all
endif endif
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) 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) $(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
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) $(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 $@ @echo Making $@
$(QUIETLY) mkdir -p 64/ ; \ $(QUIETLY) mkdir -p $(XLIBJVM_DIR) ; \
$(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. \ $(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. \
$(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c -lc -lthread -ldoor $(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); } [ -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) $(FIX_EMPTY_SEC_HDR_FLAGS) $@
$(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(XLIBJVM_DTRACE_DEBUGINFO) $(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(XLIBJVM_DTRACE_DEBUGINFO)
# $(OBJCOPY) --add-gnu-debuglink=... corrupts SUNW_* sections. # $(OBJCOPY) --add-gnu-debuglink=... corrupts SUNW_* sections.
# $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(XLIBJVM_DTRACE_DEBUGINFO) $@ # $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE) ;
$(QUIETLY) $(ADD_GNU_DEBUGLINK) $(XLIBJVM_DTRACE_DEBUGINFO) $@ # 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) ifeq ($(STRIP_POLICY),all_strip)
$(QUIETLY) $(STRIP) $@ $(QUIETLY) $(STRIP) $@
else else
@ -163,11 +170,13 @@ ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
# implied else here is no stripping at all # implied else here is no stripping at all
endif endif
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) 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) $(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
endif endif

View File

@ -24,8 +24,11 @@
# Rules to build fix_empty_sec_hdr_flags, used by vm.make on Solaris # Rules to build fix_empty_sec_hdr_flags, used by vm.make on Solaris
GENERATED = ../generated # Allow $(FIX_EMPTY_SEC_HDR_FLAGS) to be called from any directory.
FIX_EMPTY_SEC_HDR_FLAGS = $(GENERATED)/fix_empty_sec_hdr_flags # 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_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 FIX_EMPTY_SEC_HDR_FLAGS_SRC = $(FIX_EMPTY_SEC_HDR_FLAGS_DIR)/fix_empty_sec_hdr_flags.c

View File

@ -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. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
// //
// This code is free software; you can redistribute it and/or modify it // 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) { static inline jdouble replicate_immI(int con, int count, int width) {
// Load a constant replicated "count" times with width "width" // Load a constant replicated "count" times with width "width"
assert(count*width == 8 && width <= 4, "sanity");
int bit_width = width * 8; int bit_width = width * 8;
jlong elt_val = con; jlong val = con;
elt_val &= (((jlong) 1) << bit_width) - 1; // mask off sign bits val &= (((jlong) 1) << bit_width) - 1; // mask off sign bits
jlong val = elt_val;
for (int i = 0; i < count - 1; i++) { for (int i = 0; i < count - 1; i++) {
val <<= bit_width; val |= (val << bit_width);
val |= elt_val;
} }
jdouble dval = *((jdouble*) &val); // coerce to double type jdouble dval = *((jdouble*) &val); // coerce to double type
return dval; 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 // 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 ) { 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 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::stdf_op3: st_op = Op_StoreD; break;
case Assembler::ldsb_op3: ld_op = Op_LoadB; 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::lduh_op3: ld_op = Op_LoadUS; break;
case Assembler::ldsh_op3: ld_op = Op_LoadS; break; case Assembler::ldsh_op3: ld_op = Op_LoadS; break;
case Assembler::ldx_op3: // may become LoadP or stay LoadI 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::ldd_op3: ld_op = Op_LoadL; break;
case Assembler::ldf_op3: ld_op = Op_LoadF; break; case Assembler::ldf_op3: ld_op = Op_LoadF; break;
case Assembler::lddf_op3: ld_op = Op_LoadD; 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; case Assembler::prefetch_op3: ld_op = Op_LoadI; break;
default: ShouldNotReachHere(); 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_PrefetchRead && ld_op==Op_LoadI) &&
!(n->ideal_Opcode()==Op_PrefetchWrite && 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_PrefetchAllocation && ld_op==Op_LoadI) &&
!(n->ideal_Opcode()==Op_Load2I && ld_op==Op_LoadD) && !(n->ideal_Opcode()==Op_LoadVector && 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->rule() == loadUB_rule)) { !(n->rule() == loadUB_rule)) {
verify_oops_warning(n, n->ideal_Opcode(), ld_op); 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_StoreI && st_op==Op_StoreF) &&
!(n->ideal_Opcode()==Op_StoreF && st_op==Op_StoreI) && !(n->ideal_Opcode()==Op_StoreF && st_op==Op_StoreI) &&
!(n->ideal_Opcode()==Op_StoreL && 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_StoreVector && 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_StoreD && st_op==Op_StoreI && n->rule() == storeD0_rule)) { !(n->ideal_Opcode()==Op_StoreD && st_op==Op_StoreI && n->rule() == storeD0_rule)) {
verify_oops_warning(n, n->ideal_Opcode(), st_op); 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 address last_rethrow = NULL; // debugging aid for Rethrow encoding
#endif #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 // 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; return 8;
} }
// Vector ideal reg // Vector ideal reg
const uint Matcher::vector_ideal_reg(void) { const int Matcher::vector_ideal_reg(int size) {
assert(MaxVectorSize == 8, "");
return Op_RegD; 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 // USII supports fxtof through the whole range of number, USIII doesn't
const bool Matcher::convL2FSupported(void) { const bool Matcher::convL2FSupported(void) {
return VM_Version::has_fast_fxtof(); 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) ); __ 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-------------------------------------------------------------- //----------FRAME--------------------------------------------------------------
@ -5932,50 +5920,6 @@ instruct loadL_unaligned(iRegL dst, memory mem, o7RegI tmp) %{
ins_pipe(iload_mem); 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 // Load Range
instruct loadRange(iRegI dst, memory mem) %{ instruct loadRange(iRegI dst, memory mem) %{
match(Set dst (LoadRange mem)); match(Set dst (LoadRange mem));
@ -6599,17 +6543,6 @@ instruct storeF0( memory mem, immF0 src) %{
ins_pipe(fstoreF_mem_zero); 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 // Convert oop pointer into compressed form
instruct encodeHeapOop(iRegN dst, iRegP src) %{ instruct encodeHeapOop(iRegN dst, iRegP src) %{
predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull); 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----------------------------------------------- //----------MemBar Instructions-----------------------------------------------
// Memory barrier flavors // 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); 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------------------------------------------ //----------Control Flow Instructions------------------------------------------
// Compare Instructions // Compare Instructions
// Compare Integers // Compare Integers
@ -10742,6 +10475,308 @@ instruct storeS_reversed(indIndexMemory dst, iRegI src) %{
ins_pipe(istore_mem_reg); 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----------------------------------------------------- //----------PEEPHOLE RULES-----------------------------------------------------
// These must follow all instruction definitions as they use the names // These must follow all instruction definitions as they use the names
// defined in the instructions definitions. // defined in the instructions definitions.

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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. // Currently not supported anywhere.
FLAG_SET_DEFAULT(UseFPUForSpilling, false); FLAG_SET_DEFAULT(UseFPUForSpilling, false);
MaxVectorSize = 8;
assert((InteriorEntryAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size"); assert((InteriorEntryAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size");
#endif #endif

View File

@ -1637,6 +1637,13 @@ void Assembler::movaps(XMMRegister dst, XMMRegister src) {
emit_byte(0xC0 | encode); 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) { void Assembler::movb(Register dst, Address src) {
NOT_LP64(assert(dst->has_byte_register(), "must have byte register")); NOT_LP64(assert(dst->has_byte_register(), "must have byte register"));
InstructionMark im(this); InstructionMark im(this);
@ -1686,6 +1693,14 @@ void Assembler::movdl(XMMRegister dst, Address src) {
emit_operand(dst, 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) { void Assembler::movdqa(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse2(), "")); NOT_LP64(assert(VM_Version::supports_sse2(), ""));
int encode = simd_prefix_and_encode(dst, src, VEX_SIMD_66); 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); 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 // Uses zero extension on 64bit
void Assembler::movl(Register dst, int32_t imm32) { 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); 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) { void Assembler::vxorps(XMMRegister dst, XMMRegister nds, Address src) {
assert(VM_Version::supports_avx(), ""); assert(VM_Version::supports_avx(), "");
InstructionMark im(this); InstructionMark im(this);
@ -3120,6 +3171,30 @@ void Assembler::vxorps(XMMRegister dst, XMMRegister nds, Address src) {
emit_operand(dst, 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 #ifndef _LP64
// 32bit only pieces of the assembler // 32bit only pieces of the assembler

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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, void vex_prefix(XMMRegister dst, XMMRegister nds, Address src,
VexSimdPrefix pre, bool vector256 = false) { VexSimdPrefix pre, bool vector256 = false) {
vex_prefix(src, nds->encoding(), dst->encoding(), int dst_enc = dst->encoding();
pre, VEX_OPCODE_0F, false, vector256); 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, int vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc,
@ -600,9 +601,12 @@ private:
bool vex_w, bool vector256); bool vex_w, bool vector256);
int vex_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegister src, int vex_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegister src,
VexSimdPrefix pre, bool vector256 = false) { VexSimdPrefix pre, bool vector256 = false,
return vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(), VexOpcode opc = VEX_OPCODE_0F) {
pre, VEX_OPCODE_0F, false, vector256); 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, void simd_prefix(XMMRegister xreg, XMMRegister nds, Address adr,
@ -1261,6 +1265,7 @@ private:
void movdl(XMMRegister dst, Register src); void movdl(XMMRegister dst, Register src);
void movdl(Register dst, XMMRegister src); void movdl(Register dst, XMMRegister src);
void movdl(XMMRegister dst, Address src); void movdl(XMMRegister dst, Address src);
void movdl(Address dst, XMMRegister src);
// Move Double Quadword // Move Double Quadword
void movdq(XMMRegister dst, Register src); void movdq(XMMRegister dst, Register src);
@ -1274,6 +1279,14 @@ private:
void movdqu(XMMRegister dst, Address src); void movdqu(XMMRegister dst, Address src);
void movdqu(XMMRegister dst, XMMRegister 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(Register dst, int32_t imm32);
void movl(Address dst, int32_t imm32); void movl(Address dst, int32_t imm32);
void movl(Register dst, Register src); void movl(Register dst, Register src);
@ -1615,6 +1628,17 @@ private:
void vxorpd(XMMRegister dst, XMMRegister nds, Address src); void vxorpd(XMMRegister dst, XMMRegister nds, Address src);
void vxorps(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: protected:
// Next instructions require address alignment 16 bytes SSE mode. // 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, Address src) { Assembler::vsubss(dst, nds, src); }
void vsubss(XMMRegister dst, XMMRegister nds, AddressLiteral 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, Address src) { Assembler::vxorpd(dst, nds, src); }
void vxorpd(XMMRegister dst, XMMRegister nds, AddressLiteral 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, Address src) { Assembler::vxorps(dst, nds, src); }
void vxorps(XMMRegister dst, XMMRegister nds, AddressLiteral src); void vxorps(XMMRegister dst, XMMRegister nds, AddressLiteral src);

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 + const int ConcreteRegisterImpl::max_fpr = ConcreteRegisterImpl::max_gpr +
2 * FloatRegisterImpl::number_of_registers; 2 * FloatRegisterImpl::number_of_registers;
const int ConcreteRegisterImpl::max_xmm = ConcreteRegisterImpl::max_fpr + 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* RegisterImpl::name() const {
const char* names[number_of_registers] = { const char* names[number_of_registers] = {
#ifndef AMD64 #ifndef AMD64

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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); } XMMRegister successor() const { return as_XMMRegister(encoding() + 1); }
// accessors // 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; } bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; }
const char* name() const; const char* name() const;
}; };
@ -216,7 +216,7 @@ class ConcreteRegisterImpl : public AbstractRegisterImpl {
RegisterImpl::number_of_registers + // "H" half of a 64bit register RegisterImpl::number_of_registers + // "H" half of a 64bit register
#endif // AMD64 #endif // AMD64
2 * FloatRegisterImpl::number_of_registers + 2 * FloatRegisterImpl::number_of_registers +
2 * XMMRegisterImpl::number_of_registers + 8 * XMMRegisterImpl::number_of_registers +
1 // eflags 1 // eflags
}; };

View File

@ -467,6 +467,32 @@ void VM_Version::get_processor_features() {
if (!supports_avx ()) // Drop to 0 if no AVX support if (!supports_avx ()) // Drop to 0 if no AVX support
UseAVX = 0; 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 // On new cpus instructions which update whole XMM register should be used
// to prevent partial register stall due to dependencies on high half. // 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 if( is_intel() ) { // Intel cpus specific settings
@ -606,15 +638,6 @@ void VM_Version::get_processor_features() {
FLAG_SET_DEFAULT(UsePopCountInstruction, false); 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 <= ReadPrefetchInstr && ReadPrefetchInstr <= 3, "invalid value");
assert(0 <= AllocatePrefetchInstr && AllocatePrefetchInstr <= 3, "invalid value"); assert(0 <= AllocatePrefetchInstr && AllocatePrefetchInstr <= 3, "invalid value");

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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); XMMRegister xreg = ::as_XMMRegister(0);
for ( ; i < ConcreteRegisterImpl::max_xmm ; ) { for ( ; i < ConcreteRegisterImpl::max_xmm ; ) {
regName[i++] = xreg->name(); for (int j = 0 ; j < 8 ; j++) {
regName[i++] = xreg->name(); regName[i++] = xreg->name();
}
xreg = xreg->successor(); xreg = xreg->successor();
} }
for ( ; i < ConcreteRegisterImpl::number_of_registers ; i ++ ) { for ( ; i < ConcreteRegisterImpl::number_of_registers ; i ++ ) {

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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() { 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() { inline XMMRegister VMRegImpl::as_XMMRegister() {
assert( is_XMMRegister() && is_even(value()), "must be" ); assert( is_XMMRegister() && is_even(value()), "must be" );
// Yuk // Yuk
return ::as_XMMRegister((value() - ConcreteRegisterImpl::max_fpr) >> 1); return ::as_XMMRegister((value() - ConcreteRegisterImpl::max_fpr) >> 3);
} }
inline bool VMRegImpl::is_concrete() { 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

View File

@ -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 // Java thread running in Java code => find exception handler if any
// a fault inside compiled code, the interpreter, or a stub // a fault inside compiled code, the interpreter, or a stub

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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); 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. // Done with parsing, check consistency.
@ -768,11 +774,12 @@ void ADLParser::source_hpp_parse(void) {
//------------------------------reg_parse-------------------------------------- //------------------------------reg_parse--------------------------------------
void ADLParser::reg_parse(void) { void ADLParser::reg_parse(void) {
RegisterForm *regBlock = _AD.get_registers(); // Information about registers encoding
// Create the RegisterForm for the architecture description. if (regBlock == NULL) {
RegisterForm *regBlock = new RegisterForm(); // Build new Source object // Create the RegisterForm for the architecture description.
regBlock->_linenum = linenum(); regBlock = new RegisterForm(); // Build new Source object
_AD.addForm(regBlock); _AD.addForm(regBlock);
}
skipws(); // Skip leading whitespace skipws(); // Skip leading whitespace
if (_curchar == '%' && *(_ptr+1) == '{') { if (_curchar == '%' && *(_ptr+1) == '{') {
@ -796,15 +803,11 @@ void ADLParser::reg_parse(void) {
parse_err(SYNERR, "Missing %c{ ... %c} block after register keyword.\n",'%','%'); parse_err(SYNERR, "Missing %c{ ... %c} block after register keyword.\n",'%','%');
return; return;
} }
// Add reg_class spill_regs
regBlock->addSpillRegClass();
} }
//------------------------------encode_parse----------------------------------- //------------------------------encode_parse-----------------------------------
void ADLParser::encode_parse(void) { void ADLParser::encode_parse(void) {
EncodeForm *encBlock; // Information about instruction/operand encoding EncodeForm *encBlock; // Information about instruction/operand encoding
char *desc = NULL; // String representation of encode rule
_AD.getForm(&encBlock); _AD.getForm(&encBlock);
if ( encBlock == NULL) { if ( encBlock == NULL) {

View File

@ -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. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
// //
// This code is free software; you can redistribute it and/or modify it // 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 // Find last character in idealOp, it specifies the type
char last_char = 0; char last_char = 0;
const char *ptr = idealOp; const char *ptr = idealOp;
for( ; *ptr != '\0'; ++ptr) { for (; *ptr != '\0'; ++ptr) {
last_char = *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 'I': return "TypeInt::INT";
case 'P': return "TypePtr::BOTTOM"; case 'P': return "TypePtr::BOTTOM";
case 'N': return "TypeNarrowOop::BOTTOM"; case 'N': return "TypeNarrowOop::BOTTOM";

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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,"LoadN")==0 ) return Form::idealN;
if( strcmp(opType,"LoadRange")==0 ) return Form::idealI; if( strcmp(opType,"LoadRange")==0 ) return Form::idealI;
if( strcmp(opType,"LoadS")==0 ) return Form::idealS; if( strcmp(opType,"LoadS")==0 ) return Form::idealS;
if( strcmp(opType,"Load16B")==0 ) return Form::idealB; if( strcmp(opType,"LoadVector")==0 ) return Form::idealV;
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;
assert( strcmp(opType,"Load") != 0, "Must type Loads" ); assert( strcmp(opType,"Load") != 0, "Must type Loads" );
return Form::none; return Form::none;
} }
Form::DataType Form::is_store_to_memory(const char *opType) const { Form::DataType Form::is_store_to_memory(const char *opType) const {
if( strcmp(opType,"StoreB")==0) return Form::idealB; 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,"StoreC")==0) return Form::idealC;
if( strcmp(opType,"StoreD")==0) return Form::idealD; if( strcmp(opType,"StoreD")==0) return Form::idealD;
if( strcmp(opType,"StoreF")==0) return Form::idealF; if( strcmp(opType,"StoreF")==0) return Form::idealF;
if( strcmp(opType,"StoreI")==0) return Form::idealI; if( strcmp(opType,"StoreI")==0) return Form::idealI;
if( strcmp(opType,"StoreL")==0) return Form::idealL; if( strcmp(opType,"StoreL")==0) return Form::idealL;
if( strcmp(opType,"StoreP")==0) return Form::idealP; if( strcmp(opType,"StoreP")==0) return Form::idealP;
if( strcmp(opType,"StoreN")==0) return Form::idealN; if( strcmp(opType,"StoreN")==0) return Form::idealN;
if( strcmp(opType,"Store16B")==0) return Form::idealB; if( strcmp(opType,"StoreVector")==0 ) return Form::idealV;
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;
assert( strcmp(opType,"Store") != 0, "Must type Stores" ); assert( strcmp(opType,"Store") != 0, "Must type Stores" );
return Form::none; return Form::none;
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -172,7 +172,8 @@ public:
idealB = 6, // Byte type idealB = 6, // Byte type
idealC = 7, // Char type idealC = 7, // Char type
idealS = 8, // String 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' // 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; Form::DataType ideal_to_const_type(const char *ideal_type_name) const;

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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. // for spill-slots/regs.
void RegisterForm::addSpillRegClass() { void RegisterForm::addSpillRegClass() {
// Stack slots start at the next available even register number. // 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"; const char *rc_name = "stack_slots";
RegClass *reg_class = new RegClass(rc_name); RegClass *reg_class = new RegClass(rc_name);
reg_class->_stack_or_reg = true; reg_class->_stack_or_reg = true;
@ -150,9 +150,14 @@ bool RegisterForm::verify() {
int RegisterForm::RegMask_Size() { int RegisterForm::RegMask_Size() {
// Need at least this many words // Need at least this many words
int words_for_regs = (_reg_ctr + 31)>>5; 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. // 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 void RegisterForm::dump() { // Debug printer

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 _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 // Return the input register that must match the output register
// If this is not required, return 0 // If this is not required, return 0
uint InstructForm::two_address(FormDict &globals) { 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 (needs_base_oop_edge(globals)) return true;
if (is_vector()) return true;
if (is_mach_constant()) return true;
return false; return false;
} }
@ -3381,11 +3392,8 @@ int MatchNode::needs_ideal_memory_edge(FormDict &globals) const {
"StoreI","StoreL","StoreP","StoreN","StoreD","StoreF" , "StoreI","StoreL","StoreP","StoreN","StoreD","StoreF" ,
"StoreB","StoreC","Store" ,"StoreFP", "StoreB","StoreC","Store" ,"StoreFP",
"LoadI", "LoadUI2L", "LoadL", "LoadP" ,"LoadN", "LoadD" ,"LoadF" , "LoadI", "LoadUI2L", "LoadL", "LoadP" ,"LoadN", "LoadD" ,"LoadF" ,
"LoadB" , "LoadUB", "LoadUS" ,"LoadS" ,"Load" , "LoadB" , "LoadUB", "LoadUS" ,"LoadS" ,"Load" ,
"Store4I","Store2I","Store2L","Store2D","Store4F","Store2F","Store16B", "StoreVector", "LoadVector",
"Store8B","Store4B","Store8C","Store4C","Store2C",
"Load4I" ,"Load2I" ,"Load2L" ,"Load2D" ,"Load4F" ,"Load2F" ,"Load16B" ,
"Load8B" ,"Load4B" ,"Load8C" ,"Load4C" ,"Load2C" ,"Load8S", "Load4S","Load2S",
"LoadRange", "LoadKlass", "LoadNKlass", "LoadL_unaligned", "LoadD_unaligned", "LoadRange", "LoadKlass", "LoadNKlass", "LoadL_unaligned", "LoadD_unaligned",
"LoadPLocked", "LoadPLocked",
"StorePConditional", "StoreIConditional", "StoreLConditional", "StorePConditional", "StoreIConditional", "StoreLConditional",
@ -3822,6 +3830,10 @@ bool MatchRule::is_base_register(FormDict &globals) const {
strcmp(opType,"RegL")==0 || strcmp(opType,"RegL")==0 ||
strcmp(opType,"RegF")==0 || strcmp(opType,"RegF")==0 ||
strcmp(opType,"RegD")==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) ) { strcmp(opType,"Reg" )==0) ) {
return 1; return 1;
} }
@ -3938,19 +3950,12 @@ int MatchRule::is_expensive() const {
strcmp(opType,"ReverseBytesL")==0 || strcmp(opType,"ReverseBytesL")==0 ||
strcmp(opType,"ReverseBytesUS")==0 || strcmp(opType,"ReverseBytesUS")==0 ||
strcmp(opType,"ReverseBytesS")==0 || strcmp(opType,"ReverseBytesS")==0 ||
strcmp(opType,"Replicate16B")==0 || strcmp(opType,"ReplicateB")==0 ||
strcmp(opType,"Replicate8B")==0 || strcmp(opType,"ReplicateS")==0 ||
strcmp(opType,"Replicate4B")==0 || strcmp(opType,"ReplicateI")==0 ||
strcmp(opType,"Replicate8C")==0 || strcmp(opType,"ReplicateL")==0 ||
strcmp(opType,"Replicate4C")==0 || strcmp(opType,"ReplicateF")==0 ||
strcmp(opType,"Replicate8S")==0 || strcmp(opType,"ReplicateD")==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 ||
0 /* 0 to line up columns nicely */ ) 0 /* 0 to line up columns nicely */ )
return 1; return 1;
} }
@ -4034,6 +4039,23 @@ Form::DataType MatchRule::is_ideal_load() const {
return ideal_load; 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 { bool MatchRule::skip_antidep_check() const {
// Some loads operate on what is effectively immutable memory so we // Some loads operate on what is effectively immutable memory so we

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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_safepoint() const; // node matches 'SafePoint'
virtual bool is_ideal_nop() const; // node matches 'Nop' virtual bool is_ideal_nop() const; // node matches 'Nop'
virtual bool is_ideal_control() const; // control node 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::CallType is_ideal_call() const; // matches ideal 'Call'
virtual Form::DataType is_ideal_load() const; // node matches ideal 'LoadXNode' 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_goto() const; // node matches ideal 'Goto'
bool is_ideal_loopEnd() const; // node matches ideal 'LoopEnd' bool is_ideal_loopEnd() const; // node matches ideal 'LoopEnd'
bool is_ideal_bool() const; // node matches ideal 'Bool' 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' Form::DataType is_ideal_load() const;// node matches ideal 'LoadXNode'
// Should antidep checks be disabled for this rule // Should antidep checks be disabled for this rule
// See definition of MatchRule::skip_antidep_check // See definition of MatchRule::skip_antidep_check

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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/node.hpp");
AD.addInclude(AD._HPP_file, "opto/regalloc.hpp"); AD.addInclude(AD._HPP_file, "opto/regalloc.hpp");
AD.addInclude(AD._HPP_file, "opto/subnode.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, "precompiled.hpp");
AD.addInclude(AD._CPP_CLONE_file, "adfiles", get_basename(AD._HPP_file._name)); AD.addInclude(AD._CPP_CLONE_file, "adfiles", get_basename(AD._HPP_file._name));
AD.addInclude(AD._CPP_EXPAND_file, "precompiled.hpp"); AD.addInclude(AD._CPP_EXPAND_file, "precompiled.hpp");

View 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

View 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

View File

@ -23,6 +23,7 @@
*/ */
#include "precompiled.hpp" #include "precompiled.hpp"
#include "classfile/altHashing.hpp"
#include "classfile/javaClasses.hpp" #include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp" #include "classfile/symbolTable.hpp"
#include "classfile/vmSymbols.hpp" #include "classfile/vmSymbols.hpp"
@ -347,13 +348,26 @@ jchar* java_lang_String::as_unicode_string(oop java_string, int& length) {
return result; 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); typeArrayOop value = java_lang_String::value(java_string);
int offset = java_lang_String::offset(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; unsigned int java_lang_String::hash_string(oop java_string) {
return hash_string(value->char_at_addr(offset), length); 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) { Symbol* java_lang_String::as_symbol(Handle java_string, TRAPS) {

View File

@ -158,20 +158,16 @@ class java_lang_String : AllStatic {
static jchar* as_unicode_string(oop java_string, int& length); static jchar* as_unicode_string(oop java_string, int& length);
// Compute the hash value for a java.lang.String object which would // Compute the hash value for a java.lang.String object which would
// contain the characters passed in. This hash value is used for at // contain the characters passed in.
// least two purposes.
// //
// (a) As the hash value used by the StringTable for bucket selection // As the hash value used by the String object itself, in
// and comparison (stored in the HashtableEntry structures). This // String.hashCode(). This value is normally calculated in Java code
// is used in the String.intern() method. // 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 // For this reason, THIS ALGORITHM MUST MATCH String.toHash().
// String.hashCode(). This value is normally calculate in Java code template <typename T> static unsigned int to_hash(T* s, int len) {
// 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) {
unsigned int h = 0; unsigned int h = 0;
while (len-- > 0) { while (len-- > 0) {
h = 31*h + (unsigned int) *s; h = 31*h + (unsigned int) *s;
@ -179,6 +175,10 @@ class java_lang_String : AllStatic {
} }
return h; 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 unsigned int hash_string(oop java_string);
static bool equals(oop java_string, jchar* chars, int len); static bool equals(oop java_string, jchar* chars, int len);

View File

@ -23,6 +23,7 @@
*/ */
#include "precompiled.hpp" #include "precompiled.hpp"
#include "classfile/altHashing.hpp"
#include "classfile/javaClasses.hpp" #include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp" #include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp" #include "classfile/systemDictionary.hpp"
@ -34,19 +35,19 @@
#include "oops/oop.inline2.hpp" #include "oops/oop.inline2.hpp"
#include "runtime/mutexLocker.hpp" #include "runtime/mutexLocker.hpp"
#include "utilities/hashtable.inline.hpp" #include "utilities/hashtable.inline.hpp"
#include "utilities/numberSeq.hpp"
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
SymbolTable* SymbolTable::_the_table = NULL; SymbolTable* SymbolTable::_the_table = NULL;
// Static arena for symbols that are not deallocated // Static arena for symbols that are not deallocated
Arena* SymbolTable::_arena = NULL; 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) { 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*. assert (len <= Symbol::max_length(), "should be checked by caller");
if (len > Symbol::max_length()) {
THROW_MSG_0(vmSymbols::java_lang_InternalError(),
"name is too long to represent");
}
Symbol* sym; Symbol* sym;
// Allocate symbols in the C heap when dumping shared spaces in case there // Allocate symbols in the C heap when dumping shared spaces in case there
// are temporary symbols we can remove. // are temporary symbols we can remove.
@ -91,9 +92,14 @@ void SymbolTable::unlink() {
int total = 0; int total = 0;
size_t memory_total = 0; size_t memory_total = 0;
for (int i = 0; i < the_table()->table_size(); ++i) { for (int i = 0; i < the_table()->table_size(); ++i) {
for (HashtableEntry<Symbol*>** p = the_table()->bucket_addr(i); *p != NULL; ) { HashtableEntry<Symbol*>** p = the_table()->bucket_addr(i);
HashtableEntry<Symbol*>* entry = *p; HashtableEntry<Symbol*>* entry = the_table()->bucket(i);
if (entry->is_shared()) { 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; break;
} }
Symbol* s = entry->literal(); Symbol* s = entry->literal();
@ -102,6 +108,7 @@ void SymbolTable::unlink() {
assert(s != NULL, "just checking"); assert(s != NULL, "just checking");
// If reference count is zero, remove. // If reference count is zero, remove.
if (s->refcount() == 0) { if (s->refcount() == 0) {
assert(!entry->is_shared(), "shared entries should be kept live");
delete s; delete s;
removed++; removed++;
*p = entry->next(); *p = entry->next();
@ -109,6 +116,8 @@ void SymbolTable::unlink() {
} else { } else {
p = entry->next_addr(); p = entry->next_addr();
} }
// get next entry
entry = (HashtableEntry<Symbol*>*)HashtableEntry<Symbol*>::make_ptr(*p);
} }
} }
symbols_removed += removed; 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. // Lookup a symbol in a bucket.
Symbol* SymbolTable::lookup(int index, const char* name, Symbol* SymbolTable::lookup(int index, const char* name,
int len, unsigned int hash) { int len, unsigned int hash) {
int count = 0;
for (HashtableEntry<Symbol*>* e = bucket(index); e != NULL; e = e->next()) { 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) { if (e->hash() == hash) {
Symbol* sym = e->literal(); Symbol* sym = e->literal();
if (sym->equals(name, len)) { 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; 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 // We take care not to be blocking while holding the
// SymbolTable_lock. Otherwise, the system might deadlock, since the // SymbolTable_lock. Otherwise, the system might deadlock, since the
@ -156,6 +206,9 @@ Symbol* SymbolTable::lookup(const char* name, int len, TRAPS) {
// Found // Found
if (s != NULL) return s; if (s != NULL) return s;
// Grab SymbolTable_lock first.
MutexLocker ml(SymbolTable_lock, THREAD);
// Otherwise, add to symbol to table // Otherwise, add to symbol to table
return the_table()->basic_add(index, (u1*)name, len, hashValue, true, CHECK_NULL); 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 // We can't include the code in No_Safepoint_Verifier because of the
// ResourceMark. // ResourceMark.
// Grab SymbolTable_lock first.
MutexLocker ml(SymbolTable_lock, THREAD);
return the_table()->basic_add(index, (u1*)buffer, len, hashValue, true, CHECK_NULL); 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, int names_count,
const char** names, int* lengths, int* cp_indices, const char** names, int* lengths, int* cp_indices,
unsigned int* hashValues, TRAPS) { unsigned int* hashValues, TRAPS) {
// Grab SymbolTable_lock first.
MutexLocker ml(SymbolTable_lock, THREAD);
SymbolTable* table = the_table(); SymbolTable* table = the_table();
bool added = table->basic_add(class_loader, cp, names_count, names, lengths, bool added = table->basic_add(class_loader, cp, names_count, names, lengths,
cp_indices, hashValues, CHECK); cp_indices, hashValues, CHECK);
@ -281,18 +340,39 @@ Symbol* SymbolTable::new_permanent_symbol(const char* name, TRAPS) {
if (result != NULL) { if (result != NULL) {
return result; return result;
} }
// Grab SymbolTable_lock first.
MutexLocker ml(SymbolTable_lock, THREAD);
SymbolTable* table = the_table(); SymbolTable* table = the_table();
int index = table->hash_to_index(hash); int index = table->hash_to_index(hash);
return table->basic_add(index, (u1*)name, (int)strlen(name), hash, false, THREAD); return table->basic_add(index, (u1*)name, (int)strlen(name), hash, false, THREAD);
} }
Symbol* SymbolTable::basic_add(int index, u1 *name, int len, Symbol* SymbolTable::basic_add(int index_arg, u1 *name, int len,
unsigned int hashValue, bool c_heap, TRAPS) { unsigned int hashValue_arg, bool c_heap, TRAPS) {
assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(), assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(),
"proposed name of symbol must be stable"); "proposed name of symbol must be stable");
// Grab SymbolTable_lock first. // Don't allow symbols to be created which cannot fit in a Symbol*.
MutexLocker ml(SymbolTable_lock, THREAD); 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 // Since look-up was done lock-free, we need to check if another
// thread beat us in the race to insert the symbol. // 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 // Cannot hit a safepoint in this function because the "this" pointer can move.
MutexLocker ml(SymbolTable_lock, THREAD); No_Safepoint_Verifier nsv;
for (int i=0; i<names_count; i++) { 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 // Since look-up was done lock-free, we need to check if another
// thread beat us in the race to insert the symbol. // thread beat us in the race to insert the symbol.
int index = hash_to_index(hashValues[i]); int index = hash_to_index(hashValue);
Symbol* test = lookup(index, names[i], lengths[i], hashValues[i]); Symbol* test = lookup(index, names[i], lengths[i], hashValue);
if (test != NULL) { if (test != NULL) {
// A race occurred and another thread introduced the symbol, this one // A race occurred and another thread introduced the symbol, this one
// will be dropped and collected. Use test instead. // 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; bool c_heap = class_loader() != NULL;
Symbol* sym = allocate_symbol((const u1*)names[i], lengths[i], c_heap, CHECK_(false)); 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??? 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); add_entry(index, entry);
cp->symbol_at_put(cp_indices[i], sym); 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 // Non-product code
@ -468,7 +574,6 @@ void SymbolTable::print() {
} }
} }
} }
#endif // PRODUCT #endif // PRODUCT
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@ -514,38 +619,53 @@ class StableMemoryChecker : public StackObj {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
StringTable* StringTable::_the_table = NULL; 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, oop StringTable::lookup(int index, jchar* name,
int len, unsigned int hash) { int len, unsigned int hash) {
int count = 0;
for (HashtableEntry<oop>* l = bucket(index); l != NULL; l = l->next()) { for (HashtableEntry<oop>* l = bucket(index); l != NULL; l = l->next()) {
count++;
if (l->hash() == hash) { if (l->hash() == hash) {
if (java_lang_String::equals(l->literal(), name, len)) { if (java_lang_String::equals(l->literal(), name, len)) {
return l->literal(); 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; return NULL;
} }
oop StringTable::basic_add(int index, Handle string_or_null, jchar* name, oop StringTable::basic_add(int index_arg, Handle string, jchar* name,
int len, unsigned int hashValue, TRAPS) { int len, unsigned int hashValue_arg, 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);
assert(java_lang_String::equals(string(), name, len), assert(java_lang_String::equals(string(), name, len),
"string must be properly initialized"); "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 // Since look-up was done lock-free, we need to check if another
// thread beat us in the race to insert the symbol. // thread beat us in the race to insert the symbol.
@ -566,7 +686,7 @@ oop StringTable::lookup(Symbol* symbol) {
ResourceMark rm; ResourceMark rm;
int length; int length;
jchar* chars = symbol->as_unicode(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); int index = the_table()->hash_to_index(hashValue);
return the_table()->lookup(index, chars, length, 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, oop StringTable::intern(Handle string_or_null, jchar* name,
int len, TRAPS) { 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); 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 // 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 // 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); hashValue, CHECK_NULL);
} }
@ -625,18 +761,24 @@ void StringTable::unlink(BoolObjectClosure* is_alive) {
// entries at a safepoint. // entries at a safepoint.
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
for (int i = 0; i < the_table()->table_size(); ++i) { for (int i = 0; i < the_table()->table_size(); ++i) {
for (HashtableEntry<oop>** p = the_table()->bucket_addr(i); *p != NULL; ) { HashtableEntry<oop>** p = the_table()->bucket_addr(i);
HashtableEntry<oop>* entry = *p; HashtableEntry<oop>* entry = the_table()->bucket(i);
if (entry->is_shared()) { 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; break;
} }
assert(entry->literal() != NULL, "just checking"); 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(); p = entry->next_addr();
} else { } else {
*p = entry->next(); *p = entry->next();
the_table()->free_entry(entry); 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;
}

View File

@ -40,6 +40,7 @@
// - symbolTableEntrys are allocated in blocks to reduce the space overhead. // - symbolTableEntrys are allocated in blocks to reduce the space overhead.
class BoolObjectClosure; class BoolObjectClosure;
class outputStream;
// Class to hold a newly created or referenced Symbol* temporarily in scope. // Class to hold a newly created or referenced Symbol* temporarily in scope.
@ -78,6 +79,10 @@ private:
// The symbol table // The symbol table
static SymbolTable* _the_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 // For statistics
static int symbols_removed; static int symbols_removed;
static int symbols_counted; static int symbols_counted;
@ -119,6 +124,11 @@ private:
static Arena* arena() { return _arena; } // called for statistics static Arena* arena() { return _arena; } // called for statistics
static void initialize_symbols(int arena_alloc_size = 0); 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: public:
enum { enum {
symbol_alloc_batch_size = 8, symbol_alloc_batch_size = 8,
@ -146,6 +156,8 @@ public:
initialize_symbols(); initialize_symbols();
} }
static unsigned int hash_symbol(const char* s, int len);
static Symbol* lookup(const char* name, int len, TRAPS); static Symbol* lookup(const char* name, int len, TRAPS);
// lookup only, won't add. Also calculate hash. // lookup only, won't add. Also calculate hash.
static Symbol* lookup_only(const char* name, int len, unsigned int& hash); static Symbol* lookup_only(const char* name, int len, unsigned int& hash);
@ -208,6 +220,7 @@ public:
// Debugging // Debugging
static void verify(); static void verify();
static void dump(outputStream* st);
// Sharing // Sharing
static void copy_buckets(char** top, char*end) { static void copy_buckets(char** top, char*end) {
@ -219,8 +232,13 @@ public:
static void reverse(void* boundary = NULL) { static void reverse(void* boundary = NULL) {
the_table()->Hashtable<Symbol*>::reverse(boundary); 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> { class StringTable : public Hashtable<oop> {
friend class VMStructs; friend class VMStructs;
@ -228,6 +246,10 @@ private:
// The string table // The string table
static StringTable* _the_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); 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, oop basic_add(int index, Handle string_or_null, jchar* name, int len,
unsigned int hashValue, TRAPS); unsigned int hashValue, TRAPS);
@ -241,6 +263,10 @@ private:
: Hashtable<oop>((int)StringTableSize, sizeof (HashtableEntry<oop>), t, : Hashtable<oop>((int)StringTableSize, sizeof (HashtableEntry<oop>), t,
number_of_entries) {} number_of_entries) {}
static bool use_alternate_hashcode() { return _seed != 0; }
static jint seed() { return _seed; }
unsigned int new_hash(oop s);
public: public:
// The string table // The string table
static StringTable* the_table() { return _the_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. // Invoke "f->do_oop" on the locations of all oops in the table.
static void oops_do(OopClosure* f); 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 // Probing
static oop lookup(Symbol* symbol); static oop lookup(Symbol* symbol);
@ -275,6 +309,7 @@ public:
// Debugging // Debugging
static void verify(); static void verify();
static void dump(outputStream* st);
// Sharing // Sharing
static void copy_buckets(char** top, char*end) { static void copy_buckets(char** top, char*end) {
@ -286,6 +321,9 @@ public:
static void reverse() { static void reverse() {
the_table()->Hashtable<oop>::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 #endif // SHARE_VM_CLASSFILE_SYMBOLTABLE_HPP

View File

@ -111,6 +111,10 @@
template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \ template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \
template(sun_misc_PostVMInitHook, "sun/misc/PostVMInitHook") \ 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 */ \ /* class file format tags */ \
template(tag_source_file, "SourceFile") \ template(tag_source_file, "SourceFile") \
template(tag_inner_classes, "InnerClasses") \ template(tag_inner_classes, "InnerClasses") \

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,7 +27,7 @@
#include "code/vmreg.hpp" #include "code/vmreg.hpp"
// First VMReg value that could refer to a stack slot // 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 // VMRegs are 4 bytes wide on all platforms
const int VMRegImpl::stack_slot_size = 4; const int VMRegImpl::stack_slot_size = 4;

View File

@ -4750,9 +4750,6 @@ public:
_g1h->g1_policy()->record_thread_age_table(pss.age_table()); _g1h->g1_policy()->record_thread_age_table(pss.age_table());
_g1h->update_surviving_young_words(pss.surviving_young_words()+1); _g1h->update_surviving_young_words(pss.surviving_young_words()+1);
// Clean up any par-expanded rem sets.
HeapRegionRemSet::par_cleanup();
if (ParallelGCVerbose) { if (ParallelGCVerbose) {
MutexLocker x(stats_lock()); MutexLocker x(stats_lock());
pss.print_termination_stats(worker_id); pss.print_termination_stats(worker_id);

View File

@ -53,6 +53,9 @@
develop(bool, G1TraceMarkStackOverflow, false, \ develop(bool, G1TraceMarkStackOverflow, false, \
"If true, extra debugging code for CM restart for ovflw.") \ "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, \ diagnostic(bool, G1SummarizeConcMark, false, \
"Summarize concurrent mark info") \ "Summarize concurrent mark info") \
\ \

View File

@ -30,13 +30,10 @@
#include "gc_implementation/g1/heapRegionSeq.inline.hpp" #include "gc_implementation/g1/heapRegionSeq.inline.hpp"
#include "memory/allocation.hpp" #include "memory/allocation.hpp"
#include "memory/space.inline.hpp" #include "memory/space.inline.hpp"
#include "oops/oop.inline.hpp"
#include "utilities/bitMap.inline.hpp" #include "utilities/bitMap.inline.hpp"
#include "utilities/globalDefinitions.hpp" #include "utilities/globalDefinitions.hpp"
#define HRRS_VERBOSE 0
#define PRT_COUNT_OCCUPIED 1
// OtherRegionsTable // OtherRegionsTable
class PerRegionTable: public CHeapObj { class PerRegionTable: public CHeapObj {
@ -45,14 +42,10 @@ class PerRegionTable: public CHeapObj {
HeapRegion* _hr; HeapRegion* _hr;
BitMap _bm; BitMap _bm;
#if PRT_COUNT_OCCUPIED
jint _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; static PerRegionTable* _free_list;
@ -69,63 +62,25 @@ protected:
// We need access in order to union things into the base table. // We need access in order to union things into the base table.
BitMap* bm() { return &_bm; } BitMap* bm() { return &_bm; }
#if PRT_COUNT_OCCUPIED
void recount_occupied() { void recount_occupied() {
_occupied = (jint) bm()->count_one_bits(); _occupied = (jint) bm()->count_one_bits();
} }
#endif
PerRegionTable(HeapRegion* hr) : PerRegionTable(HeapRegion* hr) :
_hr(hr), _hr(hr),
#if PRT_COUNT_OCCUPIED
_occupied(0), _occupied(0),
#endif
_bm(HeapRegion::CardsPerRegion, false /* in-resource-area */) _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) { void add_card_work(CardIdx_t from_card, bool par) {
if (!_bm.at(from_card)) { if (!_bm.at(from_card)) {
if (par) { if (par) {
if (_bm.par_at_put(from_card, 1)) { if (_bm.par_at_put(from_card, 1)) {
#if PRT_COUNT_OCCUPIED
Atomic::inc(&_occupied); Atomic::inc(&_occupied);
#endif
} }
} else { } else {
_bm.at_put(from_card, 1); _bm.at_put(from_card, 1);
#if PRT_COUNT_OCCUPIED
_occupied++; _occupied++;
#endif
} }
} }
} }
@ -134,10 +89,13 @@ protected:
// Must make this robust in case "from" is not in "_hr", because of // Must make this robust in case "from" is not in "_hr", because of
// concurrency. // concurrency.
#if HRRS_VERBOSE if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr(" PRT::Add_reference_work(" PTR_FORMAT "->" PTR_FORMAT").", gclog_or_tty->print_cr(" PRT::Add_reference_work(" PTR_FORMAT "->" PTR_FORMAT").",
from, *from); from,
#endif UseCompressedOops
? oopDesc::load_decode_heap_oop((narrowOop*)from)
: oopDesc::load_decode_heap_oop((oop*)from));
}
HeapRegion* loc_hr = hr(); HeapRegion* loc_hr = hr();
// If the test below fails, then this table was reused concurrently // If the test below fails, then this table was reused concurrently
@ -162,23 +120,16 @@ public:
HeapRegion* hr() const { return _hr; } HeapRegion* hr() const { return _hr; }
#if PRT_COUNT_OCCUPIED
jint occupied() const { jint occupied() const {
// Overkill, but if we ever need it... // Overkill, but if we ever need it...
// guarantee(_occupied == _bm.count_one_bits(), "Check"); // guarantee(_occupied == _bm.count_one_bits(), "Check");
return _occupied; return _occupied;
} }
#else
jint occupied() const {
return _bm.count_one_bits();
}
#endif
void init(HeapRegion* hr) { void init(HeapRegion* hr) {
_hr = hr; _hr = hr;
#if PRT_COUNT_OCCUPIED _next = NULL;
_occupied = 0; _occupied = 0;
#endif
_bm.clear(); _bm.clear();
} }
@ -194,9 +145,7 @@ public:
HeapWord* hr_bot = hr()->bottom(); HeapWord* hr_bot = hr()->bottom();
size_t hr_first_card_index = ctbs->index_for(hr_bot); size_t hr_first_card_index = ctbs->index_for(hr_bot);
bm()->set_intersection_at_offset(*card_bm, hr_first_card_index); bm()->set_intersection_at_offset(*card_bm, hr_first_card_index);
#if PRT_COUNT_OCCUPIED
recount_occupied(); recount_occupied();
#endif
} }
void add_card(CardIdx_t from_card_index) { void add_card(CardIdx_t from_card_index) {
@ -218,16 +167,6 @@ public:
return sizeof(this) + _bm.size_in_words() * HeapWordSize; 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()". // Requires "from" to be in "hr()".
bool contains_reference(OopOrNarrowOopStar from) const { bool contains_reference(OopOrNarrowOopStar from) const {
assert(hr()->is_in_reserved(from), "Precondition."); assert(hr()->is_in_reserved(from), "Precondition.");
@ -235,122 +174,29 @@ public:
CardTableModRefBS::card_size); CardTableModRefBS::card_size);
return _bm.at(card_ind); 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; }
static void free(PerRegionTable* prt) {
#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) {
while (true) { while (true) {
PosParPRT* fl = _free_list; PerRegionTable* fl = _free_list;
prt->set_next(fl); prt->set_next(fl);
PosParPRT* res = PerRegionTable* res =
(PosParPRT*) (PerRegionTable*)
Atomic::cmpxchg_ptr(prt, &_free_list, fl); Atomic::cmpxchg_ptr(prt, &_free_list, fl);
if (res == fl) return; if (res == fl) return;
} }
ShouldNotReachHere(); ShouldNotReachHere();
} }
static PosParPRT* alloc(HeapRegion* hr) { static PerRegionTable* alloc(HeapRegion* hr) {
PosParPRT* fl = _free_list; PerRegionTable* fl = _free_list;
while (fl != NULL) { while (fl != NULL) {
PosParPRT* nxt = fl->next(); PerRegionTable* nxt = fl->next();
PosParPRT* res = PerRegionTable* res =
(PosParPRT*) (PerRegionTable*)
Atomic::cmpxchg_ptr(nxt, &_free_list, fl); Atomic::cmpxchg_ptr(nxt, &_free_list, fl);
if (res == fl) { if (res == fl) {
fl->init(hr); fl->init(hr);
@ -360,148 +206,26 @@ public:
} }
} }
assert(fl == NULL, "Loop condition."); assert(fl == NULL, "Loop condition.");
return new PosParPRT(hr); return new PerRegionTable(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;
} }
static size_t fl_mem_size() { static size_t fl_mem_size() {
PosParPRT* cur = _free_list; PerRegionTable* cur = _free_list;
size_t res = 0; size_t res = 0;
while (cur != NULL) { while (cur != NULL) {
res += sizeof(PosParPRT); res += sizeof(PerRegionTable);
cur = cur->next(); cur = cur->next();
} }
return res; 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() { PerRegionTable* PerRegionTable::_free_list = NULL;
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;
size_t OtherRegionsTable::_max_fine_entries = 0; size_t OtherRegionsTable::_max_fine_entries = 0;
size_t OtherRegionsTable::_mod_max_fine_entries_mask = 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_stride = 0;
size_t OtherRegionsTable::_fine_eviction_sample_size = 0; size_t OtherRegionsTable::_fine_eviction_sample_size = 0;
#endif
OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) : OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) :
_g1h(G1CollectedHeap::heap()), _g1h(G1CollectedHeap::heap()),
@ -511,34 +235,36 @@ OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) :
false /* in-resource-area */), false /* in-resource-area */),
_fine_grain_regions(NULL), _fine_grain_regions(NULL),
_n_fine_entries(0), _n_coarse_entries(0), _n_fine_entries(0), _n_coarse_entries(0),
#if SAMPLE_FOR_EVICTION
_fine_eviction_start(0), _fine_eviction_start(0),
#endif
_sparse_table(hr) _sparse_table(hr)
{ {
typedef PosParPRT* PosParPRTPtr; typedef PerRegionTable* PerRegionTablePtr;
if (_max_fine_entries == 0) { if (_max_fine_entries == 0) {
assert(_mod_max_fine_entries_mask == 0, "Both or none."); assert(_mod_max_fine_entries_mask == 0, "Both or none.");
size_t max_entries_log = (size_t)log2_long((jlong)G1RSetRegionEntries); size_t max_entries_log = (size_t)log2_long((jlong)G1RSetRegionEntries);
_max_fine_entries = (size_t)(1 << max_entries_log); _max_fine_entries = (size_t)(1 << max_entries_log);
_mod_max_fine_entries_mask = _max_fine_entries - 1; _mod_max_fine_entries_mask = _max_fine_entries - 1;
#if SAMPLE_FOR_EVICTION
assert(_fine_eviction_sample_size == 0 assert(_fine_eviction_sample_size == 0
&& _fine_eviction_stride == 0, "All init at same time."); && _fine_eviction_stride == 0, "All init at same time.");
_fine_eviction_sample_size = MAX2((size_t)4, max_entries_log); _fine_eviction_sample_size = MAX2((size_t)4, max_entries_log);
_fine_eviction_stride = _max_fine_entries / _fine_eviction_sample_size; _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, vm_exit_out_of_memory(sizeof(void*)*_max_fine_entries,
"Failed to allocate _fine_grain_entries."); "Failed to allocate _fine_grain_entries.");
}
for (size_t i = 0; i < _max_fine_entries; i++) { for (size_t i = 0; i < _max_fine_entries; i++) {
_fine_grain_regions[i] = NULL; _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_max_regions = 0;
size_t OtherRegionsTable::_from_card_cache_mem_size = 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) { void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
size_t cur_hrs_ind = (size_t) hr()->hrs_index(); size_t cur_hrs_ind = (size_t) hr()->hrs_index();
#if HRRS_VERBOSE if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr("ORT::add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").", gclog_or_tty->print_cr("ORT::add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").",
from, from,
UseCompressedOops UseCompressedOops
? oopDesc::load_decode_heap_oop((narrowOop*)from) ? oopDesc::load_decode_heap_oop((narrowOop*)from)
: oopDesc::load_decode_heap_oop((oop*)from)); : oopDesc::load_decode_heap_oop((oop*)from));
#endif }
int from_card = (int)(uintptr_t(from) >> CardTableModRefBS::card_shift); int from_card = (int)(uintptr_t(from) >> CardTableModRefBS::card_shift);
#if HRRS_VERBOSE if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = %d)", gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = %d)",
hr()->bottom(), from_card, hr()->bottom(), from_card,
_from_card_cache[tid][cur_hrs_ind]); _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);
} }
#endif
if (from_card == _from_card_cache[tid][cur_hrs_ind]) { if (from_card == _from_card_cache[tid][cur_hrs_ind]) {
#if HRRS_VERBOSE if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr(" from-card cache hit."); gclog_or_tty->print_cr(" from-card cache hit.");
#endif }
#if COUNT_CACHE
Atomic::inc(&_cache_hits);
#endif
assert(contains_reference(from), "We just added it!"); assert(contains_reference(from), "We just added it!");
return; return;
} else { } else {
@ -623,16 +337,16 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
// If the region is already coarsened, return. // If the region is already coarsened, return.
if (_coarse_map.at(from_hrs_ind)) { if (_coarse_map.at(from_hrs_ind)) {
#if HRRS_VERBOSE if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr(" coarse map hit."); gclog_or_tty->print_cr(" coarse map hit.");
#endif }
assert(contains_reference(from), "We just added it!"); assert(contains_reference(from), "We just added it!");
return; return;
} }
// Otherwise find a per-region table to add it to. // Otherwise find a per-region table to add it to.
size_t ind = from_hrs_ind & _mod_max_fine_entries_mask; 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) { if (prt == NULL) {
MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
// Confirm that it's really not there... // 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)) { _sparse_table.add_card(from_hrs_ind, card_index)) {
if (G1RecordHRRSOops) { if (G1RecordHRRSOops) {
HeapRegionRemSet::record(hr(), from); HeapRegionRemSet::record(hr(), from);
#if HRRS_VERBOSE if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print(" Added card " PTR_FORMAT " to region " gclog_or_tty->print(" Added card " PTR_FORMAT " to region "
"[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n", "[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
align_size_down(uintptr_t(from), align_size_down(uintptr_t(from),
CardTableModRefBS::card_size), CardTableModRefBS::card_size),
hr()->bottom(), from); hr()->bottom(), from);
#endif }
}
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!"); assert(contains_reference_locked(from), "We just added it!");
return; return;
} else { } else {
#if HRRS_VERBOSE if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr(" [tid %d] sparse table entry " gclog_or_tty->print_cr(" [tid %d] sparse table entry "
"overflow(f: %d, t: %d)", "overflow(f: %d, t: %d)",
tid, from_hrs_ind, cur_hrs_ind); tid, from_hrs_ind, cur_hrs_ind);
#endif }
} }
if (_n_fine_entries == _max_fine_entries) { if (_n_fine_entries == _max_fine_entries) {
prt = delete_region_table(); prt = delete_region_table();
} else { } else {
prt = PosParPRT::alloc(from_hr); prt = PerRegionTable::alloc(from_hr);
} }
prt->init(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? prt->set_next(first_prt); // XXX Maybe move to init?
_fine_grain_regions[ind] = prt; _fine_grain_regions[ind] = prt;
_n_fine_entries++; _n_fine_entries++;
@ -704,38 +418,25 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
// OtherRegionsTable for why this is OK. // OtherRegionsTable for why this is OK.
assert(prt != NULL, "Inv"); assert(prt != NULL, "Inv");
if (prt->should_expand(tid)) { prt->add_reference(from);
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);
}
if (G1RecordHRRSOops) { if (G1RecordHRRSOops) {
HeapRegionRemSet::record(hr(), from); HeapRegionRemSet::record(hr(), from);
#if HRRS_VERBOSE if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print("Added card " PTR_FORMAT " to region " gclog_or_tty->print("Added card " PTR_FORMAT " to region "
"[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n", "[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
align_size_down(uintptr_t(from), align_size_down(uintptr_t(from),
CardTableModRefBS::card_size), CardTableModRefBS::card_size),
hr()->bottom(), from); hr()->bottom(), from);
#endif }
} }
assert(contains_reference(from), "We just added it!"); assert(contains_reference(from), "We just added it!");
} }
PosParPRT* PerRegionTable*
OtherRegionsTable::find_region_table(size_t ind, HeapRegion* hr) const { OtherRegionsTable::find_region_table(size_t ind, HeapRegion* hr) const {
assert(0 <= ind && ind < _max_fine_entries, "Preconditions."); 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) { while (prt != NULL && prt->hr() != hr) {
prt = prt->next(); prt = prt->next();
} }
@ -743,32 +444,16 @@ OtherRegionsTable::find_region_table(size_t ind, HeapRegion* hr) const {
return prt; 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; jint OtherRegionsTable::_n_coarsenings = 0;
PosParPRT* OtherRegionsTable::delete_region_table() { PerRegionTable* 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
assert(_m.owned_by_self(), "Precondition"); assert(_m.owned_by_self(), "Precondition");
assert(_n_fine_entries == _max_fine_entries, "Precondition"); assert(_n_fine_entries == _max_fine_entries, "Precondition");
PosParPRT* max = NULL; PerRegionTable* max = NULL;
jint max_occ = 0; jint max_occ = 0;
PosParPRT** max_prev; PerRegionTable** max_prev;
size_t max_ind; size_t max_ind;
#if SAMPLE_FOR_EVICTION
size_t i = _fine_eviction_start; size_t i = _fine_eviction_start;
for (size_t k = 0; k < _fine_eviction_sample_size; k++) { for (size_t k = 0; k < _fine_eviction_sample_size; k++) {
size_t ii = i; size_t ii = i;
@ -778,8 +463,8 @@ PosParPRT* OtherRegionsTable::delete_region_table() {
if (ii == _max_fine_entries) ii = 0; if (ii == _max_fine_entries) ii = 0;
guarantee(ii != i, "We must find one."); guarantee(ii != i, "We must find one.");
} }
PosParPRT** prev = &_fine_grain_regions[ii]; PerRegionTable** prev = &_fine_grain_regions[ii];
PosParPRT* cur = *prev; PerRegionTable* cur = *prev;
while (cur != NULL) { while (cur != NULL) {
jint cur_occ = cur->occupied(); jint cur_occ = cur->occupied();
if (max == NULL || cur_occ > max_occ) { if (max == NULL || cur_occ > max_occ) {
@ -794,64 +479,27 @@ PosParPRT* OtherRegionsTable::delete_region_table() {
i = i + _fine_eviction_stride; i = i + _fine_eviction_stride;
if (i >= _n_fine_entries) i = i - _n_fine_entries; if (i >= _n_fine_entries) i = i - _n_fine_entries;
} }
_fine_eviction_start++; _fine_eviction_start++;
if (_fine_eviction_start >= _n_fine_entries)
if (_fine_eviction_start >= _n_fine_entries) {
_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"); 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. // Set the corresponding coarse bit.
size_t max_hrs_index = (size_t) max->hr()->hrs_index(); size_t max_hrs_index = (size_t) max->hr()->hrs_index();
if (!_coarse_map.at(max_hrs_index)) { if (!_coarse_map.at(max_hrs_index)) {
_coarse_map.at_put(max_hrs_index, true); _coarse_map.at_put(max_hrs_index, true);
_n_coarse_entries++; _n_coarse_entries++;
#if 0 if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print("Coarsened entry in region [" PTR_FORMAT "...] " gclog_or_tty->print("Coarsened entry in region [" PTR_FORMAT "...] "
"for region [" PTR_FORMAT "...] (%d coarse entries).\n", "for region [" PTR_FORMAT "...] (%d coarse entries).\n",
hr()->bottom(), hr()->bottom(),
max->hr()->bottom(), max->hr()->bottom(),
_n_coarse_entries); _n_coarse_entries);
#endif }
} }
// Unsplice. // Unsplice.
@ -883,10 +531,10 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
// Now do the fine-grained maps. // Now do the fine-grained maps.
for (size_t i = 0; i < _max_fine_entries; i++) { for (size_t i = 0; i < _max_fine_entries; i++) {
PosParPRT* cur = _fine_grain_regions[i]; PerRegionTable* cur = _fine_grain_regions[i];
PosParPRT** prev = &_fine_grain_regions[i]; PerRegionTable** prev = &_fine_grain_regions[i];
while (cur != NULL) { while (cur != NULL) {
PosParPRT* nxt = cur->next(); PerRegionTable* nxt = cur->next();
// If the entire region is dead, eliminate. // If the entire region is dead, eliminate.
if (G1RSScrubVerbose) { if (G1RSScrubVerbose) {
gclog_or_tty->print_cr(" For other region %u:", gclog_or_tty->print_cr(" For other region %u:",
@ -899,7 +547,7 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
if (G1RSScrubVerbose) { if (G1RSScrubVerbose) {
gclog_or_tty->print_cr(" deleted via region map."); gclog_or_tty->print_cr(" deleted via region map.");
} }
PosParPRT::free(cur); PerRegionTable::free(cur);
} else { } else {
// Do fine-grain elimination. // Do fine-grain elimination.
if (G1RSScrubVerbose) { if (G1RSScrubVerbose) {
@ -914,7 +562,7 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
*prev = nxt; *prev = nxt;
cur->set_next(NULL); cur->set_next(NULL);
_n_fine_entries--; _n_fine_entries--;
PosParPRT::free(cur); PerRegionTable::free(cur);
} else { } else {
prev = cur->next_addr(); prev = cur->next_addr();
} }
@ -940,7 +588,7 @@ size_t OtherRegionsTable::occupied() const {
size_t OtherRegionsTable::occ_fine() const { size_t OtherRegionsTable::occ_fine() const {
size_t sum = 0; size_t sum = 0;
for (size_t i = 0; i < _max_fine_entries; i++) { 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) { while (cur != NULL) {
sum += cur->occupied(); sum += cur->occupied();
cur = cur->next(); cur = cur->next();
@ -962,13 +610,13 @@ size_t OtherRegionsTable::mem_size() const {
MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag); MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag);
size_t sum = 0; size_t sum = 0;
for (size_t i = 0; i < _max_fine_entries; i++) { 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) { while (cur != NULL) {
sum += cur->mem_size(); sum += cur->mem_size();
cur = cur->next(); cur = cur->next();
} }
} }
sum += (sizeof(PosParPRT*) * _max_fine_entries); sum += (sizeof(PerRegionTable*) * _max_fine_entries);
sum += (_coarse_map.size_in_words() * HeapWordSize); sum += (_coarse_map.size_in_words() * HeapWordSize);
sum += (_sparse_table.mem_size()); sum += (_sparse_table.mem_size());
sum += sizeof(*this) - sizeof(_sparse_table); // Avoid double counting above. 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() { size_t OtherRegionsTable::fl_mem_size() {
return PerRegionTable::fl_mem_size() + PosParPRT::fl_mem_size(); return PerRegionTable::fl_mem_size();
} }
void OtherRegionsTable::clear_fcc() { void OtherRegionsTable::clear_fcc() {
@ -992,10 +640,10 @@ void OtherRegionsTable::clear_fcc() {
void OtherRegionsTable::clear() { void OtherRegionsTable::clear() {
MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag); MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
for (size_t i = 0; i < _max_fine_entries; i++) { 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) { while (cur != NULL) {
PosParPRT* nxt = cur->next(); PerRegionTable* nxt = cur->next();
PosParPRT::free(cur); PerRegionTable::free(cur);
cur = nxt; cur = nxt;
} }
_fine_grain_regions[i] = NULL; _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, bool OtherRegionsTable::del_single_region_table(size_t ind,
HeapRegion* hr) { HeapRegion* hr) {
assert(0 <= ind && ind < _max_fine_entries, "Preconditions."); assert(0 <= ind && ind < _max_fine_entries, "Preconditions.");
PosParPRT** prev_addr = &_fine_grain_regions[ind]; PerRegionTable** prev_addr = &_fine_grain_regions[ind];
PosParPRT* prt = *prev_addr; PerRegionTable* prt = *prev_addr;
while (prt != NULL && prt->hr() != hr) { while (prt != NULL && prt->hr() != hr) {
prev_addr = prt->next_addr(); prev_addr = prt->next_addr();
prt = prt->next(); prt = prt->next();
@ -1044,7 +692,7 @@ bool OtherRegionsTable::del_single_region_table(size_t ind,
if (prt != NULL) { if (prt != NULL) {
assert(prt->hr() == hr, "Loop postcondition."); assert(prt->hr() == hr, "Loop postcondition.");
*prev_addr = prt->next(); *prev_addr = prt->next();
PosParPRT::free(prt); PerRegionTable::free(prt);
_n_fine_entries--; _n_fine_entries--;
return true; return true;
} else { } else {
@ -1065,7 +713,7 @@ bool OtherRegionsTable::contains_reference_locked(OopOrNarrowOopStar from) const
// Is this region in the coarse map? // Is this region in the coarse map?
if (_coarse_map.at(hr_ind)) return true; 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); hr);
if (prt != NULL) { if (prt != NULL) {
return prt->contains_reference(from); return prt->contains_reference(from);
@ -1145,7 +793,7 @@ void HeapRegionRemSet::print() const {
G1CollectedHeap::heap()->bot_shared()->address_for_index(card_index); G1CollectedHeap::heap()->bot_shared()->address_for_index(card_index);
gclog_or_tty->print_cr(" Card " PTR_FORMAT, card_start); gclog_or_tty->print_cr(" Card " PTR_FORMAT, card_start);
} }
// XXX
if (iter.n_yielded() != occupied()) { if (iter.n_yielded() != occupied()) {
gclog_or_tty->print_cr("Yielded disagrees with occupied:"); gclog_or_tty->print_cr("Yielded disagrees with occupied:");
gclog_or_tty->print_cr(" %6d yielded (%6d coarse, %6d fine).", gclog_or_tty->print_cr(" %6d yielded (%6d coarse, %6d fine).",
@ -1163,10 +811,6 @@ void HeapRegionRemSet::cleanup() {
SparsePRT::cleanup_all(); SparsePRT::cleanup_all();
} }
void HeapRegionRemSet::par_cleanup() {
PosParPRT::par_contract_all();
}
void HeapRegionRemSet::clear() { void HeapRegionRemSet::clear() {
_other_regions.clear(); _other_regions.clear();
assert(occupied() == 0, "Should be clear."); assert(occupied() == 0, "Should be clear.");

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -35,7 +35,7 @@ class G1CollectedHeap;
class G1BlockOffsetSharedArray; class G1BlockOffsetSharedArray;
class HeapRegion; class HeapRegion;
class HeapRegionRemSetIterator; class HeapRegionRemSetIterator;
class PosParPRT; class PerRegionTable;
class SparsePRT; class SparsePRT;
// Essentially a wrapper around SparsePRTCleanupTask. See // Essentially a wrapper around SparsePRTCleanupTask. See
@ -79,15 +79,14 @@ class OtherRegionsTable VALUE_OBJ_CLASS_SPEC {
size_t _n_coarse_entries; size_t _n_coarse_entries;
static jint _n_coarsenings; static jint _n_coarsenings;
PosParPRT** _fine_grain_regions; PerRegionTable** _fine_grain_regions;
size_t _n_fine_entries; size_t _n_fine_entries;
#define SAMPLE_FOR_EVICTION 1 // Used to sample a subset of the fine grain PRTs to determine which
#if SAMPLE_FOR_EVICTION // PRT to evict and coarsen.
size_t _fine_eviction_start; size_t _fine_eviction_start;
static size_t _fine_eviction_stride; static size_t _fine_eviction_stride;
static size_t _fine_eviction_sample_size; static size_t _fine_eviction_sample_size;
#endif
SparsePRT _sparse_table; 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 // Requires "prt" to be the first element of the bucket list appropriate
// for "hr". If this list contains an entry for "hr", return it, // for "hr". If this list contains an entry for "hr", return it,
// otherwise return "NULL". // 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 // adding the deleted region to the coarse bitmap. Requires the caller
// to hold _m, and the fine-grain table to be full. // 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 // 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 // be the correct index for "hr"), delete it and return true; else return
// false. // false.
bool del_single_region_table(size_t ind, HeapRegion* hr); 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. // Indexed by thread X heap region, to minimize thread contention.
static int** _from_card_cache; static int** _from_card_cache;
static size_t _from_card_cache_max_regions; static size_t _from_card_cache_max_regions;
@ -127,10 +123,6 @@ public:
// sense. // sense.
void add_reference(OopOrNarrowOopStar from, int tid); 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 // Removes any entries shown by the given bitmaps to contain only dead
// objects. // objects.
void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm); void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm);
@ -233,14 +225,12 @@ public:
static jint n_coarsenings() { return OtherRegionsTable::n_coarsenings(); } static jint n_coarsenings() { return OtherRegionsTable::n_coarsenings(); }
/* Used in the sequential case. Returns "true" iff this addition causes // Used in the sequential case.
the size limit to be reached. */
void add_reference(OopOrNarrowOopStar from) { 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 // Used in the parallel case.
the size limit to be reached. */
void add_reference(OopOrNarrowOopStar from, int tid) { void add_reference(OopOrNarrowOopStar from, int tid) {
_other_regions.add_reference(from, tid); _other_regions.add_reference(from, tid);
} }
@ -253,15 +243,6 @@ public:
// entries for this region in other remsets. // entries for this region in other remsets.
void clear(); 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 // Attempt to claim the region. Returns true iff this call caused an
// atomic transition from Unclaimed to Claimed. // atomic transition from Unclaimed to Claimed.
bool claim_iter(); bool claim_iter();
@ -290,12 +271,6 @@ public:
// Initialize the given iterator to iterate over this rem set. // Initialize the given iterator to iterate over this rem set.
void init_iterator(HeapRegionRemSetIterator* iter) const; 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. // The actual # of bytes this hr_remset takes up.
size_t mem_size() { size_t mem_size() {
return _other_regions.mem_size() return _other_regions.mem_size()
@ -322,10 +297,7 @@ public:
void print() const; void print() const;
// Called during a stop-world phase to perform any deferred cleanups. // 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 cleanup();
static void par_cleanup();
// Declare the heap size (in # of regions) to the HeapRegionRemSet(s). // Declare the heap size (in # of regions) to the HeapRegionRemSet(s).
// (Uses it to initialize from_card_cache). // (Uses it to initialize from_card_cache).
@ -367,7 +339,7 @@ class HeapRegionRemSetIterator : public CHeapObj {
// Local caching of HRRS fields. // Local caching of HRRS fields.
const BitMap* _coarse_map; const BitMap* _coarse_map;
PosParPRT** _fine_grain_regions; PerRegionTable** _fine_grain_regions;
G1BlockOffsetSharedArray* _bosa; G1BlockOffsetSharedArray* _bosa;
G1CollectedHeap* _g1h; G1CollectedHeap* _g1h;
@ -404,8 +376,9 @@ class HeapRegionRemSetIterator : public CHeapObj {
// Index of bucket-list we're working on. // Index of bucket-list we're working on.
int _fine_array_index; int _fine_array_index;
// Per Region Table we're doing within current bucket list. // Per Region Table we're doing within current bucket list.
PosParPRT* _fine_cur_prt; PerRegionTable* _fine_cur_prt;
/* SparsePRT::*/ SparsePRTIter _sparse_iter; /* 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 #endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONREMSET_HPP

View File

@ -62,8 +62,8 @@ public:
// written later, increasing the likelihood that the shared page contain // written later, increasing the likelihood that the shared page contain
// the hash can be shared. // the hash can be shared.
// //
// NOTE THAT the algorithm in StringTable::hash_string() MUST MATCH the // NOTE THAT we have to call java_lang_String::to_hash() to match the
// algorithm in java.lang.String.hashCode(). // algorithm in java.lang.String.toHash().
class StringHashCodeClosure: public OopClosure { class StringHashCodeClosure: public OopClosure {
private: private:
@ -80,7 +80,7 @@ public:
oop obj = *p; oop obj = *p;
if (obj->klass() == SystemDictionary::String_klass() && if (obj->klass() == SystemDictionary::String_klass() &&
java_lang_String::has_hash_field()) { 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); obj->int_field_put(hash_offset, hash);
} }
} }

View File

@ -273,7 +273,7 @@ class Universe: AllStatic {
} }
static klassOop typeArrayKlassObj(BasicType t) { 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"); assert(_typeArrayKlassObjs[t] != NULL, "domain check");
return _typeArrayKlassObjs[t]; return _typeArrayKlassObjs[t];
} }

View File

@ -81,6 +81,13 @@
product(intx, MaxLoopPad, (OptoLoopAlignment-1), \ product(intx, MaxLoopPad, (OptoLoopAlignment-1), \
"Align a loop if padding size in bytes is less or equal to this value") \ "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, \ product(intx, NumberOfLoopInstrToAlign, 4, \
"Number of first instructions in a loop to align") \ "Number of first instructions in a loop to align") \
\ \
@ -292,9 +299,12 @@
develop(bool, SuperWordRTDepCheck, false, \ develop(bool, SuperWordRTDepCheck, false, \
"Enable runtime dependency checks.") \ "Enable runtime dependency checks.") \
\ \
product(bool, TraceSuperWord, false, \ notproduct(bool, TraceSuperWord, false, \
"Trace superword transforms") \ "Trace superword transforms") \
\ \
notproduct(bool, TraceNewVectors, false, \
"Trace creation of Vector nodes") \
\
product_pd(bool, OptoBundling, \ product_pd(bool, OptoBundling, \
"Generate nops to fill i-cache lines") \ "Generate nops to fill i-cache lines") \
\ \

View File

@ -172,9 +172,11 @@ public:
JVMState* DynamicCallGenerator::generate(JVMState* jvms) { JVMState* DynamicCallGenerator::generate(JVMState* jvms) {
GraphKit kit(jvms); GraphKit kit(jvms);
Compile* C = kit.C;
PhaseGVN& gvn = kit.gvn();
if (kit.C->log() != NULL) { if (C->log() != NULL) {
kit.C->log()->elem("dynamic_call bci='%d'", jvms->bci()); C->log()->elem("dynamic_call bci='%d'", jvms->bci());
} }
// Get the constant pool cache from the caller class. // 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); size_t call_site_offset = cpcache->get_f1_offset(index);
// Load the CallSite object from the constant pool cache. // Load the CallSite object from the constant pool cache.
const TypeOopPtr* cpcache_ptr = TypeOopPtr::make_from_constant(cpcache); const TypeOopPtr* cpcache_type = TypeOopPtr::make_from_constant(cpcache); // returns TypeAryPtr of type T_OBJECT
Node* cpcache_adr = kit.makecon(cpcache_ptr); const TypeOopPtr* call_site_type = TypeOopPtr::make_from_klass(C->env()->CallSite_klass());
Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, cpcache_adr, call_site_offset); Node* cpcache_adr = kit.makecon(cpcache_type);
Node* call_site = kit.make_load(kit.control(), call_site_adr, TypeInstPtr::BOTTOM, T_OBJECT, Compile::AliasIdxRaw); 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. // 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()); const TypeOopPtr* target_type = TypeOopPtr::make_from_klass(C->env()->MethodHandle_klass());
Node* target_mh = kit.make_load(kit.control(), target_mh_adr, TypeInstPtr::BOTTOM, T_OBJECT); 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(); 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. // invokedynamic is treated as an optimized invokevirtual.
call->set_optimized_virtual(true); call->set_optimized_virtual(true);
// Take extra care (in the presence of argument motion) not to trash the SP: // 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) { JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) {
GraphKit kit(jvms); GraphKit kit(jvms);
Compile* C = kit.C;
PhaseGVN& gvn = kit.gvn(); PhaseGVN& gvn = kit.gvn();
CompileLog* log = kit.C->log(); CompileLog* log = C->log();
if (log != NULL) { if (log != NULL) {
log->elem("predicted_dynamic_call bci='%d'", jvms->bci()); log->elem("predicted_dynamic_call bci='%d'", jvms->bci());
} }
@ -803,8 +809,8 @@ JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) {
Node* receiver = kit.argument(0); Node* receiver = kit.argument(0);
// Check if the MethodHandle is the expected one // Check if the MethodHandle is the expected one
Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(receiver, predicted_mh)); Node* cmp = gvn.transform(new (C, 3) CmpPNode(receiver, predicted_mh));
bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) ); bol = gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::eq) );
} else { } else {
// Get the constant pool cache from the caller class. // Get the constant pool cache from the caller class.
ciMethod* caller_method = jvms->method(); ciMethod* caller_method = jvms->method();
@ -818,22 +824,25 @@ JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) {
size_t call_site_offset = cpcache->get_f1_offset(index); size_t call_site_offset = cpcache->get_f1_offset(index);
// Load the CallSite object from the constant pool cache. // Load the CallSite object from the constant pool cache.
const TypeOopPtr* cpcache_ptr = TypeOopPtr::make_from_constant(cpcache); const TypeOopPtr* cpcache_type = TypeOopPtr::make_from_constant(cpcache); // returns TypeAryPtr of type T_OBJECT
Node* cpcache_adr = kit.makecon(cpcache_ptr); const TypeOopPtr* call_site_type = TypeOopPtr::make_from_klass(C->env()->CallSite_klass());
Node* call_site_adr = kit.basic_plus_adr(cpcache_adr, cpcache_adr, call_site_offset); Node* cpcache_adr = kit.makecon(cpcache_type);
Node* call_site = kit.make_load(kit.control(), call_site_adr, TypeInstPtr::BOTTOM, T_OBJECT, Compile::AliasIdxRaw); 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. // 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_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. // Check if the MethodHandle is still the same.
Node* cmp = gvn.transform(new(kit.C, 3) CmpPNode(target_mh, predicted_mh)); Node* cmp = gvn.transform(new (C, 3) CmpPNode(target_mh, predicted_mh));
bol = gvn.transform(new(kit.C, 2) BoolNode(cmp, BoolTest::eq) ); bol = gvn.transform(new (C, 2) BoolNode(cmp, BoolTest::eq) );
} }
IfNode* iff = kit.create_and_xform_if(kit.control(), bol, _hit_prob, COUNT_UNKNOWN); 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))); kit.set_control( gvn.transform(new (C, 1) IfTrueNode (iff)));
Node* slow_ctl = gvn.transform(new(kit.C, 1) IfFalseNode(iff)); Node* slow_ctl = gvn.transform(new (C, 1) IfFalseNode(iff));
SafePointNode* slow_map = NULL; SafePointNode* slow_map = NULL;
JVMState* slow_jvms; JVMState* slow_jvms;
@ -882,7 +891,7 @@ JVMState* PredictedDynamicCallGenerator::generate(JVMState* jvms) {
// Finish the diamond. // Finish the diamond.
kit.C->set_has_split_ifs(true); // Has chance for split-if optimization 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(1, kit.control());
region->init_req(2, slow_map->control()); region->init_req(2, slow_map->control());
kit.set_control(gvn.transform(region)); kit.set_control(gvn.transform(region));

View File

@ -75,6 +75,7 @@ void LRG::dump( ) const {
// Flags // Flags
if( _is_oop ) tty->print("Oop "); if( _is_oop ) tty->print("Oop ");
if( _is_float ) tty->print("Float "); if( _is_float ) tty->print("Float ");
if( _is_vector ) tty->print("Vector ");
if( _was_spilled1 ) tty->print("Spilled "); if( _was_spilled1 ) tty->print("Spilled ");
if( _was_spilled2 ) tty->print("Spilled2 "); if( _was_spilled2 ) tty->print("Spilled2 ");
if( _direct_conflict ) tty->print("Direct_conflict "); 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. // Move important info out of the live_arena to longer lasting storage.
alloc_node_regs(_names.Size()); alloc_node_regs(_names.Size());
for( uint i=0; i < _names.Size(); i++ ) { for (uint i=0; i < _names.Size(); i++) {
if( _names[i] ) { // Live range associated with Node? if (_names[i]) { // Live range associated with Node?
LRG &lrg = lrgs( _names[i] ); LRG &lrg = lrgs(_names[i]);
if( lrg.num_regs() == 1 ) { if (!lrg.alive()) {
_node_regs[i].set1( lrg.reg() ); _node_regs[i].set_bad();
} else if (lrg.num_regs() == 1) {
_node_regs[i].set1(lrg.reg());
} else { // Must be a register-pair } 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. // Live ranges record the highest register in their mask.
// We want the low register for the AD file writer's convenience. // 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 } else { // Misaligned; extract 2 bits
OptoReg::Name hi = lrg.reg(); // Get hi register OptoReg::Name hi = lrg.reg(); // Get hi register
lrg.Remove(hi); // Yank from mask 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 // Check for float-vs-int live range (used in register-pressure
// calculations) // calculations)
const Type *n_type = n->bottom_type(); const Type *n_type = n->bottom_type();
if( n_type->is_floatingpoint() ) if (n_type->is_floatingpoint())
lrg._is_float = 1; lrg._is_float = 1;
// Check for twice prior spilling. Once prior spilling might have // 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 // Limit result register mask to acceptable registers
const RegMask &rm = n->out_RegMask(); const RegMask &rm = n->out_RegMask();
lrg.AND( rm ); 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(); int ireg = n->ideal_reg();
assert( !n->bottom_type()->isa_oop_ptr() || ireg == Op_RegP, assert( !n->bottom_type()->isa_oop_ptr() || ireg == Op_RegP,
"oops must be in Op_RegP's" ); "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 oop-iness, or long/double
// Check for multi-kill projection // Check for multi-kill projection
switch( ireg ) { switch( ireg ) {
@ -689,7 +702,7 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) {
// AND changes how we count interferences. A mis-aligned // AND changes how we count interferences. A mis-aligned
// double can interfere with TWO aligned pairs, or effectively // double can interfere with TWO aligned pairs, or effectively
// FOUR registers! // FOUR registers!
if( rm.is_misaligned_Pair() ) { if (rm.is_misaligned_pair()) {
lrg._fat_proj = 1; lrg._fat_proj = 1;
lrg._is_bound = 1; lrg._is_bound = 1;
} }
@ -706,6 +719,33 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) {
lrg.set_reg_pressure(1); lrg.set_reg_pressure(1);
#endif #endif
break; 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: default:
ShouldNotReachHere(); ShouldNotReachHere();
} }
@ -763,24 +803,38 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) {
} else { } else {
lrg.AND( rm ); lrg.AND( rm );
} }
// Check for bound register masks // Check for bound register masks
const RegMask &lrgmask = lrg.mask(); 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; lrg._is_bound = 1;
// If this use of a double forces a mis-aligned double, // If this use of a double forces a mis-aligned double,
// flag as '_fat_proj' - really flag as allowing misalignment // flag as '_fat_proj' - really flag as allowing misalignment
// AND changes how we count interferences. A mis-aligned // AND changes how we count interferences. A mis-aligned
// double can interfere with TWO aligned pairs, or effectively // double can interfere with TWO aligned pairs, or effectively
// FOUR registers! // 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._fat_proj = 1;
lrg._is_bound = 1; lrg._is_bound = 1;
} }
// if the LRG is an unaligned pair, we will have to spill // 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 // so clear the LRG's register mask if it is not already spilled
if ( !n->is_SpillCopy() && if (!is_vect && !n->is_SpillCopy() &&
(lrg._def == NULL || lrg.is_multidef() || !lrg._def->is_SpillCopy()) && (lrg._def == NULL || lrg.is_multidef() || !lrg._def->is_SpillCopy()) &&
lrgmask.is_misaligned_Pair()) { lrgmask.is_misaligned_pair()) {
lrg.Clear(); lrg.Clear();
} }
@ -793,12 +847,14 @@ void PhaseChaitin::gather_lrg_masks( bool after_aggressive ) {
} // end for all blocks } // end for all blocks
// Final per-liverange setup // Final per-liverange setup
for( uint i2=0; i2<_maxlrg; i2++ ) { for (uint i2=0; i2<_maxlrg; i2++) {
LRG &lrg = lrgs(i2); LRG &lrg = lrgs(i2);
if( lrg.num_regs() == 2 && !lrg._fat_proj ) assert(!lrg._is_vector || !lrg._fat_proj, "sanity");
lrg.ClearToPairs(); if (lrg.num_regs() > 1 && !lrg._fat_proj) {
lrg.clear_to_sets();
}
lrg.compute_set_mask_size(); 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.set_reg(OptoReg::Name(LRG::SPILL_REG));
lrg._direct_conflict = 1; 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 // Choose a color which is legal for him
RegMask tempmask = lrg.mask(); RegMask tempmask = lrg.mask();
tempmask.AND(lrgs(copy_lrg).mask()); tempmask.AND(lrgs(copy_lrg).mask());
OptoReg::Name reg; tempmask.clear_to_sets(lrg.num_regs());
if( lrg.num_regs() == 1 ) { OptoReg::Name reg = tempmask.find_first_set(lrg.num_regs());
reg = tempmask.find_first_elem(); if (OptoReg::is_valid(reg))
} else {
tempmask.ClearToPairs();
reg = tempmask.find_first_pair();
}
if( OptoReg::is_valid(reg) )
return reg; return reg;
} }
} }
// If no bias info exists, just go with the register selection ordering // If no bias info exists, just go with the register selection ordering
if( lrg.num_regs() == 2 ) { if (lrg._is_vector || lrg.num_regs() == 2) {
// Find an aligned pair // Find an aligned set
return OptoReg::add(lrg.mask().find_first_pair(),chunk); return OptoReg::add(lrg.mask().find_first_set(lrg.num_regs()),chunk);
} }
// CNC - Fun hack. Alternate 1st and 2nd selection. Enables post-allocate // 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 // Use a heuristic to "bias" the color choice
return bias_color(lrg, chunk); 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" ); assert( lrg.num_regs() >= 2, "dead live ranges do not color" );
// Fat-proj case or misaligned double argument. // 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"); //assert(is_allstack == lrg->mask().is_AllStack(), "nbrs must not change AllStackedness");
// Aligned pairs need aligned masks // Aligned pairs need aligned masks
if( lrg->num_regs() == 2 && !lrg->_fat_proj ) assert(!lrg->_is_vector || !lrg->_fat_proj, "sanity");
lrg->ClearToPairs(); if (lrg->num_regs() > 1 && !lrg->_fat_proj) {
lrg->clear_to_sets();
}
// Check if a color is available and if so pick the color // Check if a color is available and if so pick the color
OptoReg::Name reg = choose_color( *lrg, chunk ); OptoReg::Name reg = choose_color( *lrg, chunk );
#ifdef SPARC #ifdef SPARC
debug_only(lrg->compute_set_mask_size()); 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 #endif
//--------------- //---------------
@ -1277,17 +1331,16 @@ uint PhaseChaitin::Select( ) {
// If the live range is not bound, then we actually had some choices // 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 // to make. In this case, the mask has more bits in it than the colors
// chosen. Restrict the mask to just what was picked. // 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->Clear(); // Clear the mask
lrg->Insert(reg); // Set regmask to match selected reg lrg->Insert(reg); // Set regmask to match selected reg
lrg->set_mask_size(1); // For vectors and pairs, also insert the low bit of the pair
} else if( !lrg->_fat_proj ) { for (int i = 1; i < n_regs; i++)
// For pairs, also insert the low bit of the pair lrg->Insert(OptoReg::add(reg,-i));
assert( lrg->num_regs() == 2, "unbound fatproj???" ); lrg->set_mask_size(n_regs);
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);
} else { // Else fatproj } else { // Else fatproj
// mask must be equal to fatproj bits, by definition // 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 // Check for AddP-related opcodes
if( !derived->is_Phi() ) { 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); Node *base = derived->in(AddPNode::Base);
derived_base_map[derived->_idx] = base; derived_base_map[derived->_idx] = base;
return 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 sprintf(buf,"L%d",lidx); // No register binding yet
} else if( !lidx ) { // Special, not allocated value } else if( !lidx ) { // Special, not allocated value
strcpy(buf,"Special"); strcpy(buf,"Special");
} else if( (lrgs(lidx).num_regs() == 1) } else {
? !lrgs(lidx).mask().is_bound1() if (lrgs(lidx)._is_vector) {
: !lrgs(lidx).mask().is_bound2() ) { if (lrgs(lidx).mask().is_bound_set(lrgs(lidx).num_regs()))
sprintf(buf,"L%d",lidx); // No register binding yet print_reg( lrgs(lidx).reg(), this, buf ); // a bound machine register
} else { // Hah! We have a bound machine register else
print_reg( lrgs(lidx).reg(), this, buf ); 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); return buf+strlen(buf);

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -99,8 +99,15 @@ public:
void set_mask_size( int size ) { void set_mask_size( int size ) {
assert((size == 65535) || (size == (int)_mask.Size()), ""); assert((size == 65535) || (size == (int)_mask.Size()), "");
_mask_size = size; _mask_size = size;
debug_only(_msize_valid=1;) #ifdef ASSERT
debug_only( if( _num_regs == 2 && !_fat_proj ) _mask.VerifyPairs(); ) _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()); } void compute_set_mask_size() { set_mask_size(compute_mask_size()); }
int mask_size() const { assert( _msize_valid, "mask size not valid" ); 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 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 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 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 // Number of registers this live range uses when it colors
private: private:
@ -150,6 +158,7 @@ public:
uint _is_oop:1, // Live-range holds an oop uint _is_oop:1, // Live-range holds an oop
_is_float:1, // True if in float registers _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_spilled1:1, // True if prior spilling on def
_was_spilled2:1, // True if twice prior spilling on def _was_spilled2:1, // True if twice prior spilling on def
_is_bound:1, // live range starts life with no _is_bound:1, // live range starts life with no

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -245,14 +245,12 @@ macro(XorI)
macro(XorL) macro(XorL)
macro(Vector) macro(Vector)
macro(AddVB) macro(AddVB)
macro(AddVC)
macro(AddVS) macro(AddVS)
macro(AddVI) macro(AddVI)
macro(AddVL) macro(AddVL)
macro(AddVF) macro(AddVF)
macro(AddVD) macro(AddVD)
macro(SubVB) macro(SubVB)
macro(SubVC)
macro(SubVS) macro(SubVS)
macro(SubVI) macro(SubVI)
macro(SubVL) macro(SubVL)
@ -263,74 +261,36 @@ macro(MulVD)
macro(DivVF) macro(DivVF)
macro(DivVD) macro(DivVD)
macro(LShiftVB) macro(LShiftVB)
macro(LShiftVC)
macro(LShiftVS) macro(LShiftVS)
macro(LShiftVI) macro(LShiftVI)
macro(URShiftVB) macro(RShiftVB)
macro(URShiftVC) macro(RShiftVS)
macro(URShiftVS) macro(RShiftVI)
macro(URShiftVI)
macro(AndV) macro(AndV)
macro(OrV) macro(OrV)
macro(XorV) macro(XorV)
macro(VectorLoad) macro(LoadVector)
macro(Load16B) macro(StoreVector)
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(Pack) macro(Pack)
macro(PackB) macro(PackB)
macro(PackS) macro(PackS)
macro(PackC)
macro(PackI) macro(PackI)
macro(PackL) macro(PackL)
macro(PackF) macro(PackF)
macro(PackD) macro(PackD)
macro(Pack2x1B) macro(Pack2L)
macro(Pack2x2B) macro(Pack2D)
macro(Replicate16B) macro(ReplicateB)
macro(Replicate8B) macro(ReplicateS)
macro(Replicate4B) macro(ReplicateI)
macro(Replicate8S) macro(ReplicateL)
macro(Replicate4S) macro(ReplicateF)
macro(Replicate2S) macro(ReplicateD)
macro(Replicate8C)
macro(Replicate4C)
macro(Replicate2C)
macro(Replicate4I)
macro(Replicate2I)
macro(Replicate2L)
macro(Replicate4F)
macro(Replicate2F)
macro(Replicate2D)
macro(Extract) macro(Extract)
macro(ExtractB) macro(ExtractB)
macro(ExtractS) macro(ExtractUB)
macro(ExtractC) macro(ExtractC)
macro(ExtractS)
macro(ExtractI) macro(ExtractI)
macro(ExtractL) macro(ExtractL)
macro(ExtractF) macro(ExtractF)

View File

@ -2591,38 +2591,12 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc ) {
} }
break; break;
case Op_Load16B: case Op_LoadVector:
case Op_Load8B: case Op_StoreVector:
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:
break; break;
case Op_PackB: case Op_PackB:
case Op_PackS: case Op_PackS:
case Op_PackC:
case Op_PackI: case Op_PackI:
case Op_PackF: case Op_PackF:
case Op_PackL: case Op_PackL:

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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() && if( lrgs(lidx).mask().is_UP() &&
lrgs(lidx).mask_size() && lrgs(lidx).mask_size() &&
!lrgs(lidx)._is_float && !lrgs(lidx)._is_float &&
!lrgs(lidx)._is_vector &&
lrgs(lidx).mask().overlap(*Matcher::idealreg2regmask[Op_RegI]) ) lrgs(lidx).mask().overlap(*Matcher::idealreg2regmask[Op_RegI]) )
cnt += lrgs(lidx).reg_pressure(); cnt += lrgs(lidx).reg_pressure();
} }
@ -430,7 +431,7 @@ uint PhaseChaitin::count_float_pressure( IndexSet *liveout ) {
while ((lidx = elements.next()) != 0) { while ((lidx = elements.next()) != 0) {
if( lrgs(lidx).mask().is_UP() && if( lrgs(lidx).mask().is_UP() &&
lrgs(lidx).mask_size() && lrgs(lidx).mask_size() &&
lrgs(lidx)._is_float ) (lrgs(lidx)._is_float || lrgs(lidx)._is_vector))
cnt += lrgs(lidx).reg_pressure(); cnt += lrgs(lidx).reg_pressure();
} }
return cnt; return cnt;
@ -439,8 +440,8 @@ uint PhaseChaitin::count_float_pressure( IndexSet *liveout ) {
//------------------------------lower_pressure--------------------------------- //------------------------------lower_pressure---------------------------------
// Adjust register pressure down by 1. Capture last hi-to-low transition, // 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 ) { 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->mask().is_UP() && lrg->mask_size()) {
if( lrg->_is_float ) { if (lrg->_is_float || lrg->_is_vector) {
pressure[1] -= lrg->reg_pressure(); pressure[1] -= lrg->reg_pressure();
if( pressure[1] == (uint)FLOATPRESSURE ) { if( pressure[1] == (uint)FLOATPRESSURE ) {
hrp_index[1] = where; hrp_index[1] = where;
@ -522,8 +523,8 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) {
LRG &lrg = lrgs(lidx); LRG &lrg = lrgs(lidx);
lrg._area += cost; lrg._area += cost;
// Compute initial register pressure // Compute initial register pressure
if( lrg.mask().is_UP() && lrg.mask_size() ) { if (lrg.mask().is_UP() && lrg.mask_size()) {
if( lrg._is_float ) { // Count float pressure if (lrg._is_float || lrg._is_vector) { // Count float pressure
pressure[1] += lrg.reg_pressure(); pressure[1] += lrg.reg_pressure();
#ifdef EXACT_PRESSURE #ifdef EXACT_PRESSURE
if( pressure[1] > b->_freg_pressure ) if( pressure[1] > b->_freg_pressure )
@ -681,13 +682,10 @@ uint PhaseChaitin::build_ifg_physical( ResourceArea *a ) {
// according to its bindings. // according to its bindings.
const RegMask &rmask = lrgs(r).mask(); const RegMask &rmask = lrgs(r).mask();
if( lrgs(r).is_bound() && !(n->rematerialize()) && rmask.is_NotEmpty() ) { 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 // Check for common case
int r_size = lrgs(r).num_regs(); int r_size = lrgs(r).num_regs();
OptoReg::Name r_reg = (r_size == 1) ? rmask.find_first_elem() : OptoReg::Physical; OptoReg::Name r_reg = (r_size == 1) ? rmask.find_first_elem() : OptoReg::Physical;
// Smear odd bits
IndexSetIterator elements(&liveout); IndexSetIterator elements(&liveout);
uint l; uint l;
while ((l = elements.next()) != 0) { 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 // Remove the bits from LRG 'r' from LRG 'l' so 'l' no
// longer interferes with 'r'. If 'l' requires aligned // longer interferes with 'r'. If 'l' requires aligned
// adjacent pairs, subtract out bit pairs. // 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.SUBTRACT( r2mask );
lrg.compute_set_mask_size(); lrg.compute_set_mask_size();
} else if( r_size != 1 ) { } else if( r_size != 1 ) { // fat proj
lrg.SUBTRACT( rmask ); lrg.SUBTRACT( rmask );
lrg.compute_set_mask_size(); lrg.compute_set_mask_size();
} else { // Common case: size 1 bound removal } 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 // Newly live things assumed live from here to top of block
lrg._area += cost; lrg._area += cost;
// Adjust register pressure // Adjust register pressure
if( lrg.mask().is_UP() && lrg.mask_size() ) { if (lrg.mask().is_UP() && lrg.mask_size()) {
if( lrg._is_float ) { if (lrg._is_float || lrg._is_vector) {
pressure[1] += lrg.reg_pressure(); pressure[1] += lrg.reg_pressure();
#ifdef EXACT_PRESSURE #ifdef EXACT_PRESSURE
if( pressure[1] > b->_freg_pressure ) if( pressure[1] > b->_freg_pressure )

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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(); int iop = mach->ideal_Opcode();
switch( iop ) { switch( iop ) {
case Op_LoadB: case Op_LoadB:
case Op_LoadUB:
case Op_LoadUS: case Op_LoadUS:
case Op_LoadD: case Op_LoadD:
case Op_LoadF: 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 ) if( e->is_MachNullCheck() && e->in(1) == n )
continue; 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; uint n_choice = 2;
// See if this instruction is consumed by a branch. If so, then (as the // See if this instruction is consumed by a branch. If so, then (as the

View File

@ -3592,8 +3592,10 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) {
} }
// Bail out if length is negative. // Bail out if length is negative.
// ...Not needed, since the new_array will throw the right exception. // Without this the new_array would throw
//generate_negative_guard(length, bailout, &length); // NegativeArraySizeException but IllegalArgumentException is what
// should be thrown
generate_negative_guard(length, bailout, &length);
if (bailout->req() > 1) { if (bailout->req() > 1) {
PreserveJVMState pjvms(this); PreserveJVMState pjvms(this);
@ -3617,7 +3619,9 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) {
// Extreme case: Arrays.copyOf((Integer[])x, 10, String[].class). // Extreme case: Arrays.copyOf((Integer[])x, 10, String[].class).
// This will fail a store-check if x contains any non-nulls. // This will fail a store-check if x contains any non-nulls.
bool disjoint_bases = true; 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, generate_arraycopy(TypeAryPtr::OOPS, T_OBJECT,
original, start, newcopy, intcon(0), moved, original, start, newcopy, intcon(0), moved,
disjoint_bases, length_never_negative); disjoint_bases, length_never_negative);

View File

@ -2751,7 +2751,8 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
// Do not count uncommon calls // Do not count uncommon calls
if( !n->is_CallStaticJava() || !n->as_CallStaticJava()->_name ) { if( !n->is_CallStaticJava() || !n->as_CallStaticJava()->_name ) {
Node *iff = n->in(0)->in(0); 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 && (n->in(0)->Opcode() == Op_IfFalse &&
(1.0 - iff->as_If()->_prob) >= 0.01) || (1.0 - iff->as_If()->_prob) >= 0.01) ||
(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_ModF:
case Op_ModD: case Op_ModD:
case Op_LoadB: // Same with Loads; they can sink 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_LoadD:
case Op_LoadF: case Op_LoadF:
case Op_LoadI: case Op_LoadI:

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 // Don't remateralize somebody with bound inputs - it stretches a
// fixed register lifetime. // fixed register lifetime.
uint idx = oper_input_base(); uint idx = oper_input_base();
if( req() > idx ) { if (req() > idx) {
const RegMask &rm = in_RegMask(idx); const RegMask &rm = in_RegMask(idx);
if( rm.is_bound1() || rm.is_bound2() ) if (rm.is_bound(ideal_reg()))
return false; return false;
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -319,6 +319,7 @@ public:
class MachTypeNode : public MachNode { class MachTypeNode : public MachNode {
virtual uint size_of() const { return sizeof(*this); } // Size is bigger virtual uint size_of() const { return sizeof(*this); } // Size is bigger
public: public:
MachTypeNode( ) {}
const Type *_bottom_type; const Type *_bottom_type;
virtual const class Type *bottom_type() const { return _bottom_type; } virtual const class Type *bottom_type() const { return _bottom_type; }
@ -370,12 +371,12 @@ public:
//------------------------------MachConstantNode------------------------------- //------------------------------MachConstantNode-------------------------------
// Machine node that holds a constant which is stored in the constant table. // Machine node that holds a constant which is stored in the constant table.
class MachConstantNode : public MachNode { class MachConstantNode : public MachTypeNode {
protected: protected:
Compile::Constant _constant; // This node's constant. Compile::Constant _constant; // This node's constant.
public: public:
MachConstantNode() : MachNode() { MachConstantNode() : MachTypeNode() {
init_class_id(Class_MachConstant); init_class_id(Class_MachConstant);
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -35,6 +35,7 @@
#include "opto/rootnode.hpp" #include "opto/rootnode.hpp"
#include "opto/runtime.hpp" #include "opto/runtime.hpp"
#include "opto/type.hpp" #include "opto/type.hpp"
#include "opto/vectornode.hpp"
#include "runtime/atomic.hpp" #include "runtime/atomic.hpp"
#include "runtime/os.hpp" #include "runtime/os.hpp"
#ifdef TARGET_ARCH_MODEL_x86_32 #ifdef TARGET_ARCH_MODEL_x86_32
@ -58,18 +59,6 @@
OptoReg::Name OptoReg::c_frame_pointer; 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]; const RegMask *Matcher::idealreg2regmask[_last_machine_leaf];
RegMask Matcher::mreg2regmask[_last_Mach_Reg]; RegMask Matcher::mreg2regmask[_last_Mach_Reg];
RegMask Matcher::STACK_ONLY_mask; RegMask Matcher::STACK_ONLY_mask;
@ -107,6 +96,10 @@ Matcher::Matcher( Node_List &proj_list ) :
idealreg2spillmask [Op_RegF] = NULL; idealreg2spillmask [Op_RegF] = NULL;
idealreg2spillmask [Op_RegD] = NULL; idealreg2spillmask [Op_RegD] = NULL;
idealreg2spillmask [Op_RegP] = 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_RegI] = NULL;
idealreg2debugmask [Op_RegN] = NULL; idealreg2debugmask [Op_RegN] = NULL;
@ -114,6 +107,10 @@ Matcher::Matcher( Node_List &proj_list ) :
idealreg2debugmask [Op_RegF] = NULL; idealreg2debugmask [Op_RegF] = NULL;
idealreg2debugmask [Op_RegD] = NULL; idealreg2debugmask [Op_RegD] = NULL;
idealreg2debugmask [Op_RegP] = 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_RegI] = NULL;
idealreg2mhdebugmask[Op_RegN] = NULL; idealreg2mhdebugmask[Op_RegN] = NULL;
@ -121,6 +118,10 @@ Matcher::Matcher( Node_List &proj_list ) :
idealreg2mhdebugmask[Op_RegF] = NULL; idealreg2mhdebugmask[Op_RegF] = NULL;
idealreg2mhdebugmask[Op_RegD] = NULL; idealreg2mhdebugmask[Op_RegD] = NULL;
idealreg2mhdebugmask[Op_RegP] = 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 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()); warped = OptoReg::add(warped, C->out_preserve_stack_slots());
if( warped >= _in_arg_limit ) if( warped >= _in_arg_limit )
_in_arg_limit = OptoReg::add(warped, 1); // Bump max stack slot seen _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 // the compiler cannot represent this method's calling sequence
C->record_method_not_compilable_all_tiers("unsupported incoming calling sequence"); C->record_method_not_compilable_all_tiers("unsupported incoming calling sequence");
return OptoReg::Bad; return OptoReg::Bad;
@ -302,7 +303,7 @@ void Matcher::match( ) {
_out_arg_limit = OptoReg::add(_new_SP, C->out_preserve_stack_slots()); _out_arg_limit = OptoReg::add(_new_SP, C->out_preserve_stack_slots());
assert( is_even(_out_arg_limit), "out_preserve must be even" ); 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 // 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"); 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() { void Matcher::init_first_stack_mask() {
// Allocate storage for spill masks as masks for the appropriate load type. // 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_RegN] = &rms[0];
idealreg2spillmask [Op_RegI] = &rms[1]; idealreg2spillmask [Op_RegI] = &rms[1];
@ -451,6 +452,11 @@ void Matcher::init_first_stack_mask() {
idealreg2mhdebugmask[Op_RegD] = &rms[16]; idealreg2mhdebugmask[Op_RegD] = &rms[16];
idealreg2mhdebugmask[Op_RegP] = &rms[17]; 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; OptoReg::Name i;
// At first, start with the empty mask // At first, start with the empty mask
@ -462,7 +468,7 @@ void Matcher::init_first_stack_mask() {
C->FIRST_STACK_mask().Insert(i); C->FIRST_STACK_mask().Insert(i);
// Add in all bits past the outgoing argument area // 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"); "must be able to represent all call arguments in reg mask");
init = _out_arg_limit; init = _out_arg_limit;
for (i = init; RegMask::can_represent(i); i = OptoReg::add(i,1)) 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(); C->FIRST_STACK_mask().set_AllStack();
// Make spill masks. Registers for their class, plus FIRST_STACK_mask. // 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 #ifdef _LP64
*idealreg2spillmask[Op_RegN] = *idealreg2regmask[Op_RegN]; *idealreg2spillmask[Op_RegN] = *idealreg2regmask[Op_RegN];
idealreg2spillmask[Op_RegN]->OR(C->FIRST_STACK_mask()); 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 #endif
*idealreg2spillmask[Op_RegI] = *idealreg2regmask[Op_RegI]; *idealreg2spillmask[Op_RegI] = *idealreg2regmask[Op_RegI];
idealreg2spillmask[Op_RegI]->OR(C->FIRST_STACK_mask()); idealreg2spillmask[Op_RegI]->OR(C->FIRST_STACK_mask());
*idealreg2spillmask[Op_RegL] = *idealreg2regmask[Op_RegL]; *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] = *idealreg2regmask[Op_RegF];
idealreg2spillmask[Op_RegF]->OR(C->FIRST_STACK_mask()); idealreg2spillmask[Op_RegF]->OR(C->FIRST_STACK_mask());
*idealreg2spillmask[Op_RegD] = *idealreg2regmask[Op_RegD]; *idealreg2spillmask[Op_RegD] = *idealreg2regmask[Op_RegD];
idealreg2spillmask[Op_RegD]->OR(C->FIRST_STACK_mask()); idealreg2spillmask[Op_RegD]->OR(aligned_stack_mask);
*idealreg2spillmask[Op_RegP] = *idealreg2regmask[Op_RegP];
idealreg2spillmask[Op_RegP]->OR(C->FIRST_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) { if (UseFPUForSpilling) {
// This mask logic assumes that the spill operations are // This mask logic assumes that the spill operations are
// symmetric and that the registers involved are the same size. // 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_RegF] = &spillF->out_RegMask();
idealreg2regmask[Op_RegD] = &spillD->out_RegMask(); idealreg2regmask[Op_RegD] = &spillD->out_RegMask();
idealreg2regmask[Op_RegP] = &spillP->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 #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. // that is killed by the call.
if( warped >= out_arg_limit_per_call ) if( warped >= out_arg_limit_per_call )
out_arg_limit_per_call = OptoReg::add(warped,1); 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"); C->record_method_not_compilable_all_tiers("unsupported calling sequence");
return OptoReg::Bad; return OptoReg::Bad;
} }
@ -1251,7 +1303,7 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) {
// this killed area. // this killed area.
uint r_cnt = mcall->tf()->range()->cnt(); uint r_cnt = mcall->tf()->range()->cnt();
MachProjNode *proj = new (C, 1) MachProjNode( mcall, r_cnt+10000, RegMask::Empty, MachProjNode::fat_proj ); 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"); C->record_method_not_compilable_all_tiers("unsupported outgoing calling sequence");
} else { } else {
for (int i = begin_out_arg_area; i < out_arg_limit_per_call; i++) for (int i = begin_out_arg_area; i < out_arg_limit_per_call; i++)

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -250,10 +250,21 @@ public:
static const bool convL2FSupported(void); static const bool convL2FSupported(void);
// Vector width in bytes // 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 // 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.) // Used to determine a "low complexity" 64-bit constant. (Zero is simple.)
// The standard of comparison is one (StoreL ConL) vs. two (StoreI ConI). // The standard of comparison is one (StoreL ConL) vs. two (StoreI ConI).

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 // had an original form like p1:(AddP x x (LShiftL quux 3)), where the
// expression (LShiftL quux 3) independently optimized to the constant 8. // expression (LShiftL quux 3) independently optimized to the constant 8.
if ((t->isa_int() == NULL) && (t->isa_long() == NULL) if ((t->isa_int() == NULL) && (t->isa_long() == NULL)
&& (_type->isa_vect() == NULL)
&& Opcode() != Op_LoadKlass && Opcode() != Op_LoadNKlass) { && Opcode() != Op_LoadKlass && Opcode() != Op_LoadNKlass) {
// t might actually be lower than _type, if _type is a unique // t might actually be lower than _type, if _type is a unique
// concrete subclass of abstract class t. // concrete subclass of abstract class t.

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -41,7 +41,9 @@ class PhaseTransform;
class MulNode : public Node { class MulNode : public Node {
virtual uint hash() const; virtual uint hash() const;
public: 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 // 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. // we are equivalent to. We look for "add of zero" as an identity.

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -1576,6 +1576,9 @@ void Node::dump() const {
} else { } else {
tty->print("no type"); tty->print("no type");
} }
} else if (t->isa_vect() && this->is_MachSpillCopy()) {
// Dump MachSpillcopy vector type.
t->dump();
} }
if (is_new) { if (is_new) {
debug_only(dump_orig(debug_orig())); debug_only(dump_orig(debug_orig()));

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -100,6 +100,7 @@ class MemBarNode;
class MemBarStoreStoreNode; class MemBarStoreStoreNode;
class MemNode; class MemNode;
class MergeMemNode; class MergeMemNode;
class MulNode;
class MultiNode; class MultiNode;
class MultiBranchNode; class MultiBranchNode;
class NeverBranchNode; class NeverBranchNode;
@ -133,8 +134,8 @@ class Type;
class TypeNode; class TypeNode;
class UnlockNode; class UnlockNode;
class VectorNode; class VectorNode;
class VectorLoadNode; class LoadVectorNode;
class VectorStoreNode; class StoreVectorNode;
class VectorSet; class VectorSet;
typedef void (*NFunc)(Node&,void*); typedef void (*NFunc)(Node&,void*);
extern "C" { extern "C" {
@ -609,9 +610,9 @@ public:
DEFINE_CLASS_ID(Mem, Node, 4) DEFINE_CLASS_ID(Mem, Node, 4)
DEFINE_CLASS_ID(Load, Mem, 0) 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(Store, Mem, 1)
DEFINE_CLASS_ID(VectorStore, Store, 0) DEFINE_CLASS_ID(StoreVector, Store, 0)
DEFINE_CLASS_ID(LoadStore, Mem, 2) DEFINE_CLASS_ID(LoadStore, Mem, 2)
DEFINE_CLASS_ID(Region, Node, 5) DEFINE_CLASS_ID(Region, Node, 5)
@ -629,8 +630,9 @@ public:
DEFINE_CLASS_ID(AddP, Node, 9) DEFINE_CLASS_ID(AddP, Node, 9)
DEFINE_CLASS_ID(BoxLock, Node, 10) DEFINE_CLASS_ID(BoxLock, Node, 10)
DEFINE_CLASS_ID(Add, Node, 11) DEFINE_CLASS_ID(Add, Node, 11)
DEFINE_CLASS_ID(Vector, Node, 12) DEFINE_CLASS_ID(Mul, Node, 12)
DEFINE_CLASS_ID(ClearArray, Node, 13) DEFINE_CLASS_ID(Vector, Node, 13)
DEFINE_CLASS_ID(ClearArray, Node, 14)
_max_classes = ClassMask_ClearArray _max_classes = ClassMask_ClearArray
}; };
@ -752,6 +754,7 @@ public:
DEFINE_CLASS_QUERY(MemBar) DEFINE_CLASS_QUERY(MemBar)
DEFINE_CLASS_QUERY(MemBarStoreStore) DEFINE_CLASS_QUERY(MemBarStoreStore)
DEFINE_CLASS_QUERY(MergeMem) DEFINE_CLASS_QUERY(MergeMem)
DEFINE_CLASS_QUERY(Mul)
DEFINE_CLASS_QUERY(Multi) DEFINE_CLASS_QUERY(Multi)
DEFINE_CLASS_QUERY(MultiBranch) DEFINE_CLASS_QUERY(MultiBranch)
DEFINE_CLASS_QUERY(Parm) DEFINE_CLASS_QUERY(Parm)
@ -767,8 +770,8 @@ public:
DEFINE_CLASS_QUERY(Sub) DEFINE_CLASS_QUERY(Sub)
DEFINE_CLASS_QUERY(Type) DEFINE_CLASS_QUERY(Type)
DEFINE_CLASS_QUERY(Vector) DEFINE_CLASS_QUERY(Vector)
DEFINE_CLASS_QUERY(VectorLoad) DEFINE_CLASS_QUERY(LoadVector)
DEFINE_CLASS_QUERY(VectorStore) DEFINE_CLASS_QUERY(StoreVector)
DEFINE_CLASS_QUERY(Unlock) DEFINE_CLASS_QUERY(Unlock)
#undef DEFINE_CLASS_QUERY #undef DEFINE_CLASS_QUERY

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -38,6 +38,10 @@ const char *NodeClassNames[] = {
"RegD", "RegD",
"RegL", "RegL",
"RegFlags", "RegFlags",
"VecS",
"VecD",
"VecX",
"VecY",
"_last_machine_leaf", "_last_machine_leaf",
#include "classes.hpp" #include "classes.hpp"
"_last_class_name", "_last_class_name",

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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(RegF) // Machine float register
macro(RegD) // Machine double register macro(RegD) // Machine double register
macro(RegL) // Machine long 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 macro(RegFlags) // Machine flags register
_last_machine_leaf, // Split between regular opcodes and machine _last_machine_leaf, // Split between regular opcodes and machine
#include "classes.hpp" #include "classes.hpp"

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,13 +27,15 @@
#include "opto/chaitin.hpp" #include "opto/chaitin.hpp"
#include "opto/machnode.hpp" #include "opto/machnode.hpp"
// see if this register kind does not requires two registers // See if this register (or pairs, or vector) already contains the value.
static bool is_single_register(uint x) { static bool register_contains_value(Node* val, OptoReg::Name reg, int n_regs,
#ifdef _LP64 Node_List& value) {
return (x != Op_RegD && x != Op_RegL && x != Op_RegP); for (int i = 0; i < n_regs; i++) {
#else OptoReg::Name nreg = OptoReg::add(reg,-i);
return (x != Op_RegD && x != Op_RegL); if (value[nreg] != val)
#endif return false;
}
return true;
} }
//---------------------------may_be_copy_of_callee----------------------------- //---------------------------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); const RegMask &use_mask = n->in_RegMask(idx);
bool can_use = ( RegMask::can_represent(def_reg) ? (use_mask.Member(def_reg) != 0) bool can_use = ( RegMask::can_represent(def_reg) ? (use_mask.Member(def_reg) != 0)
: (use_mask.is_AllStack() != 0)); : (use_mask.is_AllStack() != 0));
// Check for a copy to or from a misaligned pair. if (!RegMask::is_vector(def->ideal_reg())) {
can_use = can_use && !use_mask.is_misaligned_Pair() && !def_lrg.mask().is_misaligned_Pair(); // 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) if (!can_use)
return 0; 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)); 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); uint val_idx = n2lidx(val);
OptoReg::Name val_reg = lrgs(val_idx).reg(); OptoReg::Name val_reg = lrgs(val_idx).reg();
// See if it happens to already be in the correct register! // See if it happens to already be in the correct register!
// (either Phi's direct register, or the common case of the name // (either Phi's direct register, or the common case of the name
// never-clobbered original-def register) // never-clobbered original-def register)
if( value[val_reg] == val && if (register_contains_value(val, val_reg, n_regs, value)) {
// Doubles check both halves
( single || value[val_reg-1] == val ) ) {
blk_adjust += use_prior_register(n,k,regnd[val_reg],current_block,value,regnd); blk_adjust += use_prior_register(n,k,regnd[val_reg],current_block,value,regnd);
if( n->in(k) == regnd[val_reg] ) // Success! Quit trying if( n->in(k) == regnd[val_reg] ) // Success! Quit trying
return blk_adjust; 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]; Node *vv = value[reg];
if( !single ) { // Doubles check for aligned-adjacent pair if (n_regs > 1) { // Doubles and vectors check for aligned-adjacent set
if( (reg&1)==0 ) continue; // Wrong half of a pair uint last = (n_regs-1); // Looking for the last part of a set
if( vv != value[reg-1] ) continue; // Not a complete pair 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? if( vv == val || // Got a direct hit?
(t && vv && vv->bottom_type() == t && vv->is_Mach() && (t && vv && vv->bottom_type() == t && vv->is_Mach() &&
@ -526,8 +529,9 @@ void PhaseChaitin::post_allocate_copy_removal() {
if( pidx ) { if( pidx ) {
value.map(preg,phi); value.map(preg,phi);
regnd.map(preg,phi); regnd.map(preg,phi);
OptoReg::Name preg_lo = OptoReg::add(preg,-1); int n_regs = RegMask::num_registers(phi->ideal_reg());
if( !is_single_register(phi->ideal_reg()) ) { for (int l = 1; l < n_regs; l++) {
OptoReg::Name preg_lo = OptoReg::add(preg,-l);
value.map(preg_lo,phi); value.map(preg_lo,phi);
regnd.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 value.map(ureg,valdef); // record improved reaching-def info
regnd.map(ureg, def); regnd.map(ureg, def);
// Record other half of doubles // Record other half of doubles
OptoReg::Name ureg_lo = OptoReg::add(ureg,-1); uint def_ideal_reg = def->ideal_reg();
if( !is_single_register(def->ideal_reg()) && int n_regs = RegMask::num_registers(def_ideal_reg);
( !RegMask::can_represent(ureg_lo) || for (int l = 1; l < n_regs; l++) {
lrgs(useidx).mask().Member(ureg_lo) ) && // Nearly always adjacent OptoReg::Name ureg_lo = OptoReg::add(ureg,-l);
!value[ureg_lo] ) { if (!value[ureg_lo] &&
value.map(ureg_lo,valdef); // record improved reaching-def info (!RegMask::can_represent(ureg_lo) ||
regnd.map(ureg_lo, def); 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(); 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, // If Node 'n' does not change the value mapped by the register,
// then 'n' is a useless copy. Do not update the register->node // then 'n' is a useless copy. Do not update the register->node
// mapping so 'n' will go dead. // mapping so 'n' will go dead.
@ -625,6 +633,25 @@ void PhaseChaitin::post_allocate_copy_removal() {
assert( n->is_Copy(), "" ); assert( n->is_Copy(), "" );
j -= replace_and_yank_if_dead(n, nreg, b, value, regnd); 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 { } else {
// If the value occupies a register pair, record same info // If the value occupies a register pair, record same info
// in both registers. // in both registers.

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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_i_mask = w_mask->overlap( *i_mask ) ? w_mask : i_mask;
const RegMask *w_o_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 if( w_mask->overlap( *o_mask ) && // Overlap AND
((ireg != Op_RegL && ireg != Op_RegD // Single use or aligned ((num_regs == 1) // Single use or aligned
#ifdef _LP64 || is_vect // or vector
&& ireg != Op_RegP || !is_vect && o_mask->is_aligned_pairs()) ) {
#endif assert(!is_vect || o_mask->is_aligned_sets(num_regs), "vectors are aligned");
) || o_mask->is_aligned_Pairs()) ) {
// Don't come here for mis-aligned doubles // Don't come here for mis-aligned doubles
w_o_mask = w_mask; w_o_mask = w_mask;
} else { // wide ideal mask does not overlap with o_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 // CNC - Turned off 7/8/99, causes too much spilling
// if( lrg->_is_bound ) return false; // 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 // 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; if( insidx < hrp_idx ) return false;
// Register pressure for the block as a whole depends on reg class // 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; // Bound live ranges will split at the binding points first;
// Intermediate splits should assume the live range's register set // Intermediate splits should assume the live range's register set
// got "freed up" and that num_regs will become INT_PRESSURE. // 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. // Effective register pressure limit.
int lrg_pres = (lrg->get_invalid_mask_size() > lrg->num_regs()) int lrg_pres = (lrg->get_invalid_mask_size() > lrg->num_regs())
? (lrg->get_invalid_mask_size() >> (lrg->num_regs()-1)) : bound_pres; ? (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; if( i < n->req() ) break;
insert_point--; insert_point--;
} }
uint orig_eidx = b->end_idx();
maxlrg = split_DEF( n1, b, insert_point, maxlrg, Reachblock, debug_defs, splits, slidx); maxlrg = split_DEF( n1, b, insert_point, maxlrg, Reachblock, debug_defs, splits, slidx);
// If it wasn't split bail // If it wasn't split bail
if (!maxlrg) { if (!maxlrg) {
return 0; 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 // This is a new DEF, so update UP
UPblock[slidx] = false; UPblock[slidx] = false;
@ -960,7 +966,7 @@ uint PhaseChaitin::Split( uint maxlrg ) {
// Grab register mask info // Grab register mask info
const RegMask &dmask = def->out_RegMask(); const RegMask &dmask = def->out_RegMask();
const RegMask &umask = n->in_RegMask(inpidx); 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"); assert(inpidx < oopoff, "cannot use-split oop map info");
bool dup = UPblock[slidx]; bool dup = UPblock[slidx];
@ -972,7 +978,7 @@ uint PhaseChaitin::Split( uint maxlrg ) {
if( !umask.is_AllStack() && if( !umask.is_AllStack() &&
(int)umask.Size() <= lrgs(useidx).num_regs() && (int)umask.Size() <= lrgs(useidx).num_regs() &&
(!def->rematerialize() || (!def->rematerialize() ||
umask.is_misaligned_Pair())) { !is_vect && umask.is_misaligned_pair())) {
// These need a Split regardless of overlap or pressure // These need a Split regardless of overlap or pressure
// SPLIT - NO DEF - NO CISC SPILL // SPLIT - NO DEF - NO CISC SPILL
maxlrg = split_USE(def,b,n,inpidx,maxlrg,dup,false, splits,slidx); 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 // Grab UP info for DEF
const RegMask &dmask = n->out_RegMask(); const RegMask &dmask = n->out_RegMask();
bool defup = dmask.is_UP(); 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) // Only split at Def if this is a HRP block or bound (and spilled once)
if( !n->rematerialize() && if( !n->rematerialize() &&
(((dmask.is_bound1() || dmask.is_bound2() || dmask.is_misaligned_Pair()) && (((dmask.is_bound(ireg) || !is_vect && dmask.is_misaligned_pair()) &&
(deflrg._direct_conflict || deflrg._must_spill)) || (deflrg._direct_conflict || deflrg._must_spill)) ||
// Check for LRG being up in a register and we are inside a high // Check for LRG being up in a register and we are inside a high
// pressure area. Spill it down immediately. // pressure area. Spill it down immediately.
(defup && is_high_pressure(b,&deflrg,insidx))) ) { (defup && is_high_pressure(b,&deflrg,insidx))) ) {

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -129,11 +129,34 @@ const RegMask RegMask::Empty(
0 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_first_pair--------------------------------
// Find the lowest-numbered register pair in the mask. Return the // Find the lowest-numbered register pair in the mask. Return the
// HIGHEST register number in the pair, or BAD if no pairs. // HIGHEST register number in the pair, or BAD if no pairs.
OptoReg::Name RegMask::find_first_pair() const { OptoReg::Name RegMask::find_first_pair() const {
VerifyPairs(); verify_pairs();
for( int i = 0; i < RM_SIZE; i++ ) { for( int i = 0; i < RM_SIZE; i++ ) {
if( _A[i] ) { // Found some bits if( _A[i] ) { // Found some bits
int bit = _A[i] & -_A[i]; // Extract low bit int bit = _A[i] & -_A[i]; // Extract low bit
@ -146,30 +169,30 @@ OptoReg::Name RegMask::find_first_pair() const {
//------------------------------ClearToPairs----------------------------------- //------------------------------ClearToPairs-----------------------------------
// Clear out partial bits; leave only bit pairs // Clear out partial bits; leave only bit pairs
void RegMask::ClearToPairs() { void RegMask::clear_to_pairs() {
for( int i = 0; i < RM_SIZE; i++ ) { for( int i = 0; i < RM_SIZE; i++ ) {
int bits = _A[i]; int bits = _A[i];
bits &= ((bits & 0x55555555)<<1); // 1 hi-bit set for each pair bits &= ((bits & 0x55555555)<<1); // 1 hi-bit set for each pair
bits |= (bits>>1); // Smear 1 hi-bit into a pair bits |= (bits>>1); // Smear 1 hi-bit into a pair
_A[i] = bits; _A[i] = bits;
} }
VerifyPairs(); verify_pairs();
} }
//------------------------------SmearToPairs----------------------------------- //------------------------------SmearToPairs-----------------------------------
// Smear out partial bits; leave only bit pairs // Smear out partial bits; leave only bit pairs
void RegMask::SmearToPairs() { void RegMask::smear_to_pairs() {
for( int i = 0; i < RM_SIZE; i++ ) { for( int i = 0; i < RM_SIZE; i++ ) {
int bits = _A[i]; int bits = _A[i];
bits |= ((bits & 0x55555555)<<1); // Smear lo bit hi per pair bits |= ((bits & 0x55555555)<<1); // Smear lo bit hi per pair
bits |= ((bits & 0xAAAAAAAA)>>1); // Smear hi bit lo per pair bits |= ((bits & 0xAAAAAAAA)>>1); // Smear hi bit lo per pair
_A[i] = bits; _A[i] = bits;
} }
VerifyPairs(); verify_pairs();
} }
//------------------------------is_aligned_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. // Assert that the register mask contains only bit pairs.
for( int i = 0; i < RM_SIZE; i++ ) { for( int i = 0; i < RM_SIZE; i++ ) {
int bits = _A[i]; int bits = _A[i];
@ -204,7 +227,7 @@ int RegMask::is_bound1() const {
//------------------------------is_bound2-------------------------------------- //------------------------------is_bound2--------------------------------------
// Return TRUE if the mask contains an adjacent pair of bits and no other bits. // 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; if( is_AllStack() ) return false;
int bit = -1; // Set to hold the one bit allowed int bit = -1; // Set to hold the one bit allowed
@ -226,6 +249,132 @@ int RegMask::is_bound2() const {
return true; 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------------------------------------------ //------------------------------is_UP------------------------------------------
// UP means register only, Register plus stack, or stack only is DOWN // UP means register only, Register plus stack, or stack only is DOWN
bool RegMask::is_UP() const { bool RegMask::is_UP() const {

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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 // the controlling alignment constraint. Note that this alignment
// requirement is internal to the allocator, and independent of any // requirement is internal to the allocator, and independent of any
// particular platform. // 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 // 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); // in directly. Calls to this look something like RM(1,2,3,4);
@ -193,20 +197,53 @@ public:
OptoReg::Name find_first_pair() const; OptoReg::Name find_first_pair() const;
// Clear out partial bits; leave only aligned adjacent bit pairs. // 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. // 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 // 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 // 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 // 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 // Test for single register
int is_bound1() const; int is_bound1() const;
// Test for a single adjacent pair // 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. // Fast overlap test. Non-zero if any registers in common.
int overlap( const RegMask &rm ) const { int overlap( const RegMask &rm ) const {
@ -280,9 +317,15 @@ public:
static bool can_represent(OptoReg::Name reg) { static bool can_represent(OptoReg::Name reg) {
// NOTE: -1 in computation reflects the usage of the last // 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); 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! // Do not use this constant directly in client code!

View File

@ -112,6 +112,7 @@ class StringConcat : public ResourceObj {
_arguments->ins_req(0, value); _arguments->ins_req(0, value);
_mode.insert_before(0, mode); _mode.insert_before(0, mode);
} }
void push_string(Node* value) { void push_string(Node* value) {
push(value, StringMode); push(value, StringMode);
} }
@ -125,9 +126,56 @@ class StringConcat : public ResourceObj {
push(value, CharMode); 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) { Node* argument(int i) {
return _arguments->in(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) { void set_argument(int i, Node* value) {
_arguments->set_req(i, value); _arguments->set_req(i, value);
} }
@ -206,9 +254,11 @@ class StringConcat : public ResourceObj {
void StringConcat::eliminate_unneeded_control() { void StringConcat::eliminate_unneeded_control() {
eliminate_initialize(begin()->initialization());
for (uint i = 0; i < _control.size(); i++) { for (uint i = 0; i < _control.size(); i++) {
Node* n = _control.at(i); Node* n = _control.at(i);
if (n->is_Allocate()) {
eliminate_initialize(n->as_Allocate()->initialization());
}
if (n->is_Call()) { if (n->is_Call()) {
if (n != _end) { if (n != _end) {
eliminate_call(n->as_Call()); 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(other->_end), "what?");
assert(result->_control.contains(_begin), "what?"); assert(result->_control.contains(_begin), "what?");
for (int x = 0; x < num_arguments(); x++) { 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 // replace the toString result with the all the arguments that
// made up the other StringConcat // made up the other StringConcat
for (int y = 0; y < other->num_arguments(); y++) { for (int y = 0; y < other->num_arguments(); y++) {
result->append(other->argument(y), other->mode(y)); result->append(other->argument(y), other->mode(y));
} }
} else { } else {
result->append(argument(x), mode(x)); result->append(argx, mode(x));
} }
} }
result->set_allocation(other->_begin); result->set_allocation(other->_begin);
@ -327,14 +378,9 @@ Node_List PhaseStringOpts::collect_toString_calls() {
while (worklist.size() > 0) { while (worklist.size() > 0) {
Node* ctrl = worklist.pop(); Node* ctrl = worklist.pop();
if (ctrl->is_CallStaticJava()) { if (StringConcat::is_SB_toString(ctrl)) {
CallStaticJavaNode* csj = ctrl->as_CallStaticJava(); CallStaticJavaNode* csj = ctrl->as_CallStaticJava();
ciMethod* m = csj->method(); string_calls.push(csj);
if (m != NULL &&
(m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString ||
m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString)) {
string_calls.push(csj);
}
} }
if (ctrl->in(0) != NULL && !_visited.test_set(ctrl->in(0)->_idx)) { if (ctrl->in(0) != NULL && !_visited.test_set(ctrl->in(0)->_idx)) {
worklist.push(ctrl->in(0)); worklist.push(ctrl->in(0));
@ -550,44 +596,40 @@ PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List*):
for (int c = 0; c < concats.length(); c++) { for (int c = 0; c < concats.length(); c++) {
StringConcat* sc = concats.at(c); StringConcat* sc = concats.at(c);
for (int i = 0; i < sc->num_arguments(); i++) { for (int i = 0; i < sc->num_arguments(); i++) {
Node* arg = sc->argument(i); Node* arg = sc->argument_uncast(i);
if (arg->is_Proj() && arg->in(0)->is_CallStaticJava()) { if (arg->is_Proj() && StringConcat::is_SB_toString(arg->in(0))) {
CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava(); CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava();
if (csj->method() != NULL && for (int o = 0; o < concats.length(); o++) {
(csj->method()->intrinsic_id() == vmIntrinsics::_StringBuilder_toString || if (c == o) continue;
csj->method()->intrinsic_id() == vmIntrinsics::_StringBuffer_toString)) { StringConcat* other = concats.at(o);
for (int o = 0; o < concats.length(); o++) { if (other->end() == csj) {
if (c == o) continue;
StringConcat* other = concats.at(o);
if (other->end() == csj) {
#ifndef PRODUCT #ifndef PRODUCT
if (PrintOptimizeStringConcat) { if (PrintOptimizeStringConcat) {
tty->print_cr("considering stacked concats"); tty->print_cr("considering stacked concats");
} }
#endif #endif
StringConcat* merged = sc->merge(other, arg); StringConcat* merged = sc->merge(other, arg);
if (merged->validate_control_flow()) { if (merged->validate_control_flow()) {
#ifndef PRODUCT #ifndef PRODUCT
if (PrintOptimizeStringConcat) { if (PrintOptimizeStringConcat) {
tty->print_cr("stacking would succeed"); 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
} }
#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
} }
} }
} }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -67,6 +67,10 @@ SuperWord::SuperWord(PhaseIdealLoop* phase) :
//------------------------------transform_loop--------------------------- //------------------------------transform_loop---------------------------
void SuperWord::transform_loop(IdealLoopTree* lpt) { 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"); assert(lpt->_head->is_CountedLoop(), "must be");
CountedLoopNode *cl = lpt->_head->as_CountedLoop(); CountedLoopNode *cl = lpt->_head->as_CountedLoop();
@ -89,15 +93,12 @@ void SuperWord::transform_loop(IdealLoopTree* lpt) {
Node *pre_opaq1 = pre_end->limit(); Node *pre_opaq1 = pre_end->limit();
if (pre_opaq1->Opcode() != Op_Opaque1) return; if (pre_opaq1->Opcode() != Op_Opaque1) return;
// Do vectors exist on this architecture?
if (vector_width_in_bytes() == 0) return;
init(); // initialize data structures init(); // initialize data structures
set_lpt(lpt); set_lpt(lpt);
set_lp(cl); 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); set_bb(cl);
assert(_packset.length() == 0, "packset must be empty"); assert(_packset.length() == 0, "packset must be empty");
@ -177,7 +178,7 @@ void SuperWord::find_adjacent_refs() {
Node_List memops; Node_List memops;
for (int i = 0; i < _block.length(); i++) { for (int i = 0; i < _block.length(); i++) {
Node* n = _block.at(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())) { is_java_primitive(n->as_Mem()->memory_type())) {
int align = memory_alignment(n->as_Mem(), 0); int align = memory_alignment(n->as_Mem(), 0);
if (align != bottom_align) { 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 Node_List align_to_refs;
// is modified to align this reference to a vector-aligned address int best_iv_adjustment = 0;
find_align_to_ref(memops); MemNode* best_align_to_mem_ref = NULL;
if (align_to_ref() == NULL) return;
SWPointer align_to_ref_p(align_to_ref(), this); while (memops.size() != 0) {
int offset = align_to_ref_p.offset_in_bytes(); // Find a memory reference to align to.
int scale = align_to_ref_p.scale_in_bytes(); MemNode* mem_ref = find_align_to_ref(memops);
int vw = vector_width_in_bytes(); if (mem_ref == NULL) break;
int stride_sign = (scale * iv_stride()) > 0 ? 1 : -1; align_to_refs.push(mem_ref);
int iv_adjustment = (stride_sign * vw - (offset % vw)) % vw; int iv_adjustment = get_iv_adjustment(mem_ref);
#ifndef PRODUCT if (best_align_to_mem_ref == NULL) {
if (TraceSuperWord) // Set memory reference which is the best from all memory operations
tty->print_cr("\noffset = %d iv_adjustment = %d elt_align = %d scale = %d iv_stride = %d", // to be used for alignment. The pre-loop trip count is modified to align
offset, iv_adjustment, align_to_ref_p.memory_size(), align_to_ref_p.scale_in_bytes(), iv_stride()); // this reference to a vector-aligned address.
#endif best_align_to_mem_ref = mem_ref;
best_iv_adjustment = iv_adjustment;
// 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);
} }
}
// Create initial pack pairs of memory operations SWPointer align_to_ref_p(mem_ref, this);
for (uint i = 0; i < memops.size(); i++) { // Set alignment relative to "align_to_ref" for all related memory operations.
Node* s1 = memops.at(i); for (int i = memops.size() - 1; i >= 0; i--) {
for (uint j = 0; j < memops.size(); j++) { MemNode* s = memops.at(i)->as_Mem();
Node* s2 = memops.at(j); if (isomorphic(s, mem_ref)) {
if (s1 != s2 && are_adjacent_refs(s1, s2)) { SWPointer p2(s, this);
int align = alignment(s1); if (p2.comparable(align_to_ref_p)) {
if (stmts_can_pack(s1, s2, align)) { int align = memory_alignment(s, iv_adjustment);
Node_List* pair = new Node_List(); set_alignment(s, align);
pair->push(s1);
pair->push(s2);
_packset.append(pair);
} }
} }
} }
}
// 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 #ifndef PRODUCT
if (TraceSuperWord) { if (TraceSuperWord) {
@ -246,7 +334,7 @@ void SuperWord::find_adjacent_refs() {
// Find a memory reference to align the loop induction variable to. // Find a memory reference to align the loop induction variable to.
// Looks first at stores then at loads, looking for a memory reference // Looks first at stores then at loads, looking for a memory reference
// with the largest number of references similar to it. // 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); GrowableArray<int> cmp_ct(arena(), memops.size(), memops.size(), 0);
// Count number of comparable memory ops // 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_ct = 0;
int max_vw = 0;
int max_idx = -1; int max_idx = -1;
int min_size = max_jint; int min_size = max_jint;
int min_iv_offset = max_jint; int min_iv_offset = max_jint;
for (uint j = 0; j < memops.size(); j++) { for (uint j = 0; j < memops.size(); j++) {
MemNode* s = memops.at(j)->as_Mem(); MemNode* s = memops.at(j)->as_Mem();
if (s->is_Store()) { if (s->is_Store()) {
int vw = vector_width_in_bytes(s);
assert(vw > 1, "sanity");
SWPointer p(s, this); SWPointer p(s, this);
if (cmp_ct.at(j) > max_ct || if (cmp_ct.at(j) > max_ct ||
cmp_ct.at(j) == max_ct && (data_size(s) < min_size || cmp_ct.at(j) == max_ct &&
data_size(s) == min_size && (vw > max_vw ||
p.offset_in_bytes() < min_iv_offset)) { 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_ct = cmp_ct.at(j);
max_vw = vw;
max_idx = j; max_idx = j;
min_size = data_size(s); min_size = data_size(s);
min_iv_offset = p.offset_in_bytes(); 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++) { for (uint j = 0; j < memops.size(); j++) {
MemNode* s = memops.at(j)->as_Mem(); MemNode* s = memops.at(j)->as_Mem();
if (s->is_Load()) { if (s->is_Load()) {
int vw = vector_width_in_bytes(s);
assert(vw > 1, "sanity");
SWPointer p(s, this); SWPointer p(s, this);
if (cmp_ct.at(j) > max_ct || if (cmp_ct.at(j) > max_ct ||
cmp_ct.at(j) == max_ct && (data_size(s) < min_size || cmp_ct.at(j) == max_ct &&
data_size(s) == min_size && (vw > max_vw ||
p.offset_in_bytes() < min_iv_offset)) { 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_ct = cmp_ct.at(j);
max_vw = vw;
max_idx = j; max_idx = j;
min_size = data_size(s); min_size = data_size(s);
min_iv_offset = p.offset_in_bytes(); min_iv_offset = p.offset_in_bytes();
@ -309,10 +411,7 @@ void SuperWord::find_align_to_ref(Node_List &memops) {
} }
} }
if (max_ct > 0) #ifdef ASSERT
set_align_to_ref(memops.at(max_idx)->as_Mem());
#ifndef PRODUCT
if (TraceSuperWord && Verbose) { if (TraceSuperWord && Verbose) {
tty->print_cr("\nVector memops after find_align_to_refs"); tty->print_cr("\nVector memops after find_align_to_refs");
for (uint i = 0; i < memops.size(); i++) { for (uint i = 0; i < memops.size(); i++) {
@ -321,6 +420,17 @@ void SuperWord::find_align_to_ref(Node_List &memops) {
} }
} }
#endif #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--------------------------- //------------------------------ref_is_alignable---------------------------
@ -341,7 +451,8 @@ bool SuperWord::ref_is_alignable(SWPointer& p) {
// If initial offset from start of object is computable, // If initial offset from start of object is computable,
// compute alignment within the vector. // 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) { if (vw % span == 0) {
Node* init_nd = pre_end->init_trip(); Node* init_nd = pre_end->init_trip();
if (init_nd->is_Con() && p.invar() == NULL) { if (init_nd->is_Con() && p.invar() == NULL) {
@ -361,6 +472,25 @@ bool SuperWord::ref_is_alignable(SWPointer& p) {
return false; 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--------------------------- //---------------------------dependence_graph---------------------------
// Construct dependency graph. // Construct dependency graph.
// Add dependence edges to load/store nodes for memory dependence // 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) { bool SuperWord::stmts_can_pack(Node* s1, Node* s2, int align) {
// Do not use superword for non-primitives // Do not use superword for non-primitives
if((s1->is_Mem() && !is_java_primitive(s1->as_Mem()->memory_type())) || BasicType bt1 = velt_basic_type(s1);
(s2->is_Mem() && !is_java_primitive(s2->as_Mem()->memory_type()))) BasicType bt2 = velt_basic_type(s2);
if(!is_java_primitive(bt1) || !is_java_primitive(bt2))
return false; return false;
if (Matcher::max_vector_size(bt1) < 2) {
return false; // No vectors for this type
}
if (isomorphic(s1, s2)) { if (isomorphic(s1, s2)) {
if (independent(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->Opcode() != s2->Opcode()) return false;
if (s1->req() != s2->req()) return false; if (s1->req() != s2->req()) return false;
if (s1->in(0) != s2->in(0)) 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; return true;
} }
@ -595,14 +729,16 @@ bool SuperWord::independent_path(Node* shallow, Node* deep, uint dp) {
//------------------------------set_alignment--------------------------- //------------------------------set_alignment---------------------------
void SuperWord::set_alignment(Node* s1, Node* s2, int align) { void SuperWord::set_alignment(Node* s1, Node* s2, int align) {
set_alignment(s1, 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--------------------------- //------------------------------data_size---------------------------
int SuperWord::data_size(Node* s) { int SuperWord::data_size(Node* s) {
const Type* t = velt_type(s); int bsize = type2aelembytes(velt_basic_type(s));
BasicType bt = t->array_element_basic_type();
int bsize = type2aelembytes(bt);
assert(bsize != 0, "valid size"); assert(bsize != 0, "valid size");
return bsize; return bsize;
} }
@ -631,9 +767,9 @@ void SuperWord::extend_packlist() {
//------------------------------follow_use_defs--------------------------- //------------------------------follow_use_defs---------------------------
// Extend the packset by visiting operand definitions of nodes in pack p // Extend the packset by visiting operand definitions of nodes in pack p
bool SuperWord::follow_use_defs(Node_List* p) { bool SuperWord::follow_use_defs(Node_List* p) {
assert(p->size() == 2, "just checking");
Node* s1 = p->at(0); Node* s1 = p->at(0);
Node* s2 = p->at(1); Node* s2 = p->at(1);
assert(p->size() == 2, "just checking");
assert(s1->req() == s2->req(), "just checking"); assert(s1->req() == s2->req(), "just checking");
assert(alignment(s1) + data_size(s1) == alignment(s2), "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 (i1++; i1 < ct; i1++) if (u1->in(i1) == d1) break;
for (i2++; i2 < ct; i2++) if (u2->in(i2) == d2) break; for (i2++; i2 < ct; i2++) if (u2->in(i2) == d2) break;
if (i1 != i2) { 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); } while (i1 < ct);
return true; return true;
@ -727,7 +868,7 @@ bool SuperWord::opnd_positions_match(Node* d1, Node* u1, Node* d2, Node* u2) {
//------------------------------est_savings--------------------------- //------------------------------est_savings---------------------------
// Estimate the savings from executing s1 and s2 as a pack // Estimate the savings from executing s1 and s2 as a pack
int SuperWord::est_savings(Node* s1, Node* s2) { 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 // inputs
for (uint i = 1; i < s1->req(); i++) { 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); Node* x2 = s2->in(i);
if (x1 != x2) { if (x1 != x2) {
if (are_adjacent_refs(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)) { } else if (!in_packset(x1, x2)) {
save -= pack_cost(2); save_in -= pack_cost(2);
} else { } else {
save += unpack_cost(2); save_in += unpack_cost(2);
} }
} }
} }
// uses of result // uses of result
uint ct = 0; uint ct = 0;
int save_use = 0;
for (DUIterator_Fast imax, i = s1->fast_outs(imax); i < imax; i++) { for (DUIterator_Fast imax, i = s1->fast_outs(imax); i < imax; i++) {
Node* s1_use = s1->fast_out(i); Node* s1_use = s1->fast_out(i);
for (int j = 0; j < _packset.length(); j++) { 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) { if (p->at(p->size()-1) == s2_use) {
ct++; ct++;
if (are_adjacent_refs(s1_use, s2_use)) { 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 < s1->outcnt()) save_use += unpack_cost(1);
if (ct < s2->outcnt()) save += unpack_cost(1); if (ct < s2->outcnt()) save_use += unpack_cost(1);
return save; return MAX2(save_in, save_use);
} }
//------------------------------costs--------------------------- //------------------------------costs---------------------------
@ -778,8 +920,9 @@ int SuperWord::unpack_cost(int ct) { return ct; }
//------------------------------combine_packs--------------------------- //------------------------------combine_packs---------------------------
// Combine packs A and B with A.last == B.first into A.first..,A.last,B.second,..B.last // Combine packs A and B with A.last == B.first into A.first..,A.last,B.second,..B.last
void SuperWord::combine_packs() { void SuperWord::combine_packs() {
bool changed; bool changed = true;
do { // Combine packs regardless max vector size.
while (changed) {
changed = false; changed = false;
for (int i = 0; i < _packset.length(); i++) { for (int i = 0; i < _packset.length(); i++) {
Node_List* p1 = _packset.at(i); Node_List* p1 = _packset.at(i);
@ -787,6 +930,7 @@ void SuperWord::combine_packs() {
for (int j = 0; j < _packset.length(); j++) { for (int j = 0; j < _packset.length(); j++) {
Node_List* p2 = _packset.at(j); Node_List* p2 = _packset.at(j);
if (p2 == NULL) continue; if (p2 == NULL) continue;
if (i == j) continue;
if (p1->at(p1->size()-1) == p2->at(0)) { if (p1->at(p1->size()-1) == p2->at(0)) {
for (uint k = 1; k < p2->size(); k++) { for (uint k = 1; k < p2->size(); k++) {
p1->push(p2->at(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--) { for (int i = _packset.length() - 1; i >= 0; i--) {
Node_List* p1 = _packset.at(i); Node_List* p1 = _packset.at(i);
if (p1 == NULL) { if (p1 == NULL) {
@ -880,8 +1055,7 @@ void SuperWord::filter_packs() {
// Can code be generated for pack p? // Can code be generated for pack p?
bool SuperWord::implemented(Node_List* p) { bool SuperWord::implemented(Node_List* p) {
Node* p0 = p->at(0); Node* p0 = p->at(0);
int vopc = VectorNode::opcode(p0->Opcode(), p->size(), velt_type(p0)); return VectorNode::implemented(p0->Opcode(), p->size(), velt_basic_type(p0));
return vopc > 0 && Matcher::has_match_rule(vopc);
} }
//------------------------------profitable--------------------------- //------------------------------profitable---------------------------
@ -939,36 +1113,36 @@ void SuperWord::schedule() {
} }
//-------------------------------remove_and_insert------------------- //-------------------------------remove_and_insert-------------------
//remove "current" from its current position in the memory graph and insert // Remove "current" from its current position in the memory graph and insert
//it after the appropriate insertion point (lip or uip) // it after the appropriate insertion point (lip or uip).
void SuperWord::remove_and_insert(MemNode *current, MemNode *prev, MemNode *lip, void SuperWord::remove_and_insert(MemNode *current, MemNode *prev, MemNode *lip,
Node *uip, Unique_Node_List &sched_before) { Node *uip, Unique_Node_List &sched_before) {
Node* my_mem = current->in(MemNode::Memory); Node* my_mem = current->in(MemNode::Memory);
_igvn.rehash_node_delayed(current); bool sched_up = sched_before.member(current);
_igvn.hash_delete(my_mem);
//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++) { for (DUIterator i = current->outs(); current->has_out(i); i++) {
Node* use = current->out(i); Node* use = current->out(i);
if (use->is_Mem()) { if (use->is_Mem()) {
assert(use->in(MemNode::Memory) == current, "must be"); assert(use->in(MemNode::Memory) == current, "must be");
_igvn.rehash_node_delayed(use);
if (use == prev) { // connect prev to my_mem 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)) { } else if (sched_before.member(use)) {
_igvn.hash_delete(uip); if (!sched_up) { // Will be moved together with current
use->set_req(MemNode::Memory, uip); _igvn.replace_input_of(use, MemNode::Memory, uip);
--i; //deleted this edge; rescan position
}
} else { } else {
_igvn.hash_delete(lip); if (sched_up) { // Will be moved together with current
use->set_req(MemNode::Memory, lip); _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; 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 // 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++) { 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 //connect current to insert_pt
current->set_req(MemNode::Memory, insert_pt); _igvn.replace_input_of(current, MemNode::Memory, insert_pt);
} }
//------------------------------co_locate_pack---------------------------------- //------------------------------co_locate_pack----------------------------------
@ -1025,7 +1199,7 @@ void SuperWord::co_locate_pack(Node_List* pk) {
if (use->is_Mem() && use != previous) if (use->is_Mem() && use != previous)
memops.push(use); memops.push(use);
} }
if(current == first) break; if (current == first) break;
previous = current; previous = current;
current = current->in(MemNode::Memory)->as_Mem(); current = current->in(MemNode::Memory)->as_Mem();
} }
@ -1038,27 +1212,37 @@ void SuperWord::co_locate_pack(Node_List* pk) {
Node *s2 = memops.at(j); Node *s2 = memops.at(j);
if (!independent(s1, s2)) { if (!independent(s1, s2)) {
if (in_pack(s2, pk) || schedule_before_pack.member(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); Node_List* mem_pk = my_pack(s1);
if (mem_pk != NULL) { if (mem_pk != NULL) {
for (uint ii = 0; ii < mem_pk->size(); ii++) { 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)) if (memops.member(s) && !schedule_before_pack.member(s))
schedule_before_pack.push(s); schedule_before_pack.push(s);
} }
} }
break;
} }
} }
} }
} }
} }
MemNode* lower_insert_pt = last;
Node* upper_insert_pt = first->in(MemNode::Memory); 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 previous = last; //previous store in pk
current = last->in(MemNode::Memory)->as_Mem(); current = last->in(MemNode::Memory)->as_Mem();
//start scheduling from "last" to "first" // start scheduling from "last" to "first"
while (true) { while (true) {
assert(in_bb(current), "stay in block"); assert(in_bb(current), "stay in block");
assert(in_pack(previous, pk), "previous stays in pack"); 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)) { if (in_pack(current, pk)) {
// Forward users of my memory state (except "previous) to my input memory state // 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++) { for (DUIterator i = current->outs(); current->has_out(i); i++) {
Node* use = current->out(i); Node* use = current->out(i);
if (use->is_Mem() && use != previous) { if (use->is_Mem() && use != previous) {
assert(use->in(MemNode::Memory) == current, "must be"); assert(use->in(MemNode::Memory) == current, "must be");
if (schedule_before_pack.member(use)) { if (schedule_before_pack.member(use)) {
_igvn.hash_delete(upper_insert_pt);
_igvn.replace_input_of(use, MemNode::Memory, upper_insert_pt); _igvn.replace_input_of(use, MemNode::Memory, upper_insert_pt);
} else { } else {
_igvn.hash_delete(lower_insert_pt);
_igvn.replace_input_of(use, MemNode::Memory, lower_insert_pt); _igvn.replace_input_of(use, MemNode::Memory, lower_insert_pt);
} }
--i; // deleted this edge; rescan position --i; // deleted this edge; rescan position
@ -1089,6 +1270,14 @@ void SuperWord::co_locate_pack(Node_List* pk) {
if (current == first) break; if (current == first) break;
current = my_mem->as_Mem(); current = my_mem->as_Mem();
} // end while } // 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 } else if (pk->at(0)->is_Load()) { //load
// all loads in the pack should have the same memory state. By default, // 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 // 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* vn = NULL;
Node* low_adr = p->at(0); Node* low_adr = p->at(0);
Node* first = executed_first(p); Node* first = executed_first(p);
int opc = n->Opcode();
if (n->is_Load()) { if (n->is_Load()) {
int opc = n->Opcode();
Node* ctl = n->in(MemNode::Control); Node* ctl = n->in(MemNode::Control);
Node* mem = first->in(MemNode::Memory); Node* mem = first->in(MemNode::Memory);
Node* adr = low_adr->in(MemNode::Address); Node* adr = low_adr->in(MemNode::Address);
const TypePtr* atyp = n->adr_type(); 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()) { } else if (n->is_Store()) {
// Promote value to be stored to vector // Promote value to be stored to vector
Node* val = vector_opd(p, MemNode::ValueIn); Node* val = vector_opd(p, MemNode::ValueIn);
int opc = n->Opcode();
Node* ctl = n->in(MemNode::Control); Node* ctl = n->in(MemNode::Control);
Node* mem = first->in(MemNode::Memory); Node* mem = first->in(MemNode::Memory);
Node* adr = low_adr->in(MemNode::Address); Node* adr = low_adr->in(MemNode::Address);
const TypePtr* atyp = n->adr_type(); 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) { } else if (n->req() == 3) {
// Promote operands to vector // Promote operands to vector
Node* in1 = vector_opd(p, 1); Node* in1 = vector_opd(p, 1);
Node* in2 = vector_opd(p, 2); 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 { } else {
ShouldNotReachHere(); ShouldNotReachHere();
} }
assert(vn != NULL, "sanity");
_phase->_igvn.register_new_node_with_optimizer(vn); _phase->_igvn.register_new_node_with_optimizer(vn);
_phase->set_ctrl(vn, _phase->get_ctrl(p->at(0))); _phase->set_ctrl(vn, _phase->get_ctrl(p->at(0)));
for (uint j = 0; j < p->size(); j++) { for (uint j = 0; j < p->size(); j++) {
@ -1185,6 +1369,12 @@ void SuperWord::output() {
_igvn.replace_node(pm, vn); _igvn.replace_node(pm, vn);
} }
_igvn._worklist.push(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 (same_opd) {
if (opd->is_Vector() || opd->is_VectorLoad()) { if (opd->is_Vector() || opd->is_LoadVector()) {
return opd; // input is matching vector 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 // 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 // p0's vector. Use p0's type because size of operand's container in
// vector should match p0's size regardless operand's size. // 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->_igvn.register_new_node_with_optimizer(vn);
_phase->set_ctrl(vn, _phase->get_ctrl(opd)); _phase->set_ctrl(vn, _phase->get_ctrl(opd));
#ifdef ASSERT
if (TraceNewVectors) {
tty->print("new Vector node: ");
vn->dump();
}
#endif
return vn; return vn;
} }
// Insert pack operation // Insert pack operation
const Type* p0_t = velt_type(p0); BasicType bt = velt_basic_type(p0);
PackNode* pk = PackNode::make(_phase->C, opd, p0_t); PackNode* pk = PackNode::make(_phase->C, opd, vlen, bt);
DEBUG_ONLY( const BasicType opd_bt = opd->bottom_type()->basic_type(); ) DEBUG_ONLY( const BasicType opd_bt = opd->bottom_type()->basic_type(); )
for (uint i = 1; i < vlen; i++) { 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); Node* in = pi->in(opd_idx);
assert(my_pack(in) == NULL, "Should already have been unpacked"); assert(my_pack(in) == NULL, "Should already have been unpacked");
assert(opd_bt == in->bottom_type()->basic_type(), "all same type"); 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->_igvn.register_new_node_with_optimizer(pk);
_phase->set_ctrl(pk, _phase->get_ctrl(opd)); _phase->set_ctrl(pk, _phase->get_ctrl(opd));
#ifdef ASSERT
if (TraceNewVectors) {
tty->print("new Vector node: ");
pk->dump();
}
#endif
return pk; return pk;
} }
@ -1273,16 +1475,15 @@ void SuperWord::insert_extracts(Node_List* p) {
// Insert extract operation // Insert extract operation
_igvn.hash_delete(def); _igvn.hash_delete(def);
int def_pos = alignment(def) / data_size(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->_igvn.register_new_node_with_optimizer(ex);
_phase->set_ctrl(ex, _phase->get_ctrl(def)); _phase->set_ctrl(ex, _phase->get_ctrl(def));
_igvn.replace_input_of(use, idx, ex); _igvn.replace_input_of(use, idx, ex);
_igvn._worklist.push(def); _igvn._worklist.push(def);
bb_insert_after(ex, bb_idx(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 // Initial type
for (int i = 0; i < _block.length(); i++) { for (int i = 0; i < _block.length(); i++) {
Node* n = _block.at(i); Node* n = _block.at(i);
const Type* t = n->is_Mem() ? Type::get_const_basic_type(n->as_Mem()->memory_type()) set_velt_type(n, container_type(n));
: _igvn.type(n);
const Type* vt = container_type(t);
set_velt_type(n, vt);
} }
// Propagate narrowed type backwards through operations // Propagate narrowed type backwards through operations
@ -1543,7 +1741,7 @@ void SuperWord::compute_vector_element_type() {
bool same_type = true; bool same_type = true;
for (DUIterator_Fast kmax, k = in->fast_outs(kmax); k < kmax; k++) { for (DUIterator_Fast kmax, k = in->fast_outs(kmax); k < kmax; k++) {
Node *use = in->fast_out(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; same_type = false;
break; break;
} }
@ -1575,20 +1773,24 @@ int SuperWord::memory_alignment(MemNode* s, int iv_adjust_in_bytes) {
if (!p.valid()) { if (!p.valid()) {
return bottom_align; 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(); int offset = p.offset_in_bytes();
offset += iv_adjust_in_bytes; offset += iv_adjust_in_bytes;
int off_rem = offset % vector_width_in_bytes(); int off_rem = offset % vw;
int off_mod = off_rem >= 0 ? off_rem : off_rem + vector_width_in_bytes(); int off_mod = off_rem >= 0 ? off_rem : off_rem + vw;
return off_mod; return off_mod;
} }
//---------------------------container_type--------------------------- //---------------------------container_type---------------------------
// Smallest type containing range of values // Smallest type containing range of values
const Type* SuperWord::container_type(const Type* t) { const Type* SuperWord::container_type(Node* n) {
const Type* tp = t->make_ptr(); if (n->is_Mem()) {
if (tp && tp->isa_aryptr()) { return Type::get_const_basic_type(n->as_Mem()->memory_type());
t = tp->is_aryptr()->elem();
} }
const Type* t = _igvn.type(n);
if (t->basic_type() == T_INT) { if (t->basic_type() == T_INT) {
if (t->higher_equal(TypeInt::BOOL)) return TypeInt::BOOL; if (t->higher_equal(TypeInt::BOOL)) return TypeInt::BOOL;
if (t->higher_equal(TypeInt::BYTE)) return TypeInt::BYTE; if (t->higher_equal(TypeInt::BYTE)) return TypeInt::BYTE;
@ -1599,11 +1801,22 @@ const Type* SuperWord::container_type(const Type* t) {
return 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----------------------- //-------------------------vector_opd_range-----------------------
// (Start, end] half-open range defining which operands are vector // (Start, end] half-open range defining which operands are vector
void SuperWord::vector_opd_range(Node* n, uint* start, uint* end) { void SuperWord::vector_opd_range(Node* n, uint* start, uint* end) {
switch (n->Opcode()) { 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_LoadI: case Op_LoadL:
case Op_LoadF: case Op_LoadD: case Op_LoadF: case Op_LoadD:
case Op_LoadP: 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, ""); assert(orig_limit != NULL && _igvn.type(orig_limit) != Type::TOP, "");
SWPointer align_to_ref_p(align_to_ref, this); SWPointer align_to_ref_p(align_to_ref, this);
assert(align_to_ref_p.valid(), "sanity");
// Given: // Given:
// lim0 == original pre loop limit // lim0 == original pre loop limit
@ -1773,10 +1987,12 @@ void SuperWord::align_initial_loop_index(MemNode* align_to_ref) {
// N = (V - (e - lim0)) % V // N = (V - (e - lim0)) % V
// lim = lim0 - (V - (e - lim0)) % V // lim = lim0 - (V - (e - lim0)) % V
int vw = vector_width_in_bytes(align_to_ref);
int stride = iv_stride(); int stride = iv_stride();
int scale = align_to_ref_p.scale_in_bytes(); int scale = align_to_ref_p.scale_in_bytes();
int elt_size = align_to_ref_p.memory_size(); 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; int k = align_to_ref_p.offset_in_bytes() / elt_size;
Node *kn = _igvn.intcon(k); 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->_igvn.register_new_node_with_optimizer(e);
_phase->set_ctrl(e, pre_ctrl); _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 // compute e +/- lim0
if (scale < 0) { if (scale < 0) {

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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(); } _iv = lp->as_CountedLoop()->phi()->as_Phi(); }
int iv_stride() { return lp()->as_CountedLoop()->stride_con(); } 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; } MemNode* align_to_ref() { return _align_to_ref; }
void set_align_to_ref(MemNode* m) { _align_to_ref = m; } void set_align_to_ref(MemNode* m) { _align_to_ref = m; }
@ -298,7 +304,9 @@ class SuperWord : public ResourceObj {
// vector element type // vector element type
const Type* velt_type(Node* n) { return _node_info.adr_at(bb_idx(n))->_velt_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; } 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 // my_pack
Node_List* my_pack(Node* n) { return !in_bb(n) ? NULL : _node_info.adr_at(bb_idx(n))->_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. // Find the adjacent memory references and create pack pairs for them.
void find_adjacent_refs(); void find_adjacent_refs();
// Find a memory reference to align the loop induction variable to. // 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? // Can the preloop align the reference to position zero in the vector?
bool ref_is_alignable(SWPointer& p); bool ref_is_alignable(SWPointer& p);
// Construct dependency graph. // Construct dependency graph.
@ -394,7 +404,7 @@ class SuperWord : public ResourceObj {
// (Start, end] half-open range defining which operands are vector // (Start, end] half-open range defining which operands are vector
void vector_opd_range(Node* n, uint* start, uint* end); void vector_opd_range(Node* n, uint* start, uint* end);
// Smallest type containing range of values // 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 // 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. // to align_to_ref will be a position zero in the vector.
void align_initial_loop_index(MemNode* align_to_ref); void align_initial_loop_index(MemNode* align_to_ref);
@ -462,6 +472,7 @@ class SWPointer VALUE_OBJ_CLASS_SPEC {
Node* base() { return _base; } Node* base() { return _base; }
Node* adr() { return _adr; } Node* adr() { return _adr; }
MemNode* mem() { return _mem; }
int scale_in_bytes() { return _scale; } int scale_in_bytes() { return _scale; }
Node* invar() { return _invar; } Node* invar() { return _invar; }
bool negate_invar() { return _negate_invar; } bool negate_invar() { return _negate_invar; }

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * 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_ILLEGAL, // Tuple
T_ARRAY, // Array 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, // AnyPtr // shows up in factory methods for NULL_PTR
T_ADDRESS, // RawPtr T_ADDRESS, // RawPtr
@ -414,6 +418,24 @@ void Type::Initialize_shared(Compile* current) {
// get_zero_type() should not happen for T_CONFLICT // get_zero_type() should not happen for T_CONFLICT
_zero_type[T_CONFLICT]= NULL; _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. // Restore working type arena.
current->set_type_arena(save); current->set_type_arena(save);
current->set_type_dict(NULL); current->set_type_dict(NULL);
@ -668,6 +690,10 @@ const Type::TYPES Type::dual_type[Type::lastype] = {
Bad, // Tuple - handled in v-call Bad, // Tuple - handled in v-call
Bad, // Array - 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, // AnyPtr - handled in v-call
Bad, // RawPtr - handled in v-call Bad, // RawPtr - handled in v-call
@ -728,8 +754,8 @@ void Type::dump_on(outputStream *st) const {
//------------------------------data------------------------------------------- //------------------------------data-------------------------------------------
const char * const Type::msg[Type::lastype] = { const char * const Type::msg[Type::lastype] = {
"bad","control","top","int:","long:","half", "narrowoop:", "bad","control","top","int:","long:","half", "narrowoop:",
"tuple:", "aryptr", "tuple:", "array:", "vectors:", "vectord:", "vectorx:", "vectory:",
"anyptr:", "rawptr:", "java:", "inst:", "ary:", "klass:", "anyptr:", "rawptr:", "java:", "inst:", "aryptr:", "klass:",
"func", "abIO", "return_address", "memory", "func", "abIO", "return_address", "memory",
"float_top", "ftcon:", "float", "float_top", "ftcon:", "float",
"double_top", "dblcon:", "double", "double_top", "dblcon:", "double",
@ -790,7 +816,7 @@ void Type::typerr( const Type *t ) const {
//------------------------------isa_oop_ptr------------------------------------ //------------------------------isa_oop_ptr------------------------------------
// Return true if type is an oop pointer type. False for raw pointers. // Return true if type is an oop pointer type. False for raw pointers.
static char isa_oop_ptr_tbl[Type::lastype] = { 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/*anyptr*/,0/*rawptr*/,1/*OopPtr*/,1/*InstPtr*/,1/*AryPtr*/,1/*KlassPtr*/,
0/*func*/,0,0/*return_address*/,0, 0/*func*/,0,0/*return_address*/,0,
/*floats*/0,0,0, /*doubles*/0,0,0, /*floats*/0,0,0, /*doubles*/0,0,0,
@ -1926,6 +1952,121 @@ bool TypeAry::ary_must_be_exact() const {
return false; 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. // Convenience common pre-built types.
const TypePtr *TypePtr::NULL_PTR; const TypePtr *TypePtr::NULL_PTR;
@ -2472,18 +2613,26 @@ const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_
//------------------------------make_from_constant----------------------------- //------------------------------make_from_constant-----------------------------
// Make a java pointer from an oop constant // Make a java pointer from an oop constant
const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_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... // 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); const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS);
ciKlass *klass = ciTypeArrayKlass::make((BasicType) T_BYTE); ciKlass* klass = ciArrayKlass::make(ciType::make(bt));
assert(o->can_be_constant(), "method data oops should be tenured"); assert(o->can_be_constant(), "should be tenured");
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0); return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
return arr; } 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 { } else {
assert(o->is_java_object(), "must be java language object"); assert(o->is_java_object(), "must be java language object");
assert(!o->is_null_object(), "null object not yet handled here."); assert(!o->is_null_object(), "null object not yet handled here.");
ciKlass *klass = o->klass(); ciKlass* klass = o->klass();
if (klass->is_instance_klass()) { if (klass->is_instance_klass()) {
// Element is an instance // Element is an instance
if (require_constant) { if (require_constant) {
@ -2494,8 +2643,7 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_const
return TypeInstPtr::make(o); return TypeInstPtr::make(o);
} else if (klass->is_obj_array_klass()) { } else if (klass->is_obj_array_klass()) {
// Element is an object array. Recursively call ourself. // Element is an object array. Recursively call ourself.
const Type *etype = const Type *etype = make_from_klass_raw(klass->as_obj_array_klass()->element_klass());
TypeOopPtr::make_from_klass_raw(klass->as_obj_array_klass()->element_klass());
const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length())); const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
// We used to pass NotNull in here, asserting that the sub-arrays // 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 // 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()) { } else if (!o->should_be_constant()) {
return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0); return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
} }
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0); return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
return arr;
} else if (klass->is_type_array_klass()) { } else if (klass->is_type_array_klass()) {
// Element is an typeArray // Element is an typeArray
const Type* etype = const Type* etype = get_const_basic_type(klass->as_type_array_klass()->element_type());
(Type*)get_const_basic_type(klass->as_type_array_klass()->element_type());
const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length())); const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
// We used to pass NotNull in here, asserting that the array pointer // We used to pass NotNull in here, asserting that the array pointer
// is not-null. That was not true in general. // 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()) { } else if (!o->should_be_constant()) {
return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0); return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
} }
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0); return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
return arr;
} }
} }
ShouldNotReachHere(); fatal("unhandled object type");
return NULL; return NULL;
} }
@ -4140,7 +4285,7 @@ void TypeFunc::dump2( Dict &d, uint depth, outputStream *st ) const {
// Print a 'flattened' signature // Print a 'flattened' signature
static const char * const flat_type_msg[Type::lastype] = { static const char * const flat_type_msg[Type::lastype] = {
"bad","control","top","int","long","_", "narrowoop", "bad","control","top","int","long","_", "narrowoop",
"tuple:", "array:", "tuple:", "array:", "vectors:", "vectord:", "vectorx:", "vectory:",
"ptr", "rawptr", "ptr", "ptr", "ptr", "ptr", "ptr", "rawptr", "ptr", "ptr", "ptr", "ptr",
"func", "abIO", "return_address", "mem", "func", "abIO", "return_address", "mem",
"float_top", "ftcon:", "flt", "float_top", "ftcon:", "flt",

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -51,6 +51,11 @@ class TypeLong;
class TypeNarrowOop; class TypeNarrowOop;
class TypeAry; class TypeAry;
class TypeTuple; class TypeTuple;
class TypeVect;
class TypeVectS;
class TypeVectD;
class TypeVectX;
class TypeVectY;
class TypePtr; class TypePtr;
class TypeRawPtr; class TypeRawPtr;
class TypeOopPtr; class TypeOopPtr;
@ -78,6 +83,10 @@ public:
Tuple, // Method signature or object layout Tuple, // Method signature or object layout
Array, // Array types 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 AnyPtr, // Any old raw, klass, inst, or array pointer
RawPtr, // Raw (non-oop) pointers RawPtr, // Raw (non-oop) pointers
@ -222,6 +231,8 @@ public:
const TypeF *isa_float_constant() const; // Returns NULL if not a FloatCon const TypeF *isa_float_constant() const; // Returns NULL if not a FloatCon
const TypeTuple *is_tuple() const; // Collection of fields, NOT a pointer const TypeTuple *is_tuple() const; // Collection of fields, NOT a pointer
const TypeAry *is_ary() const; // Array, NOT array 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 *is_ptr() const; // Asserts it is a ptr type
const TypePtr *isa_ptr() const; // Returns NULL if not ptr type const TypePtr *isa_ptr() const; // Returns NULL if not ptr type
const TypeRawPtr *isa_rawptr() const; // NOT Java oop const TypeRawPtr *isa_rawptr() const; // NOT Java oop
@ -574,6 +585,69 @@ public:
#endif #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---------------------------------------- //------------------------------TypePtr----------------------------------------
// Class of machine Pointer Types: raw data, instances or arrays. // Class of machine Pointer Types: raw data, instances or arrays.
// If the _base enum is AnyPtr, then this refers to all of the above. // 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; 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 { inline const TypePtr *Type::is_ptr() const {
// AnyPtr is the first Ptr and KlassPtr the last, with no non-ptrs between. // AnyPtr is the first Ptr and KlassPtr the last, with no non-ptrs between.
assert(_base >= AnyPtr && _base <= KlassPtr, "Not a pointer"); assert(_base >= AnyPtr && _base <= KlassPtr, "Not a pointer");

View File

@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -28,147 +28,16 @@
//------------------------------VectorNode-------------------------------------- //------------------------------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 // 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. // supports the vector operation.
int VectorNode::opcode(int sopc, uint vlen, const Type* opd_t) { int VectorNode::opcode(int sopc, uint vlen, BasicType bt) {
BasicType bt = opd_t->array_element_basic_type();
if (!(is_power_of_2(vlen) && vlen <= max_vlen(bt)))
return 0; // unimplemented
switch (sopc) { switch (sopc) {
case Op_AddI: case Op_AddI:
switch (bt) { switch (bt) {
case T_BOOLEAN: case T_BOOLEAN:
case T_BYTE: return Op_AddVB; case T_BYTE: return Op_AddVB;
case T_CHAR: return Op_AddVC; case T_CHAR:
case T_SHORT: return Op_AddVS; case T_SHORT: return Op_AddVS;
case T_INT: return Op_AddVI; case T_INT: return Op_AddVI;
} }
@ -186,7 +55,7 @@ int VectorNode::opcode(int sopc, uint vlen, const Type* opd_t) {
switch (bt) { switch (bt) {
case T_BOOLEAN: case T_BOOLEAN:
case T_BYTE: return Op_SubVB; case T_BYTE: return Op_SubVB;
case T_CHAR: return Op_SubVC; case T_CHAR:
case T_SHORT: return Op_SubVS; case T_SHORT: return Op_SubVS;
case T_INT: return Op_SubVI; case T_INT: return Op_SubVI;
} }
@ -216,18 +85,18 @@ int VectorNode::opcode(int sopc, uint vlen, const Type* opd_t) {
switch (bt) { switch (bt) {
case T_BOOLEAN: case T_BOOLEAN:
case T_BYTE: return Op_LShiftVB; case T_BYTE: return Op_LShiftVB;
case T_CHAR: return Op_LShiftVC; case T_CHAR:
case T_SHORT: return Op_LShiftVS; case T_SHORT: return Op_LShiftVS;
case T_INT: return Op_LShiftVI; case T_INT: return Op_LShiftVI;
} }
ShouldNotReachHere(); ShouldNotReachHere();
case Op_URShiftI: case Op_RShiftI:
switch (bt) { switch (bt) {
case T_BOOLEAN: case T_BOOLEAN:
case T_BYTE: return Op_URShiftVB; case T_BYTE: return Op_RShiftVB;
case T_CHAR: return Op_URShiftVC; case T_CHAR:
case T_SHORT: return Op_URShiftVS; case T_SHORT: return Op_RShiftVS;
case T_INT: return Op_URShiftVI; case T_INT: return Op_RShiftVI;
} }
ShouldNotReachHere(); ShouldNotReachHere();
case Op_AndI: case Op_AndI:
@ -241,13 +110,14 @@ int VectorNode::opcode(int sopc, uint vlen, const Type* opd_t) {
return Op_XorV; return Op_XorV;
case Op_LoadB: case Op_LoadB:
case Op_LoadUB:
case Op_LoadUS: case Op_LoadUS:
case Op_LoadS: case Op_LoadS:
case Op_LoadI: case Op_LoadI:
case Op_LoadL: case Op_LoadL:
case Op_LoadF: case Op_LoadF:
case Op_LoadD: case Op_LoadD:
return VectorLoadNode::opcode(sopc, vlen); return Op_LoadVector;
case Op_StoreB: case Op_StoreB:
case Op_StoreC: case Op_StoreC:
@ -255,211 +125,170 @@ int VectorNode::opcode(int sopc, uint vlen, const Type* opd_t) {
case Op_StoreL: case Op_StoreL:
case Op_StoreF: case Op_StoreF:
case Op_StoreD: case Op_StoreD:
return VectorStoreNode::opcode(sopc, vlen); return Op_StoreVector;
} }
return 0; // Unimplemented return 0; // Unimplemented
} }
// Helper for above. bool VectorNode::implemented(int opc, uint vlen, BasicType bt) {
int VectorLoadNode::opcode(int sopc, uint vlen) { if (is_java_primitive(bt) &&
switch (sopc) { (vlen > 1) && is_power_of_2(vlen) &&
case Op_LoadB: Matcher::vector_size_supported(bt, vlen)) {
switch (vlen) { int vopc = VectorNode::opcode(opc, vlen, bt);
case 2: return 0; // Unimplemented return vopc > 0 && Matcher::has_match_rule(vopc);
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;
} }
return 0; // Unimplemented return false;
}
// 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 the vector version of a scalar operation node. // 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) { VectorNode* VectorNode::make(Compile* C, int opc, Node* n1, Node* n2, uint vlen, BasicType bt) {
int vopc = opcode(sopc, vlen, opd_t); const TypeVect* vt = TypeVect::make(bt, vlen);
int vopc = VectorNode::opcode(opc, vlen, bt);
switch (vopc) { switch (vopc) {
case Op_AddVB: return new (C, 3) AddVBNode(n1, n2, vlen); case Op_AddVB: return new (C, 3) AddVBNode(n1, n2, vt);
case Op_AddVC: return new (C, 3) AddVCNode(n1, n2, vlen); case Op_AddVS: return new (C, 3) AddVSNode(n1, n2, vt);
case Op_AddVS: return new (C, 3) AddVSNode(n1, n2, vlen); case Op_AddVI: return new (C, 3) AddVINode(n1, n2, vt);
case Op_AddVI: return new (C, 3) AddVINode(n1, n2, vlen); case Op_AddVL: return new (C, 3) AddVLNode(n1, n2, vt);
case Op_AddVL: return new (C, 3) AddVLNode(n1, n2, vlen); case Op_AddVF: return new (C, 3) AddVFNode(n1, n2, vt);
case Op_AddVF: return new (C, 3) AddVFNode(n1, n2, vlen); case Op_AddVD: return new (C, 3) AddVDNode(n1, n2, vt);
case Op_AddVD: return new (C, 3) AddVDNode(n1, n2, vlen);
case Op_SubVB: return new (C, 3) SubVBNode(n1, n2, vlen); case Op_SubVB: return new (C, 3) SubVBNode(n1, n2, vt);
case Op_SubVC: return new (C, 3) SubVCNode(n1, n2, vlen); case Op_SubVS: return new (C, 3) SubVSNode(n1, n2, vt);
case Op_SubVS: return new (C, 3) SubVSNode(n1, n2, vlen); case Op_SubVI: return new (C, 3) SubVINode(n1, n2, vt);
case Op_SubVI: return new (C, 3) SubVINode(n1, n2, vlen); case Op_SubVL: return new (C, 3) SubVLNode(n1, n2, vt);
case Op_SubVL: return new (C, 3) SubVLNode(n1, n2, vlen); case Op_SubVF: return new (C, 3) SubVFNode(n1, n2, vt);
case Op_SubVF: return new (C, 3) SubVFNode(n1, n2, vlen); case Op_SubVD: return new (C, 3) SubVDNode(n1, n2, vt);
case Op_SubVD: return new (C, 3) SubVDNode(n1, n2, vlen);
case Op_MulVF: return new (C, 3) MulVFNode(n1, n2, vlen); case Op_MulVF: return new (C, 3) MulVFNode(n1, n2, vt);
case Op_MulVD: return new (C, 3) MulVDNode(n1, n2, vlen); case Op_MulVD: return new (C, 3) MulVDNode(n1, n2, vt);
case Op_DivVF: return new (C, 3) DivVFNode(n1, n2, vlen); case Op_DivVF: return new (C, 3) DivVFNode(n1, n2, vt);
case Op_DivVD: return new (C, 3) DivVDNode(n1, n2, vlen); case Op_DivVD: return new (C, 3) DivVDNode(n1, n2, vt);
case Op_LShiftVB: return new (C, 3) LShiftVBNode(n1, n2, vlen); case Op_LShiftVB: return new (C, 3) LShiftVBNode(n1, n2, vt);
case Op_LShiftVC: return new (C, 3) LShiftVCNode(n1, n2, vlen); case Op_LShiftVS: return new (C, 3) LShiftVSNode(n1, n2, vt);
case Op_LShiftVS: return new (C, 3) LShiftVSNode(n1, n2, vlen); case Op_LShiftVI: return new (C, 3) LShiftVINode(n1, n2, vt);
case Op_LShiftVI: return new (C, 3) LShiftVINode(n1, n2, vlen);
case Op_URShiftVB: return new (C, 3) URShiftVBNode(n1, n2, vlen); case Op_RShiftVB: return new (C, 3) RShiftVBNode(n1, n2, vt);
case Op_URShiftVC: return new (C, 3) URShiftVCNode(n1, n2, vlen); case Op_RShiftVS: return new (C, 3) RShiftVSNode(n1, n2, vt);
case Op_URShiftVS: return new (C, 3) URShiftVSNode(n1, n2, vlen); case Op_RShiftVI: return new (C, 3) RShiftVINode(n1, n2, vt);
case Op_URShiftVI: return new (C, 3) URShiftVINode(n1, n2, vlen);
case Op_AndV: return new (C, 3) AndVNode(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, vlen, opd_t->array_element_basic_type()); case Op_OrV: return new (C, 3) OrVNode (n1, n2, vt);
case Op_XorV: return new (C, 3) XorVNode(n1, n2, vlen, opd_t->array_element_basic_type()); case Op_XorV: return new (C, 3) XorVNode(n1, n2, vt);
} }
ShouldNotReachHere(); ShouldNotReachHere();
return NULL; 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. // Return the vector version of a scalar load node.
VectorLoadNode* VectorLoadNode::make(Compile* C, int opc, Node* ctl, Node* mem, LoadVectorNode* LoadVectorNode::make(Compile* C, int opc, Node* ctl, Node* mem,
Node* adr, const TypePtr* atyp, uint vlen) { Node* adr, const TypePtr* atyp, uint vlen, BasicType bt) {
int vopc = opcode(opc, vlen); const TypeVect* vt = TypeVect::make(bt, vlen);
return new (C, 3) LoadVectorNode(ctl, mem, adr, atyp, vt);
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();
return NULL; return NULL;
} }
// Return the vector version of a scalar store node. // 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, Node* adr, const TypePtr* atyp, Node* val,
uint vlen) { uint vlen) {
int vopc = opcode(opc, vlen); return new (C, 4) StoreVectorNode(ctl, mem, adr, atyp, val);
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;
} }
// Extract a scalar element of vector. // Extract a scalar element of vector.
Node* ExtractNode::make(Compile* C, Node* v, uint position, const Type* opd_t) { Node* ExtractNode::make(Compile* C, Node* v, uint position, BasicType bt) {
BasicType bt = opd_t->array_element_basic_type(); assert((int)position < Matcher::max_vector_size(bt), "pos in range");
assert(position < VectorNode::max_vlen(bt), "pos in range");
ConINode* pos = ConINode::make(C, (int)position); ConINode* pos = ConINode::make(C, (int)position);
switch (bt) { switch (bt) {
case T_BOOLEAN: case T_BOOLEAN:
return new (C, 3) ExtractUBNode(v, pos);
case T_BYTE: case T_BYTE:
return new (C, 3) ExtractBNode(v, pos); return new (C, 3) ExtractBNode(v, pos);
case T_CHAR: case T_CHAR:
@ -478,3 +307,4 @@ Node* ExtractNode::make(Compile* C, Node* v, uint position, const Type* opd_t) {
ShouldNotReachHere(); ShouldNotReachHere();
return NULL; return NULL;
} }

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,7 @@
*/ */
#include "precompiled.hpp" #include "precompiled.hpp"
#include "classfile/altHashing.hpp"
#include "classfile/classLoader.hpp" #include "classfile/classLoader.hpp"
#include "classfile/javaClasses.hpp" #include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.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(arrayOopDesc::test_max_array_length());
run_unit_test(CollectedHeap::test_is_in()); run_unit_test(CollectedHeap::test_is_in());
run_unit_test(QuickSort::test_quick_sort()); run_unit_test(QuickSort::test_quick_sort());
run_unit_test(AltHashing::test_alt_hash());
tty->print_cr("All internal VM tests passed"); tty->print_cr("All internal VM tests passed");
} }
} }

View File

@ -585,7 +585,7 @@ class CallbackWrapper : public StackObj {
_o = klassOop_if_java_lang_Class(o); _o = klassOop_if_java_lang_Class(o);
// object size // object size
_obj_size = _o->size() * wordSize; _obj_size = (jlong)_o->size() * wordSize;
// record the context // record the context
_tag_map = tag_map; _tag_map = tag_map;

View File

@ -39,6 +39,10 @@ oop fieldDescriptor::loader() const {
} }
Symbol* fieldDescriptor::generic_signature() const { Symbol* fieldDescriptor::generic_signature() const {
if (!has_generic_signature()) {
return NULL;
}
int idx = 0; int idx = 0;
instanceKlass* ik = instanceKlass::cast(field_holder()); instanceKlass* ik = instanceKlass::cast(field_holder());
for (AllFieldStream fs(ik); !fs.done(); fs.next()) { for (AllFieldStream fs(ik); !fs.done(); fs.next()) {

View File

@ -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_access_watched() const { return access_flags().is_field_access_watched(); }
bool is_field_modification_watched() const bool is_field_modification_watched() const
{ return access_flags().is_field_modification_watched(); } { 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) { void set_is_field_access_watched(const bool value) {
_access_flags.set_is_field_access_watched(value); _access_flags.set_is_field_access_watched(value);

View File

@ -2659,6 +2659,9 @@ class CommandLineFlags {
product(bool, UseHeavyMonitors, false, \ product(bool, UseHeavyMonitors, false, \
"use heavyweight instead of lightweight Java monitors") \ "use heavyweight instead of lightweight Java monitors") \
\ \
product(bool, PrintStringTableStatistics, false, \
"print statistics about the StringTable and SymbolTable") \
\
notproduct(bool, PrintSymbolTableSizeHistogram, false, \ notproduct(bool, PrintSymbolTableSizeHistogram, false, \
"print histogram of the symbol table") \ "print histogram of the symbol table") \
\ \

View File

@ -23,6 +23,7 @@
*/ */
#include "precompiled.hpp" #include "precompiled.hpp"
#include "classfile/symbolTable.hpp"
#include "code/icBuffer.hpp" #include "code/icBuffer.hpp"
#include "gc_interface/collectedHeap.hpp" #include "gc_interface/collectedHeap.hpp"
#include "interpreter/bytecodes.hpp" #include "interpreter/bytecodes.hpp"
@ -157,6 +158,10 @@ void exit_globals() {
// Print the collected safepoint statistics. // Print the collected safepoint statistics.
SafepointSynchronize::print_stat_on_exit(); SafepointSynchronize::print_stat_on_exit();
} }
if (PrintStringTableStatistics) {
SymbolTable::dump(tty);
StringTable::dump(tty);
}
ostream_exit(); ostream_exit();
} }
} }

View File

@ -660,6 +660,7 @@ void vm_shutdown_during_initialization(const char* error, const char* message) {
} }
JDK_Version JDK_Version::_current; JDK_Version JDK_Version::_current;
const char* JDK_Version::_runtime_name;
void JDK_Version::initialize() { void JDK_Version::initialize() {
jdk_version_info info; jdk_version_info info;

View File

@ -74,6 +74,7 @@ class JDK_Version VALUE_OBJ_CLASS_SPEC {
private: private:
static JDK_Version _current; static JDK_Version _current;
static const char* _runtime_name;
// In this class, we promote the minor version of release to be the // 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 // 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; 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 // Convenience methods for queries on the current major/minor version
static bool is_jdk12x_version() { static bool is_jdk12x_version() {
return current().compare_major(2) == 0; return current().compare_major(2) == 0;

View File

@ -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_modifiers(rh(), fd->access_flags().as_int() & JVM_RECOGNIZED_FIELD_MODIFIERS);
java_lang_reflect_Field::set_override(rh(), false); java_lang_reflect_Field::set_override(rh(), false);
if (java_lang_reflect_Field::has_signature_field() && if (java_lang_reflect_Field::has_signature_field() &&
fd->generic_signature() != NULL) { fd->has_generic_signature()) {
Symbol* gs = fd->generic_signature(); Symbol* gs = fd->generic_signature();
Handle sig = java_lang_String::create_from_symbol(gs, CHECK_NULL); Handle sig = java_lang_String::create_from_symbol(gs, CHECK_NULL);
java_lang_reflect_Field::set_signature(rh(), sig()); java_lang_reflect_Field::set_signature(rh(), sig());

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