This commit is contained in:
J. Duke 2017-07-05 18:15:19 +02:00
commit e825f6b139
138 changed files with 53961 additions and 3987 deletions
.hgtags-top-repo
corba
hotspot
.hgtags
agent/src/share/classes/sun/jvm/hotspot
make
src

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

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

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

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -657,7 +657,7 @@ public class BugSpot extends JPanel {
while (fr != null) {
trace.add(new StackTraceEntry(fr, getCDebugger()));
try {
fr = fr.sender();
fr = fr.sender(t);
} catch (AddressException e) {
e.printStackTrace();
showMessageDialog("Error while walking stack; stack trace will be truncated\n(see console for details)",

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

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,6 +28,7 @@ import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.bsd.*;
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.cdbg.basic.*;
import sun.jvm.hotspot.debugger.x86.*;
final public class BsdX86CFrame extends BasicCFrame {
// package/class internals only
@ -52,8 +53,11 @@ final public class BsdX86CFrame extends BasicCFrame {
return ebp;
}
public CFrame sender() {
if (ebp == null) {
public CFrame sender(ThreadProxy thread) {
X86ThreadContext context = (X86ThreadContext) thread.getContext();
Address esp = context.getRegisterAsAddress(X86ThreadContext.ESP);
if ( (ebp == null) || ebp.lessThan(esp) ) {
return null;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -34,7 +34,7 @@ import sun.jvm.hotspot.debugger.*;
public interface CFrame {
/** Returns null when no more frames on stack */
public CFrame sender();
public CFrame sender(ThreadProxy th);
/** Get the program counter of this frame */
public Address pc();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,7 @@
package sun.jvm.hotspot.debugger.cdbg.basic.amd64;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.amd64.*;
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.cdbg.basic.*;
@ -43,8 +44,11 @@ public class AMD64CFrame extends BasicCFrame {
this.pc = pc;
}
public CFrame sender() {
if (rbp == null) {
public CFrame sender(ThreadProxy thread) {
AMD64ThreadContext context = (AMD64ThreadContext) thread.getContext();
Address rsp = context.getRegisterAsAddress(AMD64ThreadContext.RSP);
if ( (rbp == null) || rbp.lessThan(rsp) ) {
return null;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -25,6 +25,7 @@
package sun.jvm.hotspot.debugger.cdbg.basic.x86;
import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.x86.*;
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.cdbg.basic.*;
@ -43,8 +44,11 @@ public class X86CFrame extends BasicCFrame {
this.pc = pc;
}
public CFrame sender() {
if (ebp == null) {
public CFrame sender(ThreadProxy thread) {
X86ThreadContext context = (X86ThreadContext) thread.getContext();
Address esp = context.getRegisterAsAddress(X86ThreadContext.ESP);
if ( (ebp == null) || ebp.lessThan(esp) ) {
return null;
}

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

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -57,7 +57,7 @@ final public class LinuxSPARCCFrame extends BasicCFrame {
return sp;
}
public CFrame sender() {
public CFrame sender(ThreadProxy thread) {
if (sp == null) {
return null;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,6 +28,7 @@ import sun.jvm.hotspot.debugger.*;
import sun.jvm.hotspot.debugger.linux.*;
import sun.jvm.hotspot.debugger.cdbg.*;
import sun.jvm.hotspot.debugger.cdbg.basic.*;
import sun.jvm.hotspot.debugger.x86.*;
final public class LinuxX86CFrame extends BasicCFrame {
// package/class internals only
@ -52,8 +53,11 @@ final public class LinuxX86CFrame extends BasicCFrame {
return ebp;
}
public CFrame sender() {
if (ebp == null) {
public CFrame sender(ThreadProxy thread) {
X86ThreadContext context = (X86ThreadContext) thread.getContext();
Address esp = context.getRegisterAsAddress(X86ThreadContext.ESP);
if ( (ebp == null) || ebp.lessThan(esp) ) {
return null;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -37,7 +37,7 @@ final class ProcCFrame extends BasicCFrame {
return fp;
}
public CFrame sender() {
public CFrame sender(ThreadProxy t) {
return sender;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -141,18 +141,19 @@ public class OopUtilities implements /* imports */ JVMTIThreadState {
public static String stringOopToString(Oop stringOop) {
if (offsetField == null) {
InstanceKlass k = (InstanceKlass) stringOop.getKlass();
offsetField = (IntField) k.findField("offset", "I");
countField = (IntField) k.findField("count", "I");
offsetField = (IntField) k.findField("offset", "I"); // optional
countField = (IntField) k.findField("count", "I"); // optional
valueField = (OopField) k.findField("value", "[C");
if (Assert.ASSERTS_ENABLED) {
Assert.that(offsetField != null &&
countField != null &&
valueField != null, "must find all java.lang.String fields");
Assert.that(valueField != null, "Field \'value\' of java.lang.String not found");
}
}
return charArrayToString((TypeArray) valueField.getValue(stringOop),
offsetField.getValue(stringOop),
countField.getValue(stringOop));
if (offsetField != null && countField != null) {
return charArrayToString((TypeArray) valueField.getValue(stringOop),
offsetField.getValue(stringOop),
countField.getValue(stringOop));
}
return charArrayToString((TypeArray) valueField.getValue(stringOop));
}
public static String stringOopToEscapedString(Oop stringOop) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -158,7 +158,7 @@ public class PStack extends Tool {
printUnknown(out);
}
}
f = f.sender();
f = f.sender(th);
}
} catch (Exception exp) {
exp.printStackTrace();

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -85,6 +85,21 @@ public class ObjectReader {
this(new ProcImageClassLoader());
}
static void debugPrintln(String msg) {
if (DEBUG) {
System.err.println("DEBUG>" + msg);
}
}
static void debugPrintStackTrace(Exception exp) {
if (DEBUG) {
StackTraceElement[] els = exp.getStackTrace();
for (int i = 0; i < els.length; i++) {
System.err.println("DEBUG>" + els[i].toString());
}
}
}
public Object readObject(Oop oop) throws ClassNotFoundException {
if (oop instanceof Instance) {
return readInstance((Instance) oop);
@ -120,13 +135,96 @@ public class ObjectReader {
}
protected Symbol javaLangString;
protected Symbol javaUtilHashtableEntry;
protected Symbol javaUtilHashtable;
protected Symbol javaUtilProperties;
protected Symbol getVMSymbol(String name) {
return VM.getVM().getSymbolTable().probe(name);
}
protected Symbol javaLangString() {
if (javaLangString == null) {
javaLangString = VM.getVM().getSymbolTable().probe("java/lang/String");
javaLangString = getVMSymbol("java/lang/String");
}
return javaLangString;
}
protected Symbol javaUtilHashtableEntry() {
if (javaUtilHashtableEntry == null) {
javaUtilHashtableEntry = getVMSymbol("java/util/Hashtable$Entry");
}
return javaUtilHashtableEntry;
}
protected Symbol javaUtilHashtable() {
if (javaUtilHashtable == null) {
javaUtilHashtable = getVMSymbol("java/util/Hashtable");
}
return javaUtilHashtable;
}
protected Symbol javaUtilProperties() {
if (javaUtilProperties == null) {
javaUtilProperties = getVMSymbol("java/util/Properties");
}
return javaUtilProperties;
}
private void setHashtableEntry(java.util.Hashtable p, Oop oop) {
InstanceKlass ik = (InstanceKlass)oop.getKlass();
OopField keyField = (OopField)ik.findField("key", "Ljava/lang/Object;");
OopField valueField = (OopField)ik.findField("value", "Ljava/lang/Object;");
OopField nextField = (OopField)ik.findField("next", "Ljava/util/Hashtable$Entry;");
if (DEBUG) {
if (Assert.ASSERTS_ENABLED) {
Assert.that(ik.getName().equals(javaUtilHashtableEntry()), "Not a Hashtable$Entry?");
Assert.that(keyField != null && valueField != null && nextField != null, "Invalid fields!");
}
}
Object key = null;
Object value = null;
Oop next = null;
try {
key = readObject(keyField.getValue(oop));
value = readObject(valueField.getValue(oop));
next = (Oop)nextField.getValue(oop);
// For Properties, should use setProperty(k, v). Since it only runs in SA
// using put(k, v) should be OK.
p.put(key, value);
if (next != null) {
setHashtableEntry(p, next);
}
} catch (ClassNotFoundException ce) {
if( DEBUG) {
debugPrintln("Class not found " + ce);
debugPrintStackTrace(ce);
}
}
}
protected Object getHashtable(Instance oop, boolean isProperties) {
InstanceKlass k = (InstanceKlass)oop.getKlass();
OopField tableField = (OopField)k.findField("table", "[Ljava/util/Hashtable$Entry;");
if (tableField == null) {
debugPrintln("Could not find field of [Ljava/util/Hashtable$Entry;");
return null;
}
java.util.Hashtable table = (isProperties) ? new java.util.Properties()
: new java.util.Hashtable();
ObjArray kvs = (ObjArray)tableField.getValue(oop);
long size = kvs.getLength();
debugPrintln("Hashtable$Entry Size = " + size);
for (long i=0; i<size; i++) {
Oop entry = kvs.getObjAt(i);
if (entry != null && entry.isInstance()) {
setHashtableEntry(table, entry);
}
}
return table;
}
public Object readInstance(Instance oop) throws ClassNotFoundException {
Object result = getFromObjTable(oop);
if (result == null) {
@ -134,11 +232,21 @@ public class ObjectReader {
// Handle java.lang.String instances differently. As part of JSR-133, fields of immutable
// classes have been made final. The algorithm below will not be able to read Strings from
// debuggee (can't use reflection to set final fields). But, need to read Strings is very
// important. FIXME: need a framework to handle many other special cases.
// important.
// Same for Hashtable, key and hash are final, could not be set in the algorithm too.
// FIXME: need a framework to handle many other special cases.
if (kls.getName().equals(javaLangString())) {
return OopUtilities.stringOopToString(oop);
}
if (kls.getName().equals(javaUtilHashtable())) {
return getHashtable(oop, false);
}
if (kls.getName().equals(javaUtilProperties())) {
return getHashtable(oop, true);
}
Class clz = readClass(kls);
try {
result = clz.newInstance();
@ -164,8 +272,8 @@ public class ObjectReader {
break;
} catch (Exception exp) {
if (DEBUG) {
System.err.println("Can't create object using " + c);
exp.printStackTrace();
debugPrintln("Can't create object using " + c);
debugPrintStackTrace(exp);
}
}
}
@ -329,8 +437,8 @@ public class ObjectReader {
arrayObj[ifd.getIndex()] = readObject(field.getValue(getObj()));
} catch (Exception e) {
if (DEBUG) {
System.err.println("Array element set failed for " + ifd);
e.printStackTrace();
debugPrintln("Array element set failed for " + ifd);
debugPrintStackTrace(e);
}
}
}
@ -348,8 +456,8 @@ public class ObjectReader {
private void printFieldSetError(java.lang.reflect.Field f, Exception ex) {
if (DEBUG) {
if (f != null) System.err.println("Field set failed for " + f);
ex.printStackTrace();
if (f != null) debugPrintln("Field set failed for " + f);
debugPrintStackTrace(ex);
}
}
@ -601,7 +709,7 @@ public class ObjectReader {
return Class.forName(className, true, cl);
} catch (Exception e) {
if (DEBUG) {
System.err.println("Can't load class " + className);
debugPrintln("Can't load class " + className);
}
throw new RuntimeException(e);
}

@ -110,4 +110,5 @@ copy_debug_jdk::
.PHONY: universal_product universal_fastdebug universal_debug \
all_product_universal all_fastdebug_universal all_debug_universal \
universalize export_universal copy_universal
universalize export_universal copy_universal \
$(UNIVERSAL_LIPO_LIST) $(UNIVERSAL_COPY_LIST)

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

@ -102,6 +102,11 @@ jprt.my.linux.armvfp.jdk7=linux_armvfp_2.6
jprt.my.linux.armvfp.jdk7u6=${jprt.my.linux.armvfp.jdk7}
jprt.my.linux.armvfp=${jprt.my.linux.armvfp.${jprt.tools.default.release}}
jprt.my.linux.armv6.jdk8=linux_armv6_2.6
jprt.my.linux.armv6.jdk7=linux_armv6_2.6
jprt.my.linux.armv6.jdk7u6=${jprt.my.linux.armv6.jdk7}
jprt.my.linux.armv6=${jprt.my.linux.armv6.${jprt.tools.default.release}}
jprt.my.linux.armsflt.jdk8=linux_armsflt_2.6
jprt.my.linux.armsflt.jdk7=linux_armsflt_2.6
jprt.my.linux.armsflt.jdk7u6=${jprt.my.linux.armsflt.jdk7}
@ -134,7 +139,7 @@ jprt.build.targets.standard= \
${jprt.my.macosx.x64}-{product|fastdebug|debug}, \
${jprt.my.windows.i586}-{product|fastdebug|debug}, \
${jprt.my.windows.x64}-{product|fastdebug|debug}, \
${jprt.my.linux.armvfp}-{product|fastdebug}
${jprt.my.linux.armv6}-{product|fastdebug}
jprt.build.targets.open= \
${jprt.my.solaris.i586}-{productOpen}, \

@ -1,5 +1,5 @@
#
# Copyright (c) 2006, 2007, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@ -30,6 +30,13 @@ include $(GAMMADIR)/make/scm.make
ifneq ($(OSNAME), windows)
ifndef LP64
PARTIAL_NONPIC=1
endif
PIC_ARCH = ppc
ifneq ("$(filter $(PIC_ARCH),$(BUILDARCH))","")
PARTIAL_NONPIC=0
endif
ifeq ($(PARTIAL_NONPIC),1)
NONPIC_DIRS = memory oops gc_implementation gc_interface
NONPIC_DIRS := $(foreach dir,$(NONPIC_DIRS), $(GAMMADIR)/src/share/vm/$(dir))
# Look for source files under NONPIC_DIRS

@ -24,8 +24,11 @@
# Rules to build add_gnu_debuglink, used by vm.make on Solaris
GENERATED = ../generated
ADD_GNU_DEBUGLINK = $(GENERATED)/add_gnu_debuglink
# Allow $(ADD_GNU_DEBUGLINK) to be called from any directory.
# We don't set or use the GENERATED macro to avoid affecting
# other HotSpot Makefiles.
TOPDIR = $(shell echo `pwd`)
ADD_GNU_DEBUGLINK = $(TOPDIR)/../generated/add_gnu_debuglink
ADD_GNU_DEBUGLINK_DIR = $(GAMMADIR)/src/os/solaris/add_gnu_debuglink
ADD_GNU_DEBUGLINK_SRC = $(ADD_GNU_DEBUGLINK_DIR)/add_gnu_debuglink.c

@ -203,10 +203,18 @@ ifeq ($(JVM_VARIANT_SERVER),true)
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm.diz
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm_db.diz
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm_dtrace.diz
ifeq ($(ARCH_DATA_MODEL),32)
EXPORT_LIST += $(EXPORT_SERVER_DIR)/64/libjvm_db.diz
EXPORT_LIST += $(EXPORT_SERVER_DIR)/64/libjvm_dtrace.diz
endif
else
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm.debuginfo
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm_db.debuginfo
EXPORT_LIST += $(EXPORT_SERVER_DIR)/libjvm_dtrace.debuginfo
ifeq ($(ARCH_DATA_MODEL),32)
EXPORT_LIST += $(EXPORT_SERVER_DIR)/64/libjvm_db.debuginfo
EXPORT_LIST += $(EXPORT_SERVER_DIR)/64/libjvm_dtrace.debuginfo
endif
endif
endif
endif

@ -94,23 +94,24 @@ ISA = $(subst i386,i486,$(shell isainfo -n))
# Making 64/libjvm_db.so: 64-bit version of libjvm_db.so which handles 32-bit libjvm.so
ifneq ("${ISA}","${BUILDARCH}")
XLIBJVM_DB = 64/$(LIBJVM_DB)
XLIBJVM_DB_G = 64/$(LIBJVM_DB_G)
XLIBJVM_DTRACE = 64/$(LIBJVM_DTRACE)
XLIBJVM_DTRACE_G = 64/$(LIBJVM_DTRACE_G)
XLIBJVM_DIR = 64
XLIBJVM_DB = $(XLIBJVM_DIR)/$(LIBJVM_DB)
XLIBJVM_DB_G = $(XLIBJVM_DIR)/$(LIBJVM_DB_G)
XLIBJVM_DTRACE = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE)
XLIBJVM_DTRACE_G = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_G)
XLIBJVM_DB_DEBUGINFO = 64/$(LIBJVM_DB_DEBUGINFO)
XLIBJVM_DB_DIZ = 64/$(LIBJVM_DB_DIZ)
XLIBJVM_DB_G_DEBUGINFO = 64/$(LIBJVM_DB_G_DEBUGINFO)
XLIBJVM_DB_G_DIZ = 64/$(LIBJVM_DB_G_DIZ)
XLIBJVM_DTRACE_DEBUGINFO = 64/$(LIBJVM_DTRACE_DEBUGINFO)
XLIBJVM_DTRACE_DIZ = 64/$(LIBJVM_DTRACE_DIZ)
XLIBJVM_DTRACE_G_DEBUGINFO = 64/$(LIBJVM_DTRACE_G_DEBUGINFO)
XLIBJVM_DTRACE_G_DIZ = 64/$(LIBJVM_DTRACE_G_DIZ)
XLIBJVM_DB_DEBUGINFO = $(XLIBJVM_DIR)/$(LIBJVM_DB_DEBUGINFO)
XLIBJVM_DB_DIZ = $(XLIBJVM_DIR)/$(LIBJVM_DB_DIZ)
XLIBJVM_DB_G_DEBUGINFO = $(XLIBJVM_DIR)/$(LIBJVM_DB_G_DEBUGINFO)
XLIBJVM_DB_G_DIZ = $(XLIBJVM_DIR)/$(LIBJVM_DB_G_DIZ)
XLIBJVM_DTRACE_DEBUGINFO = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_DEBUGINFO)
XLIBJVM_DTRACE_DIZ = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_DIZ)
XLIBJVM_DTRACE_G_DEBUGINFO = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_G_DEBUGINFO)
XLIBJVM_DTRACE_G_DIZ = $(XLIBJVM_DIR)/$(LIBJVM_DTRACE_G_DIZ)
$(XLIBJVM_DB): $(ADD_GNU_DEBUGLINK) $(FIX_EMPTY_SEC_HDR_FLAGS) $(DTRACE_SRCDIR)/$(JVM_DB).c $(JVMOFFS).h $(LIBJVM_DB_MAPFILE)
@echo Making $@
$(QUIETLY) mkdir -p 64/ ; \
$(QUIETLY) mkdir -p $(XLIBJVM_DIR) ; \
$(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. -I$(GENERATED) \
$(SHARED_FLAG) $(LFLAGS_JVM_DB) -o $@ $(DTRACE_SRCDIR)/$(JVM_DB).c -lc
[ -f $(XLIBJVM_DB_G) ] || { ln -s $(LIBJVM_DB) $(XLIBJVM_DB_G); }
@ -124,8 +125,10 @@ ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
$(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(XLIBJVM_DB_DEBUGINFO)
# $(OBJCOPY) --add-gnu-debuglink=... corrupts SUNW_* sections.
# Use $(ADD_GNU_DEBUGLINK) until a fixed $(OBJCOPY) is available.
# $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(XLIBJVM_DB_DEBUGINFO) $@
$(QUIETLY) $(ADD_GNU_DEBUGLINK) $(XLIBJVM_DB_DEBUGINFO) $@
# $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB) ;
# Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) is not
# in the link name:
( cd $(XLIBJVM_DIR) && $(ADD_GNU_DEBUGLINK) $(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB) )
ifeq ($(STRIP_POLICY),all_strip)
$(QUIETLY) $(STRIP) $@
else
@ -134,17 +137,19 @@ ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
# implied else here is no stripping at all
endif
endif
[ -f $(XLIBJVM_DB_G_DEBUGINFO) ] || { ln -s $(XLIBJVM_DB_DEBUGINFO) $(XLIBJVM_DB_G_DEBUGINFO); }
[ -f $(XLIBJVM_DB_G_DEBUGINFO) ] || { cd $(XLIBJVM_DIR) && ln -s $(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB_G_DEBUGINFO); }
ifeq ($(ZIP_DEBUGINFO_FILES),1)
$(ZIPEXE) -q -y $(XLIBJVM_DB_DIZ) $(XLIBJVM_DB_DEBUGINFO) $(XLIBJVM_DB_G_DEBUGINFO)
# Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) is not
# in the archived name:
( cd $(XLIBJVM_DIR) && $(ZIPEXE) -q -y $(LIBJVM_DB_DIZ) $(LIBJVM_DB_DEBUGINFO) $(LIBJVM_DB_G_DEBUGINFO) )
$(RM) $(XLIBJVM_DB_DEBUGINFO) $(XLIBJVM_DB_G_DEBUGINFO)
[ -f $(XLIBJVM_DB_G_DIZ) ] || { ln -s $(XLIBJVM_DB_DIZ) $(XLIBJVM_DB_G_DIZ); }
[ -f $(XLIBJVM_DB_G_DIZ) ] || { cd $(XLIBJVM_DIR) && ln -s $(LIBJVM_DB_DIZ) $(LIBJVM_DB_G_DIZ); }
endif
endif
$(XLIBJVM_DTRACE): $(ADD_GNU_DEBUGLINK) $(FIX_EMPTY_SEC_HDR_FLAGS) $(DTRACE_SRCDIR)/$(JVM_DTRACE).c $(DTRACE_SRCDIR)/$(JVM_DTRACE).h $(LIBJVM_DTRACE_MAPFILE)
@echo Making $@
$(QUIETLY) mkdir -p 64/ ; \
$(QUIETLY) mkdir -p $(XLIBJVM_DIR) ; \
$(CC) $(SYMFLAG) $(ARCHFLAG/$(ISA)) -D$(TYPE) -I. \
$(SHARED_FLAG) $(LFLAGS_JVM_DTRACE) -o $@ $(DTRACE_SRCDIR)/$(JVM_DTRACE).c -lc -lthread -ldoor
[ -f $(XLIBJVM_DTRACE_G) ] || { ln -s $(LIBJVM_DTRACE) $(XLIBJVM_DTRACE_G); }
@ -153,8 +158,10 @@ ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
$(QUIETLY) $(FIX_EMPTY_SEC_HDR_FLAGS) $@
$(QUIETLY) $(OBJCOPY) --only-keep-debug $@ $(XLIBJVM_DTRACE_DEBUGINFO)
# $(OBJCOPY) --add-gnu-debuglink=... corrupts SUNW_* sections.
# $(QUIETLY) $(OBJCOPY) --add-gnu-debuglink=$(XLIBJVM_DTRACE_DEBUGINFO) $@
$(QUIETLY) $(ADD_GNU_DEBUGLINK) $(XLIBJVM_DTRACE_DEBUGINFO) $@
# $(OBJCOPY) --add-gnu-debuglink=$(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE) ;
# Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) is not
# in the link name:
( cd $(XLIBJVM_DIR) && $(ADD_GNU_DEBUGLINK) $(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE) )
ifeq ($(STRIP_POLICY),all_strip)
$(QUIETLY) $(STRIP) $@
else
@ -163,11 +170,13 @@ ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
# implied else here is no stripping at all
endif
endif
[ -f $(XLIBJVM_DTRACE_G_DEBUGINFO) ] || { ln -s $(XLIBJVM_DTRACE_DEBUGINFO) $(XLIBJVM_DTRACE_G_DEBUGINFO); }
[ -f $(XLIBJVM_DTRACE_G_DEBUGINFO) ] || { cd $(XLIBJVM_DIR) && ln -s $(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE_G_DEBUGINFO); }
ifeq ($(ZIP_DEBUGINFO_FILES),1)
$(ZIPEXE) -q -y $(XLIBJVM_DTRACE_DIZ) $(XLIBJVM_DTRACE_DEBUGINFO) $(XLIBJVM_DTRACE_G_DEBUGINFO)
# Do this part in the $(XLIBJVM_DIR) subdir so $(XLIBJVM_DIR) is not
# in the archived name:
( cd $(XLIBJVM_DIR) && $(ZIPEXE) -q -y $(LIBJVM_DTRACE_DIZ) $(LIBJVM_DTRACE_DEBUGINFO) $(LIBJVM_DTRACE_G_DEBUGINFO) )
$(RM) $(XLIBJVM_DTRACE_DEBUGINFO) $(XLIBJVM_DTRACE_G_DEBUGINFO)
[ -f $(XLIBJVM_DTRACE_G_DIZ) ] || { ln -s $(XLIBJVM_DTRACE_DIZ) $(XLIBJVM_DTRACE_G_DIZ); }
[ -f $(XLIBJVM_DTRACE_G_DIZ) ] || { cd $(XLIBJVM_DIR) && ln -s $(LIBJVM_DTRACE_DIZ) $(LIBJVM_DTRACE_G_DIZ); }
endif
endif

@ -24,8 +24,11 @@
# Rules to build fix_empty_sec_hdr_flags, used by vm.make on Solaris
GENERATED = ../generated
FIX_EMPTY_SEC_HDR_FLAGS = $(GENERATED)/fix_empty_sec_hdr_flags
# Allow $(FIX_EMPTY_SEC_HDR_FLAGS) to be called from any directory.
# We don't set or use the GENERATED macro to avoid affecting
# other HotSpot Makefiles.
TOPDIR = $(shell echo `pwd`)
FIX_EMPTY_SEC_HDR_FLAGS = $(TOPDIR)/../generated/fix_empty_sec_hdr_flags
FIX_EMPTY_SEC_HDR_FLAGS_DIR = $(GAMMADIR)/src/os/solaris/fix_empty_sec_hdr_flags
FIX_EMPTY_SEC_HDR_FLAGS_SRC = $(FIX_EMPTY_SEC_HDR_FLAGS_DIR)/fix_empty_sec_hdr_flags.c

@ -1,5 +1,5 @@
//
// Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// This code is free software; you can redistribute it and/or modify it
@ -678,18 +678,26 @@ intptr_t get_offset_from_base_2(const MachNode* n, const TypePtr* atype, int dis
static inline jdouble replicate_immI(int con, int count, int width) {
// Load a constant replicated "count" times with width "width"
assert(count*width == 8 && width <= 4, "sanity");
int bit_width = width * 8;
jlong elt_val = con;
elt_val &= (((jlong) 1) << bit_width) - 1; // mask off sign bits
jlong val = elt_val;
jlong val = con;
val &= (((jlong) 1) << bit_width) - 1; // mask off sign bits
for (int i = 0; i < count - 1; i++) {
val <<= bit_width;
val |= elt_val;
val |= (val << bit_width);
}
jdouble dval = *((jdouble*) &val); // coerce to double type
return dval;
}
static inline jdouble replicate_immF(float con) {
// Replicate float con 2 times and pack into vector.
int val = *((int*)&con);
jlong lval = val;
lval = (lval << 32) | (lval & 0xFFFFFFFFl);
jdouble dval = *((jdouble*) &lval); // coerce to double type
return dval;
}
// Standard Sparc opcode form2 field breakdown
static inline void emit2_19(CodeBuffer &cbuf, int f30, int f29, int f25, int f22, int f20, int f19, int f0 ) {
f0 &= (1<<19)-1; // Mask displacement to 19 bits
@ -791,6 +799,7 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, const MachNode* n, int primary, int te
case Assembler::stdf_op3: st_op = Op_StoreD; break;
case Assembler::ldsb_op3: ld_op = Op_LoadB; break;
case Assembler::ldub_op3: ld_op = Op_LoadUB; break;
case Assembler::lduh_op3: ld_op = Op_LoadUS; break;
case Assembler::ldsh_op3: ld_op = Op_LoadS; break;
case Assembler::ldx_op3: // may become LoadP or stay LoadI
@ -799,7 +808,6 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, const MachNode* n, int primary, int te
case Assembler::ldd_op3: ld_op = Op_LoadL; break;
case Assembler::ldf_op3: ld_op = Op_LoadF; break;
case Assembler::lddf_op3: ld_op = Op_LoadD; break;
case Assembler::ldub_op3: ld_op = Op_LoadB; break;
case Assembler::prefetch_op3: ld_op = Op_LoadI; break;
default: ShouldNotReachHere();
@ -840,10 +848,7 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, const MachNode* n, int primary, int te
!(n->ideal_Opcode()==Op_PrefetchRead && ld_op==Op_LoadI) &&
!(n->ideal_Opcode()==Op_PrefetchWrite && ld_op==Op_LoadI) &&
!(n->ideal_Opcode()==Op_PrefetchAllocation && ld_op==Op_LoadI) &&
!(n->ideal_Opcode()==Op_Load2I && ld_op==Op_LoadD) &&
!(n->ideal_Opcode()==Op_Load4C && ld_op==Op_LoadD) &&
!(n->ideal_Opcode()==Op_Load4S && ld_op==Op_LoadD) &&
!(n->ideal_Opcode()==Op_Load8B && ld_op==Op_LoadD) &&
!(n->ideal_Opcode()==Op_LoadVector && ld_op==Op_LoadD) &&
!(n->rule() == loadUB_rule)) {
verify_oops_warning(n, n->ideal_Opcode(), ld_op);
}
@ -855,9 +860,7 @@ void emit_form3_mem_reg(CodeBuffer &cbuf, const MachNode* n, int primary, int te
!(n->ideal_Opcode()==Op_StoreI && st_op==Op_StoreF) &&
!(n->ideal_Opcode()==Op_StoreF && st_op==Op_StoreI) &&
!(n->ideal_Opcode()==Op_StoreL && st_op==Op_StoreI) &&
!(n->ideal_Opcode()==Op_Store2I && st_op==Op_StoreD) &&
!(n->ideal_Opcode()==Op_Store4C && st_op==Op_StoreD) &&
!(n->ideal_Opcode()==Op_Store8B && st_op==Op_StoreD) &&
!(n->ideal_Opcode()==Op_StoreVector && st_op==Op_StoreD) &&
!(n->ideal_Opcode()==Op_StoreD && st_op==Op_StoreI && n->rule() == storeD0_rule)) {
verify_oops_warning(n, n->ideal_Opcode(), st_op);
}
@ -1849,16 +1852,45 @@ int Matcher::regnum_to_fpu_offset(int regnum) {
address last_rethrow = NULL; // debugging aid for Rethrow encoding
#endif
// Map Types to machine register types
const int Matcher::base2reg[Type::lastype] = {
Node::NotAMachineReg,0,0, Op_RegI, Op_RegL, 0, Op_RegN,
Node::NotAMachineReg, Node::NotAMachineReg, /* tuple, array */
0, Op_RegD, 0, 0, /* Vectors */
Op_RegP, Op_RegP, Op_RegP, Op_RegP, Op_RegP, Op_RegP, /* the pointers */
0, 0/*abio*/,
Op_RegP /* Return address */, 0, /* the memories */
Op_RegF, Op_RegF, Op_RegF, Op_RegD, Op_RegD, Op_RegD,
0 /*bottom*/
};
// Vector width in bytes
const uint Matcher::vector_width_in_bytes(void) {
const int Matcher::vector_width_in_bytes(BasicType bt) {
assert(MaxVectorSize == 8, "");
return 8;
}
// Vector ideal reg
const uint Matcher::vector_ideal_reg(void) {
const int Matcher::vector_ideal_reg(int size) {
assert(MaxVectorSize == 8, "");
return Op_RegD;
}
// Limits on vector size (number of elements) loaded into vector.
const int Matcher::max_vector_size(const BasicType bt) {
assert(is_java_primitive(bt), "only primitive type vectors");
return vector_width_in_bytes(bt)/type2aelembytes(bt);
}
const int Matcher::min_vector_size(const BasicType bt) {
return max_vector_size(bt); // Same as max.
}
// SPARC doesn't support misaligned vectors store/load.
const bool Matcher::misaligned_vectors_ok() {
return false;
}
// USII supports fxtof through the whole range of number, USIII doesn't
const bool Matcher::convL2FSupported(void) {
return VM_Version::has_fast_fxtof();
@ -3125,50 +3157,6 @@ enc_class enc_Array_Equals(o0RegP ary1, o1RegP ary2, g3RegP tmp1, notemp_iRegI r
__ membar( Assembler::Membar_mask_bits(Assembler::StoreLoad) );
%}
enc_class enc_repl8b( iRegI src, iRegL dst ) %{
MacroAssembler _masm(&cbuf);
Register src_reg = reg_to_register_object($src$$reg);
Register dst_reg = reg_to_register_object($dst$$reg);
__ sllx(src_reg, 56, dst_reg);
__ srlx(dst_reg, 8, O7);
__ or3 (dst_reg, O7, dst_reg);
__ srlx(dst_reg, 16, O7);
__ or3 (dst_reg, O7, dst_reg);
__ srlx(dst_reg, 32, O7);
__ or3 (dst_reg, O7, dst_reg);
%}
enc_class enc_repl4b( iRegI src, iRegL dst ) %{
MacroAssembler _masm(&cbuf);
Register src_reg = reg_to_register_object($src$$reg);
Register dst_reg = reg_to_register_object($dst$$reg);
__ sll(src_reg, 24, dst_reg);
__ srl(dst_reg, 8, O7);
__ or3(dst_reg, O7, dst_reg);
__ srl(dst_reg, 16, O7);
__ or3(dst_reg, O7, dst_reg);
%}
enc_class enc_repl4s( iRegI src, iRegL dst ) %{
MacroAssembler _masm(&cbuf);
Register src_reg = reg_to_register_object($src$$reg);
Register dst_reg = reg_to_register_object($dst$$reg);
__ sllx(src_reg, 48, dst_reg);
__ srlx(dst_reg, 16, O7);
__ or3 (dst_reg, O7, dst_reg);
__ srlx(dst_reg, 32, O7);
__ or3 (dst_reg, O7, dst_reg);
%}
enc_class enc_repl2i( iRegI src, iRegL dst ) %{
MacroAssembler _masm(&cbuf);
Register src_reg = reg_to_register_object($src$$reg);
Register dst_reg = reg_to_register_object($dst$$reg);
__ sllx(src_reg, 32, dst_reg);
__ srlx(dst_reg, 32, O7);
__ or3 (dst_reg, O7, dst_reg);
%}
%}
//----------FRAME--------------------------------------------------------------
@ -5932,50 +5920,6 @@ instruct loadL_unaligned(iRegL dst, memory mem, o7RegI tmp) %{
ins_pipe(iload_mem);
%}
// Load Aligned Packed Byte into a Double Register
instruct loadA8B(regD dst, memory mem) %{
match(Set dst (Load8B mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDDF $mem,$dst\t! packed8B" %}
opcode(Assembler::lddf_op3);
ins_encode(simple_form3_mem_reg( mem, dst ) );
ins_pipe(floadD_mem);
%}
// Load Aligned Packed Char into a Double Register
instruct loadA4C(regD dst, memory mem) %{
match(Set dst (Load4C mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDDF $mem,$dst\t! packed4C" %}
opcode(Assembler::lddf_op3);
ins_encode(simple_form3_mem_reg( mem, dst ) );
ins_pipe(floadD_mem);
%}
// Load Aligned Packed Short into a Double Register
instruct loadA4S(regD dst, memory mem) %{
match(Set dst (Load4S mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDDF $mem,$dst\t! packed4S" %}
opcode(Assembler::lddf_op3);
ins_encode(simple_form3_mem_reg( mem, dst ) );
ins_pipe(floadD_mem);
%}
// Load Aligned Packed Int into a Double Register
instruct loadA2I(regD dst, memory mem) %{
match(Set dst (Load2I mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDDF $mem,$dst\t! packed2I" %}
opcode(Assembler::lddf_op3);
ins_encode(simple_form3_mem_reg( mem, dst ) );
ins_pipe(floadD_mem);
%}
// Load Range
instruct loadRange(iRegI dst, memory mem) %{
match(Set dst (LoadRange mem));
@ -6599,17 +6543,6 @@ instruct storeF0( memory mem, immF0 src) %{
ins_pipe(fstoreF_mem_zero);
%}
// Store Aligned Packed Bytes in Double register to memory
instruct storeA8B(memory mem, regD src) %{
match(Set mem (Store8B mem src));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STDF $src,$mem\t! packed8B" %}
opcode(Assembler::stdf_op3);
ins_encode(simple_form3_mem_reg( mem, src ) );
ins_pipe(fstoreD_mem_reg);
%}
// Convert oop pointer into compressed form
instruct encodeHeapOop(iRegN dst, iRegP src) %{
predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull);
@ -6654,62 +6587,6 @@ instruct decodeHeapOop_not_null(iRegP dst, iRegN src) %{
%}
// Store Zero into Aligned Packed Bytes
instruct storeA8B0(memory mem, immI0 zero) %{
match(Set mem (Store8B mem zero));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STX $zero,$mem\t! packed8B" %}
opcode(Assembler::stx_op3);
ins_encode(simple_form3_mem_reg( mem, R_G0 ) );
ins_pipe(fstoreD_mem_zero);
%}
// Store Aligned Packed Chars/Shorts in Double register to memory
instruct storeA4C(memory mem, regD src) %{
match(Set mem (Store4C mem src));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STDF $src,$mem\t! packed4C" %}
opcode(Assembler::stdf_op3);
ins_encode(simple_form3_mem_reg( mem, src ) );
ins_pipe(fstoreD_mem_reg);
%}
// Store Zero into Aligned Packed Chars/Shorts
instruct storeA4C0(memory mem, immI0 zero) %{
match(Set mem (Store4C mem (Replicate4C zero)));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STX $zero,$mem\t! packed4C" %}
opcode(Assembler::stx_op3);
ins_encode(simple_form3_mem_reg( mem, R_G0 ) );
ins_pipe(fstoreD_mem_zero);
%}
// Store Aligned Packed Ints in Double register to memory
instruct storeA2I(memory mem, regD src) %{
match(Set mem (Store2I mem src));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STDF $src,$mem\t! packed2I" %}
opcode(Assembler::stdf_op3);
ins_encode(simple_form3_mem_reg( mem, src ) );
ins_pipe(fstoreD_mem_reg);
%}
// Store Zero into Aligned Packed Ints
instruct storeA2I0(memory mem, immI0 zero) %{
match(Set mem (Store2I mem zero));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STX $zero,$mem\t! packed2I" %}
opcode(Assembler::stx_op3);
ins_encode(simple_form3_mem_reg( mem, R_G0 ) );
ins_pipe(fstoreD_mem_zero);
%}
//----------MemBar Instructions-----------------------------------------------
// Memory barrier flavors
@ -8880,150 +8757,6 @@ instruct shrL_reg_imm6_L2I(iRegI dst, iRegL src, immI_32_63 cnt) %{
ins_pipe(ialu_reg_imm);
%}
// Replicate scalar to packed byte values in Double register
instruct Repl8B_reg_helper(iRegL dst, iRegI src) %{
effect(DEF dst, USE src);
format %{ "SLLX $src,56,$dst\n\t"
"SRLX $dst, 8,O7\n\t"
"OR $dst,O7,$dst\n\t"
"SRLX $dst,16,O7\n\t"
"OR $dst,O7,$dst\n\t"
"SRLX $dst,32,O7\n\t"
"OR $dst,O7,$dst\t! replicate8B" %}
ins_encode( enc_repl8b(src, dst));
ins_pipe(ialu_reg);
%}
// Replicate scalar to packed byte values in Double register
instruct Repl8B_reg(stackSlotD dst, iRegI src) %{
match(Set dst (Replicate8B src));
expand %{
iRegL tmp;
Repl8B_reg_helper(tmp, src);
regL_to_stkD(dst, tmp);
%}
%}
// Replicate scalar constant to packed byte values in Double register
instruct Repl8B_immI(regD dst, immI13 con, o7RegI tmp) %{
match(Set dst (Replicate8B con));
effect(KILL tmp);
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl8B($con)" %}
ins_encode %{
// XXX This is a quick fix for 6833573.
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 8, 1)), $dst$$FloatRegister);
RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 8, 1)), $tmp$$Register);
__ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
%}
ins_pipe(loadConFD);
%}
// Replicate scalar to packed char values into stack slot
instruct Repl4C_reg_helper(iRegL dst, iRegI src) %{
effect(DEF dst, USE src);
format %{ "SLLX $src,48,$dst\n\t"
"SRLX $dst,16,O7\n\t"
"OR $dst,O7,$dst\n\t"
"SRLX $dst,32,O7\n\t"
"OR $dst,O7,$dst\t! replicate4C" %}
ins_encode( enc_repl4s(src, dst) );
ins_pipe(ialu_reg);
%}
// Replicate scalar to packed char values into stack slot
instruct Repl4C_reg(stackSlotD dst, iRegI src) %{
match(Set dst (Replicate4C src));
expand %{
iRegL tmp;
Repl4C_reg_helper(tmp, src);
regL_to_stkD(dst, tmp);
%}
%}
// Replicate scalar constant to packed char values in Double register
instruct Repl4C_immI(regD dst, immI con, o7RegI tmp) %{
match(Set dst (Replicate4C con));
effect(KILL tmp);
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl4C($con)" %}
ins_encode %{
// XXX This is a quick fix for 6833573.
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 4, 2)), $dst$$FloatRegister);
RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 4, 2)), $tmp$$Register);
__ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
%}
ins_pipe(loadConFD);
%}
// Replicate scalar to packed short values into stack slot
instruct Repl4S_reg_helper(iRegL dst, iRegI src) %{
effect(DEF dst, USE src);
format %{ "SLLX $src,48,$dst\n\t"
"SRLX $dst,16,O7\n\t"
"OR $dst,O7,$dst\n\t"
"SRLX $dst,32,O7\n\t"
"OR $dst,O7,$dst\t! replicate4S" %}
ins_encode( enc_repl4s(src, dst) );
ins_pipe(ialu_reg);
%}
// Replicate scalar to packed short values into stack slot
instruct Repl4S_reg(stackSlotD dst, iRegI src) %{
match(Set dst (Replicate4S src));
expand %{
iRegL tmp;
Repl4S_reg_helper(tmp, src);
regL_to_stkD(dst, tmp);
%}
%}
// Replicate scalar constant to packed short values in Double register
instruct Repl4S_immI(regD dst, immI con, o7RegI tmp) %{
match(Set dst (Replicate4S con));
effect(KILL tmp);
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl4S($con)" %}
ins_encode %{
// XXX This is a quick fix for 6833573.
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 4, 2)), $dst$$FloatRegister);
RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 4, 2)), $tmp$$Register);
__ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
%}
ins_pipe(loadConFD);
%}
// Replicate scalar to packed int values in Double register
instruct Repl2I_reg_helper(iRegL dst, iRegI src) %{
effect(DEF dst, USE src);
format %{ "SLLX $src,32,$dst\n\t"
"SRLX $dst,32,O7\n\t"
"OR $dst,O7,$dst\t! replicate2I" %}
ins_encode( enc_repl2i(src, dst));
ins_pipe(ialu_reg);
%}
// Replicate scalar to packed int values in Double register
instruct Repl2I_reg(stackSlotD dst, iRegI src) %{
match(Set dst (Replicate2I src));
expand %{
iRegL tmp;
Repl2I_reg_helper(tmp, src);
regL_to_stkD(dst, tmp);
%}
%}
// Replicate scalar zero constant to packed int values in Double register
instruct Repl2I_immI(regD dst, immI con, o7RegI tmp) %{
match(Set dst (Replicate2I con));
effect(KILL tmp);
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl2I($con)" %}
ins_encode %{
// XXX This is a quick fix for 6833573.
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 2, 4)), $dst$$FloatRegister);
RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 2, 4)), $tmp$$Register);
__ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
%}
ins_pipe(loadConFD);
%}
//----------Control Flow Instructions------------------------------------------
// Compare Instructions
// Compare Integers
@ -10742,6 +10475,308 @@ instruct storeS_reversed(indIndexMemory dst, iRegI src) %{
ins_pipe(istore_mem_reg);
%}
// ====================VECTOR INSTRUCTIONS=====================================
// Load Aligned Packed values into a Double Register
instruct loadV8(regD dst, memory mem) %{
predicate(n->as_LoadVector()->memory_size() == 8);
match(Set dst (LoadVector mem));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "LDDF $mem,$dst\t! load vector (8 bytes)" %}
ins_encode %{
__ ldf(FloatRegisterImpl::D, $mem$$Address, as_DoubleFloatRegister($dst$$reg));
%}
ins_pipe(floadD_mem);
%}
// Store Vector in Double register to memory
instruct storeV8(memory mem, regD src) %{
predicate(n->as_StoreVector()->memory_size() == 8);
match(Set mem (StoreVector mem src));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STDF $src,$mem\t! store vector (8 bytes)" %}
ins_encode %{
__ stf(FloatRegisterImpl::D, as_DoubleFloatRegister($src$$reg), $mem$$Address);
%}
ins_pipe(fstoreD_mem_reg);
%}
// Store Zero into vector in memory
instruct storeV8B_zero(memory mem, immI0 zero) %{
predicate(n->as_StoreVector()->memory_size() == 8);
match(Set mem (StoreVector mem (ReplicateB zero)));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STX $zero,$mem\t! store zero vector (8 bytes)" %}
ins_encode %{
__ stx(G0, $mem$$Address);
%}
ins_pipe(fstoreD_mem_zero);
%}
instruct storeV4S_zero(memory mem, immI0 zero) %{
predicate(n->as_StoreVector()->memory_size() == 8);
match(Set mem (StoreVector mem (ReplicateS zero)));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STX $zero,$mem\t! store zero vector (4 shorts)" %}
ins_encode %{
__ stx(G0, $mem$$Address);
%}
ins_pipe(fstoreD_mem_zero);
%}
instruct storeV2I_zero(memory mem, immI0 zero) %{
predicate(n->as_StoreVector()->memory_size() == 8);
match(Set mem (StoreVector mem (ReplicateI zero)));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STX $zero,$mem\t! store zero vector (2 ints)" %}
ins_encode %{
__ stx(G0, $mem$$Address);
%}
ins_pipe(fstoreD_mem_zero);
%}
instruct storeV2F_zero(memory mem, immF0 zero) %{
predicate(n->as_StoreVector()->memory_size() == 8);
match(Set mem (StoreVector mem (ReplicateF zero)));
ins_cost(MEMORY_REF_COST);
size(4);
format %{ "STX $zero,$mem\t! store zero vector (2 floats)" %}
ins_encode %{
__ stx(G0, $mem$$Address);
%}
ins_pipe(fstoreD_mem_zero);
%}
// Replicate scalar to packed byte values into Double register
instruct Repl8B_reg(regD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
predicate(n->as_Vector()->length() == 8 && UseVIS >= 3);
match(Set dst (ReplicateB src));
effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
format %{ "SLLX $src,56,$tmp\n\t"
"SRLX $tmp, 8,$tmp2\n\t"
"OR $tmp,$tmp2,$tmp\n\t"
"SRLX $tmp,16,$tmp2\n\t"
"OR $tmp,$tmp2,$tmp\n\t"
"SRLX $tmp,32,$tmp2\n\t"
"OR $tmp,$tmp2,$tmp\t! replicate8B\n\t"
"MOVXTOD $tmp,$dst\t! MoveL2D" %}
ins_encode %{
Register Rsrc = $src$$Register;
Register Rtmp = $tmp$$Register;
Register Rtmp2 = $tmp2$$Register;
__ sllx(Rsrc, 56, Rtmp);
__ srlx(Rtmp, 8, Rtmp2);
__ or3 (Rtmp, Rtmp2, Rtmp);
__ srlx(Rtmp, 16, Rtmp2);
__ or3 (Rtmp, Rtmp2, Rtmp);
__ srlx(Rtmp, 32, Rtmp2);
__ or3 (Rtmp, Rtmp2, Rtmp);
__ movxtod(Rtmp, as_DoubleFloatRegister($dst$$reg));
%}
ins_pipe(ialu_reg);
%}
// Replicate scalar to packed byte values into Double stack
instruct Repl8B_stk(stackSlotD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
predicate(n->as_Vector()->length() == 8 && UseVIS < 3);
match(Set dst (ReplicateB src));
effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
format %{ "SLLX $src,56,$tmp\n\t"
"SRLX $tmp, 8,$tmp2\n\t"
"OR $tmp,$tmp2,$tmp\n\t"
"SRLX $tmp,16,$tmp2\n\t"
"OR $tmp,$tmp2,$tmp\n\t"
"SRLX $tmp,32,$tmp2\n\t"
"OR $tmp,$tmp2,$tmp\t! replicate8B\n\t"
"STX $tmp,$dst\t! regL to stkD" %}
ins_encode %{
Register Rsrc = $src$$Register;
Register Rtmp = $tmp$$Register;
Register Rtmp2 = $tmp2$$Register;
__ sllx(Rsrc, 56, Rtmp);
__ srlx(Rtmp, 8, Rtmp2);
__ or3 (Rtmp, Rtmp2, Rtmp);
__ srlx(Rtmp, 16, Rtmp2);
__ or3 (Rtmp, Rtmp2, Rtmp);
__ srlx(Rtmp, 32, Rtmp2);
__ or3 (Rtmp, Rtmp2, Rtmp);
__ set ($dst$$disp + STACK_BIAS, Rtmp2);
__ stx (Rtmp, Rtmp2, $dst$$base$$Register);
%}
ins_pipe(ialu_reg);
%}
// Replicate scalar constant to packed byte values in Double register
instruct Repl8B_immI(regD dst, immI13 con, o7RegI tmp) %{
predicate(n->as_Vector()->length() == 8);
match(Set dst (ReplicateB con));
effect(KILL tmp);
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl8B($con)" %}
ins_encode %{
// XXX This is a quick fix for 6833573.
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 8, 1)), $dst$$FloatRegister);
RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 8, 1)), $tmp$$Register);
__ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
%}
ins_pipe(loadConFD);
%}
// Replicate scalar to packed char/short values into Double register
instruct Repl4S_reg(regD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
predicate(n->as_Vector()->length() == 4 && UseVIS >= 3);
match(Set dst (ReplicateS src));
effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
format %{ "SLLX $src,48,$tmp\n\t"
"SRLX $tmp,16,$tmp2\n\t"
"OR $tmp,$tmp2,$tmp\n\t"
"SRLX $tmp,32,$tmp2\n\t"
"OR $tmp,$tmp2,$tmp\t! replicate4S\n\t"
"MOVXTOD $tmp,$dst\t! MoveL2D" %}
ins_encode %{
Register Rsrc = $src$$Register;
Register Rtmp = $tmp$$Register;
Register Rtmp2 = $tmp2$$Register;
__ sllx(Rsrc, 48, Rtmp);
__ srlx(Rtmp, 16, Rtmp2);
__ or3 (Rtmp, Rtmp2, Rtmp);
__ srlx(Rtmp, 32, Rtmp2);
__ or3 (Rtmp, Rtmp2, Rtmp);
__ movxtod(Rtmp, as_DoubleFloatRegister($dst$$reg));
%}
ins_pipe(ialu_reg);
%}
// Replicate scalar to packed char/short values into Double stack
instruct Repl4S_stk(stackSlotD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
predicate(n->as_Vector()->length() == 4 && UseVIS < 3);
match(Set dst (ReplicateS src));
effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
format %{ "SLLX $src,48,$tmp\n\t"
"SRLX $tmp,16,$tmp2\n\t"
"OR $tmp,$tmp2,$tmp\n\t"
"SRLX $tmp,32,$tmp2\n\t"
"OR $tmp,$tmp2,$tmp\t! replicate4S\n\t"
"STX $tmp,$dst\t! regL to stkD" %}
ins_encode %{
Register Rsrc = $src$$Register;
Register Rtmp = $tmp$$Register;
Register Rtmp2 = $tmp2$$Register;
__ sllx(Rsrc, 48, Rtmp);
__ srlx(Rtmp, 16, Rtmp2);
__ or3 (Rtmp, Rtmp2, Rtmp);
__ srlx(Rtmp, 32, Rtmp2);
__ or3 (Rtmp, Rtmp2, Rtmp);
__ set ($dst$$disp + STACK_BIAS, Rtmp2);
__ stx (Rtmp, Rtmp2, $dst$$base$$Register);
%}
ins_pipe(ialu_reg);
%}
// Replicate scalar constant to packed char/short values in Double register
instruct Repl4S_immI(regD dst, immI con, o7RegI tmp) %{
predicate(n->as_Vector()->length() == 4);
match(Set dst (ReplicateS con));
effect(KILL tmp);
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl4S($con)" %}
ins_encode %{
// XXX This is a quick fix for 6833573.
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 4, 2)), $dst$$FloatRegister);
RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 4, 2)), $tmp$$Register);
__ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
%}
ins_pipe(loadConFD);
%}
// Replicate scalar to packed int values into Double register
instruct Repl2I_reg(regD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
predicate(n->as_Vector()->length() == 2 && UseVIS >= 3);
match(Set dst (ReplicateI src));
effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
format %{ "SLLX $src,32,$tmp\n\t"
"SRLX $tmp,32,$tmp2\n\t"
"OR $tmp,$tmp2,$tmp\t! replicate2I\n\t"
"MOVXTOD $tmp,$dst\t! MoveL2D" %}
ins_encode %{
Register Rsrc = $src$$Register;
Register Rtmp = $tmp$$Register;
Register Rtmp2 = $tmp2$$Register;
__ sllx(Rsrc, 32, Rtmp);
__ srlx(Rtmp, 32, Rtmp2);
__ or3 (Rtmp, Rtmp2, Rtmp);
__ movxtod(Rtmp, as_DoubleFloatRegister($dst$$reg));
%}
ins_pipe(ialu_reg);
%}
// Replicate scalar to packed int values into Double stack
instruct Repl2I_stk(stackSlotD dst, iRegI src, iRegL tmp, o7RegL tmp2) %{
predicate(n->as_Vector()->length() == 2 && UseVIS < 3);
match(Set dst (ReplicateI src));
effect(DEF dst, USE src, TEMP tmp, KILL tmp2);
format %{ "SLLX $src,32,$tmp\n\t"
"SRLX $tmp,32,$tmp2\n\t"
"OR $tmp,$tmp2,$tmp\t! replicate2I\n\t"
"STX $tmp,$dst\t! regL to stkD" %}
ins_encode %{
Register Rsrc = $src$$Register;
Register Rtmp = $tmp$$Register;
Register Rtmp2 = $tmp2$$Register;
__ sllx(Rsrc, 32, Rtmp);
__ srlx(Rtmp, 32, Rtmp2);
__ or3 (Rtmp, Rtmp2, Rtmp);
__ set ($dst$$disp + STACK_BIAS, Rtmp2);
__ stx (Rtmp, Rtmp2, $dst$$base$$Register);
%}
ins_pipe(ialu_reg);
%}
// Replicate scalar zero constant to packed int values in Double register
instruct Repl2I_immI(regD dst, immI con, o7RegI tmp) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (ReplicateI con));
effect(KILL tmp);
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl2I($con)" %}
ins_encode %{
// XXX This is a quick fix for 6833573.
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immI($con$$constant, 2, 4)), $dst$$FloatRegister);
RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immI($con$$constant, 2, 4)), $tmp$$Register);
__ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
%}
ins_pipe(loadConFD);
%}
// Replicate scalar to packed float values into Double stack
instruct Repl2F_stk(stackSlotD dst, regF src) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (ReplicateF src));
ins_cost(MEMORY_REF_COST*2);
format %{ "STF $src,$dst.hi\t! packed2F\n\t"
"STF $src,$dst.lo" %}
opcode(Assembler::stf_op3);
ins_encode(simple_form3_mem_reg(dst, src), form3_mem_plus_4_reg(dst, src));
ins_pipe(fstoreF_stk_reg);
%}
// Replicate scalar zero constant to packed float values in Double register
instruct Repl2F_immF(regD dst, immF con, o7RegI tmp) %{
predicate(n->as_Vector()->length() == 2);
match(Set dst (ReplicateF con));
effect(KILL tmp);
format %{ "LDDF [$constanttablebase + $constantoffset],$dst\t! load from constant table: Repl2F($con)" %}
ins_encode %{
// XXX This is a quick fix for 6833573.
//__ ldf(FloatRegisterImpl::D, $constanttablebase, $constantoffset(replicate_immF($con$$constant)), $dst$$FloatRegister);
RegisterOrConstant con_offset = __ ensure_simm13_or_reg($constantoffset(replicate_immF($con$$constant)), $tmp$$Register);
__ ldf(FloatRegisterImpl::D, $constanttablebase, con_offset, as_DoubleFloatRegister($dst$$reg));
%}
ins_pipe(loadConFD);
%}
//----------PEEPHOLE RULES-----------------------------------------------------
// These must follow all instruction definitions as they use the names
// defined in the instructions definitions.

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -217,6 +217,8 @@ void VM_Version::initialize() {
// Currently not supported anywhere.
FLAG_SET_DEFAULT(UseFPUForSpilling, false);
MaxVectorSize = 8;
assert((InteriorEntryAlignment % relocInfo::addr_unit()) == 0, "alignment is not a multiple of NOP size");
#endif

@ -1637,6 +1637,13 @@ void Assembler::movaps(XMMRegister dst, XMMRegister src) {
emit_byte(0xC0 | encode);
}
void Assembler::movlhps(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse(), ""));
int encode = simd_prefix_and_encode(dst, src, src, VEX_SIMD_NONE);
emit_byte(0x16);
emit_byte(0xC0 | encode);
}
void Assembler::movb(Register dst, Address src) {
NOT_LP64(assert(dst->has_byte_register(), "must have byte register"));
InstructionMark im(this);
@ -1686,6 +1693,14 @@ void Assembler::movdl(XMMRegister dst, Address src) {
emit_operand(dst, src);
}
void Assembler::movdl(Address dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
InstructionMark im(this);
simd_prefix(dst, src, VEX_SIMD_66);
emit_byte(0x7E);
emit_operand(src, dst);
}
void Assembler::movdqa(XMMRegister dst, XMMRegister src) {
NOT_LP64(assert(VM_Version::supports_sse2(), ""));
int encode = simd_prefix_and_encode(dst, src, VEX_SIMD_66);
@ -1716,6 +1731,35 @@ void Assembler::movdqu(Address dst, XMMRegister src) {
emit_operand(src, dst);
}
// Move Unaligned 256bit Vector
void Assembler::vmovdqu(XMMRegister dst, XMMRegister src) {
assert(UseAVX, "");
bool vector256 = true;
int encode = vex_prefix_and_encode(dst, xnoreg, src, VEX_SIMD_F3, vector256);
emit_byte(0x6F);
emit_byte(0xC0 | encode);
}
void Assembler::vmovdqu(XMMRegister dst, Address src) {
assert(UseAVX, "");
InstructionMark im(this);
bool vector256 = true;
vex_prefix(dst, xnoreg, src, VEX_SIMD_F3, vector256);
emit_byte(0x6F);
emit_operand(dst, src);
}
void Assembler::vmovdqu(Address dst, XMMRegister src) {
assert(UseAVX, "");
InstructionMark im(this);
bool vector256 = true;
// swap src<->dst for encoding
assert(src != xnoreg, "sanity");
vex_prefix(src, xnoreg, dst, VEX_SIMD_F3, vector256);
emit_byte(0x7F);
emit_operand(src, dst);
}
// Uses zero extension on 64bit
void Assembler::movl(Register dst, int32_t imm32) {
@ -3112,6 +3156,13 @@ void Assembler::vxorpd(XMMRegister dst, XMMRegister nds, Address src) {
emit_operand(dst, src);
}
void Assembler::vxorpd(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) {
assert(VM_Version::supports_avx(), "");
int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector256);
emit_byte(0x57);
emit_byte(0xC0 | encode);
}
void Assembler::vxorps(XMMRegister dst, XMMRegister nds, Address src) {
assert(VM_Version::supports_avx(), "");
InstructionMark im(this);
@ -3120,6 +3171,30 @@ void Assembler::vxorps(XMMRegister dst, XMMRegister nds, Address src) {
emit_operand(dst, src);
}
void Assembler::vxorps(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) {
assert(VM_Version::supports_avx(), "");
int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_NONE, vector256);
emit_byte(0x57);
emit_byte(0xC0 | encode);
}
void Assembler::vinsertf128h(XMMRegister dst, XMMRegister nds, XMMRegister src) {
assert(VM_Version::supports_avx(), "");
bool vector256 = true;
int encode = vex_prefix_and_encode(dst, nds, src, VEX_SIMD_66, vector256, VEX_OPCODE_0F_3A);
emit_byte(0x18);
emit_byte(0xC0 | encode);
// 0x00 - insert into lower 128 bits
// 0x01 - insert into upper 128 bits
emit_byte(0x01);
}
void Assembler::vzeroupper() {
assert(VM_Version::supports_avx(), "");
(void)vex_prefix_and_encode(xmm0, xmm0, xmm0, VEX_SIMD_NONE);
emit_byte(0x77);
}
#ifndef _LP64
// 32bit only pieces of the assembler

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -591,8 +591,9 @@ private:
void vex_prefix(XMMRegister dst, XMMRegister nds, Address src,
VexSimdPrefix pre, bool vector256 = false) {
vex_prefix(src, nds->encoding(), dst->encoding(),
pre, VEX_OPCODE_0F, false, vector256);
int dst_enc = dst->encoding();
int nds_enc = nds->is_valid() ? nds->encoding() : 0;
vex_prefix(src, nds_enc, dst_enc, pre, VEX_OPCODE_0F, false, vector256);
}
int vex_prefix_and_encode(int dst_enc, int nds_enc, int src_enc,
@ -600,9 +601,12 @@ private:
bool vex_w, bool vector256);
int vex_prefix_and_encode(XMMRegister dst, XMMRegister nds, XMMRegister src,
VexSimdPrefix pre, bool vector256 = false) {
return vex_prefix_and_encode(dst->encoding(), nds->encoding(), src->encoding(),
pre, VEX_OPCODE_0F, false, vector256);
VexSimdPrefix pre, bool vector256 = false,
VexOpcode opc = VEX_OPCODE_0F) {
int src_enc = src->encoding();
int dst_enc = dst->encoding();
int nds_enc = nds->is_valid() ? nds->encoding() : 0;
return vex_prefix_and_encode(dst_enc, nds_enc, src_enc, pre, opc, false, vector256);
}
void simd_prefix(XMMRegister xreg, XMMRegister nds, Address adr,
@ -1261,6 +1265,7 @@ private:
void movdl(XMMRegister dst, Register src);
void movdl(Register dst, XMMRegister src);
void movdl(XMMRegister dst, Address src);
void movdl(Address dst, XMMRegister src);
// Move Double Quadword
void movdq(XMMRegister dst, Register src);
@ -1274,6 +1279,14 @@ private:
void movdqu(XMMRegister dst, Address src);
void movdqu(XMMRegister dst, XMMRegister src);
// Move Unaligned 256bit Vector
void vmovdqu(Address dst, XMMRegister src);
void vmovdqu(XMMRegister dst, Address src);
void vmovdqu(XMMRegister dst, XMMRegister src);
// Move lower 64bit to high 64bit in 128bit register
void movlhps(XMMRegister dst, XMMRegister src);
void movl(Register dst, int32_t imm32);
void movl(Address dst, int32_t imm32);
void movl(Register dst, Register src);
@ -1615,6 +1628,17 @@ private:
void vxorpd(XMMRegister dst, XMMRegister nds, Address src);
void vxorps(XMMRegister dst, XMMRegister nds, Address src);
// AVX Vector instrucitons.
void vxorpd(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256);
void vxorps(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256);
void vinsertf128h(XMMRegister dst, XMMRegister nds, XMMRegister src);
// AVX instruction which is used to clear upper 128 bits of YMM registers and
// to avoid transaction penalty between AVX and SSE states. There is no
// penalty if legacy SSE instructions are encoded using VEX prefix because
// they always clear upper 128 bits. It should be used before calling
// runtime code and native libraries.
void vzeroupper();
protected:
// Next instructions require address alignment 16 bytes SSE mode.
@ -2529,9 +2553,13 @@ public:
void vsubss(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vsubss(dst, nds, src); }
void vsubss(XMMRegister dst, XMMRegister nds, AddressLiteral src);
// AVX Vector instructions
void vxorpd(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { Assembler::vxorpd(dst, nds, src, vector256); }
void vxorpd(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vxorpd(dst, nds, src); }
void vxorpd(XMMRegister dst, XMMRegister nds, AddressLiteral src);
void vxorps(XMMRegister dst, XMMRegister nds, XMMRegister src, bool vector256) { Assembler::vxorps(dst, nds, src, vector256); }
void vxorps(XMMRegister dst, XMMRegister nds, Address src) { Assembler::vxorps(dst, nds, src); }
void vxorps(XMMRegister dst, XMMRegister nds, AddressLiteral src);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,7 +35,7 @@ const int ConcreteRegisterImpl::max_gpr = RegisterImpl::number_of_registers << 1
const int ConcreteRegisterImpl::max_fpr = ConcreteRegisterImpl::max_gpr +
2 * FloatRegisterImpl::number_of_registers;
const int ConcreteRegisterImpl::max_xmm = ConcreteRegisterImpl::max_fpr +
2 * XMMRegisterImpl::number_of_registers;
8 * XMMRegisterImpl::number_of_registers;
const char* RegisterImpl::name() const {
const char* names[number_of_registers] = {
#ifndef AMD64

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -158,7 +158,7 @@ class XMMRegisterImpl: public AbstractRegisterImpl {
XMMRegister successor() const { return as_XMMRegister(encoding() + 1); }
// accessors
int encoding() const { assert(is_valid(), "invalid register"); return (intptr_t)this; }
int encoding() const { assert(is_valid(), err_msg("invalid register (%d)", (int)(intptr_t)this )); return (intptr_t)this; }
bool is_valid() const { return 0 <= (intptr_t)this && (intptr_t)this < number_of_registers; }
const char* name() const;
};
@ -216,7 +216,7 @@ class ConcreteRegisterImpl : public AbstractRegisterImpl {
RegisterImpl::number_of_registers + // "H" half of a 64bit register
#endif // AMD64
2 * FloatRegisterImpl::number_of_registers +
2 * XMMRegisterImpl::number_of_registers +
8 * XMMRegisterImpl::number_of_registers +
1 // eflags
};

@ -467,6 +467,32 @@ void VM_Version::get_processor_features() {
if (!supports_avx ()) // Drop to 0 if no AVX support
UseAVX = 0;
#ifdef COMPILER2
if (UseFPUForSpilling) {
if (UseSSE < 2) {
// Only supported with SSE2+
FLAG_SET_DEFAULT(UseFPUForSpilling, false);
}
}
if (MaxVectorSize > 0) {
if (!is_power_of_2(MaxVectorSize)) {
warning("MaxVectorSize must be a power of 2");
FLAG_SET_DEFAULT(MaxVectorSize, 32);
}
if (MaxVectorSize > 32) {
FLAG_SET_DEFAULT(MaxVectorSize, 32);
}
if (MaxVectorSize > 16 && UseAVX == 0) {
// Only supported with AVX+
FLAG_SET_DEFAULT(MaxVectorSize, 16);
}
if (UseSSE < 2) {
// Only supported with SSE2+
FLAG_SET_DEFAULT(MaxVectorSize, 0);
}
}
#endif
// On new cpus instructions which update whole XMM register should be used
// to prevent partial register stall due to dependencies on high half.
//
@ -544,6 +570,12 @@ void VM_Version::get_processor_features() {
}
}
#ifdef COMPILER2
if (MaxVectorSize > 16) {
// Limit vectors size to 16 bytes on current AMD cpus.
FLAG_SET_DEFAULT(MaxVectorSize, 16);
}
#endif // COMPILER2
}
if( is_intel() ) { // Intel cpus specific settings
@ -606,15 +638,6 @@ void VM_Version::get_processor_features() {
FLAG_SET_DEFAULT(UsePopCountInstruction, false);
}
#ifdef COMPILER2
if (UseFPUForSpilling) {
if (UseSSE < 2) {
// Only supported with SSE2+
FLAG_SET_DEFAULT(UseFPUForSpilling, false);
}
}
#endif
assert(0 <= ReadPrefetchInstr && ReadPrefetchInstr <= 3, "invalid value");
assert(0 <= AllocatePrefetchInstr && AllocatePrefetchInstr <= 3, "invalid value");

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -48,8 +48,9 @@ void VMRegImpl::set_regName() {
XMMRegister xreg = ::as_XMMRegister(0);
for ( ; i < ConcreteRegisterImpl::max_xmm ; ) {
regName[i++] = xreg->name();
regName[i++] = xreg->name();
for (int j = 0 ; j < 8 ; j++) {
regName[i++] = xreg->name();
}
xreg = xreg->successor();
}
for ( ; i < ConcreteRegisterImpl::number_of_registers ; i ++ ) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -39,7 +39,7 @@ inline VMReg FloatRegisterImpl::as_VMReg() {
}
inline VMReg XMMRegisterImpl::as_VMReg() {
return VMRegImpl::as_VMReg((encoding() << 1) + ConcreteRegisterImpl::max_fpr);
return VMRegImpl::as_VMReg((encoding() << 3) + ConcreteRegisterImpl::max_fpr);
}
@ -75,7 +75,7 @@ inline FloatRegister VMRegImpl::as_FloatRegister() {
inline XMMRegister VMRegImpl::as_XMMRegister() {
assert( is_XMMRegister() && is_even(value()), "must be" );
// Yuk
return ::as_XMMRegister((value() - ConcreteRegisterImpl::max_fpr) >> 1);
return ::as_XMMRegister((value() - ConcreteRegisterImpl::max_fpr) >> 3);
}
inline bool VMRegImpl::is_concrete() {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -516,7 +516,12 @@ JVM_handle_bsd_signal(int sig,
}
}
if (thread->thread_state() == _thread_in_Java) {
// We test if stub is already set (by the stack overflow code
// above) so it is not overwritten by the code that follows. This
// check is not required on other platforms, because on other
// platforms we check for SIGSEGV only or SIGBUS only, where here
// we have to check for both SIGSEGV and SIGBUS.
if (thread->thread_state() == _thread_in_Java && stub == NULL) {
// Java thread running in Java code => find exception handler if any
// a fault inside compiled code, the interpreter, or a stub

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -115,6 +115,12 @@ void ADLParser::parse() {
parse_err(SYNERR, "expected one of - instruct, operand, ins_attrib, op_attrib, source, register, pipeline, encode\n Found %s",ident);
}
}
// Add reg_class spill_regs after parsing.
RegisterForm *regBlock = _AD.get_registers();
if (regBlock == NULL) {
parse_err(SEMERR, "Did not declare 'register' definitions");
}
regBlock->addSpillRegClass();
// Done with parsing, check consistency.
@ -768,11 +774,12 @@ void ADLParser::source_hpp_parse(void) {
//------------------------------reg_parse--------------------------------------
void ADLParser::reg_parse(void) {
// Create the RegisterForm for the architecture description.
RegisterForm *regBlock = new RegisterForm(); // Build new Source object
regBlock->_linenum = linenum();
_AD.addForm(regBlock);
RegisterForm *regBlock = _AD.get_registers(); // Information about registers encoding
if (regBlock == NULL) {
// Create the RegisterForm for the architecture description.
regBlock = new RegisterForm(); // Build new Source object
_AD.addForm(regBlock);
}
skipws(); // Skip leading whitespace
if (_curchar == '%' && *(_ptr+1) == '{') {
@ -796,15 +803,11 @@ void ADLParser::reg_parse(void) {
parse_err(SYNERR, "Missing %c{ ... %c} block after register keyword.\n",'%','%');
return;
}
// Add reg_class spill_regs
regBlock->addSpillRegClass();
}
//------------------------------encode_parse-----------------------------------
void ADLParser::encode_parse(void) {
EncodeForm *encBlock; // Information about instruction/operand encoding
char *desc = NULL; // String representation of encode rule
_AD.getForm(&encBlock);
if ( encBlock == NULL) {

@ -1,5 +1,5 @@
//
// Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// This code is free software; you can redistribute it and/or modify it
@ -911,12 +911,24 @@ const char *ArchDesc::getIdealType(const char *idealOp) {
// Find last character in idealOp, it specifies the type
char last_char = 0;
const char *ptr = idealOp;
for( ; *ptr != '\0'; ++ptr) {
for (; *ptr != '\0'; ++ptr) {
last_char = *ptr;
}
// Match Vector types.
if (strncmp(idealOp, "Vec",3)==0) {
switch(last_char) {
case 'S': return "TypeVect::VECTS";
case 'D': return "TypeVect::VECTD";
case 'X': return "TypeVect::VECTX";
case 'Y': return "TypeVect::VECTY";
default:
internal_err("Vector type %s with unrecognized type\n",idealOp);
}
}
// !!!!!
switch( last_char ) {
switch(last_char) {
case 'I': return "TypeInt::INT";
case 'P': return "TypePtr::BOTTOM";
case 'N': return "TypeNarrowOop::BOTTOM";

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -265,47 +265,22 @@ Form::DataType Form::is_load_from_memory(const char *opType) const {
if( strcmp(opType,"LoadN")==0 ) return Form::idealN;
if( strcmp(opType,"LoadRange")==0 ) return Form::idealI;
if( strcmp(opType,"LoadS")==0 ) return Form::idealS;
if( strcmp(opType,"Load16B")==0 ) return Form::idealB;
if( strcmp(opType,"Load8B")==0 ) return Form::idealB;
if( strcmp(opType,"Load4B")==0 ) return Form::idealB;
if( strcmp(opType,"Load8C")==0 ) return Form::idealC;
if( strcmp(opType,"Load4C")==0 ) return Form::idealC;
if( strcmp(opType,"Load2C")==0 ) return Form::idealC;
if( strcmp(opType,"Load8S")==0 ) return Form::idealS;
if( strcmp(opType,"Load4S")==0 ) return Form::idealS;
if( strcmp(opType,"Load2S")==0 ) return Form::idealS;
if( strcmp(opType,"Load2D")==0 ) return Form::idealD;
if( strcmp(opType,"Load4F")==0 ) return Form::idealF;
if( strcmp(opType,"Load2F")==0 ) return Form::idealF;
if( strcmp(opType,"Load4I")==0 ) return Form::idealI;
if( strcmp(opType,"Load2I")==0 ) return Form::idealI;
if( strcmp(opType,"Load2L")==0 ) return Form::idealL;
if( strcmp(opType,"LoadVector")==0 ) return Form::idealV;
assert( strcmp(opType,"Load") != 0, "Must type Loads" );
return Form::none;
}
Form::DataType Form::is_store_to_memory(const char *opType) const {
if( strcmp(opType,"StoreB")==0) return Form::idealB;
if( strcmp(opType,"StoreCM")==0) return Form::idealB;
if( strcmp(opType,"StoreCM")==0) return Form::idealB;
if( strcmp(opType,"StoreC")==0) return Form::idealC;
if( strcmp(opType,"StoreD")==0) return Form::idealD;
if( strcmp(opType,"StoreF")==0) return Form::idealF;
if( strcmp(opType,"StoreI")==0) return Form::idealI;
if( strcmp(opType,"StoreL")==0) return Form::idealL;
if( strcmp(opType,"StoreP")==0) return Form::idealP;
if( strcmp(opType,"StoreN")==0) return Form::idealN;
if( strcmp(opType,"Store16B")==0) return Form::idealB;
if( strcmp(opType,"Store8B")==0) return Form::idealB;
if( strcmp(opType,"Store4B")==0) return Form::idealB;
if( strcmp(opType,"Store8C")==0) return Form::idealC;
if( strcmp(opType,"Store4C")==0) return Form::idealC;
if( strcmp(opType,"Store2C")==0) return Form::idealC;
if( strcmp(opType,"Store2D")==0) return Form::idealD;
if( strcmp(opType,"Store4F")==0) return Form::idealF;
if( strcmp(opType,"Store2F")==0) return Form::idealF;
if( strcmp(opType,"Store4I")==0) return Form::idealI;
if( strcmp(opType,"Store2I")==0) return Form::idealI;
if( strcmp(opType,"Store2L")==0) return Form::idealL;
if( strcmp(opType,"StoreN")==0) return Form::idealN;
if( strcmp(opType,"StoreVector")==0 ) return Form::idealV;
assert( strcmp(opType,"Store") != 0, "Must type Stores" );
return Form::none;
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -172,7 +172,8 @@ public:
idealB = 6, // Byte type
idealC = 7, // Char type
idealS = 8, // String type
idealN = 9 // Narrow oop types
idealN = 9, // Narrow oop types
idealV = 10 // Vector type
};
// Convert ideal name to a DataType, return DataType::none if not a 'ConX'
Form::DataType ideal_to_const_type(const char *ideal_type_name) const;

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -66,7 +66,7 @@ AllocClass *RegisterForm::addAllocClass(char *className) {
// for spill-slots/regs.
void RegisterForm::addSpillRegClass() {
// Stack slots start at the next available even register number.
_reg_ctr = (_reg_ctr+1) & ~1;
_reg_ctr = (_reg_ctr+7) & ~7;
const char *rc_name = "stack_slots";
RegClass *reg_class = new RegClass(rc_name);
reg_class->_stack_or_reg = true;
@ -150,9 +150,14 @@ bool RegisterForm::verify() {
int RegisterForm::RegMask_Size() {
// Need at least this many words
int words_for_regs = (_reg_ctr + 31)>>5;
// Add a few for incoming & outgoing arguments to calls.
// The array of Register Mask bits should be large enough to cover
// all the machine registers and all parameters that need to be passed
// on the stack (stack registers) up to some interesting limit. Methods
// that need more parameters will NOT be compiled. On Intel, the limit
// is something like 90+ parameters.
// Add a few (3 words == 96 bits) for incoming & outgoing arguments to calls.
// Round up to the next doubleword size.
return (words_for_regs + 2 + 1) & ~1;
return (words_for_regs + 3 + 1) & ~1;
}
void RegisterForm::dump() { // Debug printer

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -432,6 +432,14 @@ Form::DataType InstructForm::is_ideal_store() const {
return _matrule->is_ideal_store();
}
// Return 'true' if this instruction matches an ideal vector node
bool InstructForm::is_vector() const {
if( _matrule == NULL ) return false;
return _matrule->is_vector();
}
// Return the input register that must match the output register
// If this is not required, return 0
uint InstructForm::two_address(FormDict &globals) {
@ -751,6 +759,9 @@ bool InstructForm::captures_bottom_type(FormDict &globals) const {
if (needs_base_oop_edge(globals)) return true;
if (is_vector()) return true;
if (is_mach_constant()) return true;
return false;
}
@ -3381,11 +3392,8 @@ int MatchNode::needs_ideal_memory_edge(FormDict &globals) const {
"StoreI","StoreL","StoreP","StoreN","StoreD","StoreF" ,
"StoreB","StoreC","Store" ,"StoreFP",
"LoadI", "LoadUI2L", "LoadL", "LoadP" ,"LoadN", "LoadD" ,"LoadF" ,
"LoadB" , "LoadUB", "LoadUS" ,"LoadS" ,"Load" ,
"Store4I","Store2I","Store2L","Store2D","Store4F","Store2F","Store16B",
"Store8B","Store4B","Store8C","Store4C","Store2C",
"Load4I" ,"Load2I" ,"Load2L" ,"Load2D" ,"Load4F" ,"Load2F" ,"Load16B" ,
"Load8B" ,"Load4B" ,"Load8C" ,"Load4C" ,"Load2C" ,"Load8S", "Load4S","Load2S",
"LoadB" , "LoadUB", "LoadUS" ,"LoadS" ,"Load" ,
"StoreVector", "LoadVector",
"LoadRange", "LoadKlass", "LoadNKlass", "LoadL_unaligned", "LoadD_unaligned",
"LoadPLocked",
"StorePConditional", "StoreIConditional", "StoreLConditional",
@ -3822,6 +3830,10 @@ bool MatchRule::is_base_register(FormDict &globals) const {
strcmp(opType,"RegL")==0 ||
strcmp(opType,"RegF")==0 ||
strcmp(opType,"RegD")==0 ||
strcmp(opType,"VecS")==0 ||
strcmp(opType,"VecD")==0 ||
strcmp(opType,"VecX")==0 ||
strcmp(opType,"VecY")==0 ||
strcmp(opType,"Reg" )==0) ) {
return 1;
}
@ -3938,19 +3950,12 @@ int MatchRule::is_expensive() const {
strcmp(opType,"ReverseBytesL")==0 ||
strcmp(opType,"ReverseBytesUS")==0 ||
strcmp(opType,"ReverseBytesS")==0 ||
strcmp(opType,"Replicate16B")==0 ||
strcmp(opType,"Replicate8B")==0 ||
strcmp(opType,"Replicate4B")==0 ||
strcmp(opType,"Replicate8C")==0 ||
strcmp(opType,"Replicate4C")==0 ||
strcmp(opType,"Replicate8S")==0 ||
strcmp(opType,"Replicate4S")==0 ||
strcmp(opType,"Replicate4I")==0 ||
strcmp(opType,"Replicate2I")==0 ||
strcmp(opType,"Replicate2L")==0 ||
strcmp(opType,"Replicate4F")==0 ||
strcmp(opType,"Replicate2F")==0 ||
strcmp(opType,"Replicate2D")==0 ||
strcmp(opType,"ReplicateB")==0 ||
strcmp(opType,"ReplicateS")==0 ||
strcmp(opType,"ReplicateI")==0 ||
strcmp(opType,"ReplicateL")==0 ||
strcmp(opType,"ReplicateF")==0 ||
strcmp(opType,"ReplicateD")==0 ||
0 /* 0 to line up columns nicely */ )
return 1;
}
@ -4034,6 +4039,23 @@ Form::DataType MatchRule::is_ideal_load() const {
return ideal_load;
}
bool MatchRule::is_vector() const {
if( _rChild ) {
const char *opType = _rChild->_opType;
if( strcmp(opType,"ReplicateB")==0 ||
strcmp(opType,"ReplicateS")==0 ||
strcmp(opType,"ReplicateI")==0 ||
strcmp(opType,"ReplicateL")==0 ||
strcmp(opType,"ReplicateF")==0 ||
strcmp(opType,"ReplicateD")==0 ||
strcmp(opType,"LoadVector")==0 ||
strcmp(opType,"StoreVector")==0 ||
0 /* 0 to line up columns nicely */ )
return true;
}
return false;
}
bool MatchRule::skip_antidep_check() const {
// Some loads operate on what is effectively immutable memory so we

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -160,6 +160,7 @@ public:
virtual bool is_ideal_safepoint() const; // node matches 'SafePoint'
virtual bool is_ideal_nop() const; // node matches 'Nop'
virtual bool is_ideal_control() const; // control node
virtual bool is_vector() const; // vector instruction
virtual Form::CallType is_ideal_call() const; // matches ideal 'Call'
virtual Form::DataType is_ideal_load() const; // node matches ideal 'LoadXNode'
@ -1011,6 +1012,7 @@ public:
bool is_ideal_goto() const; // node matches ideal 'Goto'
bool is_ideal_loopEnd() const; // node matches ideal 'LoopEnd'
bool is_ideal_bool() const; // node matches ideal 'Bool'
bool is_vector() const; // vector instruction
Form::DataType is_ideal_load() const;// node matches ideal 'LoadXNode'
// Should antidep checks be disabled for this rule
// See definition of MatchRule::skip_antidep_check

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -250,6 +250,7 @@ int main(int argc, char *argv[])
AD.addInclude(AD._HPP_file, "opto/node.hpp");
AD.addInclude(AD._HPP_file, "opto/regalloc.hpp");
AD.addInclude(AD._HPP_file, "opto/subnode.hpp");
AD.addInclude(AD._HPP_file, "opto/vectornode.hpp");
AD.addInclude(AD._CPP_CLONE_file, "precompiled.hpp");
AD.addInclude(AD._CPP_CLONE_file, "adfiles", get_basename(AD._HPP_file._name));
AD.addInclude(AD._CPP_EXPAND_file, "precompiled.hpp");

@ -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

@ -0,0 +1,62 @@
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_CLASSFILE_ALTHASHING_HPP
#define SHARE_VM_CLASSFILE_ALTHASHING_HPP
#include "prims/jni.h"
#include "classfile/symbolTable.hpp"
/**
* Hashing utilities.
*
* Implementation of Murmur3 hashing.
* This code was translated from src/share/classes/sun/misc/Hashing.java
* code in the JDK.
*/
class AltHashing : AllStatic {
// utility function copied from java/lang/Integer
static jint Integer_rotateLeft(jint i, int distance) {
return (i << distance) | (((juint)i) >> (32-distance));
}
static jint murmur3_32(const int* data, int len);
static jint murmur3_32(jint seed, const int* data, int len);
#ifndef PRODUCT
// Hashing functions used for internal testing
static jint murmur3_32(const jbyte* data, int len);
static jint murmur3_32(const jchar* data, int len);
static void testMurmur3_32_ByteArray();
static void testEquivalentHashes();
#endif // PRODUCT
public:
static jint compute_seed();
static jint murmur3_32(jint seed, const jbyte* data, int len);
static jint murmur3_32(jint seed, const jchar* data, int len);
NOT_PRODUCT(static void test_alt_hash();)
};
#endif // SHARE_VM_CLASSFILE_ALTHASHING_HPP

@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "classfile/altHashing.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/vmSymbols.hpp"
@ -347,13 +348,26 @@ jchar* java_lang_String::as_unicode_string(oop java_string, int& length) {
return result;
}
unsigned int java_lang_String::hash_string(oop java_string) {
unsigned int java_lang_String::to_hash(oop java_string) {
int length = java_lang_String::length(java_string);
// Zero length string will hash to zero with String.toHash() function.
if (length == 0) return 0;
typeArrayOop value = java_lang_String::value(java_string);
int offset = java_lang_String::offset(java_string);
int length = java_lang_String::length(java_string);
return java_lang_String::to_hash(value->char_at_addr(offset), length);
}
if (length == 0) return 0;
return hash_string(value->char_at_addr(offset), length);
unsigned int java_lang_String::hash_string(oop java_string) {
int length = java_lang_String::length(java_string);
// Zero length string doesn't hash necessarily hash to zero.
if (length == 0) {
return StringTable::hash_string(NULL, 0);
}
typeArrayOop value = java_lang_String::value(java_string);
int offset = java_lang_String::offset(java_string);
return StringTable::hash_string(value->char_at_addr(offset), length);
}
Symbol* java_lang_String::as_symbol(Handle java_string, TRAPS) {

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

@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "classfile/altHashing.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
@ -34,19 +35,19 @@
#include "oops/oop.inline2.hpp"
#include "runtime/mutexLocker.hpp"
#include "utilities/hashtable.inline.hpp"
#include "utilities/numberSeq.hpp"
// --------------------------------------------------------------------------
SymbolTable* SymbolTable::_the_table = NULL;
// Static arena for symbols that are not deallocated
Arena* SymbolTable::_arena = NULL;
bool SymbolTable::_needs_rehashing = false;
jint SymbolTable::_seed = 0;
Symbol* SymbolTable::allocate_symbol(const u1* name, int len, bool c_heap, TRAPS) {
// Don't allow symbols to be created which cannot fit in a Symbol*.
if (len > Symbol::max_length()) {
THROW_MSG_0(vmSymbols::java_lang_InternalError(),
"name is too long to represent");
}
assert (len <= Symbol::max_length(), "should be checked by caller");
Symbol* sym;
// Allocate symbols in the C heap when dumping shared spaces in case there
// are temporary symbols we can remove.
@ -91,9 +92,14 @@ void SymbolTable::unlink() {
int total = 0;
size_t memory_total = 0;
for (int i = 0; i < the_table()->table_size(); ++i) {
for (HashtableEntry<Symbol*>** p = the_table()->bucket_addr(i); *p != NULL; ) {
HashtableEntry<Symbol*>* entry = *p;
if (entry->is_shared()) {
HashtableEntry<Symbol*>** p = the_table()->bucket_addr(i);
HashtableEntry<Symbol*>* entry = the_table()->bucket(i);
while (entry != NULL) {
// Shared entries are normally at the end of the bucket and if we run into
// a shared entry, then there is nothing more to remove. However, if we
// have rehashed the table, then the shared entries are no longer at the
// end of the bucket.
if (entry->is_shared() && !use_alternate_hashcode()) {
break;
}
Symbol* s = entry->literal();
@ -102,6 +108,7 @@ void SymbolTable::unlink() {
assert(s != NULL, "just checking");
// If reference count is zero, remove.
if (s->refcount() == 0) {
assert(!entry->is_shared(), "shared entries should be kept live");
delete s;
removed++;
*p = entry->next();
@ -109,6 +116,8 @@ void SymbolTable::unlink() {
} else {
p = entry->next_addr();
}
// get next entry
entry = (HashtableEntry<Symbol*>*)HashtableEntry<Symbol*>::make_ptr(*p);
}
}
symbols_removed += removed;
@ -121,12 +130,42 @@ void SymbolTable::unlink() {
}
}
unsigned int SymbolTable::new_hash(Symbol* sym) {
ResourceMark rm;
// Use alternate hashing algorithm on this symbol.
return AltHashing::murmur3_32(seed(), (const jbyte*)sym->as_C_string(), sym->utf8_length());
}
// Create a new table and using alternate hash code, populate the new table
// with the existing strings. Set flag to use the alternate hash code afterwards.
void SymbolTable::rehash_table() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
// This should never happen with -Xshare:dump but it might in testing mode.
if (DumpSharedSpaces) return;
// Create a new symbol table
SymbolTable* new_table = new SymbolTable();
// Initialize the global seed for hashing.
_seed = AltHashing::compute_seed();
assert(seed() != 0, "shouldn't be zero");
the_table()->move_to(new_table);
// Delete the table and buckets (entries are reused in new table).
delete _the_table;
// Don't check if we need rehashing until the table gets unbalanced again.
// Then rehash with a new global seed.
_needs_rehashing = false;
_the_table = new_table;
}
// Lookup a symbol in a bucket.
Symbol* SymbolTable::lookup(int index, const char* name,
int len, unsigned int hash) {
int count = 0;
for (HashtableEntry<Symbol*>* e = bucket(index); e != NULL; e = e->next()) {
count++; // count all entries in this bucket, not just ones with same hash
if (e->hash() == hash) {
Symbol* sym = e->literal();
if (sym->equals(name, len)) {
@ -136,9 +175,20 @@ Symbol* SymbolTable::lookup(int index, const char* name,
}
}
}
// If the bucket size is too deep check if this hash code is insufficient.
if (count >= BasicHashtable::rehash_count && !needs_rehashing()) {
_needs_rehashing = check_rehash_table(count);
}
return NULL;
}
// Pick hashing algorithm.
unsigned int SymbolTable::hash_symbol(const char* s, int len) {
return use_alternate_hashcode() ?
AltHashing::murmur3_32(seed(), (const jbyte*)s, len) :
java_lang_String::to_hash(s, len);
}
// We take care not to be blocking while holding the
// SymbolTable_lock. Otherwise, the system might deadlock, since the
@ -156,6 +206,9 @@ Symbol* SymbolTable::lookup(const char* name, int len, TRAPS) {
// Found
if (s != NULL) return s;
// Grab SymbolTable_lock first.
MutexLocker ml(SymbolTable_lock, THREAD);
// Otherwise, add to symbol to table
return the_table()->basic_add(index, (u1*)name, len, hashValue, true, CHECK_NULL);
}
@ -193,6 +246,9 @@ Symbol* SymbolTable::lookup(const Symbol* sym, int begin, int end, TRAPS) {
// We can't include the code in No_Safepoint_Verifier because of the
// ResourceMark.
// Grab SymbolTable_lock first.
MutexLocker ml(SymbolTable_lock, THREAD);
return the_table()->basic_add(index, (u1*)buffer, len, hashValue, true, CHECK_NULL);
}
@ -261,6 +317,9 @@ void SymbolTable::add(Handle class_loader, constantPoolHandle cp,
int names_count,
const char** names, int* lengths, int* cp_indices,
unsigned int* hashValues, TRAPS) {
// Grab SymbolTable_lock first.
MutexLocker ml(SymbolTable_lock, THREAD);
SymbolTable* table = the_table();
bool added = table->basic_add(class_loader, cp, names_count, names, lengths,
cp_indices, hashValues, CHECK);
@ -281,18 +340,39 @@ Symbol* SymbolTable::new_permanent_symbol(const char* name, TRAPS) {
if (result != NULL) {
return result;
}
// Grab SymbolTable_lock first.
MutexLocker ml(SymbolTable_lock, THREAD);
SymbolTable* table = the_table();
int index = table->hash_to_index(hash);
return table->basic_add(index, (u1*)name, (int)strlen(name), hash, false, THREAD);
}
Symbol* SymbolTable::basic_add(int index, u1 *name, int len,
unsigned int hashValue, bool c_heap, TRAPS) {
Symbol* SymbolTable::basic_add(int index_arg, u1 *name, int len,
unsigned int hashValue_arg, bool c_heap, TRAPS) {
assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(),
"proposed name of symbol must be stable");
// Grab SymbolTable_lock first.
MutexLocker ml(SymbolTable_lock, THREAD);
// Don't allow symbols to be created which cannot fit in a Symbol*.
if (len > Symbol::max_length()) {
THROW_MSG_0(vmSymbols::java_lang_InternalError(),
"name is too long to represent");
}
// Cannot hit a safepoint in this function because the "this" pointer can move.
No_Safepoint_Verifier nsv;
// Check if the symbol table has been rehashed, if so, need to recalculate
// the hash value and index.
unsigned int hashValue;
int index;
if (use_alternate_hashcode()) {
hashValue = hash_symbol((const char*)name, len);
index = hash_to_index(hashValue);
} else {
hashValue = hashValue_arg;
index = index_arg;
}
// Since look-up was done lock-free, we need to check if another
// thread beat us in the race to insert the symbol.
@ -328,14 +408,22 @@ bool SymbolTable::basic_add(Handle class_loader, constantPoolHandle cp,
}
}
// Hold SymbolTable_lock through the symbol creation
MutexLocker ml(SymbolTable_lock, THREAD);
// Cannot hit a safepoint in this function because the "this" pointer can move.
No_Safepoint_Verifier nsv;
for (int i=0; i<names_count; i++) {
// Check if the symbol table has been rehashed, if so, need to recalculate
// the hash value.
unsigned int hashValue;
if (use_alternate_hashcode()) {
hashValue = hash_symbol(names[i], lengths[i]);
} else {
hashValue = hashValues[i];
}
// Since look-up was done lock-free, we need to check if another
// thread beat us in the race to insert the symbol.
int index = hash_to_index(hashValues[i]);
Symbol* test = lookup(index, names[i], lengths[i], hashValues[i]);
int index = hash_to_index(hashValue);
Symbol* test = lookup(index, names[i], lengths[i], hashValue);
if (test != NULL) {
// A race occurred and another thread introduced the symbol, this one
// will be dropped and collected. Use test instead.
@ -347,7 +435,7 @@ bool SymbolTable::basic_add(Handle class_loader, constantPoolHandle cp,
bool c_heap = class_loader() != NULL;
Symbol* sym = allocate_symbol((const u1*)names[i], lengths[i], c_heap, CHECK_(false));
assert(sym->equals(names[i], lengths[i]), "symbol must be properly initialized"); // why wouldn't it be???
HashtableEntry<Symbol*>* entry = new_entry(hashValues[i], sym);
HashtableEntry<Symbol*>* entry = new_entry(hashValue, sym);
add_entry(index, entry);
cp->symbol_at_put(cp_indices[i], sym);
}
@ -370,6 +458,24 @@ void SymbolTable::verify() {
}
}
void SymbolTable::dump(outputStream* st) {
NumberSeq summary;
for (int i = 0; i < the_table()->table_size(); ++i) {
int count = 0;
for (HashtableEntry<Symbol*>* e = the_table()->bucket(i);
e != NULL; e = e->next()) {
count++;
}
summary.add((double)count);
}
st->print_cr("SymbolTable statistics:");
st->print_cr("Number of buckets : %7d", summary.num());
st->print_cr("Average bucket size : %7.0f", summary.avg());
st->print_cr("Variance of bucket size : %7.0f", summary.variance());
st->print_cr("Std. dev. of bucket size: %7.0f", summary.sd());
st->print_cr("Maximum bucket size : %7.0f", summary.maximum());
}
//---------------------------------------------------------------------------
// Non-product code
@ -468,7 +574,6 @@ void SymbolTable::print() {
}
}
}
#endif // PRODUCT
// --------------------------------------------------------------------------
@ -514,38 +619,53 @@ class StableMemoryChecker : public StackObj {
// --------------------------------------------------------------------------
StringTable* StringTable::_the_table = NULL;
bool StringTable::_needs_rehashing = false;
jint StringTable::_seed = 0;
// Pick hashing algorithm
unsigned int StringTable::hash_string(const jchar* s, int len) {
return use_alternate_hashcode() ? AltHashing::murmur3_32(seed(), s, len) :
java_lang_String::to_hash(s, len);
}
oop StringTable::lookup(int index, jchar* name,
int len, unsigned int hash) {
int count = 0;
for (HashtableEntry<oop>* l = bucket(index); l != NULL; l = l->next()) {
count++;
if (l->hash() == hash) {
if (java_lang_String::equals(l->literal(), name, len)) {
return l->literal();
}
}
}
// If the bucket size is too deep check if this hash code is insufficient.
if (count >= BasicHashtable::rehash_count && !needs_rehashing()) {
_needs_rehashing = check_rehash_table(count);
}
return NULL;
}
oop StringTable::basic_add(int index, Handle string_or_null, jchar* name,
int len, unsigned int hashValue, TRAPS) {
debug_only(StableMemoryChecker smc(name, len * sizeof(name[0])));
assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(),
"proposed name of symbol must be stable");
Handle string;
// try to reuse the string if possible
if (!string_or_null.is_null() && (!JavaObjectsInPerm || string_or_null()->is_perm())) {
string = string_or_null;
} else {
string = java_lang_String::create_tenured_from_unicode(name, len, CHECK_NULL);
}
// Allocation must be done before grapping the SymbolTable_lock lock
MutexLocker ml(StringTable_lock, THREAD);
oop StringTable::basic_add(int index_arg, Handle string, jchar* name,
int len, unsigned int hashValue_arg, TRAPS) {
assert(java_lang_String::equals(string(), name, len),
"string must be properly initialized");
// Cannot hit a safepoint in this function because the "this" pointer can move.
No_Safepoint_Verifier nsv;
// Check if the symbol table has been rehashed, if so, need to recalculate
// the hash value and index before second lookup.
unsigned int hashValue;
int index;
if (use_alternate_hashcode()) {
hashValue = hash_string(name, len);
index = hash_to_index(hashValue);
} else {
hashValue = hashValue_arg;
index = index_arg;
}
// Since look-up was done lock-free, we need to check if another
// thread beat us in the race to insert the symbol.
@ -566,7 +686,7 @@ oop StringTable::lookup(Symbol* symbol) {
ResourceMark rm;
int length;
jchar* chars = symbol->as_unicode(length);
unsigned int hashValue = java_lang_String::hash_string(chars, length);
unsigned int hashValue = hash_string(chars, length);
int index = the_table()->hash_to_index(hashValue);
return the_table()->lookup(index, chars, length, hashValue);
}
@ -574,15 +694,31 @@ oop StringTable::lookup(Symbol* symbol) {
oop StringTable::intern(Handle string_or_null, jchar* name,
int len, TRAPS) {
unsigned int hashValue = java_lang_String::hash_string(name, len);
unsigned int hashValue = hash_string(name, len);
int index = the_table()->hash_to_index(hashValue);
oop string = the_table()->lookup(index, name, len, hashValue);
oop found_string = the_table()->lookup(index, name, len, hashValue);
// Found
if (string != NULL) return string;
if (found_string != NULL) return found_string;
debug_only(StableMemoryChecker smc(name, len * sizeof(name[0])));
assert(!Universe::heap()->is_in_reserved(name) || GC_locker::is_active(),
"proposed name of symbol must be stable");
Handle string;
// try to reuse the string if possible
if (!string_or_null.is_null() && (!JavaObjectsInPerm || string_or_null()->is_perm())) {
string = string_or_null;
} else {
string = java_lang_String::create_tenured_from_unicode(name, len, CHECK_NULL);
}
// Grab the StringTable_lock before getting the_table() because it could
// change at safepoint.
MutexLocker ml(StringTable_lock, THREAD);
// Otherwise, add to symbol to table
return the_table()->basic_add(index, string_or_null, name, len,
return the_table()->basic_add(index, string, name, len,
hashValue, CHECK_NULL);
}
@ -625,18 +761,24 @@ void StringTable::unlink(BoolObjectClosure* is_alive) {
// entries at a safepoint.
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
for (int i = 0; i < the_table()->table_size(); ++i) {
for (HashtableEntry<oop>** p = the_table()->bucket_addr(i); *p != NULL; ) {
HashtableEntry<oop>* entry = *p;
if (entry->is_shared()) {
HashtableEntry<oop>** p = the_table()->bucket_addr(i);
HashtableEntry<oop>* entry = the_table()->bucket(i);
while (entry != NULL) {
// Shared entries are normally at the end of the bucket and if we run into
// a shared entry, then there is nothing more to remove. However, if we
// have rehashed the table, then the shared entries are no longer at the
// end of the bucket.
if (entry->is_shared() && !use_alternate_hashcode()) {
break;
}
assert(entry->literal() != NULL, "just checking");
if (is_alive->do_object_b(entry->literal())) {
if (entry->is_shared() || is_alive->do_object_b(entry->literal())) {
p = entry->next_addr();
} else {
*p = entry->next();
the_table()->free_entry(entry);
}
entry = (HashtableEntry<oop>*)HashtableEntry<oop>::make_ptr(*p);
}
}
}
@ -675,3 +817,53 @@ void StringTable::verify() {
}
}
}
void StringTable::dump(outputStream* st) {
NumberSeq summary;
for (int i = 0; i < the_table()->table_size(); ++i) {
HashtableEntry<oop>* p = the_table()->bucket(i);
int count = 0;
for ( ; p != NULL; p = p->next()) {
count++;
}
summary.add((double)count);
}
st->print_cr("StringTable statistics:");
st->print_cr("Number of buckets : %7d", summary.num());
st->print_cr("Average bucket size : %7.0f", summary.avg());
st->print_cr("Variance of bucket size : %7.0f", summary.variance());
st->print_cr("Std. dev. of bucket size: %7.0f", summary.sd());
st->print_cr("Maximum bucket size : %7.0f", summary.maximum());
}
unsigned int StringTable::new_hash(oop string) {
ResourceMark rm;
int length;
jchar* chars = java_lang_String::as_unicode_string(string, length);
// Use alternate hashing algorithm on the string
return AltHashing::murmur3_32(seed(), chars, length);
}
// Create a new table and using alternate hash code, populate the new table
// with the existing strings. Set flag to use the alternate hash code afterwards.
void StringTable::rehash_table() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
// This should never happen with -Xshare:dump but it might in testing mode.
if (DumpSharedSpaces) return;
StringTable* new_table = new StringTable();
// Initialize new global seed for hashing.
_seed = AltHashing::compute_seed();
assert(seed() != 0, "shouldn't be zero");
// Rehash the table
the_table()->move_to(new_table);
// Delete the table and buckets (entries are reused in new table).
delete _the_table;
// Don't check if we need rehashing until the table gets unbalanced again.
// Then rehash with a new global seed.
_needs_rehashing = false;
_the_table = new_table;
}

@ -40,6 +40,7 @@
// - symbolTableEntrys are allocated in blocks to reduce the space overhead.
class BoolObjectClosure;
class outputStream;
// Class to hold a newly created or referenced Symbol* temporarily in scope.
@ -78,6 +79,10 @@ private:
// The symbol table
static SymbolTable* _the_table;
// Set if one bucket is out of balance due to hash algorithm deficiency
static bool _needs_rehashing;
static jint _seed;
// For statistics
static int symbols_removed;
static int symbols_counted;
@ -119,6 +124,11 @@ private:
static Arena* arena() { return _arena; } // called for statistics
static void initialize_symbols(int arena_alloc_size = 0);
static bool use_alternate_hashcode() { return _seed != 0; }
static jint seed() { return _seed; }
unsigned int new_hash(Symbol* sym);
public:
enum {
symbol_alloc_batch_size = 8,
@ -146,6 +156,8 @@ public:
initialize_symbols();
}
static unsigned int hash_symbol(const char* s, int len);
static Symbol* lookup(const char* name, int len, TRAPS);
// lookup only, won't add. Also calculate hash.
static Symbol* lookup_only(const char* name, int len, unsigned int& hash);
@ -208,6 +220,7 @@ public:
// Debugging
static void verify();
static void dump(outputStream* st);
// Sharing
static void copy_buckets(char** top, char*end) {
@ -219,8 +232,13 @@ public:
static void reverse(void* boundary = NULL) {
the_table()->Hashtable<Symbol*>::reverse(boundary);
}
// Rehash the symbol table if it gets out of balance
static void rehash_table();
static bool needs_rehashing() { return _needs_rehashing; }
};
class StringTable : public Hashtable<oop> {
friend class VMStructs;
@ -228,6 +246,10 @@ private:
// The string table
static StringTable* _the_table;
// Set if one bucket is out of balance due to hash algorithm deficiency
static bool _needs_rehashing;
static jint _seed;
static oop intern(Handle string_or_null, jchar* chars, int length, TRAPS);
oop basic_add(int index, Handle string_or_null, jchar* name, int len,
unsigned int hashValue, TRAPS);
@ -241,6 +263,10 @@ private:
: Hashtable<oop>((int)StringTableSize, sizeof (HashtableEntry<oop>), t,
number_of_entries) {}
static bool use_alternate_hashcode() { return _seed != 0; }
static jint seed() { return _seed; }
unsigned int new_hash(oop s);
public:
// The string table
static StringTable* the_table() { return _the_table; }
@ -265,6 +291,14 @@ public:
// Invoke "f->do_oop" on the locations of all oops in the table.
static void oops_do(OopClosure* f);
// Hashing algorithm, used as the hash value used by the
// StringTable for bucket selection and comparison (stored in the
// HashtableEntry structures). This is used in the String.intern() method.
static unsigned int hash_string(const jchar* s, int len);
// Internal test.
static void test_alt_hash() PRODUCT_RETURN;
// Probing
static oop lookup(Symbol* symbol);
@ -275,6 +309,7 @@ public:
// Debugging
static void verify();
static void dump(outputStream* st);
// Sharing
static void copy_buckets(char** top, char*end) {
@ -286,6 +321,9 @@ public:
static void reverse() {
the_table()->Hashtable<oop>::reverse();
}
};
// Rehash the symbol table if it gets out of balance
static void rehash_table();
static bool needs_rehashing() { return _needs_rehashing; }
};
#endif // SHARE_VM_CLASSFILE_SYMBOLTABLE_HPP

@ -111,6 +111,10 @@
template(getBootClassPathEntryForClass_name, "getBootClassPathEntryForClass") \
template(sun_misc_PostVMInitHook, "sun/misc/PostVMInitHook") \
\
/* Java runtime version access */ \
template(sun_misc_Version, "sun/misc/Version") \
template(java_runtime_name_name, "java_runtime_name") \
\
/* class file format tags */ \
template(tag_source_file, "SourceFile") \
template(tag_inner_classes, "InnerClasses") \

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,7 +27,7 @@
#include "code/vmreg.hpp"
// First VMReg value that could refer to a stack slot
VMReg VMRegImpl::stack0 = (VMReg)(intptr_t)((ConcreteRegisterImpl::number_of_registers + 1) & ~1);
VMReg VMRegImpl::stack0 = (VMReg)(intptr_t)((ConcreteRegisterImpl::number_of_registers + 7) & ~7);
// VMRegs are 4 bytes wide on all platforms
const int VMRegImpl::stack_slot_size = 4;

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

@ -53,6 +53,9 @@
develop(bool, G1TraceMarkStackOverflow, false, \
"If true, extra debugging code for CM restart for ovflw.") \
\
develop(bool, G1TraceHeapRegionRememberedSet, false, \
"Enables heap region remembered set debug logs") \
\
diagnostic(bool, G1SummarizeConcMark, false, \
"Summarize concurrent mark info") \
\

@ -30,13 +30,10 @@
#include "gc_implementation/g1/heapRegionSeq.inline.hpp"
#include "memory/allocation.hpp"
#include "memory/space.inline.hpp"
#include "oops/oop.inline.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/globalDefinitions.hpp"
#define HRRS_VERBOSE 0
#define PRT_COUNT_OCCUPIED 1
// OtherRegionsTable
class PerRegionTable: public CHeapObj {
@ -45,14 +42,10 @@ class PerRegionTable: public CHeapObj {
HeapRegion* _hr;
BitMap _bm;
#if PRT_COUNT_OCCUPIED
jint _occupied;
#endif
PerRegionTable* _next_free;
PerRegionTable* next_free() { return _next_free; }
void set_next_free(PerRegionTable* prt) { _next_free = prt; }
// next pointer for free/allocated lis
PerRegionTable* _next;
static PerRegionTable* _free_list;
@ -69,63 +62,25 @@ protected:
// We need access in order to union things into the base table.
BitMap* bm() { return &_bm; }
#if PRT_COUNT_OCCUPIED
void recount_occupied() {
_occupied = (jint) bm()->count_one_bits();
}
#endif
PerRegionTable(HeapRegion* hr) :
_hr(hr),
#if PRT_COUNT_OCCUPIED
_occupied(0),
#endif
_bm(HeapRegion::CardsPerRegion, false /* in-resource-area */)
{}
static void free(PerRegionTable* prt) {
while (true) {
PerRegionTable* fl = _free_list;
prt->set_next_free(fl);
PerRegionTable* res =
(PerRegionTable*)
Atomic::cmpxchg_ptr(prt, &_free_list, fl);
if (res == fl) return;
}
ShouldNotReachHere();
}
static PerRegionTable* alloc(HeapRegion* hr) {
PerRegionTable* fl = _free_list;
while (fl != NULL) {
PerRegionTable* nxt = fl->next_free();
PerRegionTable* res =
(PerRegionTable*)
Atomic::cmpxchg_ptr(nxt, &_free_list, fl);
if (res == fl) {
fl->init(hr);
return fl;
} else {
fl = _free_list;
}
}
assert(fl == NULL, "Loop condition.");
return new PerRegionTable(hr);
}
void add_card_work(CardIdx_t from_card, bool par) {
if (!_bm.at(from_card)) {
if (par) {
if (_bm.par_at_put(from_card, 1)) {
#if PRT_COUNT_OCCUPIED
Atomic::inc(&_occupied);
#endif
}
} else {
_bm.at_put(from_card, 1);
#if PRT_COUNT_OCCUPIED
_occupied++;
#endif
}
}
}
@ -134,10 +89,13 @@ protected:
// Must make this robust in case "from" is not in "_hr", because of
// concurrency.
#if HRRS_VERBOSE
gclog_or_tty->print_cr(" PRT::Add_reference_work(" PTR_FORMAT "->" PTR_FORMAT").",
from, *from);
#endif
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr(" PRT::Add_reference_work(" PTR_FORMAT "->" PTR_FORMAT").",
from,
UseCompressedOops
? oopDesc::load_decode_heap_oop((narrowOop*)from)
: oopDesc::load_decode_heap_oop((oop*)from));
}
HeapRegion* loc_hr = hr();
// If the test below fails, then this table was reused concurrently
@ -162,23 +120,16 @@ public:
HeapRegion* hr() const { return _hr; }
#if PRT_COUNT_OCCUPIED
jint occupied() const {
// Overkill, but if we ever need it...
// guarantee(_occupied == _bm.count_one_bits(), "Check");
return _occupied;
}
#else
jint occupied() const {
return _bm.count_one_bits();
}
#endif
void init(HeapRegion* hr) {
_hr = hr;
#if PRT_COUNT_OCCUPIED
_next = NULL;
_occupied = 0;
#endif
_bm.clear();
}
@ -194,9 +145,7 @@ public:
HeapWord* hr_bot = hr()->bottom();
size_t hr_first_card_index = ctbs->index_for(hr_bot);
bm()->set_intersection_at_offset(*card_bm, hr_first_card_index);
#if PRT_COUNT_OCCUPIED
recount_occupied();
#endif
}
void add_card(CardIdx_t from_card_index) {
@ -218,16 +167,6 @@ public:
return sizeof(this) + _bm.size_in_words() * HeapWordSize;
}
static size_t fl_mem_size() {
PerRegionTable* cur = _free_list;
size_t res = 0;
while (cur != NULL) {
res += sizeof(PerRegionTable);
cur = cur->next_free();
}
return res;
}
// Requires "from" to be in "hr()".
bool contains_reference(OopOrNarrowOopStar from) const {
assert(hr()->is_in_reserved(from), "Precondition.");
@ -235,122 +174,29 @@ public:
CardTableModRefBS::card_size);
return _bm.at(card_ind);
}
};
PerRegionTable* PerRegionTable::_free_list = NULL;
PerRegionTable* next() const { return _next; }
void set_next(PerRegionTable* nxt) { _next = nxt; }
PerRegionTable** next_addr() { return &_next; }
#define COUNT_PAR_EXPANDS 0
#if COUNT_PAR_EXPANDS
static jint n_par_expands = 0;
static jint n_par_contracts = 0;
static jint par_expand_list_len = 0;
static jint max_par_expand_list_len = 0;
static void print_par_expand() {
Atomic::inc(&n_par_expands);
Atomic::inc(&par_expand_list_len);
if (par_expand_list_len > max_par_expand_list_len) {
max_par_expand_list_len = par_expand_list_len;
}
if ((n_par_expands % 10) == 0) {
gclog_or_tty->print_cr("\n\n%d par expands: %d contracts, "
"len = %d, max_len = %d\n.",
n_par_expands, n_par_contracts, par_expand_list_len,
max_par_expand_list_len);
}
}
#endif
class PosParPRT: public PerRegionTable {
PerRegionTable** _par_tables;
enum SomePrivateConstants {
ReserveParTableExpansion = 1
};
void par_contract() {
assert(_par_tables != NULL, "Precondition.");
int n = HeapRegionRemSet::num_par_rem_sets()-1;
for (int i = 0; i < n; i++) {
_par_tables[i]->union_bitmap_into(bm());
PerRegionTable::free(_par_tables[i]);
_par_tables[i] = NULL;
}
#if PRT_COUNT_OCCUPIED
// We must recount the "occupied."
recount_occupied();
#endif
FREE_C_HEAP_ARRAY(PerRegionTable*, _par_tables);
_par_tables = NULL;
#if COUNT_PAR_EXPANDS
Atomic::inc(&n_par_contracts);
Atomic::dec(&par_expand_list_len);
#endif
}
static PerRegionTable** _par_table_fl;
PosParPRT* _next;
static PosParPRT* _free_list;
PerRegionTable** par_tables() const {
assert(uintptr_t(NULL) == 0, "Assumption.");
if (uintptr_t(_par_tables) <= ReserveParTableExpansion)
return NULL;
else
return _par_tables;
}
PosParPRT* _next_par_expanded;
PosParPRT* next_par_expanded() { return _next_par_expanded; }
void set_next_par_expanded(PosParPRT* ppprt) { _next_par_expanded = ppprt; }
static PosParPRT* _par_expanded_list;
public:
PosParPRT(HeapRegion* hr) : PerRegionTable(hr), _par_tables(NULL) {}
jint occupied() const {
jint res = PerRegionTable::occupied();
if (par_tables() != NULL) {
for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets()-1; i++) {
res += par_tables()[i]->occupied();
}
}
return res;
}
void init(HeapRegion* hr) {
PerRegionTable::init(hr);
_next = NULL;
if (par_tables() != NULL) {
for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets()-1; i++) {
par_tables()[i]->init(hr);
}
}
}
static void free(PosParPRT* prt) {
static void free(PerRegionTable* prt) {
while (true) {
PosParPRT* fl = _free_list;
PerRegionTable* fl = _free_list;
prt->set_next(fl);
PosParPRT* res =
(PosParPRT*)
PerRegionTable* res =
(PerRegionTable*)
Atomic::cmpxchg_ptr(prt, &_free_list, fl);
if (res == fl) return;
}
ShouldNotReachHere();
}
static PosParPRT* alloc(HeapRegion* hr) {
PosParPRT* fl = _free_list;
static PerRegionTable* alloc(HeapRegion* hr) {
PerRegionTable* fl = _free_list;
while (fl != NULL) {
PosParPRT* nxt = fl->next();
PosParPRT* res =
(PosParPRT*)
PerRegionTable* nxt = fl->next();
PerRegionTable* res =
(PerRegionTable*)
Atomic::cmpxchg_ptr(nxt, &_free_list, fl);
if (res == fl) {
fl->init(hr);
@ -360,148 +206,26 @@ public:
}
}
assert(fl == NULL, "Loop condition.");
return new PosParPRT(hr);
}
PosParPRT* next() const { return _next; }
void set_next(PosParPRT* nxt) { _next = nxt; }
PosParPRT** next_addr() { return &_next; }
bool should_expand(int tid) {
// Given that we now defer RSet updates for after a GC we don't
// really need to expand the tables any more. This code should be
// cleaned up in the future (see CR 6921087).
return false;
}
void par_expand() {
int n = HeapRegionRemSet::num_par_rem_sets()-1;
if (n <= 0) return;
if (_par_tables == NULL) {
PerRegionTable* res =
(PerRegionTable*)
Atomic::cmpxchg_ptr((PerRegionTable*)ReserveParTableExpansion,
&_par_tables, NULL);
if (res != NULL) return;
// Otherwise, we reserved the right to do the expansion.
PerRegionTable** ptables = NEW_C_HEAP_ARRAY(PerRegionTable*, n);
for (int i = 0; i < n; i++) {
PerRegionTable* ptable = PerRegionTable::alloc(hr());
ptables[i] = ptable;
}
// Here we do not need an atomic.
_par_tables = ptables;
#if COUNT_PAR_EXPANDS
print_par_expand();
#endif
// We must put this table on the expanded list.
PosParPRT* exp_head = _par_expanded_list;
while (true) {
set_next_par_expanded(exp_head);
PosParPRT* res =
(PosParPRT*)
Atomic::cmpxchg_ptr(this, &_par_expanded_list, exp_head);
if (res == exp_head) return;
// Otherwise.
exp_head = res;
}
ShouldNotReachHere();
}
}
void add_reference(OopOrNarrowOopStar from, int tid) {
// Expand if necessary.
PerRegionTable** pt = par_tables();
if (pt != NULL) {
// We always have to assume that mods to table 0 are in parallel,
// because of the claiming scheme in parallel expansion. A thread
// with tid != 0 that finds the table to be NULL, but doesn't succeed
// in claiming the right of expanding it, will end up in the else
// clause of the above if test. That thread could be delayed, and a
// thread 0 add reference could see the table expanded, and come
// here. Both threads would be adding in parallel. But we get to
// not use atomics for tids > 0.
if (tid == 0) {
PerRegionTable::add_reference(from);
} else {
pt[tid-1]->seq_add_reference(from);
}
} else {
// Not expanded -- add to the base table.
PerRegionTable::add_reference(from);
}
}
void scrub(CardTableModRefBS* ctbs, BitMap* card_bm) {
assert(_par_tables == NULL, "Precondition");
PerRegionTable::scrub(ctbs, card_bm);
}
size_t mem_size() const {
size_t res =
PerRegionTable::mem_size() + sizeof(this) - sizeof(PerRegionTable);
if (_par_tables != NULL) {
for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets()-1; i++) {
res += _par_tables[i]->mem_size();
}
}
return res;
return new PerRegionTable(hr);
}
static size_t fl_mem_size() {
PosParPRT* cur = _free_list;
PerRegionTable* cur = _free_list;
size_t res = 0;
while (cur != NULL) {
res += sizeof(PosParPRT);
res += sizeof(PerRegionTable);
cur = cur->next();
}
return res;
}
bool contains_reference(OopOrNarrowOopStar from) const {
if (PerRegionTable::contains_reference(from)) return true;
if (_par_tables != NULL) {
for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets()-1; i++) {
if (_par_tables[i]->contains_reference(from)) return true;
}
}
return false;
}
static void par_contract_all();
};
void PosParPRT::par_contract_all() {
PosParPRT* hd = _par_expanded_list;
while (hd != NULL) {
PosParPRT* nxt = hd->next_par_expanded();
PosParPRT* res =
(PosParPRT*)
Atomic::cmpxchg_ptr(nxt, &_par_expanded_list, hd);
if (res == hd) {
// We claimed the right to contract this table.
hd->set_next_par_expanded(NULL);
hd->par_contract();
hd = _par_expanded_list;
} else {
hd = res;
}
}
}
PosParPRT* PosParPRT::_free_list = NULL;
PosParPRT* PosParPRT::_par_expanded_list = NULL;
jint OtherRegionsTable::_cache_probes = 0;
jint OtherRegionsTable::_cache_hits = 0;
PerRegionTable* PerRegionTable::_free_list = NULL;
size_t OtherRegionsTable::_max_fine_entries = 0;
size_t OtherRegionsTable::_mod_max_fine_entries_mask = 0;
#if SAMPLE_FOR_EVICTION
size_t OtherRegionsTable::_fine_eviction_stride = 0;
size_t OtherRegionsTable::_fine_eviction_sample_size = 0;
#endif
OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) :
_g1h(G1CollectedHeap::heap()),
@ -511,34 +235,36 @@ OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) :
false /* in-resource-area */),
_fine_grain_regions(NULL),
_n_fine_entries(0), _n_coarse_entries(0),
#if SAMPLE_FOR_EVICTION
_fine_eviction_start(0),
#endif
_sparse_table(hr)
{
typedef PosParPRT* PosParPRTPtr;
typedef PerRegionTable* PerRegionTablePtr;
if (_max_fine_entries == 0) {
assert(_mod_max_fine_entries_mask == 0, "Both or none.");
size_t max_entries_log = (size_t)log2_long((jlong)G1RSetRegionEntries);
_max_fine_entries = (size_t)(1 << max_entries_log);
_mod_max_fine_entries_mask = _max_fine_entries - 1;
#if SAMPLE_FOR_EVICTION
assert(_fine_eviction_sample_size == 0
&& _fine_eviction_stride == 0, "All init at same time.");
_fine_eviction_sample_size = MAX2((size_t)4, max_entries_log);
_fine_eviction_stride = _max_fine_entries / _fine_eviction_sample_size;
#endif
}
_fine_grain_regions = new PosParPRTPtr[_max_fine_entries];
if (_fine_grain_regions == NULL)
_fine_grain_regions = new PerRegionTablePtr[_max_fine_entries];
if (_fine_grain_regions == NULL) {
vm_exit_out_of_memory(sizeof(void*)*_max_fine_entries,
"Failed to allocate _fine_grain_entries.");
}
for (size_t i = 0; i < _max_fine_entries; i++) {
_fine_grain_regions[i] = NULL;
}
}
int** OtherRegionsTable::_from_card_cache = NULL;
int** OtherRegionsTable::_from_card_cache = NULL;
size_t OtherRegionsTable::_from_card_cache_max_regions = 0;
size_t OtherRegionsTable::_from_card_cache_mem_size = 0;
@ -579,38 +305,26 @@ void OtherRegionsTable::print_from_card_cache() {
void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
size_t cur_hrs_ind = (size_t) hr()->hrs_index();
#if HRRS_VERBOSE
gclog_or_tty->print_cr("ORT::add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").",
from,
UseCompressedOops
? oopDesc::load_decode_heap_oop((narrowOop*)from)
: oopDesc::load_decode_heap_oop((oop*)from));
#endif
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr("ORT::add_reference_work(" PTR_FORMAT "->" PTR_FORMAT ").",
from,
UseCompressedOops
? oopDesc::load_decode_heap_oop((narrowOop*)from)
: oopDesc::load_decode_heap_oop((oop*)from));
}
int from_card = (int)(uintptr_t(from) >> CardTableModRefBS::card_shift);
#if HRRS_VERBOSE
gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = %d)",
hr()->bottom(), from_card,
_from_card_cache[tid][cur_hrs_ind]);
#endif
#define COUNT_CACHE 0
#if COUNT_CACHE
jint p = Atomic::add(1, &_cache_probes);
if ((p % 10000) == 0) {
jint hits = _cache_hits;
gclog_or_tty->print_cr("%d/%d = %5.2f%% RS cache hits.",
_cache_hits, p, 100.0* (float)hits/(float)p);
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = %d)",
hr()->bottom(), from_card,
_from_card_cache[tid][cur_hrs_ind]);
}
#endif
if (from_card == _from_card_cache[tid][cur_hrs_ind]) {
#if HRRS_VERBOSE
gclog_or_tty->print_cr(" from-card cache hit.");
#endif
#if COUNT_CACHE
Atomic::inc(&_cache_hits);
#endif
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr(" from-card cache hit.");
}
assert(contains_reference(from), "We just added it!");
return;
} else {
@ -623,16 +337,16 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
// If the region is already coarsened, return.
if (_coarse_map.at(from_hrs_ind)) {
#if HRRS_VERBOSE
gclog_or_tty->print_cr(" coarse map hit.");
#endif
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr(" coarse map hit.");
}
assert(contains_reference(from), "We just added it!");
return;
}
// Otherwise find a per-region table to add it to.
size_t ind = from_hrs_ind & _mod_max_fine_entries_mask;
PosParPRT* prt = find_region_table(ind, from_hr);
PerRegionTable* prt = find_region_table(ind, from_hr);
if (prt == NULL) {
MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
// Confirm that it's really not there...
@ -649,35 +363,35 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
_sparse_table.add_card(from_hrs_ind, card_index)) {
if (G1RecordHRRSOops) {
HeapRegionRemSet::record(hr(), from);
#if HRRS_VERBOSE
gclog_or_tty->print(" Added card " PTR_FORMAT " to region "
"[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
align_size_down(uintptr_t(from),
CardTableModRefBS::card_size),
hr()->bottom(), from);
#endif
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print(" Added card " PTR_FORMAT " to region "
"[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
align_size_down(uintptr_t(from),
CardTableModRefBS::card_size),
hr()->bottom(), from);
}
}
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr(" added card to sparse table.");
}
#if HRRS_VERBOSE
gclog_or_tty->print_cr(" added card to sparse table.");
#endif
assert(contains_reference_locked(from), "We just added it!");
return;
} else {
#if HRRS_VERBOSE
gclog_or_tty->print_cr(" [tid %d] sparse table entry "
"overflow(f: %d, t: %d)",
tid, from_hrs_ind, cur_hrs_ind);
#endif
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print_cr(" [tid %d] sparse table entry "
"overflow(f: %d, t: %d)",
tid, from_hrs_ind, cur_hrs_ind);
}
}
if (_n_fine_entries == _max_fine_entries) {
prt = delete_region_table();
} else {
prt = PosParPRT::alloc(from_hr);
prt = PerRegionTable::alloc(from_hr);
}
prt->init(from_hr);
PosParPRT* first_prt = _fine_grain_regions[ind];
PerRegionTable* first_prt = _fine_grain_regions[ind];
prt->set_next(first_prt); // XXX Maybe move to init?
_fine_grain_regions[ind] = prt;
_n_fine_entries++;
@ -704,38 +418,25 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
// OtherRegionsTable for why this is OK.
assert(prt != NULL, "Inv");
if (prt->should_expand(tid)) {
MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
HeapRegion* prt_hr = prt->hr();
if (prt_hr == from_hr) {
// Make sure the table still corresponds to the same region
prt->par_expand();
prt->add_reference(from, tid);
}
// else: The table has been concurrently coarsened, evicted, and
// the table data structure re-used for another table. So, we
// don't need to add the reference any more given that the table
// has been coarsened and the whole region will be scanned anyway.
} else {
prt->add_reference(from, tid);
}
prt->add_reference(from);
if (G1RecordHRRSOops) {
HeapRegionRemSet::record(hr(), from);
#if HRRS_VERBOSE
gclog_or_tty->print("Added card " PTR_FORMAT " to region "
"[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
align_size_down(uintptr_t(from),
CardTableModRefBS::card_size),
hr()->bottom(), from);
#endif
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print("Added card " PTR_FORMAT " to region "
"[" PTR_FORMAT "...) for ref " PTR_FORMAT ".\n",
align_size_down(uintptr_t(from),
CardTableModRefBS::card_size),
hr()->bottom(), from);
}
}
assert(contains_reference(from), "We just added it!");
}
PosParPRT*
PerRegionTable*
OtherRegionsTable::find_region_table(size_t ind, HeapRegion* hr) const {
assert(0 <= ind && ind < _max_fine_entries, "Preconditions.");
PosParPRT* prt = _fine_grain_regions[ind];
PerRegionTable* prt = _fine_grain_regions[ind];
while (prt != NULL && prt->hr() != hr) {
prt = prt->next();
}
@ -743,32 +444,16 @@ OtherRegionsTable::find_region_table(size_t ind, HeapRegion* hr) const {
return prt;
}
#define DRT_CENSUS 0
#if DRT_CENSUS
static const int HistoSize = 6;
static int global_histo[HistoSize] = { 0, 0, 0, 0, 0, 0 };
static int coarsenings = 0;
static int occ_sum = 0;
#endif
jint OtherRegionsTable::_n_coarsenings = 0;
PosParPRT* OtherRegionsTable::delete_region_table() {
#if DRT_CENSUS
int histo[HistoSize] = { 0, 0, 0, 0, 0, 0 };
const int histo_limits[] = { 1, 4, 16, 64, 256, 2048 };
#endif
PerRegionTable* OtherRegionsTable::delete_region_table() {
assert(_m.owned_by_self(), "Precondition");
assert(_n_fine_entries == _max_fine_entries, "Precondition");
PosParPRT* max = NULL;
PerRegionTable* max = NULL;
jint max_occ = 0;
PosParPRT** max_prev;
PerRegionTable** max_prev;
size_t max_ind;
#if SAMPLE_FOR_EVICTION
size_t i = _fine_eviction_start;
for (size_t k = 0; k < _fine_eviction_sample_size; k++) {
size_t ii = i;
@ -778,8 +463,8 @@ PosParPRT* OtherRegionsTable::delete_region_table() {
if (ii == _max_fine_entries) ii = 0;
guarantee(ii != i, "We must find one.");
}
PosParPRT** prev = &_fine_grain_regions[ii];
PosParPRT* cur = *prev;
PerRegionTable** prev = &_fine_grain_regions[ii];
PerRegionTable* cur = *prev;
while (cur != NULL) {
jint cur_occ = cur->occupied();
if (max == NULL || cur_occ > max_occ) {
@ -794,64 +479,27 @@ PosParPRT* OtherRegionsTable::delete_region_table() {
i = i + _fine_eviction_stride;
if (i >= _n_fine_entries) i = i - _n_fine_entries;
}
_fine_eviction_start++;
if (_fine_eviction_start >= _n_fine_entries)
if (_fine_eviction_start >= _n_fine_entries) {
_fine_eviction_start -= _n_fine_entries;
#else
for (int i = 0; i < _max_fine_entries; i++) {
PosParPRT** prev = &_fine_grain_regions[i];
PosParPRT* cur = *prev;
while (cur != NULL) {
jint cur_occ = cur->occupied();
#if DRT_CENSUS
for (int k = 0; k < HistoSize; k++) {
if (cur_occ <= histo_limits[k]) {
histo[k]++; global_histo[k]++; break;
}
}
#endif
if (max == NULL || cur_occ > max_occ) {
max = cur;
max_prev = prev;
max_ind = i;
max_occ = cur_occ;
}
prev = cur->next_addr();
cur = cur->next();
}
}
#endif
// XXX
guarantee(max != NULL, "Since _n_fine_entries > 0");
#if DRT_CENSUS
gclog_or_tty->print_cr("In a coarsening: histo of occs:");
for (int k = 0; k < HistoSize; k++) {
gclog_or_tty->print_cr(" <= %4d: %5d.", histo_limits[k], histo[k]);
}
coarsenings++;
occ_sum += max_occ;
if ((coarsenings % 100) == 0) {
gclog_or_tty->print_cr("\ncoarsenings = %d; global summary:", coarsenings);
for (int k = 0; k < HistoSize; k++) {
gclog_or_tty->print_cr(" <= %4d: %5d.", histo_limits[k], global_histo[k]);
}
gclog_or_tty->print_cr("Avg occ of deleted region = %6.2f.",
(float)occ_sum/(float)coarsenings);
}
#endif
// Set the corresponding coarse bit.
size_t max_hrs_index = (size_t) max->hr()->hrs_index();
if (!_coarse_map.at(max_hrs_index)) {
_coarse_map.at_put(max_hrs_index, true);
_n_coarse_entries++;
#if 0
gclog_or_tty->print("Coarsened entry in region [" PTR_FORMAT "...] "
"for region [" PTR_FORMAT "...] (%d coarse entries).\n",
hr()->bottom(),
max->hr()->bottom(),
_n_coarse_entries);
#endif
if (G1TraceHeapRegionRememberedSet) {
gclog_or_tty->print("Coarsened entry in region [" PTR_FORMAT "...] "
"for region [" PTR_FORMAT "...] (%d coarse entries).\n",
hr()->bottom(),
max->hr()->bottom(),
_n_coarse_entries);
}
}
// Unsplice.
@ -883,10 +531,10 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
// Now do the fine-grained maps.
for (size_t i = 0; i < _max_fine_entries; i++) {
PosParPRT* cur = _fine_grain_regions[i];
PosParPRT** prev = &_fine_grain_regions[i];
PerRegionTable* cur = _fine_grain_regions[i];
PerRegionTable** prev = &_fine_grain_regions[i];
while (cur != NULL) {
PosParPRT* nxt = cur->next();
PerRegionTable* nxt = cur->next();
// If the entire region is dead, eliminate.
if (G1RSScrubVerbose) {
gclog_or_tty->print_cr(" For other region %u:",
@ -899,7 +547,7 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
if (G1RSScrubVerbose) {
gclog_or_tty->print_cr(" deleted via region map.");
}
PosParPRT::free(cur);
PerRegionTable::free(cur);
} else {
// Do fine-grain elimination.
if (G1RSScrubVerbose) {
@ -914,7 +562,7 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
*prev = nxt;
cur->set_next(NULL);
_n_fine_entries--;
PosParPRT::free(cur);
PerRegionTable::free(cur);
} else {
prev = cur->next_addr();
}
@ -940,7 +588,7 @@ size_t OtherRegionsTable::occupied() const {
size_t OtherRegionsTable::occ_fine() const {
size_t sum = 0;
for (size_t i = 0; i < _max_fine_entries; i++) {
PosParPRT* cur = _fine_grain_regions[i];
PerRegionTable* cur = _fine_grain_regions[i];
while (cur != NULL) {
sum += cur->occupied();
cur = cur->next();
@ -962,13 +610,13 @@ size_t OtherRegionsTable::mem_size() const {
MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag);
size_t sum = 0;
for (size_t i = 0; i < _max_fine_entries; i++) {
PosParPRT* cur = _fine_grain_regions[i];
PerRegionTable* cur = _fine_grain_regions[i];
while (cur != NULL) {
sum += cur->mem_size();
cur = cur->next();
}
}
sum += (sizeof(PosParPRT*) * _max_fine_entries);
sum += (sizeof(PerRegionTable*) * _max_fine_entries);
sum += (_coarse_map.size_in_words() * HeapWordSize);
sum += (_sparse_table.mem_size());
sum += sizeof(*this) - sizeof(_sparse_table); // Avoid double counting above.
@ -980,7 +628,7 @@ size_t OtherRegionsTable::static_mem_size() {
}
size_t OtherRegionsTable::fl_mem_size() {
return PerRegionTable::fl_mem_size() + PosParPRT::fl_mem_size();
return PerRegionTable::fl_mem_size();
}
void OtherRegionsTable::clear_fcc() {
@ -992,10 +640,10 @@ void OtherRegionsTable::clear_fcc() {
void OtherRegionsTable::clear() {
MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
for (size_t i = 0; i < _max_fine_entries; i++) {
PosParPRT* cur = _fine_grain_regions[i];
PerRegionTable* cur = _fine_grain_regions[i];
while (cur != NULL) {
PosParPRT* nxt = cur->next();
PosParPRT::free(cur);
PerRegionTable* nxt = cur->next();
PerRegionTable::free(cur);
cur = nxt;
}
_fine_grain_regions[i] = NULL;
@ -1035,8 +683,8 @@ void OtherRegionsTable::clear_incoming_entry(HeapRegion* from_hr) {
bool OtherRegionsTable::del_single_region_table(size_t ind,
HeapRegion* hr) {
assert(0 <= ind && ind < _max_fine_entries, "Preconditions.");
PosParPRT** prev_addr = &_fine_grain_regions[ind];
PosParPRT* prt = *prev_addr;
PerRegionTable** prev_addr = &_fine_grain_regions[ind];
PerRegionTable* prt = *prev_addr;
while (prt != NULL && prt->hr() != hr) {
prev_addr = prt->next_addr();
prt = prt->next();
@ -1044,7 +692,7 @@ bool OtherRegionsTable::del_single_region_table(size_t ind,
if (prt != NULL) {
assert(prt->hr() == hr, "Loop postcondition.");
*prev_addr = prt->next();
PosParPRT::free(prt);
PerRegionTable::free(prt);
_n_fine_entries--;
return true;
} else {
@ -1065,7 +713,7 @@ bool OtherRegionsTable::contains_reference_locked(OopOrNarrowOopStar from) const
// Is this region in the coarse map?
if (_coarse_map.at(hr_ind)) return true;
PosParPRT* prt = find_region_table(hr_ind & _mod_max_fine_entries_mask,
PerRegionTable* prt = find_region_table(hr_ind & _mod_max_fine_entries_mask,
hr);
if (prt != NULL) {
return prt->contains_reference(from);
@ -1145,7 +793,7 @@ void HeapRegionRemSet::print() const {
G1CollectedHeap::heap()->bot_shared()->address_for_index(card_index);
gclog_or_tty->print_cr(" Card " PTR_FORMAT, card_start);
}
// XXX
if (iter.n_yielded() != occupied()) {
gclog_or_tty->print_cr("Yielded disagrees with occupied:");
gclog_or_tty->print_cr(" %6d yielded (%6d coarse, %6d fine).",
@ -1163,10 +811,6 @@ void HeapRegionRemSet::cleanup() {
SparsePRT::cleanup_all();
}
void HeapRegionRemSet::par_cleanup() {
PosParPRT::par_contract_all();
}
void HeapRegionRemSet::clear() {
_other_regions.clear();
assert(occupied() == 0, "Should be clear.");

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,7 +35,7 @@ class G1CollectedHeap;
class G1BlockOffsetSharedArray;
class HeapRegion;
class HeapRegionRemSetIterator;
class PosParPRT;
class PerRegionTable;
class SparsePRT;
// Essentially a wrapper around SparsePRTCleanupTask. See
@ -79,15 +79,14 @@ class OtherRegionsTable VALUE_OBJ_CLASS_SPEC {
size_t _n_coarse_entries;
static jint _n_coarsenings;
PosParPRT** _fine_grain_regions;
size_t _n_fine_entries;
PerRegionTable** _fine_grain_regions;
size_t _n_fine_entries;
#define SAMPLE_FOR_EVICTION 1
#if SAMPLE_FOR_EVICTION
// Used to sample a subset of the fine grain PRTs to determine which
// PRT to evict and coarsen.
size_t _fine_eviction_start;
static size_t _fine_eviction_stride;
static size_t _fine_eviction_sample_size;
#endif
SparsePRT _sparse_table;
@ -98,21 +97,18 @@ class OtherRegionsTable VALUE_OBJ_CLASS_SPEC {
// Requires "prt" to be the first element of the bucket list appropriate
// for "hr". If this list contains an entry for "hr", return it,
// otherwise return "NULL".
PosParPRT* find_region_table(size_t ind, HeapRegion* hr) const;
PerRegionTable* find_region_table(size_t ind, HeapRegion* hr) const;
// Find, delete, and return a candidate PosParPRT, if any exists,
// Find, delete, and return a candidate PerRegionTable, if any exists,
// adding the deleted region to the coarse bitmap. Requires the caller
// to hold _m, and the fine-grain table to be full.
PosParPRT* delete_region_table();
PerRegionTable* delete_region_table();
// If a PRT for "hr" is in the bucket list indicated by "ind" (which must
// be the correct index for "hr"), delete it and return true; else return
// false.
bool del_single_region_table(size_t ind, HeapRegion* hr);
static jint _cache_probes;
static jint _cache_hits;
// Indexed by thread X heap region, to minimize thread contention.
static int** _from_card_cache;
static size_t _from_card_cache_max_regions;
@ -127,10 +123,6 @@ public:
// sense.
void add_reference(OopOrNarrowOopStar from, int tid);
void add_reference(OopOrNarrowOopStar from) {
return add_reference(from, 0);
}
// Removes any entries shown by the given bitmaps to contain only dead
// objects.
void scrub(CardTableModRefBS* ctbs, BitMap* region_bm, BitMap* card_bm);
@ -233,14 +225,12 @@ public:
static jint n_coarsenings() { return OtherRegionsTable::n_coarsenings(); }
/* Used in the sequential case. Returns "true" iff this addition causes
the size limit to be reached. */
// Used in the sequential case.
void add_reference(OopOrNarrowOopStar from) {
_other_regions.add_reference(from);
_other_regions.add_reference(from, 0);
}
/* Used in the parallel case. Returns "true" iff this addition causes
the size limit to be reached. */
// Used in the parallel case.
void add_reference(OopOrNarrowOopStar from, int tid) {
_other_regions.add_reference(from, tid);
}
@ -253,15 +243,6 @@ public:
// entries for this region in other remsets.
void clear();
// Forget any entries due to pointers from "from_hr".
void clear_incoming_entry(HeapRegion* from_hr) {
_other_regions.clear_incoming_entry(from_hr);
}
#if 0
virtual void cleanup() = 0;
#endif
// Attempt to claim the region. Returns true iff this call caused an
// atomic transition from Unclaimed to Claimed.
bool claim_iter();
@ -290,12 +271,6 @@ public:
// Initialize the given iterator to iterate over this rem set.
void init_iterator(HeapRegionRemSetIterator* iter) const;
#if 0
// Apply the "do_card" method to the start address of every card in the
// rem set. Returns false if some application of the closure aborted.
virtual bool card_iterate(CardClosure* iter) = 0;
#endif
// The actual # of bytes this hr_remset takes up.
size_t mem_size() {
return _other_regions.mem_size()
@ -322,10 +297,7 @@ public:
void print() const;
// Called during a stop-world phase to perform any deferred cleanups.
// The second version may be called by parallel threads after then finish
// collection work.
static void cleanup();
static void par_cleanup();
// Declare the heap size (in # of regions) to the HeapRegionRemSet(s).
// (Uses it to initialize from_card_cache).
@ -367,7 +339,7 @@ class HeapRegionRemSetIterator : public CHeapObj {
// Local caching of HRRS fields.
const BitMap* _coarse_map;
PosParPRT** _fine_grain_regions;
PerRegionTable** _fine_grain_regions;
G1BlockOffsetSharedArray* _bosa;
G1CollectedHeap* _g1h;
@ -404,8 +376,9 @@ class HeapRegionRemSetIterator : public CHeapObj {
// Index of bucket-list we're working on.
int _fine_array_index;
// Per Region Table we're doing within current bucket list.
PosParPRT* _fine_cur_prt;
PerRegionTable* _fine_cur_prt;
/* SparsePRT::*/ SparsePRTIter _sparse_iter;
@ -435,12 +408,4 @@ public:
}
};
#if 0
class CardClosure: public Closure {
public:
virtual void do_card(HeapWord* card_start) = 0;
};
#endif
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONREMSET_HPP

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

@ -273,7 +273,7 @@ class Universe: AllStatic {
}
static klassOop typeArrayKlassObj(BasicType t) {
assert((uint)t < T_VOID+1, "range check");
assert((uint)t < T_VOID+1, err_msg("range check for type: %s", type2name(t)));
assert(_typeArrayKlassObjs[t] != NULL, "domain check");
return _typeArrayKlassObjs[t];
}

@ -81,6 +81,13 @@
product(intx, MaxLoopPad, (OptoLoopAlignment-1), \
"Align a loop if padding size in bytes is less or equal to this value") \
\
product(intx, MaxVectorSize, 32, \
"Max vector size in bytes, " \
"actual size could be less depending on elements type") \
\
product(bool, AlignVector, false, \
"Perform vector store/load alignment in loop") \
\
product(intx, NumberOfLoopInstrToAlign, 4, \
"Number of first instructions in a loop to align") \
\
@ -292,9 +299,12 @@
develop(bool, SuperWordRTDepCheck, false, \
"Enable runtime dependency checks.") \
\
product(bool, TraceSuperWord, false, \
notproduct(bool, TraceSuperWord, false, \
"Trace superword transforms") \
\
notproduct(bool, TraceNewVectors, false, \
"Trace creation of Vector nodes") \
\
product_pd(bool, OptoBundling, \
"Generate nops to fill i-cache lines") \
\

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

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

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -99,8 +99,15 @@ public:
void set_mask_size( int size ) {
assert((size == 65535) || (size == (int)_mask.Size()), "");
_mask_size = size;
debug_only(_msize_valid=1;)
debug_only( if( _num_regs == 2 && !_fat_proj ) _mask.VerifyPairs(); )
#ifdef ASSERT
_msize_valid=1;
if (_is_vector) {
assert(!_fat_proj, "sanity");
_mask.verify_sets(_num_regs);
} else if (_num_regs == 2 && !_fat_proj) {
_mask.verify_pairs();
}
#endif
}
void compute_set_mask_size() { set_mask_size(compute_mask_size()); }
int mask_size() const { assert( _msize_valid, "mask size not valid" );
@ -116,7 +123,8 @@ public:
void Set_All() { _mask.Set_All(); debug_only(_msize_valid=1); _mask_size = RegMask::CHUNK_SIZE; }
void Insert( OptoReg::Name reg ) { _mask.Insert(reg); debug_only(_msize_valid=0;) }
void Remove( OptoReg::Name reg ) { _mask.Remove(reg); debug_only(_msize_valid=0;) }
void ClearToPairs() { _mask.ClearToPairs(); debug_only(_msize_valid=0;) }
void clear_to_pairs() { _mask.clear_to_pairs(); debug_only(_msize_valid=0;) }
void clear_to_sets() { _mask.clear_to_sets(_num_regs); debug_only(_msize_valid=0;) }
// Number of registers this live range uses when it colors
private:
@ -150,6 +158,7 @@ public:
uint _is_oop:1, // Live-range holds an oop
_is_float:1, // True if in float registers
_is_vector:1, // True if in vector registers
_was_spilled1:1, // True if prior spilling on def
_was_spilled2:1, // True if twice prior spilling on def
_is_bound:1, // live range starts life with no

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -245,14 +245,12 @@ macro(XorI)
macro(XorL)
macro(Vector)
macro(AddVB)
macro(AddVC)
macro(AddVS)
macro(AddVI)
macro(AddVL)
macro(AddVF)
macro(AddVD)
macro(SubVB)
macro(SubVC)
macro(SubVS)
macro(SubVI)
macro(SubVL)
@ -263,74 +261,36 @@ macro(MulVD)
macro(DivVF)
macro(DivVD)
macro(LShiftVB)
macro(LShiftVC)
macro(LShiftVS)
macro(LShiftVI)
macro(URShiftVB)
macro(URShiftVC)
macro(URShiftVS)
macro(URShiftVI)
macro(RShiftVB)
macro(RShiftVS)
macro(RShiftVI)
macro(AndV)
macro(OrV)
macro(XorV)
macro(VectorLoad)
macro(Load16B)
macro(Load8B)
macro(Load4B)
macro(Load8C)
macro(Load4C)
macro(Load2C)
macro(Load8S)
macro(Load4S)
macro(Load2S)
macro(Load4I)
macro(Load2I)
macro(Load2L)
macro(Load4F)
macro(Load2F)
macro(Load2D)
macro(VectorStore)
macro(Store16B)
macro(Store8B)
macro(Store4B)
macro(Store8C)
macro(Store4C)
macro(Store2C)
macro(Store4I)
macro(Store2I)
macro(Store2L)
macro(Store4F)
macro(Store2F)
macro(Store2D)
macro(LoadVector)
macro(StoreVector)
macro(Pack)
macro(PackB)
macro(PackS)
macro(PackC)
macro(PackI)
macro(PackL)
macro(PackF)
macro(PackD)
macro(Pack2x1B)
macro(Pack2x2B)
macro(Replicate16B)
macro(Replicate8B)
macro(Replicate4B)
macro(Replicate8S)
macro(Replicate4S)
macro(Replicate2S)
macro(Replicate8C)
macro(Replicate4C)
macro(Replicate2C)
macro(Replicate4I)
macro(Replicate2I)
macro(Replicate2L)
macro(Replicate4F)
macro(Replicate2F)
macro(Replicate2D)
macro(Pack2L)
macro(Pack2D)
macro(ReplicateB)
macro(ReplicateS)
macro(ReplicateI)
macro(ReplicateL)
macro(ReplicateF)
macro(ReplicateD)
macro(Extract)
macro(ExtractB)
macro(ExtractS)
macro(ExtractUB)
macro(ExtractC)
macro(ExtractS)
macro(ExtractI)
macro(ExtractL)
macro(ExtractF)

@ -2591,38 +2591,12 @@ static void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc ) {
}
break;
case Op_Load16B:
case Op_Load8B:
case Op_Load4B:
case Op_Load8S:
case Op_Load4S:
case Op_Load2S:
case Op_Load8C:
case Op_Load4C:
case Op_Load2C:
case Op_Load4I:
case Op_Load2I:
case Op_Load2L:
case Op_Load4F:
case Op_Load2F:
case Op_Load2D:
case Op_Store16B:
case Op_Store8B:
case Op_Store4B:
case Op_Store8C:
case Op_Store4C:
case Op_Store2C:
case Op_Store4I:
case Op_Store2I:
case Op_Store2L:
case Op_Store4F:
case Op_Store2F:
case Op_Store2D:
case Op_LoadVector:
case Op_StoreVector:
break;
case Op_PackB:
case Op_PackS:
case Op_PackC:
case Op_PackI:
case Op_PackF:
case Op_PackL:

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

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -139,6 +139,7 @@ void Block::implicit_null_check(PhaseCFG *cfg, Node *proj, Node *val, int allowe
int iop = mach->ideal_Opcode();
switch( iop ) {
case Op_LoadB:
case Op_LoadUB:
case Op_LoadUS:
case Op_LoadD:
case Op_LoadF:
@ -445,6 +446,11 @@ Node *Block::select(PhaseCFG *cfg, Node_List &worklist, GrowableArray<int> &read
if( e->is_MachNullCheck() && e->in(1) == n )
continue;
// Schedule IV increment last.
if (e->is_Mach() && e->as_Mach()->ideal_Opcode() == Op_CountedLoopEnd &&
e->in(1)->in(1) == n && n->is_iteratively_computed())
continue;
uint n_choice = 2;
// See if this instruction is consumed by a branch. If so, then (as the

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

@ -2751,7 +2751,8 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
// Do not count uncommon calls
if( !n->is_CallStaticJava() || !n->as_CallStaticJava()->_name ) {
Node *iff = n->in(0)->in(0);
if( !iff->is_If() ||
// No any calls for vectorized loops.
if( UseSuperWord || !iff->is_If() ||
(n->in(0)->Opcode() == Op_IfFalse &&
(1.0 - iff->as_If()->_prob) >= 0.01) ||
(iff->as_If()->_prob >= 0.01) )
@ -3216,7 +3217,8 @@ void PhaseIdealLoop::build_loop_late_post( Node *n ) {
case Op_ModF:
case Op_ModD:
case Op_LoadB: // Same with Loads; they can sink
case Op_LoadUS: // during loop optimizations.
case Op_LoadUB: // during loop optimizations.
case Op_LoadUS:
case Op_LoadD:
case Op_LoadF:
case Op_LoadI:

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -439,9 +439,9 @@ bool MachNode::rematerialize() const {
// Don't remateralize somebody with bound inputs - it stretches a
// fixed register lifetime.
uint idx = oper_input_base();
if( req() > idx ) {
if (req() > idx) {
const RegMask &rm = in_RegMask(idx);
if( rm.is_bound1() || rm.is_bound2() )
if (rm.is_bound(ideal_reg()))
return false;
}

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

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -35,6 +35,7 @@
#include "opto/rootnode.hpp"
#include "opto/runtime.hpp"
#include "opto/type.hpp"
#include "opto/vectornode.hpp"
#include "runtime/atomic.hpp"
#include "runtime/os.hpp"
#ifdef TARGET_ARCH_MODEL_x86_32
@ -58,18 +59,6 @@
OptoReg::Name OptoReg::c_frame_pointer;
const int Matcher::base2reg[Type::lastype] = {
Node::NotAMachineReg,0,0, Op_RegI, Op_RegL, 0, Op_RegN,
Node::NotAMachineReg, Node::NotAMachineReg, /* tuple, array */
Op_RegP, Op_RegP, Op_RegP, Op_RegP, Op_RegP, Op_RegP, /* the pointers */
0, 0/*abio*/,
Op_RegP /* Return address */, 0, /* the memories */
Op_RegF, Op_RegF, Op_RegF, Op_RegD, Op_RegD, Op_RegD,
0 /*bottom*/
};
const RegMask *Matcher::idealreg2regmask[_last_machine_leaf];
RegMask Matcher::mreg2regmask[_last_Mach_Reg];
RegMask Matcher::STACK_ONLY_mask;
@ -107,6 +96,10 @@ Matcher::Matcher( Node_List &proj_list ) :
idealreg2spillmask [Op_RegF] = NULL;
idealreg2spillmask [Op_RegD] = NULL;
idealreg2spillmask [Op_RegP] = NULL;
idealreg2spillmask [Op_VecS] = NULL;
idealreg2spillmask [Op_VecD] = NULL;
idealreg2spillmask [Op_VecX] = NULL;
idealreg2spillmask [Op_VecY] = NULL;
idealreg2debugmask [Op_RegI] = NULL;
idealreg2debugmask [Op_RegN] = NULL;
@ -114,6 +107,10 @@ Matcher::Matcher( Node_List &proj_list ) :
idealreg2debugmask [Op_RegF] = NULL;
idealreg2debugmask [Op_RegD] = NULL;
idealreg2debugmask [Op_RegP] = NULL;
idealreg2debugmask [Op_VecS] = NULL;
idealreg2debugmask [Op_VecD] = NULL;
idealreg2debugmask [Op_VecX] = NULL;
idealreg2debugmask [Op_VecY] = NULL;
idealreg2mhdebugmask[Op_RegI] = NULL;
idealreg2mhdebugmask[Op_RegN] = NULL;
@ -121,6 +118,10 @@ Matcher::Matcher( Node_List &proj_list ) :
idealreg2mhdebugmask[Op_RegF] = NULL;
idealreg2mhdebugmask[Op_RegD] = NULL;
idealreg2mhdebugmask[Op_RegP] = NULL;
idealreg2mhdebugmask[Op_VecS] = NULL;
idealreg2mhdebugmask[Op_VecD] = NULL;
idealreg2mhdebugmask[Op_VecX] = NULL;
idealreg2mhdebugmask[Op_VecY] = NULL;
debug_only(_mem_node = NULL;) // Ideal memory node consumed by mach node
}
@ -134,7 +135,7 @@ OptoReg::Name Matcher::warp_incoming_stk_arg( VMReg reg ) {
warped = OptoReg::add(warped, C->out_preserve_stack_slots());
if( warped >= _in_arg_limit )
_in_arg_limit = OptoReg::add(warped, 1); // Bump max stack slot seen
if (!RegMask::can_represent(warped)) {
if (!RegMask::can_represent_arg(warped)) {
// the compiler cannot represent this method's calling sequence
C->record_method_not_compilable_all_tiers("unsupported incoming calling sequence");
return OptoReg::Bad;
@ -302,7 +303,7 @@ void Matcher::match( ) {
_out_arg_limit = OptoReg::add(_new_SP, C->out_preserve_stack_slots());
assert( is_even(_out_arg_limit), "out_preserve must be even" );
if (!RegMask::can_represent(OptoReg::add(_out_arg_limit,-1))) {
if (!RegMask::can_represent_arg(OptoReg::add(_out_arg_limit,-1))) {
// the compiler cannot represent this method's calling sequence
C->record_method_not_compilable("must be able to represent all call arguments in reg mask");
}
@ -428,7 +429,7 @@ static RegMask *init_input_masks( uint size, RegMask &ret_adr, RegMask &fp ) {
void Matcher::init_first_stack_mask() {
// Allocate storage for spill masks as masks for the appropriate load type.
RegMask *rms = (RegMask*)C->comp_arena()->Amalloc_D(sizeof(RegMask) * 3*6);
RegMask *rms = (RegMask*)C->comp_arena()->Amalloc_D(sizeof(RegMask) * (3*6+4));
idealreg2spillmask [Op_RegN] = &rms[0];
idealreg2spillmask [Op_RegI] = &rms[1];
@ -451,6 +452,11 @@ void Matcher::init_first_stack_mask() {
idealreg2mhdebugmask[Op_RegD] = &rms[16];
idealreg2mhdebugmask[Op_RegP] = &rms[17];
idealreg2spillmask [Op_VecS] = &rms[18];
idealreg2spillmask [Op_VecD] = &rms[19];
idealreg2spillmask [Op_VecX] = &rms[20];
idealreg2spillmask [Op_VecY] = &rms[21];
OptoReg::Name i;
// At first, start with the empty mask
@ -462,7 +468,7 @@ void Matcher::init_first_stack_mask() {
C->FIRST_STACK_mask().Insert(i);
// Add in all bits past the outgoing argument area
guarantee(RegMask::can_represent(OptoReg::add(_out_arg_limit,-1)),
guarantee(RegMask::can_represent_arg(OptoReg::add(_out_arg_limit,-1)),
"must be able to represent all call arguments in reg mask");
init = _out_arg_limit;
for (i = init; RegMask::can_represent(i); i = OptoReg::add(i,1))
@ -472,21 +478,48 @@ void Matcher::init_first_stack_mask() {
C->FIRST_STACK_mask().set_AllStack();
// Make spill masks. Registers for their class, plus FIRST_STACK_mask.
RegMask aligned_stack_mask = C->FIRST_STACK_mask();
// Keep spill masks aligned.
aligned_stack_mask.clear_to_pairs();
assert(aligned_stack_mask.is_AllStack(), "should be infinite stack");
*idealreg2spillmask[Op_RegP] = *idealreg2regmask[Op_RegP];
#ifdef _LP64
*idealreg2spillmask[Op_RegN] = *idealreg2regmask[Op_RegN];
idealreg2spillmask[Op_RegN]->OR(C->FIRST_STACK_mask());
idealreg2spillmask[Op_RegP]->OR(aligned_stack_mask);
#else
idealreg2spillmask[Op_RegP]->OR(C->FIRST_STACK_mask());
#endif
*idealreg2spillmask[Op_RegI] = *idealreg2regmask[Op_RegI];
idealreg2spillmask[Op_RegI]->OR(C->FIRST_STACK_mask());
*idealreg2spillmask[Op_RegL] = *idealreg2regmask[Op_RegL];
idealreg2spillmask[Op_RegL]->OR(C->FIRST_STACK_mask());
idealreg2spillmask[Op_RegL]->OR(aligned_stack_mask);
*idealreg2spillmask[Op_RegF] = *idealreg2regmask[Op_RegF];
idealreg2spillmask[Op_RegF]->OR(C->FIRST_STACK_mask());
*idealreg2spillmask[Op_RegD] = *idealreg2regmask[Op_RegD];
idealreg2spillmask[Op_RegD]->OR(C->FIRST_STACK_mask());
*idealreg2spillmask[Op_RegP] = *idealreg2regmask[Op_RegP];
idealreg2spillmask[Op_RegP]->OR(C->FIRST_STACK_mask());
idealreg2spillmask[Op_RegD]->OR(aligned_stack_mask);
if (Matcher::vector_size_supported(T_BYTE,4)) {
*idealreg2spillmask[Op_VecS] = *idealreg2regmask[Op_VecS];
idealreg2spillmask[Op_VecS]->OR(C->FIRST_STACK_mask());
}
if (Matcher::vector_size_supported(T_FLOAT,2)) {
*idealreg2spillmask[Op_VecD] = *idealreg2regmask[Op_VecD];
idealreg2spillmask[Op_VecD]->OR(aligned_stack_mask);
}
if (Matcher::vector_size_supported(T_FLOAT,4)) {
aligned_stack_mask.clear_to_sets(RegMask::SlotsPerVecX);
assert(aligned_stack_mask.is_AllStack(), "should be infinite stack");
*idealreg2spillmask[Op_VecX] = *idealreg2regmask[Op_VecX];
idealreg2spillmask[Op_VecX]->OR(aligned_stack_mask);
}
if (Matcher::vector_size_supported(T_FLOAT,8)) {
aligned_stack_mask.clear_to_sets(RegMask::SlotsPerVecY);
assert(aligned_stack_mask.is_AllStack(), "should be infinite stack");
*idealreg2spillmask[Op_VecY] = *idealreg2regmask[Op_VecY];
idealreg2spillmask[Op_VecY]->OR(aligned_stack_mask);
}
if (UseFPUForSpilling) {
// This mask logic assumes that the spill operations are
// symmetric and that the registers involved are the same size.
@ -807,6 +840,25 @@ void Matcher::init_spill_mask( Node *ret ) {
idealreg2regmask[Op_RegF] = &spillF->out_RegMask();
idealreg2regmask[Op_RegD] = &spillD->out_RegMask();
idealreg2regmask[Op_RegP] = &spillP->out_RegMask();
// Vector regmasks.
if (Matcher::vector_size_supported(T_BYTE,4)) {
TypeVect::VECTS = TypeVect::make(T_BYTE, 4);
MachNode *spillVectS = match_tree(new (C, 3) LoadVectorNode(NULL,mem,fp,atp,TypeVect::VECTS));
idealreg2regmask[Op_VecS] = &spillVectS->out_RegMask();
}
if (Matcher::vector_size_supported(T_FLOAT,2)) {
MachNode *spillVectD = match_tree(new (C, 3) LoadVectorNode(NULL,mem,fp,atp,TypeVect::VECTD));
idealreg2regmask[Op_VecD] = &spillVectD->out_RegMask();
}
if (Matcher::vector_size_supported(T_FLOAT,4)) {
MachNode *spillVectX = match_tree(new (C, 3) LoadVectorNode(NULL,mem,fp,atp,TypeVect::VECTX));
idealreg2regmask[Op_VecX] = &spillVectX->out_RegMask();
}
if (Matcher::vector_size_supported(T_FLOAT,8)) {
MachNode *spillVectY = match_tree(new (C, 3) LoadVectorNode(NULL,mem,fp,atp,TypeVect::VECTY));
idealreg2regmask[Op_VecY] = &spillVectY->out_RegMask();
}
}
#ifdef ASSERT
@ -1063,7 +1115,7 @@ OptoReg::Name Matcher::warp_outgoing_stk_arg( VMReg reg, OptoReg::Name begin_out
// that is killed by the call.
if( warped >= out_arg_limit_per_call )
out_arg_limit_per_call = OptoReg::add(warped,1);
if (!RegMask::can_represent(warped)) {
if (!RegMask::can_represent_arg(warped)) {
C->record_method_not_compilable_all_tiers("unsupported calling sequence");
return OptoReg::Bad;
}
@ -1251,7 +1303,7 @@ MachNode *Matcher::match_sfpt( SafePointNode *sfpt ) {
// this killed area.
uint r_cnt = mcall->tf()->range()->cnt();
MachProjNode *proj = new (C, 1) MachProjNode( mcall, r_cnt+10000, RegMask::Empty, MachProjNode::fat_proj );
if (!RegMask::can_represent(OptoReg::Name(out_arg_limit_per_call-1))) {
if (!RegMask::can_represent_arg(OptoReg::Name(out_arg_limit_per_call-1))) {
C->record_method_not_compilable_all_tiers("unsupported outgoing calling sequence");
} else {
for (int i = begin_out_arg_area; i < out_arg_limit_per_call; i++)

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -250,10 +250,21 @@ public:
static const bool convL2FSupported(void);
// Vector width in bytes
static const uint vector_width_in_bytes(void);
static const int vector_width_in_bytes(BasicType bt);
// Limits on vector size (number of elements).
static const int max_vector_size(const BasicType bt);
static const int min_vector_size(const BasicType bt);
static const bool vector_size_supported(const BasicType bt, int size) {
return (Matcher::max_vector_size(bt) >= size &&
Matcher::min_vector_size(bt) <= size);
}
// Vector ideal reg
static const uint vector_ideal_reg(void);
static const int vector_ideal_reg(int len);
// CPU supports misaligned vectors store/load.
static const bool misaligned_vectors_ok();
// Used to determine a "low complexity" 64-bit constant. (Zero is simple.)
// The standard of comparison is one (StoreL ConL) vs. two (StoreI ConI).

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1543,6 +1543,7 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const {
// had an original form like p1:(AddP x x (LShiftL quux 3)), where the
// expression (LShiftL quux 3) independently optimized to the constant 8.
if ((t->isa_int() == NULL) && (t->isa_long() == NULL)
&& (_type->isa_vect() == NULL)
&& Opcode() != Op_LoadKlass && Opcode() != Op_LoadNKlass) {
// t might actually be lower than _type, if _type is a unique
// concrete subclass of abstract class t.

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -41,7 +41,9 @@ class PhaseTransform;
class MulNode : public Node {
virtual uint hash() const;
public:
MulNode( Node *in1, Node *in2 ): Node(0,in1,in2) {}
MulNode( Node *in1, Node *in2 ): Node(0,in1,in2) {
init_class_id(Class_Mul);
}
// Handle algebraic identities here. If we have an identity, return the Node
// we are equivalent to. We look for "add of zero" as an identity.

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1576,6 +1576,9 @@ void Node::dump() const {
} else {
tty->print("no type");
}
} else if (t->isa_vect() && this->is_MachSpillCopy()) {
// Dump MachSpillcopy vector type.
t->dump();
}
if (is_new) {
debug_only(dump_orig(debug_orig()));

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

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -38,6 +38,10 @@ const char *NodeClassNames[] = {
"RegD",
"RegL",
"RegFlags",
"VecS",
"VecD",
"VecX",
"VecY",
"_last_machine_leaf",
#include "classes.hpp"
"_last_class_name",

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -36,6 +36,10 @@ enum Opcodes {
macro(RegF) // Machine float register
macro(RegD) // Machine double register
macro(RegL) // Machine long register
macro(VecS) // Machine vectors register
macro(VecD) // Machine vectord register
macro(VecX) // Machine vectorx register
macro(VecY) // Machine vectory register
macro(RegFlags) // Machine flags register
_last_machine_leaf, // Split between regular opcodes and machine
#include "classes.hpp"

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

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -74,12 +74,13 @@ Node *PhaseChaitin::get_spillcopy_wide( Node *def, Node *use, uint uidx ) {
const RegMask *w_i_mask = w_mask->overlap( *i_mask ) ? w_mask : i_mask;
const RegMask *w_o_mask;
int num_regs = RegMask::num_registers(ireg);
bool is_vect = RegMask::is_vector(ireg);
if( w_mask->overlap( *o_mask ) && // Overlap AND
((ireg != Op_RegL && ireg != Op_RegD // Single use or aligned
#ifdef _LP64
&& ireg != Op_RegP
#endif
) || o_mask->is_aligned_Pairs()) ) {
((num_regs == 1) // Single use or aligned
|| is_vect // or vector
|| !is_vect && o_mask->is_aligned_pairs()) ) {
assert(!is_vect || o_mask->is_aligned_sets(num_regs), "vectors are aligned");
// Don't come here for mis-aligned doubles
w_o_mask = w_mask;
} else { // wide ideal mask does not overlap with o_mask
@ -400,15 +401,17 @@ bool PhaseChaitin::is_high_pressure( Block *b, LRG *lrg, uint insidx ) {
// CNC - Turned off 7/8/99, causes too much spilling
// if( lrg->_is_bound ) return false;
// Use float pressure numbers for vectors.
bool is_float_or_vector = lrg->_is_float || lrg->_is_vector;
// Not yet reached the high-pressure cutoff point, so low pressure
uint hrp_idx = lrg->_is_float ? b->_fhrp_index : b->_ihrp_index;
uint hrp_idx = is_float_or_vector ? b->_fhrp_index : b->_ihrp_index;
if( insidx < hrp_idx ) return false;
// Register pressure for the block as a whole depends on reg class
int block_pres = lrg->_is_float ? b->_freg_pressure : b->_reg_pressure;
int block_pres = is_float_or_vector ? b->_freg_pressure : b->_reg_pressure;
// Bound live ranges will split at the binding points first;
// Intermediate splits should assume the live range's register set
// got "freed up" and that num_regs will become INT_PRESSURE.
int bound_pres = lrg->_is_float ? FLOATPRESSURE : INTPRESSURE;
int bound_pres = is_float_or_vector ? FLOATPRESSURE : INTPRESSURE;
// Effective register pressure limit.
int lrg_pres = (lrg->get_invalid_mask_size() > lrg->num_regs())
? (lrg->get_invalid_mask_size() >> (lrg->num_regs()-1)) : bound_pres;
@ -794,12 +797,15 @@ uint PhaseChaitin::Split( uint maxlrg ) {
if( i < n->req() ) break;
insert_point--;
}
uint orig_eidx = b->end_idx();
maxlrg = split_DEF( n1, b, insert_point, maxlrg, Reachblock, debug_defs, splits, slidx);
// If it wasn't split bail
if (!maxlrg) {
return 0;
}
insidx++;
// Spill of NULL check mem op goes into the following block.
if (b->end_idx() > orig_eidx)
insidx++;
}
// This is a new DEF, so update UP
UPblock[slidx] = false;
@ -960,7 +966,7 @@ uint PhaseChaitin::Split( uint maxlrg ) {
// Grab register mask info
const RegMask &dmask = def->out_RegMask();
const RegMask &umask = n->in_RegMask(inpidx);
bool is_vect = RegMask::is_vector(def->ideal_reg());
assert(inpidx < oopoff, "cannot use-split oop map info");
bool dup = UPblock[slidx];
@ -972,7 +978,7 @@ uint PhaseChaitin::Split( uint maxlrg ) {
if( !umask.is_AllStack() &&
(int)umask.Size() <= lrgs(useidx).num_regs() &&
(!def->rematerialize() ||
umask.is_misaligned_Pair())) {
!is_vect && umask.is_misaligned_pair())) {
// These need a Split regardless of overlap or pressure
// SPLIT - NO DEF - NO CISC SPILL
maxlrg = split_USE(def,b,n,inpidx,maxlrg,dup,false, splits,slidx);
@ -1123,10 +1129,12 @@ uint PhaseChaitin::Split( uint maxlrg ) {
// Grab UP info for DEF
const RegMask &dmask = n->out_RegMask();
bool defup = dmask.is_UP();
int ireg = n->ideal_reg();
bool is_vect = RegMask::is_vector(ireg);
// Only split at Def if this is a HRP block or bound (and spilled once)
if( !n->rematerialize() &&
(((dmask.is_bound1() || dmask.is_bound2() || dmask.is_misaligned_Pair()) &&
(deflrg._direct_conflict || deflrg._must_spill)) ||
(((dmask.is_bound(ireg) || !is_vect && dmask.is_misaligned_pair()) &&
(deflrg._direct_conflict || deflrg._must_spill)) ||
// Check for LRG being up in a register and we are inside a high
// pressure area. Spill it down immediately.
(defup && is_high_pressure(b,&deflrg,insidx))) ) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -129,11 +129,34 @@ const RegMask RegMask::Empty(
0
);
//=============================================================================
bool RegMask::is_vector(uint ireg) {
return (ireg == Op_VecS || ireg == Op_VecD || ireg == Op_VecX || ireg == Op_VecY);
}
int RegMask::num_registers(uint ireg) {
switch(ireg) {
case Op_VecY:
return 8;
case Op_VecX:
return 4;
case Op_VecD:
case Op_RegD:
case Op_RegL:
#ifdef _LP64
case Op_RegP:
#endif
return 2;
}
// Op_VecS and the rest ideal registers.
return 1;
}
//------------------------------find_first_pair--------------------------------
// Find the lowest-numbered register pair in the mask. Return the
// HIGHEST register number in the pair, or BAD if no pairs.
OptoReg::Name RegMask::find_first_pair() const {
VerifyPairs();
verify_pairs();
for( int i = 0; i < RM_SIZE; i++ ) {
if( _A[i] ) { // Found some bits
int bit = _A[i] & -_A[i]; // Extract low bit
@ -146,30 +169,30 @@ OptoReg::Name RegMask::find_first_pair() const {
//------------------------------ClearToPairs-----------------------------------
// Clear out partial bits; leave only bit pairs
void RegMask::ClearToPairs() {
void RegMask::clear_to_pairs() {
for( int i = 0; i < RM_SIZE; i++ ) {
int bits = _A[i];
bits &= ((bits & 0x55555555)<<1); // 1 hi-bit set for each pair
bits |= (bits>>1); // Smear 1 hi-bit into a pair
_A[i] = bits;
}
VerifyPairs();
verify_pairs();
}
//------------------------------SmearToPairs-----------------------------------
// Smear out partial bits; leave only bit pairs
void RegMask::SmearToPairs() {
void RegMask::smear_to_pairs() {
for( int i = 0; i < RM_SIZE; i++ ) {
int bits = _A[i];
bits |= ((bits & 0x55555555)<<1); // Smear lo bit hi per pair
bits |= ((bits & 0xAAAAAAAA)>>1); // Smear hi bit lo per pair
_A[i] = bits;
}
VerifyPairs();
verify_pairs();
}
//------------------------------is_aligned_pairs-------------------------------
bool RegMask::is_aligned_Pairs() const {
bool RegMask::is_aligned_pairs() const {
// Assert that the register mask contains only bit pairs.
for( int i = 0; i < RM_SIZE; i++ ) {
int bits = _A[i];
@ -204,7 +227,7 @@ int RegMask::is_bound1() const {
//------------------------------is_bound2--------------------------------------
// Return TRUE if the mask contains an adjacent pair of bits and no other bits.
int RegMask::is_bound2() const {
int RegMask::is_bound_pair() const {
if( is_AllStack() ) return false;
int bit = -1; // Set to hold the one bit allowed
@ -226,6 +249,132 @@ int RegMask::is_bound2() const {
return true;
}
static int low_bits[3] = { 0x55555555, 0x11111111, 0x01010101 };
//------------------------------find_first_set---------------------------------
// Find the lowest-numbered register set in the mask. Return the
// HIGHEST register number in the set, or BAD if no sets.
// Works also for size 1.
OptoReg::Name RegMask::find_first_set(int size) const {
verify_sets(size);
for (int i = 0; i < RM_SIZE; i++) {
if (_A[i]) { // Found some bits
int bit = _A[i] & -_A[i]; // Extract low bit
// Convert to bit number, return hi bit in pair
return OptoReg::Name((i<<_LogWordBits)+find_lowest_bit(bit)+(size-1));
}
}
return OptoReg::Bad;
}
//------------------------------clear_to_sets----------------------------------
// Clear out partial bits; leave only aligned adjacent bit pairs
void RegMask::clear_to_sets(int size) {
if (size == 1) return;
assert(2 <= size && size <= 8, "update low bits table");
assert(is_power_of_2(size), "sanity");
int low_bits_mask = low_bits[size>>2];
for (int i = 0; i < RM_SIZE; i++) {
int bits = _A[i];
int sets = (bits & low_bits_mask);
for (int j = 1; j < size; j++) {
sets = (bits & (sets<<1)); // filter bits which produce whole sets
}
sets |= (sets>>1); // Smear 1 hi-bit into a set
if (size > 2) {
sets |= (sets>>2); // Smear 2 hi-bits into a set
if (size > 4) {
sets |= (sets>>4); // Smear 4 hi-bits into a set
}
}
_A[i] = sets;
}
verify_sets(size);
}
//------------------------------smear_to_sets----------------------------------
// Smear out partial bits to aligned adjacent bit sets
void RegMask::smear_to_sets(int size) {
if (size == 1) return;
assert(2 <= size && size <= 8, "update low bits table");
assert(is_power_of_2(size), "sanity");
int low_bits_mask = low_bits[size>>2];
for (int i = 0; i < RM_SIZE; i++) {
int bits = _A[i];
int sets = 0;
for (int j = 0; j < size; j++) {
sets |= (bits & low_bits_mask); // collect partial bits
bits = bits>>1;
}
sets |= (sets<<1); // Smear 1 lo-bit into a set
if (size > 2) {
sets |= (sets<<2); // Smear 2 lo-bits into a set
if (size > 4) {
sets |= (sets<<4); // Smear 4 lo-bits into a set
}
}
_A[i] = sets;
}
verify_sets(size);
}
//------------------------------is_aligned_set--------------------------------
bool RegMask::is_aligned_sets(int size) const {
if (size == 1) return true;
assert(2 <= size && size <= 8, "update low bits table");
assert(is_power_of_2(size), "sanity");
int low_bits_mask = low_bits[size>>2];
// Assert that the register mask contains only bit sets.
for (int i = 0; i < RM_SIZE; i++) {
int bits = _A[i];
while (bits) { // Check bits for pairing
int bit = bits & -bits; // Extract low bit
// Low bit is not odd means its mis-aligned.
if ((bit & low_bits_mask) == 0) return false;
// Do extra work since (bit << size) may overflow.
int hi_bit = bit << (size-1); // high bit
int set = hi_bit + ((hi_bit-1) & ~(bit-1));
// Check for aligned adjacent bits in this set
if ((bits & set) != set) return false;
bits -= set; // Remove this set
}
}
return true;
}
//------------------------------is_bound_set-----------------------------------
// Return TRUE if the mask contains one adjacent set of bits and no other bits.
// Works also for size 1.
int RegMask::is_bound_set(int size) const {
if( is_AllStack() ) return false;
assert(1 <= size && size <= 8, "update low bits table");
int bit = -1; // Set to hold the one bit allowed
for (int i = 0; i < RM_SIZE; i++) {
if (_A[i] ) { // Found some bits
if (bit != -1)
return false; // Already had bits, so fail
bit = _A[i] & -_A[i]; // Extract 1 bit from mask
int hi_bit = bit << (size-1); // high bit
if (hi_bit != 0) { // Bit set stays in same word?
int set = hi_bit + ((hi_bit-1) & ~(bit-1));
if (set != _A[i])
return false; // Require adjacent bit set and no more bits
} else { // Else its a split-set case
if (((-1) & ~(bit-1)) != _A[i])
return false; // Found many bits, so fail
i++; // Skip iteration forward and check high part
assert(size <= 8, "update next code");
// The lower 24 bits should be 0 since it is split case and size <= 8.
int set = bit>>24;
set = set & -set; // Remove sign extension.
set = (((set << size) - 1) >> 8);
if (_A[i] != set) return false; // Require 1 lo bit in next word
}
}
}
// True for both the empty mask and for a bit set
return true;
}
//------------------------------is_UP------------------------------------------
// UP means register only, Register plus stack, or stack only is DOWN
bool RegMask::is_UP() const {

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -113,7 +113,11 @@ public:
// the controlling alignment constraint. Note that this alignment
// requirement is internal to the allocator, and independent of any
// particular platform.
enum { SlotsPerLong = 2 };
enum { SlotsPerLong = 2,
SlotsPerVecS = 1,
SlotsPerVecD = 2,
SlotsPerVecX = 4,
SlotsPerVecY = 8 };
// A constructor only used by the ADLC output. All mask fields are filled
// in directly. Calls to this look something like RM(1,2,3,4);
@ -193,20 +197,53 @@ public:
OptoReg::Name find_first_pair() const;
// Clear out partial bits; leave only aligned adjacent bit pairs.
void ClearToPairs();
void clear_to_pairs();
// Smear out partial bits; leave only aligned adjacent bit pairs.
void SmearToPairs();
void smear_to_pairs();
// Verify that the mask contains only aligned adjacent bit pairs
void VerifyPairs() const { assert( is_aligned_Pairs(), "mask is not aligned, adjacent pairs" ); }
void verify_pairs() const { assert( is_aligned_pairs(), "mask is not aligned, adjacent pairs" ); }
// Test that the mask contains only aligned adjacent bit pairs
bool is_aligned_Pairs() const;
bool is_aligned_pairs() const;
// mask is a pair of misaligned registers
bool is_misaligned_Pair() const { return Size()==2 && !is_aligned_Pairs();}
bool is_misaligned_pair() const { return Size()==2 && !is_aligned_pairs(); }
// Test for single register
int is_bound1() const;
// Test for a single adjacent pair
int is_bound2() const;
int is_bound_pair() const;
// Test for a single adjacent set of ideal register's size.
int is_bound(uint ireg) const {
if (is_vector(ireg)) {
if (is_bound_set(num_registers(ireg)))
return true;
} else if (is_bound1() || is_bound_pair()) {
return true;
}
return false;
}
// Find the lowest-numbered register set in the mask. Return the
// HIGHEST register number in the set, or BAD if no sets.
// Assert that the mask contains only bit sets.
OptoReg::Name find_first_set(int size) const;
// Clear out partial bits; leave only aligned adjacent bit sets of size.
void clear_to_sets(int size);
// Smear out partial bits to aligned adjacent bit sets.
void smear_to_sets(int size);
// Verify that the mask contains only aligned adjacent bit sets
void verify_sets(int size) const { assert(is_aligned_sets(size), "mask is not aligned, adjacent sets"); }
// Test that the mask contains only aligned adjacent bit sets
bool is_aligned_sets(int size) const;
// mask is a set of misaligned registers
bool is_misaligned_set(int size) const { return (int)Size()==size && !is_aligned_sets(size);}
// Test for a single adjacent set
int is_bound_set(int size) const;
static bool is_vector(uint ireg);
static int num_registers(uint ireg);
// Fast overlap test. Non-zero if any registers in common.
int overlap( const RegMask &rm ) const {
@ -280,9 +317,15 @@ public:
static bool can_represent(OptoReg::Name reg) {
// NOTE: -1 in computation reflects the usage of the last
// bit of the regmask as an infinite stack flag.
// bit of the regmask as an infinite stack flag and
// -7 is to keep mask aligned for largest value (VecY).
return (int)reg < (int)(CHUNK_SIZE-1);
}
static bool can_represent_arg(OptoReg::Name reg) {
// NOTE: -SlotsPerVecY in computation reflects the need
// to keep mask aligned for largest value (VecY).
return (int)reg < (int)(CHUNK_SIZE-SlotsPerVecY);
}
};
// Do not use this constant directly in client code!

@ -112,6 +112,7 @@ class StringConcat : public ResourceObj {
_arguments->ins_req(0, value);
_mode.insert_before(0, mode);
}
void push_string(Node* value) {
push(value, StringMode);
}
@ -125,9 +126,56 @@ class StringConcat : public ResourceObj {
push(value, CharMode);
}
static bool is_SB_toString(Node* call) {
if (call->is_CallStaticJava()) {
CallStaticJavaNode* csj = call->as_CallStaticJava();
ciMethod* m = csj->method();
if (m != NULL &&
(m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString ||
m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString)) {
return true;
}
}
return false;
}
static Node* skip_string_null_check(Node* value) {
// Look for a diamond shaped Null check of toString() result
// (could be code from String.valueOf()):
// (Proj == NULL) ? "null":"CastPP(Proj)#NotNULL
if (value->is_Phi()) {
int true_path = value->as_Phi()->is_diamond_phi();
if (true_path != 0) {
// phi->region->if_proj->ifnode->bool
BoolNode* b = value->in(0)->in(1)->in(0)->in(1)->as_Bool();
Node* cmp = b->in(1);
Node* v1 = cmp->in(1);
Node* v2 = cmp->in(2);
// Null check of the return of toString which can simply be skipped.
if (b->_test._test == BoolTest::ne &&
v2->bottom_type() == TypePtr::NULL_PTR &&
value->in(true_path)->Opcode() == Op_CastPP &&
value->in(true_path)->in(1) == v1 &&
v1->is_Proj() && is_SB_toString(v1->in(0))) {
return v1;
}
}
}
return value;
}
Node* argument(int i) {
return _arguments->in(i);
}
Node* argument_uncast(int i) {
Node* arg = argument(i);
int amode = mode(i);
if (amode == StringConcat::StringMode ||
amode == StringConcat::StringNullCheckMode) {
arg = skip_string_null_check(arg);
}
return arg;
}
void set_argument(int i, Node* value) {
_arguments->set_req(i, value);
}
@ -206,9 +254,11 @@ class StringConcat : public ResourceObj {
void StringConcat::eliminate_unneeded_control() {
eliminate_initialize(begin()->initialization());
for (uint i = 0; i < _control.size(); i++) {
Node* n = _control.at(i);
if (n->is_Allocate()) {
eliminate_initialize(n->as_Allocate()->initialization());
}
if (n->is_Call()) {
if (n != _end) {
eliminate_call(n->as_Call());
@ -239,14 +289,15 @@ StringConcat* StringConcat::merge(StringConcat* other, Node* arg) {
assert(result->_control.contains(other->_end), "what?");
assert(result->_control.contains(_begin), "what?");
for (int x = 0; x < num_arguments(); x++) {
if (argument(x) == arg) {
Node* argx = argument_uncast(x);
if (argx == arg) {
// replace the toString result with the all the arguments that
// made up the other StringConcat
for (int y = 0; y < other->num_arguments(); y++) {
result->append(other->argument(y), other->mode(y));
}
} else {
result->append(argument(x), mode(x));
result->append(argx, mode(x));
}
}
result->set_allocation(other->_begin);
@ -327,14 +378,9 @@ Node_List PhaseStringOpts::collect_toString_calls() {
while (worklist.size() > 0) {
Node* ctrl = worklist.pop();
if (ctrl->is_CallStaticJava()) {
if (StringConcat::is_SB_toString(ctrl)) {
CallStaticJavaNode* csj = ctrl->as_CallStaticJava();
ciMethod* m = csj->method();
if (m != NULL &&
(m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString ||
m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString)) {
string_calls.push(csj);
}
string_calls.push(csj);
}
if (ctrl->in(0) != NULL && !_visited.test_set(ctrl->in(0)->_idx)) {
worklist.push(ctrl->in(0));
@ -550,44 +596,40 @@ PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List*):
for (int c = 0; c < concats.length(); c++) {
StringConcat* sc = concats.at(c);
for (int i = 0; i < sc->num_arguments(); i++) {
Node* arg = sc->argument(i);
if (arg->is_Proj() && arg->in(0)->is_CallStaticJava()) {
Node* arg = sc->argument_uncast(i);
if (arg->is_Proj() && StringConcat::is_SB_toString(arg->in(0))) {
CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava();
if (csj->method() != NULL &&
(csj->method()->intrinsic_id() == vmIntrinsics::_StringBuilder_toString ||
csj->method()->intrinsic_id() == vmIntrinsics::_StringBuffer_toString)) {
for (int o = 0; o < concats.length(); o++) {
if (c == o) continue;
StringConcat* other = concats.at(o);
if (other->end() == csj) {
for (int o = 0; o < concats.length(); o++) {
if (c == o) continue;
StringConcat* other = concats.at(o);
if (other->end() == csj) {
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
tty->print_cr("considering stacked concats");
}
if (PrintOptimizeStringConcat) {
tty->print_cr("considering stacked concats");
}
#endif
StringConcat* merged = sc->merge(other, arg);
if (merged->validate_control_flow()) {
StringConcat* merged = sc->merge(other, arg);
if (merged->validate_control_flow()) {
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
tty->print_cr("stacking would succeed");
}
#endif
if (c < o) {
concats.remove_at(o);
concats.at_put(c, merged);
} else {
concats.remove_at(c);
concats.at_put(o, merged);
}
goto restart;
} else {
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
tty->print_cr("stacking would fail");
}
#endif
if (PrintOptimizeStringConcat) {
tty->print_cr("stacking would succeed");
}
#endif
if (c < o) {
concats.remove_at(o);
concats.at_put(c, merged);
} else {
concats.remove_at(c);
concats.at_put(o, merged);
}
goto restart;
} else {
#ifndef PRODUCT
if (PrintOptimizeStringConcat) {
tty->print_cr("stacking would fail");
}
#endif
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -67,6 +67,10 @@ SuperWord::SuperWord(PhaseIdealLoop* phase) :
//------------------------------transform_loop---------------------------
void SuperWord::transform_loop(IdealLoopTree* lpt) {
assert(UseSuperWord, "should be");
// Do vectors exist on this architecture?
if (Matcher::vector_width_in_bytes(T_BYTE) < 2) return;
assert(lpt->_head->is_CountedLoop(), "must be");
CountedLoopNode *cl = lpt->_head->as_CountedLoop();
@ -89,15 +93,12 @@ void SuperWord::transform_loop(IdealLoopTree* lpt) {
Node *pre_opaq1 = pre_end->limit();
if (pre_opaq1->Opcode() != Op_Opaque1) return;
// Do vectors exist on this architecture?
if (vector_width_in_bytes() == 0) return;
init(); // initialize data structures
set_lpt(lpt);
set_lp(cl);
// For now, define one block which is the entire loop body
// For now, define one block which is the entire loop body
set_bb(cl);
assert(_packset.length() == 0, "packset must be empty");
@ -177,7 +178,7 @@ void SuperWord::find_adjacent_refs() {
Node_List memops;
for (int i = 0; i < _block.length(); i++) {
Node* n = _block.at(i);
if (n->is_Mem() && in_bb(n) &&
if (n->is_Mem() && !n->is_LoadStore() && in_bb(n) &&
is_java_primitive(n->as_Mem()->memory_type())) {
int align = memory_alignment(n->as_Mem(), 0);
if (align != bottom_align) {
@ -185,54 +186,141 @@ void SuperWord::find_adjacent_refs() {
}
}
}
if (memops.size() == 0) return;
// Find a memory reference to align to. The pre-loop trip count
// is modified to align this reference to a vector-aligned address
find_align_to_ref(memops);
if (align_to_ref() == NULL) return;
Node_List align_to_refs;
int best_iv_adjustment = 0;
MemNode* best_align_to_mem_ref = NULL;
SWPointer align_to_ref_p(align_to_ref(), this);
int offset = align_to_ref_p.offset_in_bytes();
int scale = align_to_ref_p.scale_in_bytes();
int vw = vector_width_in_bytes();
int stride_sign = (scale * iv_stride()) > 0 ? 1 : -1;
int iv_adjustment = (stride_sign * vw - (offset % vw)) % vw;
while (memops.size() != 0) {
// Find a memory reference to align to.
MemNode* mem_ref = find_align_to_ref(memops);
if (mem_ref == NULL) break;
align_to_refs.push(mem_ref);
int iv_adjustment = get_iv_adjustment(mem_ref);
#ifndef PRODUCT
if (TraceSuperWord)
tty->print_cr("\noffset = %d iv_adjustment = %d elt_align = %d scale = %d iv_stride = %d",
offset, iv_adjustment, align_to_ref_p.memory_size(), align_to_ref_p.scale_in_bytes(), iv_stride());
#endif
// Set alignment relative to "align_to_ref"
for (int i = memops.size() - 1; i >= 0; i--) {
MemNode* s = memops.at(i)->as_Mem();
SWPointer p2(s, this);
if (p2.comparable(align_to_ref_p)) {
int align = memory_alignment(s, iv_adjustment);
set_alignment(s, align);
} else {
memops.remove(i);
if (best_align_to_mem_ref == NULL) {
// Set memory reference which is the best from all memory operations
// to be used for alignment. The pre-loop trip count is modified to align
// this reference to a vector-aligned address.
best_align_to_mem_ref = mem_ref;
best_iv_adjustment = iv_adjustment;
}
}
// Create initial pack pairs of memory operations
for (uint i = 0; i < memops.size(); i++) {
Node* s1 = memops.at(i);
for (uint j = 0; j < memops.size(); j++) {
Node* s2 = memops.at(j);
if (s1 != s2 && are_adjacent_refs(s1, s2)) {
int align = alignment(s1);
if (stmts_can_pack(s1, s2, align)) {
Node_List* pair = new Node_List();
pair->push(s1);
pair->push(s2);
_packset.append(pair);
SWPointer align_to_ref_p(mem_ref, this);
// Set alignment relative to "align_to_ref" for all related memory operations.
for (int i = memops.size() - 1; i >= 0; i--) {
MemNode* s = memops.at(i)->as_Mem();
if (isomorphic(s, mem_ref)) {
SWPointer p2(s, this);
if (p2.comparable(align_to_ref_p)) {
int align = memory_alignment(s, iv_adjustment);
set_alignment(s, align);
}
}
}
}
// Create initial pack pairs of memory operations for which
// alignment is set and vectors will be aligned.
bool create_pack = true;
if (memory_alignment(mem_ref, best_iv_adjustment) == 0) {
if (!Matcher::misaligned_vectors_ok()) {
int vw = vector_width(mem_ref);
int vw_best = vector_width(best_align_to_mem_ref);
if (vw > vw_best) {
// Do not vectorize a memory access with more elements per vector
// if unaligned memory access is not allowed because number of
// iterations in pre-loop will be not enough to align it.
create_pack = false;
}
}
} else {
if (same_velt_type(mem_ref, best_align_to_mem_ref)) {
// Can't allow vectorization of unaligned memory accesses with the
// same type since it could be overlapped accesses to the same array.
create_pack = false;
} else {
// Allow independent (different type) unaligned memory operations
// if HW supports them.
if (!Matcher::misaligned_vectors_ok()) {
create_pack = false;
} else {
// Check if packs of the same memory type but
// with a different alignment were created before.
for (uint i = 0; i < align_to_refs.size(); i++) {
MemNode* mr = align_to_refs.at(i)->as_Mem();
if (same_velt_type(mr, mem_ref) &&
memory_alignment(mr, iv_adjustment) != 0)
create_pack = false;
}
}
}
}
if (create_pack) {
for (uint i = 0; i < memops.size(); i++) {
Node* s1 = memops.at(i);
int align = alignment(s1);
if (align == top_align) continue;
for (uint j = 0; j < memops.size(); j++) {
Node* s2 = memops.at(j);
if (alignment(s2) == top_align) continue;
if (s1 != s2 && are_adjacent_refs(s1, s2)) {
if (stmts_can_pack(s1, s2, align)) {
Node_List* pair = new Node_List();
pair->push(s1);
pair->push(s2);
_packset.append(pair);
}
}
}
}
} else { // Don't create unaligned pack
// First, remove remaining memory ops of the same type from the list.
for (int i = memops.size() - 1; i >= 0; i--) {
MemNode* s = memops.at(i)->as_Mem();
if (same_velt_type(s, mem_ref)) {
memops.remove(i);
}
}
// Second, remove already constructed packs of the same type.
for (int i = _packset.length() - 1; i >= 0; i--) {
Node_List* p = _packset.at(i);
MemNode* s = p->at(0)->as_Mem();
if (same_velt_type(s, mem_ref)) {
remove_pack_at(i);
}
}
// If needed find the best memory reference for loop alignment again.
if (same_velt_type(mem_ref, best_align_to_mem_ref)) {
// Put memory ops from remaining packs back on memops list for
// the best alignment search.
uint orig_msize = memops.size();
for (int i = 0; i < _packset.length(); i++) {
Node_List* p = _packset.at(i);
MemNode* s = p->at(0)->as_Mem();
assert(!same_velt_type(s, mem_ref), "sanity");
memops.push(s);
}
MemNode* best_align_to_mem_ref = find_align_to_ref(memops);
if (best_align_to_mem_ref == NULL) break;
best_iv_adjustment = get_iv_adjustment(best_align_to_mem_ref);
// Restore list.
while (memops.size() > orig_msize)
(void)memops.pop();
}
} // unaligned memory accesses
// Remove used mem nodes.
for (int i = memops.size() - 1; i >= 0; i--) {
MemNode* m = memops.at(i)->as_Mem();
if (alignment(m) != top_align) {
memops.remove(i);
}
}
} // while (memops.size() != 0
set_align_to_ref(best_align_to_mem_ref);
#ifndef PRODUCT
if (TraceSuperWord) {
@ -246,7 +334,7 @@ void SuperWord::find_adjacent_refs() {
// Find a memory reference to align the loop induction variable to.
// Looks first at stores then at loads, looking for a memory reference
// with the largest number of references similar to it.
void SuperWord::find_align_to_ref(Node_List &memops) {
MemNode* SuperWord::find_align_to_ref(Node_List &memops) {
GrowableArray<int> cmp_ct(arena(), memops.size(), memops.size(), 0);
// Count number of comparable memory ops
@ -270,20 +358,28 @@ void SuperWord::find_align_to_ref(Node_List &memops) {
}
}
// Find Store (or Load) with the greatest number of "comparable" references
// Find Store (or Load) with the greatest number of "comparable" references,
// biggest vector size, smallest data size and smallest iv offset.
int max_ct = 0;
int max_vw = 0;
int max_idx = -1;
int min_size = max_jint;
int min_iv_offset = max_jint;
for (uint j = 0; j < memops.size(); j++) {
MemNode* s = memops.at(j)->as_Mem();
if (s->is_Store()) {
int vw = vector_width_in_bytes(s);
assert(vw > 1, "sanity");
SWPointer p(s, this);
if (cmp_ct.at(j) > max_ct ||
cmp_ct.at(j) == max_ct && (data_size(s) < min_size ||
data_size(s) == min_size &&
p.offset_in_bytes() < min_iv_offset)) {
if (cmp_ct.at(j) > max_ct ||
cmp_ct.at(j) == max_ct &&
(vw > max_vw ||
vw == max_vw &&
(data_size(s) < min_size ||
data_size(s) == min_size &&
(p.offset_in_bytes() < min_iv_offset)))) {
max_ct = cmp_ct.at(j);
max_vw = vw;
max_idx = j;
min_size = data_size(s);
min_iv_offset = p.offset_in_bytes();
@ -295,12 +391,18 @@ void SuperWord::find_align_to_ref(Node_List &memops) {
for (uint j = 0; j < memops.size(); j++) {
MemNode* s = memops.at(j)->as_Mem();
if (s->is_Load()) {
int vw = vector_width_in_bytes(s);
assert(vw > 1, "sanity");
SWPointer p(s, this);
if (cmp_ct.at(j) > max_ct ||
cmp_ct.at(j) == max_ct && (data_size(s) < min_size ||
data_size(s) == min_size &&
p.offset_in_bytes() < min_iv_offset)) {
if (cmp_ct.at(j) > max_ct ||
cmp_ct.at(j) == max_ct &&
(vw > max_vw ||
vw == max_vw &&
(data_size(s) < min_size ||
data_size(s) == min_size &&
(p.offset_in_bytes() < min_iv_offset)))) {
max_ct = cmp_ct.at(j);
max_vw = vw;
max_idx = j;
min_size = data_size(s);
min_iv_offset = p.offset_in_bytes();
@ -309,10 +411,7 @@ void SuperWord::find_align_to_ref(Node_List &memops) {
}
}
if (max_ct > 0)
set_align_to_ref(memops.at(max_idx)->as_Mem());
#ifndef PRODUCT
#ifdef ASSERT
if (TraceSuperWord && Verbose) {
tty->print_cr("\nVector memops after find_align_to_refs");
for (uint i = 0; i < memops.size(); i++) {
@ -321,6 +420,17 @@ void SuperWord::find_align_to_ref(Node_List &memops) {
}
}
#endif
if (max_ct > 0) {
#ifdef ASSERT
if (TraceSuperWord) {
tty->print("\nVector align to node: ");
memops.at(max_idx)->as_Mem()->dump();
}
#endif
return memops.at(max_idx)->as_Mem();
}
return NULL;
}
//------------------------------ref_is_alignable---------------------------
@ -341,7 +451,8 @@ bool SuperWord::ref_is_alignable(SWPointer& p) {
// If initial offset from start of object is computable,
// compute alignment within the vector.
int vw = vector_width_in_bytes();
int vw = vector_width_in_bytes(p.mem());
assert(vw > 1, "sanity");
if (vw % span == 0) {
Node* init_nd = pre_end->init_trip();
if (init_nd->is_Con() && p.invar() == NULL) {
@ -361,6 +472,25 @@ bool SuperWord::ref_is_alignable(SWPointer& p) {
return false;
}
//---------------------------get_iv_adjustment---------------------------
// Calculate loop's iv adjustment for this memory ops.
int SuperWord::get_iv_adjustment(MemNode* mem_ref) {
SWPointer align_to_ref_p(mem_ref, this);
int offset = align_to_ref_p.offset_in_bytes();
int scale = align_to_ref_p.scale_in_bytes();
int vw = vector_width_in_bytes(mem_ref);
assert(vw > 1, "sanity");
int stride_sign = (scale * iv_stride()) > 0 ? 1 : -1;
int iv_adjustment = (stride_sign * vw - (offset % vw)) % vw;
#ifndef PRODUCT
if (TraceSuperWord)
tty->print_cr("\noffset = %d iv_adjust = %d elt_size = %d scale = %d iv_stride = %d vect_size %d",
offset, iv_adjustment, align_to_ref_p.memory_size(), scale, iv_stride(), vw);
#endif
return iv_adjustment;
}
//---------------------------dependence_graph---------------------------
// Construct dependency graph.
// Add dependence edges to load/store nodes for memory dependence
@ -488,9 +618,13 @@ void SuperWord::mem_slice_preds(Node* start, Node* stop, GrowableArray<Node*> &p
bool SuperWord::stmts_can_pack(Node* s1, Node* s2, int align) {
// Do not use superword for non-primitives
if((s1->is_Mem() && !is_java_primitive(s1->as_Mem()->memory_type())) ||
(s2->is_Mem() && !is_java_primitive(s2->as_Mem()->memory_type())))
BasicType bt1 = velt_basic_type(s1);
BasicType bt2 = velt_basic_type(s2);
if(!is_java_primitive(bt1) || !is_java_primitive(bt2))
return false;
if (Matcher::max_vector_size(bt1) < 2) {
return false; // No vectors for this type
}
if (isomorphic(s1, s2)) {
if (independent(s1, s2)) {
@ -552,7 +686,7 @@ bool SuperWord::isomorphic(Node* s1, Node* s2) {
if (s1->Opcode() != s2->Opcode()) return false;
if (s1->req() != s2->req()) return false;
if (s1->in(0) != s2->in(0)) return false;
if (velt_type(s1) != velt_type(s2)) return false;
if (!same_velt_type(s1, s2)) return false;
return true;
}
@ -595,14 +729,16 @@ bool SuperWord::independent_path(Node* shallow, Node* deep, uint dp) {
//------------------------------set_alignment---------------------------
void SuperWord::set_alignment(Node* s1, Node* s2, int align) {
set_alignment(s1, align);
set_alignment(s2, align + data_size(s1));
if (align == top_align || align == bottom_align) {
set_alignment(s2, align);
} else {
set_alignment(s2, align + data_size(s1));
}
}
//------------------------------data_size---------------------------
int SuperWord::data_size(Node* s) {
const Type* t = velt_type(s);
BasicType bt = t->array_element_basic_type();
int bsize = type2aelembytes(bt);
int bsize = type2aelembytes(velt_basic_type(s));
assert(bsize != 0, "valid size");
return bsize;
}
@ -631,9 +767,9 @@ void SuperWord::extend_packlist() {
//------------------------------follow_use_defs---------------------------
// Extend the packset by visiting operand definitions of nodes in pack p
bool SuperWord::follow_use_defs(Node_List* p) {
assert(p->size() == 2, "just checking");
Node* s1 = p->at(0);
Node* s2 = p->at(1);
assert(p->size() == 2, "just checking");
assert(s1->req() == s2->req(), "just checking");
assert(alignment(s1) + data_size(s1) == alignment(s2), "just checking");
@ -718,7 +854,12 @@ bool SuperWord::opnd_positions_match(Node* d1, Node* u1, Node* d2, Node* u2) {
for (i1++; i1 < ct; i1++) if (u1->in(i1) == d1) break;
for (i2++; i2 < ct; i2++) if (u2->in(i2) == d2) break;
if (i1 != i2) {
return false;
if ((i1 == (3-i2)) && (u2->is_Add() || u2->is_Mul())) {
// Further analysis relies on operands position matching.
u2->swap_edges(i1, i2);
} else {
return false;
}
}
} while (i1 < ct);
return true;
@ -727,7 +868,7 @@ bool SuperWord::opnd_positions_match(Node* d1, Node* u1, Node* d2, Node* u2) {
//------------------------------est_savings---------------------------
// Estimate the savings from executing s1 and s2 as a pack
int SuperWord::est_savings(Node* s1, Node* s2) {
int save = 2 - 1; // 2 operations per instruction in packed form
int save_in = 2 - 1; // 2 operations per instruction in packed form
// inputs
for (uint i = 1; i < s1->req(); i++) {
@ -735,17 +876,18 @@ int SuperWord::est_savings(Node* s1, Node* s2) {
Node* x2 = s2->in(i);
if (x1 != x2) {
if (are_adjacent_refs(x1, x2)) {
save += adjacent_profit(x1, x2);
save_in += adjacent_profit(x1, x2);
} else if (!in_packset(x1, x2)) {
save -= pack_cost(2);
save_in -= pack_cost(2);
} else {
save += unpack_cost(2);
save_in += unpack_cost(2);
}
}
}
// uses of result
uint ct = 0;
int save_use = 0;
for (DUIterator_Fast imax, i = s1->fast_outs(imax); i < imax; i++) {
Node* s1_use = s1->fast_out(i);
for (int j = 0; j < _packset.length(); j++) {
@ -756,7 +898,7 @@ int SuperWord::est_savings(Node* s1, Node* s2) {
if (p->at(p->size()-1) == s2_use) {
ct++;
if (are_adjacent_refs(s1_use, s2_use)) {
save += adjacent_profit(s1_use, s2_use);
save_use += adjacent_profit(s1_use, s2_use);
}
}
}
@ -764,10 +906,10 @@ int SuperWord::est_savings(Node* s1, Node* s2) {
}
}
if (ct < s1->outcnt()) save += unpack_cost(1);
if (ct < s2->outcnt()) save += unpack_cost(1);
if (ct < s1->outcnt()) save_use += unpack_cost(1);
if (ct < s2->outcnt()) save_use += unpack_cost(1);
return save;
return MAX2(save_in, save_use);
}
//------------------------------costs---------------------------
@ -778,8 +920,9 @@ int SuperWord::unpack_cost(int ct) { return ct; }
//------------------------------combine_packs---------------------------
// Combine packs A and B with A.last == B.first into A.first..,A.last,B.second,..B.last
void SuperWord::combine_packs() {
bool changed;
do {
bool changed = true;
// Combine packs regardless max vector size.
while (changed) {
changed = false;
for (int i = 0; i < _packset.length(); i++) {
Node_List* p1 = _packset.at(i);
@ -787,6 +930,7 @@ void SuperWord::combine_packs() {
for (int j = 0; j < _packset.length(); j++) {
Node_List* p2 = _packset.at(j);
if (p2 == NULL) continue;
if (i == j) continue;
if (p1->at(p1->size()-1) == p2->at(0)) {
for (uint k = 1; k < p2->size(); k++) {
p1->push(p2->at(k));
@ -796,8 +940,39 @@ void SuperWord::combine_packs() {
}
}
}
} while (changed);
}
// Split packs which have size greater then max vector size.
for (int i = 0; i < _packset.length(); i++) {
Node_List* p1 = _packset.at(i);
if (p1 != NULL) {
BasicType bt = velt_basic_type(p1->at(0));
uint max_vlen = Matcher::max_vector_size(bt); // Max elements in vector
assert(is_power_of_2(max_vlen), "sanity");
uint psize = p1->size();
if (!is_power_of_2(psize)) {
// Skip pack which can't be vector.
// case1: for(...) { a[i] = i; } elements values are different (i+x)
// case2: for(...) { a[i] = b[i+1]; } can't align both, load and store
_packset.at_put(i, NULL);
continue;
}
if (psize > max_vlen) {
Node_List* pack = new Node_List();
for (uint j = 0; j < psize; j++) {
pack->push(p1->at(j));
if (pack->size() >= max_vlen) {
assert(is_power_of_2(pack->size()), "sanity");
_packset.append(pack);
pack = new Node_List();
}
}
_packset.at_put(i, NULL);
}
}
}
// Compress list.
for (int i = _packset.length() - 1; i >= 0; i--) {
Node_List* p1 = _packset.at(i);
if (p1 == NULL) {
@ -880,8 +1055,7 @@ void SuperWord::filter_packs() {
// Can code be generated for pack p?
bool SuperWord::implemented(Node_List* p) {
Node* p0 = p->at(0);
int vopc = VectorNode::opcode(p0->Opcode(), p->size(), velt_type(p0));
return vopc > 0 && Matcher::has_match_rule(vopc);
return VectorNode::implemented(p0->Opcode(), p->size(), velt_basic_type(p0));
}
//------------------------------profitable---------------------------
@ -939,36 +1113,36 @@ void SuperWord::schedule() {
}
//-------------------------------remove_and_insert-------------------
//remove "current" from its current position in the memory graph and insert
//it after the appropriate insertion point (lip or uip)
// Remove "current" from its current position in the memory graph and insert
// it after the appropriate insertion point (lip or uip).
void SuperWord::remove_and_insert(MemNode *current, MemNode *prev, MemNode *lip,
Node *uip, Unique_Node_List &sched_before) {
Node* my_mem = current->in(MemNode::Memory);
_igvn.rehash_node_delayed(current);
_igvn.hash_delete(my_mem);
bool sched_up = sched_before.member(current);
//remove current_store from its current position in the memmory graph
// remove current_store from its current position in the memmory graph
for (DUIterator i = current->outs(); current->has_out(i); i++) {
Node* use = current->out(i);
if (use->is_Mem()) {
assert(use->in(MemNode::Memory) == current, "must be");
_igvn.rehash_node_delayed(use);
if (use == prev) { // connect prev to my_mem
use->set_req(MemNode::Memory, my_mem);
_igvn.replace_input_of(use, MemNode::Memory, my_mem);
--i; //deleted this edge; rescan position
} else if (sched_before.member(use)) {
_igvn.hash_delete(uip);
use->set_req(MemNode::Memory, uip);
if (!sched_up) { // Will be moved together with current
_igvn.replace_input_of(use, MemNode::Memory, uip);
--i; //deleted this edge; rescan position
}
} else {
_igvn.hash_delete(lip);
use->set_req(MemNode::Memory, lip);
if (sched_up) { // Will be moved together with current
_igvn.replace_input_of(use, MemNode::Memory, lip);
--i; //deleted this edge; rescan position
}
}
--i; //deleted this edge; rescan position
}
}
bool sched_up = sched_before.member(current);
Node *insert_pt = sched_up ? uip : lip;
_igvn.hash_delete(insert_pt);
// all uses of insert_pt's memory state should use current's instead
for (DUIterator i = insert_pt->outs(); insert_pt->has_out(i); i++) {
@ -988,7 +1162,7 @@ void SuperWord::remove_and_insert(MemNode *current, MemNode *prev, MemNode *lip,
}
//connect current to insert_pt
current->set_req(MemNode::Memory, insert_pt);
_igvn.replace_input_of(current, MemNode::Memory, insert_pt);
}
//------------------------------co_locate_pack----------------------------------
@ -1025,7 +1199,7 @@ void SuperWord::co_locate_pack(Node_List* pk) {
if (use->is_Mem() && use != previous)
memops.push(use);
}
if(current == first) break;
if (current == first) break;
previous = current;
current = current->in(MemNode::Memory)->as_Mem();
}
@ -1038,27 +1212,37 @@ void SuperWord::co_locate_pack(Node_List* pk) {
Node *s2 = memops.at(j);
if (!independent(s1, s2)) {
if (in_pack(s2, pk) || schedule_before_pack.member(s2)) {
schedule_before_pack.push(s1); //s1 must be scheduled before
schedule_before_pack.push(s1); // s1 must be scheduled before
Node_List* mem_pk = my_pack(s1);
if (mem_pk != NULL) {
for (uint ii = 0; ii < mem_pk->size(); ii++) {
Node* s = mem_pk->at(ii); // follow partner
Node* s = mem_pk->at(ii); // follow partner
if (memops.member(s) && !schedule_before_pack.member(s))
schedule_before_pack.push(s);
}
}
break;
}
}
}
}
}
MemNode* lower_insert_pt = last;
Node* upper_insert_pt = first->in(MemNode::Memory);
// Following code moves loads connected to upper_insert_pt below aliased stores.
// Collect such loads here and reconnect them back to upper_insert_pt later.
memops.clear();
for (DUIterator i = upper_insert_pt->outs(); upper_insert_pt->has_out(i); i++) {
Node* use = upper_insert_pt->out(i);
if (!use->is_Store())
memops.push(use);
}
MemNode* lower_insert_pt = last;
previous = last; //previous store in pk
current = last->in(MemNode::Memory)->as_Mem();
//start scheduling from "last" to "first"
// start scheduling from "last" to "first"
while (true) {
assert(in_bb(current), "stay in block");
assert(in_pack(previous, pk), "previous stays in pack");
@ -1066,16 +1250,13 @@ void SuperWord::co_locate_pack(Node_List* pk) {
if (in_pack(current, pk)) {
// Forward users of my memory state (except "previous) to my input memory state
_igvn.hash_delete(current);
for (DUIterator i = current->outs(); current->has_out(i); i++) {
Node* use = current->out(i);
if (use->is_Mem() && use != previous) {
assert(use->in(MemNode::Memory) == current, "must be");
if (schedule_before_pack.member(use)) {
_igvn.hash_delete(upper_insert_pt);
_igvn.replace_input_of(use, MemNode::Memory, upper_insert_pt);
} else {
_igvn.hash_delete(lower_insert_pt);
_igvn.replace_input_of(use, MemNode::Memory, lower_insert_pt);
}
--i; // deleted this edge; rescan position
@ -1089,6 +1270,14 @@ void SuperWord::co_locate_pack(Node_List* pk) {
if (current == first) break;
current = my_mem->as_Mem();
} // end while
// Reconnect loads back to upper_insert_pt.
for (uint i = 0; i < memops.size(); i++) {
Node *ld = memops.at(i);
if (ld->in(MemNode::Memory) != upper_insert_pt) {
_igvn.replace_input_of(ld, MemNode::Memory, upper_insert_pt);
}
}
} else if (pk->at(0)->is_Load()) { //load
// all loads in the pack should have the same memory state. By default,
// we use the memory state of the last load. However, if any load could
@ -1149,35 +1338,30 @@ void SuperWord::output() {
Node* vn = NULL;
Node* low_adr = p->at(0);
Node* first = executed_first(p);
int opc = n->Opcode();
if (n->is_Load()) {
int opc = n->Opcode();
Node* ctl = n->in(MemNode::Control);
Node* mem = first->in(MemNode::Memory);
Node* adr = low_adr->in(MemNode::Address);
const TypePtr* atyp = n->adr_type();
vn = VectorLoadNode::make(_phase->C, opc, ctl, mem, adr, atyp, vlen);
vn = LoadVectorNode::make(_phase->C, opc, ctl, mem, adr, atyp, vlen, velt_basic_type(n));
} else if (n->is_Store()) {
// Promote value to be stored to vector
Node* val = vector_opd(p, MemNode::ValueIn);
int opc = n->Opcode();
Node* ctl = n->in(MemNode::Control);
Node* mem = first->in(MemNode::Memory);
Node* adr = low_adr->in(MemNode::Address);
const TypePtr* atyp = n->adr_type();
vn = VectorStoreNode::make(_phase->C, opc, ctl, mem, adr, atyp, val, vlen);
vn = StoreVectorNode::make(_phase->C, opc, ctl, mem, adr, atyp, val, vlen);
} else if (n->req() == 3) {
// Promote operands to vector
Node* in1 = vector_opd(p, 1);
Node* in2 = vector_opd(p, 2);
vn = VectorNode::make(_phase->C, n->Opcode(), in1, in2, vlen, velt_type(n));
vn = VectorNode::make(_phase->C, opc, in1, in2, vlen, velt_basic_type(n));
} else {
ShouldNotReachHere();
}
assert(vn != NULL, "sanity");
_phase->_igvn.register_new_node_with_optimizer(vn);
_phase->set_ctrl(vn, _phase->get_ctrl(p->at(0)));
for (uint j = 0; j < p->size(); j++) {
@ -1185,6 +1369,12 @@ void SuperWord::output() {
_igvn.replace_node(pm, vn);
}
_igvn._worklist.push(vn);
#ifdef ASSERT
if (TraceNewVectors) {
tty->print("new Vector node: ");
vn->dump();
}
#endif
}
}
}
@ -1207,10 +1397,10 @@ Node* SuperWord::vector_opd(Node_List* p, int opd_idx) {
}
if (same_opd) {
if (opd->is_Vector() || opd->is_VectorLoad()) {
if (opd->is_Vector() || opd->is_LoadVector()) {
return opd; // input is matching vector
}
assert(!opd->is_VectorStore(), "such vector is not expected here");
assert(!opd->is_StoreVector(), "such vector is not expected here");
// Convert scalar input to vector with the same number of elements as
// p0's vector. Use p0's type because size of operand's container in
// vector should match p0's size regardless operand's size.
@ -1219,12 +1409,18 @@ Node* SuperWord::vector_opd(Node_List* p, int opd_idx) {
_phase->_igvn.register_new_node_with_optimizer(vn);
_phase->set_ctrl(vn, _phase->get_ctrl(opd));
#ifdef ASSERT
if (TraceNewVectors) {
tty->print("new Vector node: ");
vn->dump();
}
#endif
return vn;
}
// Insert pack operation
const Type* p0_t = velt_type(p0);
PackNode* pk = PackNode::make(_phase->C, opd, p0_t);
BasicType bt = velt_basic_type(p0);
PackNode* pk = PackNode::make(_phase->C, opd, vlen, bt);
DEBUG_ONLY( const BasicType opd_bt = opd->bottom_type()->basic_type(); )
for (uint i = 1; i < vlen; i++) {
@ -1232,10 +1428,16 @@ Node* SuperWord::vector_opd(Node_List* p, int opd_idx) {
Node* in = pi->in(opd_idx);
assert(my_pack(in) == NULL, "Should already have been unpacked");
assert(opd_bt == in->bottom_type()->basic_type(), "all same type");
pk->add_opd(in);
pk->add_opd(i, in);
}
_phase->_igvn.register_new_node_with_optimizer(pk);
_phase->set_ctrl(pk, _phase->get_ctrl(opd));
#ifdef ASSERT
if (TraceNewVectors) {
tty->print("new Vector node: ");
pk->dump();
}
#endif
return pk;
}
@ -1273,16 +1475,15 @@ void SuperWord::insert_extracts(Node_List* p) {
// Insert extract operation
_igvn.hash_delete(def);
int def_pos = alignment(def) / data_size(def);
const Type* def_t = velt_type(def);
Node* ex = ExtractNode::make(_phase->C, def, def_pos, def_t);
Node* ex = ExtractNode::make(_phase->C, def, def_pos, velt_basic_type(def));
_phase->_igvn.register_new_node_with_optimizer(ex);
_phase->set_ctrl(ex, _phase->get_ctrl(def));
_igvn.replace_input_of(use, idx, ex);
_igvn._worklist.push(def);
bb_insert_after(ex, bb_idx(def));
set_velt_type(ex, def_t);
set_velt_type(ex, velt_type(def));
}
}
@ -1509,10 +1710,7 @@ void SuperWord::compute_vector_element_type() {
// Initial type
for (int i = 0; i < _block.length(); i++) {
Node* n = _block.at(i);
const Type* t = n->is_Mem() ? Type::get_const_basic_type(n->as_Mem()->memory_type())
: _igvn.type(n);
const Type* vt = container_type(t);
set_velt_type(n, vt);
set_velt_type(n, container_type(n));
}
// Propagate narrowed type backwards through operations
@ -1543,7 +1741,7 @@ void SuperWord::compute_vector_element_type() {
bool same_type = true;
for (DUIterator_Fast kmax, k = in->fast_outs(kmax); k < kmax; k++) {
Node *use = in->fast_out(k);
if (!in_bb(use) || velt_type(use) != vt) {
if (!in_bb(use) || !same_velt_type(use, n)) {
same_type = false;
break;
}
@ -1575,20 +1773,24 @@ int SuperWord::memory_alignment(MemNode* s, int iv_adjust_in_bytes) {
if (!p.valid()) {
return bottom_align;
}
int vw = vector_width_in_bytes(s);
if (vw < 2) {
return bottom_align; // No vectors for this type
}
int offset = p.offset_in_bytes();
offset += iv_adjust_in_bytes;
int off_rem = offset % vector_width_in_bytes();
int off_mod = off_rem >= 0 ? off_rem : off_rem + vector_width_in_bytes();
int off_rem = offset % vw;
int off_mod = off_rem >= 0 ? off_rem : off_rem + vw;
return off_mod;
}
//---------------------------container_type---------------------------
// Smallest type containing range of values
const Type* SuperWord::container_type(const Type* t) {
const Type* tp = t->make_ptr();
if (tp && tp->isa_aryptr()) {
t = tp->is_aryptr()->elem();
const Type* SuperWord::container_type(Node* n) {
if (n->is_Mem()) {
return Type::get_const_basic_type(n->as_Mem()->memory_type());
}
const Type* t = _igvn.type(n);
if (t->basic_type() == T_INT) {
if (t->higher_equal(TypeInt::BOOL)) return TypeInt::BOOL;
if (t->higher_equal(TypeInt::BYTE)) return TypeInt::BYTE;
@ -1599,11 +1801,22 @@ const Type* SuperWord::container_type(const Type* t) {
return t;
}
bool SuperWord::same_velt_type(Node* n1, Node* n2) {
const Type* vt1 = velt_type(n1);
const Type* vt2 = velt_type(n1);
if (vt1->basic_type() == T_INT && vt2->basic_type() == T_INT) {
// Compare vectors element sizes for integer types.
return data_size(n1) == data_size(n2);
}
return vt1 == vt2;
}
//-------------------------vector_opd_range-----------------------
// (Start, end] half-open range defining which operands are vector
void SuperWord::vector_opd_range(Node* n, uint* start, uint* end) {
switch (n->Opcode()) {
case Op_LoadB: case Op_LoadUS:
case Op_LoadB: case Op_LoadUB:
case Op_LoadS: case Op_LoadUS:
case Op_LoadI: case Op_LoadL:
case Op_LoadF: case Op_LoadD:
case Op_LoadP:
@ -1721,6 +1934,7 @@ void SuperWord::align_initial_loop_index(MemNode* align_to_ref) {
assert(orig_limit != NULL && _igvn.type(orig_limit) != Type::TOP, "");
SWPointer align_to_ref_p(align_to_ref, this);
assert(align_to_ref_p.valid(), "sanity");
// Given:
// lim0 == original pre loop limit
@ -1773,10 +1987,12 @@ void SuperWord::align_initial_loop_index(MemNode* align_to_ref) {
// N = (V - (e - lim0)) % V
// lim = lim0 - (V - (e - lim0)) % V
int vw = vector_width_in_bytes(align_to_ref);
int stride = iv_stride();
int scale = align_to_ref_p.scale_in_bytes();
int elt_size = align_to_ref_p.memory_size();
int v_align = vector_width_in_bytes() / elt_size;
int v_align = vw / elt_size;
assert(v_align > 1, "sanity");
int k = align_to_ref_p.offset_in_bytes() / elt_size;
Node *kn = _igvn.intcon(k);
@ -1796,6 +2012,25 @@ void SuperWord::align_initial_loop_index(MemNode* align_to_ref) {
_phase->_igvn.register_new_node_with_optimizer(e);
_phase->set_ctrl(e, pre_ctrl);
}
if (vw > ObjectAlignmentInBytes) {
// incorporate base e +/- base && Mask >>> log2(elt)
Node* mask = _igvn.MakeConX(~(-1 << exact_log2(vw)));
Node* xbase = new(_phase->C, 2) CastP2XNode(NULL, align_to_ref_p.base());
_phase->_igvn.register_new_node_with_optimizer(xbase);
Node* masked_xbase = new (_phase->C, 3) AndXNode(xbase, mask);
_phase->_igvn.register_new_node_with_optimizer(masked_xbase);
#ifdef _LP64
masked_xbase = new (_phase->C, 2) ConvL2INode(masked_xbase);
_phase->_igvn.register_new_node_with_optimizer(masked_xbase);
#endif
Node* log2_elt = _igvn.intcon(exact_log2(elt_size));
Node* bref = new (_phase->C, 3) URShiftINode(masked_xbase, log2_elt);
_phase->_igvn.register_new_node_with_optimizer(bref);
_phase->set_ctrl(bref, pre_ctrl);
e = new (_phase->C, 3) AddINode(e, bref);
_phase->_igvn.register_new_node_with_optimizer(e);
_phase->set_ctrl(e, pre_ctrl);
}
// compute e +/- lim0
if (scale < 0) {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -264,8 +264,14 @@ class SuperWord : public ResourceObj {
_iv = lp->as_CountedLoop()->phi()->as_Phi(); }
int iv_stride() { return lp()->as_CountedLoop()->stride_con(); }
int vector_width_in_bytes() { return Matcher::vector_width_in_bytes(); }
int vector_width(Node* n) {
BasicType bt = velt_basic_type(n);
return MIN2(ABS(iv_stride()), Matcher::max_vector_size(bt));
}
int vector_width_in_bytes(Node* n) {
BasicType bt = velt_basic_type(n);
return vector_width(n)*type2aelembytes(bt);
}
MemNode* align_to_ref() { return _align_to_ref; }
void set_align_to_ref(MemNode* m) { _align_to_ref = m; }
@ -298,7 +304,9 @@ class SuperWord : public ResourceObj {
// vector element type
const Type* velt_type(Node* n) { return _node_info.adr_at(bb_idx(n))->_velt_type; }
BasicType velt_basic_type(Node* n) { return velt_type(n)->array_element_basic_type(); }
void set_velt_type(Node* n, const Type* t) { int i = bb_idx(n); grow_node_info(i); _node_info.adr_at(i)->_velt_type = t; }
bool same_velt_type(Node* n1, Node* n2);
// my_pack
Node_List* my_pack(Node* n) { return !in_bb(n) ? NULL : _node_info.adr_at(bb_idx(n))->_my_pack; }
@ -311,7 +319,9 @@ class SuperWord : public ResourceObj {
// Find the adjacent memory references and create pack pairs for them.
void find_adjacent_refs();
// Find a memory reference to align the loop induction variable to.
void find_align_to_ref(Node_List &memops);
MemNode* find_align_to_ref(Node_List &memops);
// Calculate loop's iv adjustment for this memory ops.
int get_iv_adjustment(MemNode* mem);
// Can the preloop align the reference to position zero in the vector?
bool ref_is_alignable(SWPointer& p);
// Construct dependency graph.
@ -394,7 +404,7 @@ class SuperWord : public ResourceObj {
// (Start, end] half-open range defining which operands are vector
void vector_opd_range(Node* n, uint* start, uint* end);
// Smallest type containing range of values
static const Type* container_type(const Type* t);
const Type* container_type(Node* n);
// Adjust pre-loop limit so that in main loop, a load/store reference
// to align_to_ref will be a position zero in the vector.
void align_initial_loop_index(MemNode* align_to_ref);
@ -462,6 +472,7 @@ class SWPointer VALUE_OBJ_CLASS_SPEC {
Node* base() { return _base; }
Node* adr() { return _adr; }
MemNode* mem() { return _mem; }
int scale_in_bytes() { return _scale; }
Node* invar() { return _invar; }
bool negate_invar() { return _negate_invar; }

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -60,6 +60,10 @@ const BasicType Type::_basic_type[Type::lastype] = {
T_ILLEGAL, // Tuple
T_ARRAY, // Array
T_ILLEGAL, // VectorS
T_ILLEGAL, // VectorD
T_ILLEGAL, // VectorX
T_ILLEGAL, // VectorY
T_ADDRESS, // AnyPtr // shows up in factory methods for NULL_PTR
T_ADDRESS, // RawPtr
@ -414,6 +418,24 @@ void Type::Initialize_shared(Compile* current) {
// get_zero_type() should not happen for T_CONFLICT
_zero_type[T_CONFLICT]= NULL;
// Vector predefined types, it needs initialized _const_basic_type[].
if (Matcher::vector_size_supported(T_BYTE,4)) {
TypeVect::VECTS = TypeVect::make(T_BYTE,4);
}
if (Matcher::vector_size_supported(T_FLOAT,2)) {
TypeVect::VECTD = TypeVect::make(T_FLOAT,2);
}
if (Matcher::vector_size_supported(T_FLOAT,4)) {
TypeVect::VECTX = TypeVect::make(T_FLOAT,4);
}
if (Matcher::vector_size_supported(T_FLOAT,8)) {
TypeVect::VECTY = TypeVect::make(T_FLOAT,8);
}
mreg2type[Op_VecS] = TypeVect::VECTS;
mreg2type[Op_VecD] = TypeVect::VECTD;
mreg2type[Op_VecX] = TypeVect::VECTX;
mreg2type[Op_VecY] = TypeVect::VECTY;
// Restore working type arena.
current->set_type_arena(save);
current->set_type_dict(NULL);
@ -668,6 +690,10 @@ const Type::TYPES Type::dual_type[Type::lastype] = {
Bad, // Tuple - handled in v-call
Bad, // Array - handled in v-call
Bad, // VectorS - handled in v-call
Bad, // VectorD - handled in v-call
Bad, // VectorX - handled in v-call
Bad, // VectorY - handled in v-call
Bad, // AnyPtr - handled in v-call
Bad, // RawPtr - handled in v-call
@ -728,8 +754,8 @@ void Type::dump_on(outputStream *st) const {
//------------------------------data-------------------------------------------
const char * const Type::msg[Type::lastype] = {
"bad","control","top","int:","long:","half", "narrowoop:",
"tuple:", "aryptr",
"anyptr:", "rawptr:", "java:", "inst:", "ary:", "klass:",
"tuple:", "array:", "vectors:", "vectord:", "vectorx:", "vectory:",
"anyptr:", "rawptr:", "java:", "inst:", "aryptr:", "klass:",
"func", "abIO", "return_address", "memory",
"float_top", "ftcon:", "float",
"double_top", "dblcon:", "double",
@ -790,7 +816,7 @@ void Type::typerr( const Type *t ) const {
//------------------------------isa_oop_ptr------------------------------------
// Return true if type is an oop pointer type. False for raw pointers.
static char isa_oop_ptr_tbl[Type::lastype] = {
0,0,0,0,0,0,0/*narrowoop*/,0/*tuple*/, 0/*ary*/,
0,0,0,0,0,0,0/*narrowoop*/,0/*tuple*/, 0/*array*/, 0, 0, 0, 0/*vector*/,
0/*anyptr*/,0/*rawptr*/,1/*OopPtr*/,1/*InstPtr*/,1/*AryPtr*/,1/*KlassPtr*/,
0/*func*/,0,0/*return_address*/,0,
/*floats*/0,0,0, /*doubles*/0,0,0,
@ -1926,6 +1952,121 @@ bool TypeAry::ary_must_be_exact() const {
return false;
}
//==============================TypeVect=======================================
// Convenience common pre-built types.
const TypeVect *TypeVect::VECTS = NULL; // 32-bit vectors
const TypeVect *TypeVect::VECTD = NULL; // 64-bit vectors
const TypeVect *TypeVect::VECTX = NULL; // 128-bit vectors
const TypeVect *TypeVect::VECTY = NULL; // 256-bit vectors
//------------------------------make-------------------------------------------
const TypeVect* TypeVect::make(const Type *elem, uint length) {
BasicType elem_bt = elem->array_element_basic_type();
assert(is_java_primitive(elem_bt), "only primitive types in vector");
assert(length > 1 && is_power_of_2(length), "vector length is power of 2");
assert(Matcher::vector_size_supported(elem_bt, length), "length in range");
int size = length * type2aelembytes(elem_bt);
switch (Matcher::vector_ideal_reg(size)) {
case Op_VecS:
return (TypeVect*)(new TypeVectS(elem, length))->hashcons();
case Op_VecD:
case Op_RegD:
return (TypeVect*)(new TypeVectD(elem, length))->hashcons();
case Op_VecX:
return (TypeVect*)(new TypeVectX(elem, length))->hashcons();
case Op_VecY:
return (TypeVect*)(new TypeVectY(elem, length))->hashcons();
}
ShouldNotReachHere();
return NULL;
}
//------------------------------meet-------------------------------------------
// Compute the MEET of two types. It returns a new Type object.
const Type *TypeVect::xmeet( const Type *t ) const {
// Perform a fast test for common case; meeting the same types together.
if( this == t ) return this; // Meeting same type-rep?
// Current "this->_base" is Vector
switch (t->base()) { // switch on original type
case Bottom: // Ye Olde Default
return t;
default: // All else is a mistake
typerr(t);
case VectorS:
case VectorD:
case VectorX:
case VectorY: { // Meeting 2 vectors?
const TypeVect* v = t->is_vect();
assert( base() == v->base(), "");
assert(length() == v->length(), "");
assert(element_basic_type() == v->element_basic_type(), "");
return TypeVect::make(_elem->xmeet(v->_elem), _length);
}
case Top:
break;
}
return this;
}
//------------------------------xdual------------------------------------------
// Dual: compute field-by-field dual
const Type *TypeVect::xdual() const {
return new TypeVect(base(), _elem->dual(), _length);
}
//------------------------------eq---------------------------------------------
// Structural equality check for Type representations
bool TypeVect::eq(const Type *t) const {
const TypeVect *v = t->is_vect();
return (_elem == v->_elem) && (_length == v->_length);
}
//------------------------------hash-------------------------------------------
// Type-specific hashing function.
int TypeVect::hash(void) const {
return (intptr_t)_elem + (intptr_t)_length;
}
//------------------------------singleton--------------------------------------
// TRUE if Type is a singleton type, FALSE otherwise. Singletons are simple
// constants (Ldi nodes). Vector is singleton if all elements are the same
// constant value (when vector is created with Replicate code).
bool TypeVect::singleton(void) const {
// There is no Con node for vectors yet.
// return _elem->singleton();
return false;
}
bool TypeVect::empty(void) const {
return _elem->empty();
}
//------------------------------dump2------------------------------------------
#ifndef PRODUCT
void TypeVect::dump2(Dict &d, uint depth, outputStream *st) const {
switch (base()) {
case VectorS:
st->print("vectors["); break;
case VectorD:
st->print("vectord["); break;
case VectorX:
st->print("vectorx["); break;
case VectorY:
st->print("vectory["); break;
default:
ShouldNotReachHere();
}
st->print("%d]:{", _length);
_elem->dump2(d, depth, st);
st->print("}");
}
#endif
//=============================================================================
// Convenience common pre-built types.
const TypePtr *TypePtr::NULL_PTR;
@ -2472,18 +2613,26 @@ const TypeOopPtr* TypeOopPtr::make_from_klass_common(ciKlass *klass, bool klass_
//------------------------------make_from_constant-----------------------------
// Make a java pointer from an oop constant
const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_constant) {
if (o->is_method_data() || o->is_method() || o->is_cpcache()) {
if (o->is_method_data() || o->is_method()) {
// Treat much like a typeArray of bytes, like below, but fake the type...
const Type* etype = (Type*)get_const_basic_type(T_BYTE);
const BasicType bt = T_BYTE;
const Type* etype = get_const_basic_type(bt);
const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS);
ciKlass *klass = ciTypeArrayKlass::make((BasicType) T_BYTE);
assert(o->can_be_constant(), "method data oops should be tenured");
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
return arr;
ciKlass* klass = ciArrayKlass::make(ciType::make(bt));
assert(o->can_be_constant(), "should be tenured");
return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
} else if (o->is_cpcache()) {
// Treat much like a objArray, like below, but fake the type...
const BasicType bt = T_OBJECT;
const Type* etype = get_const_basic_type(bt);
const TypeAry* arr0 = TypeAry::make(etype, TypeInt::POS);
ciKlass* klass = ciArrayKlass::make(ciType::make(bt));
assert(o->can_be_constant(), "should be tenured");
return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
} else {
assert(o->is_java_object(), "must be java language object");
assert(!o->is_null_object(), "null object not yet handled here.");
ciKlass *klass = o->klass();
ciKlass* klass = o->klass();
if (klass->is_instance_klass()) {
// Element is an instance
if (require_constant) {
@ -2494,8 +2643,7 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_const
return TypeInstPtr::make(o);
} else if (klass->is_obj_array_klass()) {
// Element is an object array. Recursively call ourself.
const Type *etype =
TypeOopPtr::make_from_klass_raw(klass->as_obj_array_klass()->element_klass());
const Type *etype = make_from_klass_raw(klass->as_obj_array_klass()->element_klass());
const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
// We used to pass NotNull in here, asserting that the sub-arrays
// are all not-null. This is not true in generally, as code can
@ -2505,12 +2653,10 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_const
} else if (!o->should_be_constant()) {
return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
}
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
return arr;
return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
} else if (klass->is_type_array_klass()) {
// Element is an typeArray
const Type* etype =
(Type*)get_const_basic_type(klass->as_type_array_klass()->element_type());
const Type* etype = get_const_basic_type(klass->as_type_array_klass()->element_type());
const TypeAry* arr0 = TypeAry::make(etype, TypeInt::make(o->as_array()->length()));
// We used to pass NotNull in here, asserting that the array pointer
// is not-null. That was not true in general.
@ -2519,12 +2665,11 @@ const TypeOopPtr* TypeOopPtr::make_from_constant(ciObject* o, bool require_const
} else if (!o->should_be_constant()) {
return TypeAryPtr::make(TypePtr::NotNull, arr0, klass, true, 0);
}
const TypeAryPtr* arr = TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
return arr;
return TypeAryPtr::make(TypePtr::Constant, o, arr0, klass, true, 0);
}
}
ShouldNotReachHere();
fatal("unhandled object type");
return NULL;
}
@ -4140,7 +4285,7 @@ void TypeFunc::dump2( Dict &d, uint depth, outputStream *st ) const {
// Print a 'flattened' signature
static const char * const flat_type_msg[Type::lastype] = {
"bad","control","top","int","long","_", "narrowoop",
"tuple:", "array:",
"tuple:", "array:", "vectors:", "vectord:", "vectorx:", "vectory:",
"ptr", "rawptr", "ptr", "ptr", "ptr", "ptr",
"func", "abIO", "return_address", "mem",
"float_top", "ftcon:", "flt",

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -51,6 +51,11 @@ class TypeLong;
class TypeNarrowOop;
class TypeAry;
class TypeTuple;
class TypeVect;
class TypeVectS;
class TypeVectD;
class TypeVectX;
class TypeVectY;
class TypePtr;
class TypeRawPtr;
class TypeOopPtr;
@ -78,6 +83,10 @@ public:
Tuple, // Method signature or object layout
Array, // Array types
VectorS, // 32bit Vector types
VectorD, // 64bit Vector types
VectorX, // 128bit Vector types
VectorY, // 256bit Vector types
AnyPtr, // Any old raw, klass, inst, or array pointer
RawPtr, // Raw (non-oop) pointers
@ -222,6 +231,8 @@ public:
const TypeF *isa_float_constant() const; // Returns NULL if not a FloatCon
const TypeTuple *is_tuple() const; // Collection of fields, NOT a pointer
const TypeAry *is_ary() const; // Array, NOT array pointer
const TypeVect *is_vect() const; // Vector
const TypeVect *isa_vect() const; // Returns NULL if not a Vector
const TypePtr *is_ptr() const; // Asserts it is a ptr type
const TypePtr *isa_ptr() const; // Returns NULL if not ptr type
const TypeRawPtr *isa_rawptr() const; // NOT Java oop
@ -574,6 +585,69 @@ public:
#endif
};
//------------------------------TypeVect---------------------------------------
// Class of Vector Types
class TypeVect : public Type {
const Type* _elem; // Vector's element type
const uint _length; // Elements in vector (power of 2)
protected:
TypeVect(TYPES t, const Type* elem, uint length) : Type(t),
_elem(elem), _length(length) {}
public:
const Type* element_type() const { return _elem; }
BasicType element_basic_type() const { return _elem->array_element_basic_type(); }
uint length() const { return _length; }
uint length_in_bytes() const {
return _length * type2aelembytes(element_basic_type());
}
virtual bool eq(const Type *t) const;
virtual int hash() const; // Type specific hashing
virtual bool singleton(void) const; // TRUE if type is a singleton
virtual bool empty(void) const; // TRUE if type is vacuous
static const TypeVect *make(const BasicType elem_bt, uint length) {
// Use bottom primitive type.
return make(get_const_basic_type(elem_bt), length);
}
// Used directly by Replicate nodes to construct singleton vector.
static const TypeVect *make(const Type* elem, uint length);
virtual const Type *xmeet( const Type *t) const;
virtual const Type *xdual() const; // Compute dual right now.
static const TypeVect *VECTS;
static const TypeVect *VECTD;
static const TypeVect *VECTX;
static const TypeVect *VECTY;
#ifndef PRODUCT
virtual void dump2(Dict &d, uint, outputStream *st) const; // Specialized per-Type dumping
#endif
};
class TypeVectS : public TypeVect {
friend class TypeVect;
TypeVectS(const Type* elem, uint length) : TypeVect(VectorS, elem, length) {}
};
class TypeVectD : public TypeVect {
friend class TypeVect;
TypeVectD(const Type* elem, uint length) : TypeVect(VectorD, elem, length) {}
};
class TypeVectX : public TypeVect {
friend class TypeVect;
TypeVectX(const Type* elem, uint length) : TypeVect(VectorX, elem, length) {}
};
class TypeVectY : public TypeVect {
friend class TypeVect;
TypeVectY(const Type* elem, uint length) : TypeVect(VectorY, elem, length) {}
};
//------------------------------TypePtr----------------------------------------
// Class of machine Pointer Types: raw data, instances or arrays.
// If the _base enum is AnyPtr, then this refers to all of the above.
@ -1113,6 +1187,15 @@ inline const TypeAry *Type::is_ary() const {
return (TypeAry*)this;
}
inline const TypeVect *Type::is_vect() const {
assert( _base >= VectorS && _base <= VectorY, "Not a Vector" );
return (TypeVect*)this;
}
inline const TypeVect *Type::isa_vect() const {
return (_base >= VectorS && _base <= VectorY) ? (TypeVect*)this : NULL;
}
inline const TypePtr *Type::is_ptr() const {
// AnyPtr is the first Ptr and KlassPtr the last, with no non-ptrs between.
assert(_base >= AnyPtr && _base <= KlassPtr, "Not a pointer");

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -28,147 +28,16 @@
//------------------------------VectorNode--------------------------------------
// Return vector type for an element type and vector length.
const Type* VectorNode::vect_type(BasicType elt_bt, uint len) {
assert(len <= VectorNode::max_vlen(elt_bt), "len in range");
switch(elt_bt) {
case T_BOOLEAN:
case T_BYTE:
switch(len) {
case 2: return TypeInt::CHAR;
case 4: return TypeInt::INT;
case 8: return TypeLong::LONG;
}
break;
case T_CHAR:
case T_SHORT:
switch(len) {
case 2: return TypeInt::INT;
case 4: return TypeLong::LONG;
}
break;
case T_INT:
switch(len) {
case 2: return TypeLong::LONG;
}
break;
case T_LONG:
break;
case T_FLOAT:
switch(len) {
case 2: return Type::DOUBLE;
}
break;
case T_DOUBLE:
break;
}
ShouldNotReachHere();
return NULL;
}
// Scalar promotion
VectorNode* VectorNode::scalar2vector(Compile* C, Node* s, uint vlen, const Type* opd_t) {
BasicType bt = opd_t->array_element_basic_type();
assert(vlen <= VectorNode::max_vlen(bt), "vlen in range");
switch (bt) {
case T_BOOLEAN:
case T_BYTE:
if (vlen == 16) return new (C, 2) Replicate16BNode(s);
if (vlen == 8) return new (C, 2) Replicate8BNode(s);
if (vlen == 4) return new (C, 2) Replicate4BNode(s);
break;
case T_CHAR:
if (vlen == 8) return new (C, 2) Replicate8CNode(s);
if (vlen == 4) return new (C, 2) Replicate4CNode(s);
if (vlen == 2) return new (C, 2) Replicate2CNode(s);
break;
case T_SHORT:
if (vlen == 8) return new (C, 2) Replicate8SNode(s);
if (vlen == 4) return new (C, 2) Replicate4SNode(s);
if (vlen == 2) return new (C, 2) Replicate2SNode(s);
break;
case T_INT:
if (vlen == 4) return new (C, 2) Replicate4INode(s);
if (vlen == 2) return new (C, 2) Replicate2INode(s);
break;
case T_LONG:
if (vlen == 2) return new (C, 2) Replicate2LNode(s);
break;
case T_FLOAT:
if (vlen == 4) return new (C, 2) Replicate4FNode(s);
if (vlen == 2) return new (C, 2) Replicate2FNode(s);
break;
case T_DOUBLE:
if (vlen == 2) return new (C, 2) Replicate2DNode(s);
break;
}
ShouldNotReachHere();
return NULL;
}
// Return initial Pack node. Additional operands added with add_opd() calls.
PackNode* PackNode::make(Compile* C, Node* s, const Type* opd_t) {
BasicType bt = opd_t->array_element_basic_type();
switch (bt) {
case T_BOOLEAN:
case T_BYTE:
return new (C, 2) PackBNode(s);
case T_CHAR:
return new (C, 2) PackCNode(s);
case T_SHORT:
return new (C, 2) PackSNode(s);
case T_INT:
return new (C, 2) PackINode(s);
case T_LONG:
return new (C, 2) PackLNode(s);
case T_FLOAT:
return new (C, 2) PackFNode(s);
case T_DOUBLE:
return new (C, 2) PackDNode(s);
}
ShouldNotReachHere();
return NULL;
}
// Create a binary tree form for Packs. [lo, hi) (half-open) range
Node* PackNode::binaryTreePack(Compile* C, int lo, int hi) {
int ct = hi - lo;
assert(is_power_of_2(ct), "power of 2");
int mid = lo + ct/2;
Node* n1 = ct == 2 ? in(lo) : binaryTreePack(C, lo, mid);
Node* n2 = ct == 2 ? in(lo+1) : binaryTreePack(C, mid, hi );
int rslt_bsize = ct * type2aelembytes(elt_basic_type());
if (bottom_type()->is_floatingpoint()) {
switch (rslt_bsize) {
case 8: return new (C, 3) PackFNode(n1, n2);
case 16: return new (C, 3) PackDNode(n1, n2);
}
} else {
assert(bottom_type()->isa_int() || bottom_type()->isa_long(), "int or long");
switch (rslt_bsize) {
case 2: return new (C, 3) Pack2x1BNode(n1, n2);
case 4: return new (C, 3) Pack2x2BNode(n1, n2);
case 8: return new (C, 3) PackINode(n1, n2);
case 16: return new (C, 3) PackLNode(n1, n2);
}
}
ShouldNotReachHere();
return NULL;
}
// Return the vector operator for the specified scalar operation
// and vector length. One use is to check if the code generator
// and vector length. Also used to check if the code generator
// supports the vector operation.
int VectorNode::opcode(int sopc, uint vlen, const Type* opd_t) {
BasicType bt = opd_t->array_element_basic_type();
if (!(is_power_of_2(vlen) && vlen <= max_vlen(bt)))
return 0; // unimplemented
int VectorNode::opcode(int sopc, uint vlen, BasicType bt) {
switch (sopc) {
case Op_AddI:
switch (bt) {
case T_BOOLEAN:
case T_BYTE: return Op_AddVB;
case T_CHAR: return Op_AddVC;
case T_CHAR:
case T_SHORT: return Op_AddVS;
case T_INT: return Op_AddVI;
}
@ -186,7 +55,7 @@ int VectorNode::opcode(int sopc, uint vlen, const Type* opd_t) {
switch (bt) {
case T_BOOLEAN:
case T_BYTE: return Op_SubVB;
case T_CHAR: return Op_SubVC;
case T_CHAR:
case T_SHORT: return Op_SubVS;
case T_INT: return Op_SubVI;
}
@ -216,18 +85,18 @@ int VectorNode::opcode(int sopc, uint vlen, const Type* opd_t) {
switch (bt) {
case T_BOOLEAN:
case T_BYTE: return Op_LShiftVB;
case T_CHAR: return Op_LShiftVC;
case T_CHAR:
case T_SHORT: return Op_LShiftVS;
case T_INT: return Op_LShiftVI;
}
ShouldNotReachHere();
case Op_URShiftI:
case Op_RShiftI:
switch (bt) {
case T_BOOLEAN:
case T_BYTE: return Op_URShiftVB;
case T_CHAR: return Op_URShiftVC;
case T_SHORT: return Op_URShiftVS;
case T_INT: return Op_URShiftVI;
case T_BYTE: return Op_RShiftVB;
case T_CHAR:
case T_SHORT: return Op_RShiftVS;
case T_INT: return Op_RShiftVI;
}
ShouldNotReachHere();
case Op_AndI:
@ -241,13 +110,14 @@ int VectorNode::opcode(int sopc, uint vlen, const Type* opd_t) {
return Op_XorV;
case Op_LoadB:
case Op_LoadUB:
case Op_LoadUS:
case Op_LoadS:
case Op_LoadI:
case Op_LoadL:
case Op_LoadF:
case Op_LoadD:
return VectorLoadNode::opcode(sopc, vlen);
return Op_LoadVector;
case Op_StoreB:
case Op_StoreC:
@ -255,211 +125,170 @@ int VectorNode::opcode(int sopc, uint vlen, const Type* opd_t) {
case Op_StoreL:
case Op_StoreF:
case Op_StoreD:
return VectorStoreNode::opcode(sopc, vlen);
return Op_StoreVector;
}
return 0; // Unimplemented
}
// Helper for above.
int VectorLoadNode::opcode(int sopc, uint vlen) {
switch (sopc) {
case Op_LoadB:
switch (vlen) {
case 2: return 0; // Unimplemented
case 4: return Op_Load4B;
case 8: return Op_Load8B;
case 16: return Op_Load16B;
}
break;
case Op_LoadUS:
switch (vlen) {
case 2: return Op_Load2C;
case 4: return Op_Load4C;
case 8: return Op_Load8C;
}
break;
case Op_LoadS:
switch (vlen) {
case 2: return Op_Load2S;
case 4: return Op_Load4S;
case 8: return Op_Load8S;
}
break;
case Op_LoadI:
switch (vlen) {
case 2: return Op_Load2I;
case 4: return Op_Load4I;
}
break;
case Op_LoadL:
if (vlen == 2) return Op_Load2L;
break;
case Op_LoadF:
switch (vlen) {
case 2: return Op_Load2F;
case 4: return Op_Load4F;
}
break;
case Op_LoadD:
if (vlen == 2) return Op_Load2D;
break;
bool VectorNode::implemented(int opc, uint vlen, BasicType bt) {
if (is_java_primitive(bt) &&
(vlen > 1) && is_power_of_2(vlen) &&
Matcher::vector_size_supported(bt, vlen)) {
int vopc = VectorNode::opcode(opc, vlen, bt);
return vopc > 0 && Matcher::has_match_rule(vopc);
}
return 0; // Unimplemented
}
// Helper for above
int VectorStoreNode::opcode(int sopc, uint vlen) {
switch (sopc) {
case Op_StoreB:
switch (vlen) {
case 2: return 0; // Unimplemented
case 4: return Op_Store4B;
case 8: return Op_Store8B;
case 16: return Op_Store16B;
}
break;
case Op_StoreC:
switch (vlen) {
case 2: return Op_Store2C;
case 4: return Op_Store4C;
case 8: return Op_Store8C;
}
break;
case Op_StoreI:
switch (vlen) {
case 2: return Op_Store2I;
case 4: return Op_Store4I;
}
break;
case Op_StoreL:
if (vlen == 2) return Op_Store2L;
break;
case Op_StoreF:
switch (vlen) {
case 2: return Op_Store2F;
case 4: return Op_Store4F;
}
break;
case Op_StoreD:
if (vlen == 2) return Op_Store2D;
break;
}
return 0; // Unimplemented
return false;
}
// Return the vector version of a scalar operation node.
VectorNode* VectorNode::make(Compile* C, int sopc, Node* n1, Node* n2, uint vlen, const Type* opd_t) {
int vopc = opcode(sopc, vlen, opd_t);
VectorNode* VectorNode::make(Compile* C, int opc, Node* n1, Node* n2, uint vlen, BasicType bt) {
const TypeVect* vt = TypeVect::make(bt, vlen);
int vopc = VectorNode::opcode(opc, vlen, bt);
switch (vopc) {
case Op_AddVB: return new (C, 3) AddVBNode(n1, n2, vlen);
case Op_AddVC: return new (C, 3) AddVCNode(n1, n2, vlen);
case Op_AddVS: return new (C, 3) AddVSNode(n1, n2, vlen);
case Op_AddVI: return new (C, 3) AddVINode(n1, n2, vlen);
case Op_AddVL: return new (C, 3) AddVLNode(n1, n2, vlen);
case Op_AddVF: return new (C, 3) AddVFNode(n1, n2, vlen);
case Op_AddVD: return new (C, 3) AddVDNode(n1, n2, vlen);
case Op_AddVB: return new (C, 3) AddVBNode(n1, n2, vt);
case Op_AddVS: return new (C, 3) AddVSNode(n1, n2, vt);
case Op_AddVI: return new (C, 3) AddVINode(n1, n2, vt);
case Op_AddVL: return new (C, 3) AddVLNode(n1, n2, vt);
case Op_AddVF: return new (C, 3) AddVFNode(n1, n2, vt);
case Op_AddVD: return new (C, 3) AddVDNode(n1, n2, vt);
case Op_SubVB: return new (C, 3) SubVBNode(n1, n2, vlen);
case Op_SubVC: return new (C, 3) SubVCNode(n1, n2, vlen);
case Op_SubVS: return new (C, 3) SubVSNode(n1, n2, vlen);
case Op_SubVI: return new (C, 3) SubVINode(n1, n2, vlen);
case Op_SubVL: return new (C, 3) SubVLNode(n1, n2, vlen);
case Op_SubVF: return new (C, 3) SubVFNode(n1, n2, vlen);
case Op_SubVD: return new (C, 3) SubVDNode(n1, n2, vlen);
case Op_SubVB: return new (C, 3) SubVBNode(n1, n2, vt);
case Op_SubVS: return new (C, 3) SubVSNode(n1, n2, vt);
case Op_SubVI: return new (C, 3) SubVINode(n1, n2, vt);
case Op_SubVL: return new (C, 3) SubVLNode(n1, n2, vt);
case Op_SubVF: return new (C, 3) SubVFNode(n1, n2, vt);
case Op_SubVD: return new (C, 3) SubVDNode(n1, n2, vt);
case Op_MulVF: return new (C, 3) MulVFNode(n1, n2, vlen);
case Op_MulVD: return new (C, 3) MulVDNode(n1, n2, vlen);
case Op_MulVF: return new (C, 3) MulVFNode(n1, n2, vt);
case Op_MulVD: return new (C, 3) MulVDNode(n1, n2, vt);
case Op_DivVF: return new (C, 3) DivVFNode(n1, n2, vlen);
case Op_DivVD: return new (C, 3) DivVDNode(n1, n2, vlen);
case Op_DivVF: return new (C, 3) DivVFNode(n1, n2, vt);
case Op_DivVD: return new (C, 3) DivVDNode(n1, n2, vt);
case Op_LShiftVB: return new (C, 3) LShiftVBNode(n1, n2, vlen);
case Op_LShiftVC: return new (C, 3) LShiftVCNode(n1, n2, vlen);
case Op_LShiftVS: return new (C, 3) LShiftVSNode(n1, n2, vlen);
case Op_LShiftVI: return new (C, 3) LShiftVINode(n1, n2, vlen);
case Op_LShiftVB: return new (C, 3) LShiftVBNode(n1, n2, vt);
case Op_LShiftVS: return new (C, 3) LShiftVSNode(n1, n2, vt);
case Op_LShiftVI: return new (C, 3) LShiftVINode(n1, n2, vt);
case Op_URShiftVB: return new (C, 3) URShiftVBNode(n1, n2, vlen);
case Op_URShiftVC: return new (C, 3) URShiftVCNode(n1, n2, vlen);
case Op_URShiftVS: return new (C, 3) URShiftVSNode(n1, n2, vlen);
case Op_URShiftVI: return new (C, 3) URShiftVINode(n1, n2, vlen);
case Op_RShiftVB: return new (C, 3) RShiftVBNode(n1, n2, vt);
case Op_RShiftVS: return new (C, 3) RShiftVSNode(n1, n2, vt);
case Op_RShiftVI: return new (C, 3) RShiftVINode(n1, n2, vt);
case Op_AndV: return new (C, 3) AndVNode(n1, n2, vlen, opd_t->array_element_basic_type());
case Op_OrV: return new (C, 3) OrVNode (n1, n2, vlen, opd_t->array_element_basic_type());
case Op_XorV: return new (C, 3) XorVNode(n1, n2, vlen, opd_t->array_element_basic_type());
case Op_AndV: return new (C, 3) AndVNode(n1, n2, vt);
case Op_OrV: return new (C, 3) OrVNode (n1, n2, vt);
case Op_XorV: return new (C, 3) XorVNode(n1, n2, vt);
}
ShouldNotReachHere();
return NULL;
}
// Scalar promotion
VectorNode* VectorNode::scalar2vector(Compile* C, Node* s, uint vlen, const Type* opd_t) {
BasicType bt = opd_t->array_element_basic_type();
const TypeVect* vt = opd_t->singleton() ? TypeVect::make(opd_t, vlen)
: TypeVect::make(bt, vlen);
switch (bt) {
case T_BOOLEAN:
case T_BYTE:
return new (C, 2) ReplicateBNode(s, vt);
case T_CHAR:
case T_SHORT:
return new (C, 2) ReplicateSNode(s, vt);
case T_INT:
return new (C, 2) ReplicateINode(s, vt);
case T_LONG:
return new (C, 2) ReplicateLNode(s, vt);
case T_FLOAT:
return new (C, 2) ReplicateFNode(s, vt);
case T_DOUBLE:
return new (C, 2) ReplicateDNode(s, vt);
}
ShouldNotReachHere();
return NULL;
}
// Return initial Pack node. Additional operands added with add_opd() calls.
PackNode* PackNode::make(Compile* C, Node* s, uint vlen, BasicType bt) {
const TypeVect* vt = TypeVect::make(bt, vlen);
switch (bt) {
case T_BOOLEAN:
case T_BYTE:
return new (C, vlen+1) PackBNode(s, vt);
case T_CHAR:
case T_SHORT:
return new (C, vlen+1) PackSNode(s, vt);
case T_INT:
return new (C, vlen+1) PackINode(s, vt);
case T_LONG:
return new (C, vlen+1) PackLNode(s, vt);
case T_FLOAT:
return new (C, vlen+1) PackFNode(s, vt);
case T_DOUBLE:
return new (C, vlen+1) PackDNode(s, vt);
}
ShouldNotReachHere();
return NULL;
}
// Create a binary tree form for Packs. [lo, hi) (half-open) range
Node* PackNode::binaryTreePack(Compile* C, int lo, int hi) {
int ct = hi - lo;
assert(is_power_of_2(ct), "power of 2");
if (ct == 2) {
PackNode* pk = PackNode::make(C, in(lo), 2, vect_type()->element_basic_type());
pk->add_opd(1, in(lo+1));
return pk;
} else {
int mid = lo + ct/2;
Node* n1 = binaryTreePack(C, lo, mid);
Node* n2 = binaryTreePack(C, mid, hi );
BasicType bt = vect_type()->element_basic_type();
switch (bt) {
case T_BOOLEAN:
case T_BYTE:
return new (C, 3) PackSNode(n1, n2, TypeVect::make(T_SHORT, 2));
case T_CHAR:
case T_SHORT:
return new (C, 3) PackINode(n1, n2, TypeVect::make(T_INT, 2));
case T_INT:
return new (C, 3) PackLNode(n1, n2, TypeVect::make(T_LONG, 2));
case T_LONG:
return new (C, 3) Pack2LNode(n1, n2, TypeVect::make(T_LONG, 2));
case T_FLOAT:
return new (C, 3) PackDNode(n1, n2, TypeVect::make(T_DOUBLE, 2));
case T_DOUBLE:
return new (C, 3) Pack2DNode(n1, n2, TypeVect::make(T_DOUBLE, 2));
}
ShouldNotReachHere();
}
return NULL;
}
// Return the vector version of a scalar load node.
VectorLoadNode* VectorLoadNode::make(Compile* C, int opc, Node* ctl, Node* mem,
Node* adr, const TypePtr* atyp, uint vlen) {
int vopc = opcode(opc, vlen);
switch(vopc) {
case Op_Load16B: return new (C, 3) Load16BNode(ctl, mem, adr, atyp);
case Op_Load8B: return new (C, 3) Load8BNode(ctl, mem, adr, atyp);
case Op_Load4B: return new (C, 3) Load4BNode(ctl, mem, adr, atyp);
case Op_Load8C: return new (C, 3) Load8CNode(ctl, mem, adr, atyp);
case Op_Load4C: return new (C, 3) Load4CNode(ctl, mem, adr, atyp);
case Op_Load2C: return new (C, 3) Load2CNode(ctl, mem, adr, atyp);
case Op_Load8S: return new (C, 3) Load8SNode(ctl, mem, adr, atyp);
case Op_Load4S: return new (C, 3) Load4SNode(ctl, mem, adr, atyp);
case Op_Load2S: return new (C, 3) Load2SNode(ctl, mem, adr, atyp);
case Op_Load4I: return new (C, 3) Load4INode(ctl, mem, adr, atyp);
case Op_Load2I: return new (C, 3) Load2INode(ctl, mem, adr, atyp);
case Op_Load2L: return new (C, 3) Load2LNode(ctl, mem, adr, atyp);
case Op_Load4F: return new (C, 3) Load4FNode(ctl, mem, adr, atyp);
case Op_Load2F: return new (C, 3) Load2FNode(ctl, mem, adr, atyp);
case Op_Load2D: return new (C, 3) Load2DNode(ctl, mem, adr, atyp);
}
ShouldNotReachHere();
LoadVectorNode* LoadVectorNode::make(Compile* C, int opc, Node* ctl, Node* mem,
Node* adr, const TypePtr* atyp, uint vlen, BasicType bt) {
const TypeVect* vt = TypeVect::make(bt, vlen);
return new (C, 3) LoadVectorNode(ctl, mem, adr, atyp, vt);
return NULL;
}
// Return the vector version of a scalar store node.
VectorStoreNode* VectorStoreNode::make(Compile* C, int opc, Node* ctl, Node* mem,
StoreVectorNode* StoreVectorNode::make(Compile* C, int opc, Node* ctl, Node* mem,
Node* adr, const TypePtr* atyp, Node* val,
uint vlen) {
int vopc = opcode(opc, vlen);
switch(vopc) {
case Op_Store16B: return new (C, 4) Store16BNode(ctl, mem, adr, atyp, val);
case Op_Store8B: return new (C, 4) Store8BNode(ctl, mem, adr, atyp, val);
case Op_Store4B: return new (C, 4) Store4BNode(ctl, mem, adr, atyp, val);
case Op_Store8C: return new (C, 4) Store8CNode(ctl, mem, adr, atyp, val);
case Op_Store4C: return new (C, 4) Store4CNode(ctl, mem, adr, atyp, val);
case Op_Store2C: return new (C, 4) Store2CNode(ctl, mem, adr, atyp, val);
case Op_Store4I: return new (C, 4) Store4INode(ctl, mem, adr, atyp, val);
case Op_Store2I: return new (C, 4) Store2INode(ctl, mem, adr, atyp, val);
case Op_Store2L: return new (C, 4) Store2LNode(ctl, mem, adr, atyp, val);
case Op_Store4F: return new (C, 4) Store4FNode(ctl, mem, adr, atyp, val);
case Op_Store2F: return new (C, 4) Store2FNode(ctl, mem, adr, atyp, val);
case Op_Store2D: return new (C, 4) Store2DNode(ctl, mem, adr, atyp, val);
}
ShouldNotReachHere();
return NULL;
return new (C, 4) StoreVectorNode(ctl, mem, adr, atyp, val);
}
// Extract a scalar element of vector.
Node* ExtractNode::make(Compile* C, Node* v, uint position, const Type* opd_t) {
BasicType bt = opd_t->array_element_basic_type();
assert(position < VectorNode::max_vlen(bt), "pos in range");
Node* ExtractNode::make(Compile* C, Node* v, uint position, BasicType bt) {
assert((int)position < Matcher::max_vector_size(bt), "pos in range");
ConINode* pos = ConINode::make(C, (int)position);
switch (bt) {
case T_BOOLEAN:
return new (C, 3) ExtractUBNode(v, pos);
case T_BYTE:
return new (C, 3) ExtractBNode(v, pos);
case T_CHAR:
@ -478,3 +307,4 @@ Node* ExtractNode::make(Compile* C, Node* v, uint position, const Type* opd_t) {
ShouldNotReachHere();
return NULL;
}

File diff suppressed because it is too large Load Diff

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

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

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

@ -100,6 +100,7 @@ class fieldDescriptor VALUE_OBJ_CLASS_SPEC {
bool is_field_access_watched() const { return access_flags().is_field_access_watched(); }
bool is_field_modification_watched() const
{ return access_flags().is_field_modification_watched(); }
bool has_generic_signature() const { return access_flags().field_has_generic_signature(); }
void set_is_field_access_watched(const bool value) {
_access_flags.set_is_field_access_watched(value);

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

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

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

@ -74,6 +74,7 @@ class JDK_Version VALUE_OBJ_CLASS_SPEC {
private:
static JDK_Version _current;
static const char* _runtime_name;
// In this class, we promote the minor version of release to be the
// major version for releases >= 5 in anticipation of the JDK doing the
@ -181,6 +182,13 @@ class JDK_Version VALUE_OBJ_CLASS_SPEC {
void to_string(char* buffer, size_t buflen) const;
static const char* runtime_name() {
return _runtime_name;
}
static void set_runtime_name(const char* name) {
_runtime_name = name;
}
// Convenience methods for queries on the current major/minor version
static bool is_jdk12x_version() {
return current().compare_major(2) == 0;

@ -829,7 +829,7 @@ oop Reflection::new_field(fieldDescriptor* fd, bool intern_name, TRAPS) {
java_lang_reflect_Field::set_modifiers(rh(), fd->access_flags().as_int() & JVM_RECOGNIZED_FIELD_MODIFIERS);
java_lang_reflect_Field::set_override(rh(), false);
if (java_lang_reflect_Field::has_signature_field() &&
fd->generic_signature() != NULL) {
fd->has_generic_signature()) {
Symbol* gs = fd->generic_signature();
Handle sig = java_lang_String::create_from_symbol(gs, CHECK_NULL);
java_lang_reflect_Field::set_signature(rh(), sig());

@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
@ -526,8 +527,20 @@ void SafepointSynchronize::do_cleanup_tasks() {
CompilationPolicy::policy()->do_safepoint_work();
}
TraceTime t4("sweeping nmethods", TraceSafepointCleanupTime);
NMethodSweeper::scan_stacks();
{
TraceTime t4("sweeping nmethods", TraceSafepointCleanupTime);
NMethodSweeper::scan_stacks();
}
if (SymbolTable::needs_rehashing()) {
TraceTime t5("rehashing symbol table", TraceSafepointCleanupTime);
SymbolTable::rehash_table();
}
if (StringTable::needs_rehashing()) {
TraceTime t6("rehashing string table", TraceSafepointCleanupTime);
StringTable::rehash_table();
}
// rotate log files?
if (UseGCLogFileRotation) {

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