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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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)",

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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();

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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);
}

View File

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

View File

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

View File

@ -102,6 +102,11 @@ jprt.my.linux.armvfp.jdk7=linux_armvfp_2.6
jprt.my.linux.armvfp.jdk7u6=${jprt.my.linux.armvfp.jdk7}
jprt.my.linux.armvfp=${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}, \

View File

@ -1,5 +1,5 @@
#
# Copyright (c) 2006, 2007, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# 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

View File

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

View File

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

View File

@ -94,23 +94,24 @@ ISA = $(subst i386,i486,$(shell isainfo -n))
# Making 64/libjvm_db.so: 64-bit version of libjvm_db.so which handles 32-bit libjvm.so
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

View File

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

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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
};

View File

@ -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");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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 ++ ) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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) {

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
// Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
//
// 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";

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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");

View File

@ -0,0 +1,304 @@
/*
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "classfile/altHashing.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "oops/markOop.hpp"
#include "runtime/thread.hpp"
// Get the hash code of the classes mirror if it exists, otherwise just
// return a random number, which is one of the possible hash code used for
// objects. We don't want to call the synchronizer hash code to install
// this value because it may safepoint.
intptr_t object_hash(klassOop k) {
intptr_t hc = k->java_mirror()->mark()->hash();
return hc != markOopDesc::no_hash ? hc : os::random();
}
// Seed value used for each alternative hash calculated.
jint AltHashing::compute_seed() {
jlong nanos = os::javaTimeNanos();
jlong now = os::javaTimeMillis();
jint SEED_MATERIAL[8] = {
(jint) object_hash(SystemDictionary::String_klass()),
(jint) object_hash(SystemDictionary::System_klass()),
(jint) os::random(), // current thread isn't a java thread
(jint) (((julong)nanos) >> 32),
(jint) nanos,
(jint) (((julong)now) >> 32),
(jint) now,
(jint) (os::javaTimeNanos() >> 2)
};
return murmur3_32(SEED_MATERIAL, 8);
}
// Murmur3 hashing for Symbol
jint AltHashing::murmur3_32(jint seed, const jbyte* data, int len) {
jint h1 = seed;
int count = len;
int offset = 0;
// body
while (count >= 4) {
jint k1 = (data[offset] & 0x0FF)
| (data[offset + 1] & 0x0FF) << 8
| (data[offset + 2] & 0x0FF) << 16
| data[offset + 3] << 24;
count -= 4;
offset += 4;
k1 *= 0xcc9e2d51;
k1 = Integer_rotateLeft(k1, 15);
k1 *= 0x1b873593;
h1 ^= k1;
h1 = Integer_rotateLeft(h1, 13);
h1 = h1 * 5 + 0xe6546b64;
}
// tail
if (count > 0) {
jint k1 = 0;
switch (count) {
case 3:
k1 ^= (data[offset + 2] & 0xff) << 16;
// fall through
case 2:
k1 ^= (data[offset + 1] & 0xff) << 8;
// fall through
case 1:
k1 ^= (data[offset] & 0xff);
// fall through
default:
k1 *= 0xcc9e2d51;
k1 = Integer_rotateLeft(k1, 15);
k1 *= 0x1b873593;
h1 ^= k1;
}
}
// finalization
h1 ^= len;
// finalization mix force all bits of a hash block to avalanche
h1 ^= ((unsigned int)h1) >> 16;
h1 *= 0x85ebca6b;
h1 ^= ((unsigned int)h1) >> 13;
h1 *= 0xc2b2ae35;
h1 ^= ((unsigned int)h1) >> 16;
return h1;
}
// Murmur3 hashing for Strings
jint AltHashing::murmur3_32(jint seed, const jchar* data, int len) {
jint h1 = seed;
int off = 0;
int count = len;
// body
while (count >= 2) {
jchar d1 = data[off++] & 0xFFFF;
jchar d2 = data[off++];
jint k1 = (d1 | d2 << 16);
count -= 2;
k1 *= 0xcc9e2d51;
k1 = Integer_rotateLeft(k1, 15);
k1 *= 0x1b873593;
h1 ^= k1;
h1 = Integer_rotateLeft(h1, 13);
h1 = h1 * 5 + 0xe6546b64;
}
// tail
if (count > 0) {
int k1 = data[off];
k1 *= 0xcc9e2d51;
k1 = Integer_rotateLeft(k1, 15);
k1 *= 0x1b873593;
h1 ^= k1;
}
// finalization
h1 ^= len * 2; // (Character.SIZE / Byte.SIZE);
// finalization mix force all bits of a hash block to avalanche
h1 ^= ((unsigned int)h1) >> 16;
h1 *= 0x85ebca6b;
h1 ^= ((unsigned int)h1) >> 13;
h1 *= 0xc2b2ae35;
h1 ^= ((unsigned int)h1) >> 16;
return h1;
}
// Hash used for the seed.
jint AltHashing::murmur3_32(jint seed, const int* data, int len) {
jint h1 = seed;
int off = 0;
int end = len;
// body
while (off < end) {
jint k1 = data[off++];
k1 *= 0xcc9e2d51;
k1 = Integer_rotateLeft(k1, 15);
k1 *= 0x1b873593;
h1 ^= k1;
h1 = Integer_rotateLeft(h1, 13);
h1 = h1 * 5 + 0xe6546b64;
}
// tail (always empty, as body is always 32-bit chunks)
// finalization
h1 ^= len * 4; // (Integer.SIZE / Byte.SIZE);
// finalization mix force all bits of a hash block to avalanche
h1 ^= ((juint)h1) >> 16;
h1 *= 0x85ebca6b;
h1 ^= ((juint)h1) >> 13;
h1 *= 0xc2b2ae35;
h1 ^= ((juint)h1) >> 16;
return h1;
}
jint AltHashing::murmur3_32(const int* data, int len) {
return murmur3_32(0, data, len);
}
#ifndef PRODUCT
// Overloaded versions for internal test.
jint AltHashing::murmur3_32(const jbyte* data, int len) {
return murmur3_32(0, data, len);
}
jint AltHashing::murmur3_32(const jchar* data, int len) {
return murmur3_32(0, data, len);
}
// Internal test for alternate hashing. Translated from JDK version
// test/sun/misc/Hashing.java
static const jbyte ONE_BYTE[] = { (jbyte) 0x80};
static const jbyte TWO_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81};
static const jchar ONE_CHAR[] = { (jchar) 0x8180};
static const jbyte THREE_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82};
static const jbyte FOUR_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, (jbyte) 0x83};
static const jchar TWO_CHAR[] = { (jchar) 0x8180, (jchar) 0x8382};
static const jint ONE_INT[] = { 0x83828180};
static const jbyte SIX_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, (jbyte) 0x83, (jbyte) 0x84, (jbyte) 0x85};
static const jchar THREE_CHAR[] = { (jchar) 0x8180, (jchar) 0x8382, (jchar) 0x8584};
static const jbyte EIGHT_BYTE[] = {
(jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82,
(jbyte) 0x83, (jbyte) 0x84, (jbyte) 0x85,
(jbyte) 0x86, (jbyte) 0x87};
static const jchar FOUR_CHAR[] = {
(jchar) 0x8180, (jchar) 0x8382,
(jchar) 0x8584, (jchar) 0x8786};
static const jint TWO_INT[] = { 0x83828180, 0x87868584};
static const juint MURMUR3_32_X86_CHECK_VALUE = 0xB0F57EE3;
void AltHashing::testMurmur3_32_ByteArray() {
// printf("testMurmur3_32_ByteArray\n");
jbyte* vector = new jbyte[256];
jbyte* hashes = new jbyte[4 * 256];
for (int i = 0; i < 256; i++) {
vector[i] = (jbyte) i;
}
// Hash subranges {}, {0}, {0,1}, {0,1,2}, ..., {0,...,255}
for (int i = 0; i < 256; i++) {
jint hash = murmur3_32(256 - i, vector, i);
hashes[i * 4] = (jbyte) hash;
hashes[i * 4 + 1] = (jbyte) (((juint)hash) >> 8);
hashes[i * 4 + 2] = (jbyte) (((juint)hash) >> 16);
hashes[i * 4 + 3] = (jbyte) (((juint)hash) >> 24);
}
// hash to get const result.
juint final_hash = murmur3_32(hashes, 4*256);
assert (MURMUR3_32_X86_CHECK_VALUE == final_hash,
err_msg(
"Calculated hash result not as expected. Expected %08X got %08X\n",
MURMUR3_32_X86_CHECK_VALUE,
final_hash));
}
void AltHashing::testEquivalentHashes() {
jint jbytes, jchars, ints;
// printf("testEquivalentHashes\n");
jbytes = murmur3_32(TWO_BYTE, 2);
jchars = murmur3_32(ONE_CHAR, 1);
assert (jbytes == jchars,
err_msg("Hashes did not match. b:%08x != c:%08x\n", jbytes, jchars));
jbytes = murmur3_32(FOUR_BYTE, 4);
jchars = murmur3_32(TWO_CHAR, 2);
ints = murmur3_32(ONE_INT, 1);
assert ((jbytes == jchars) && (jbytes == ints),
err_msg("Hashes did not match. b:%08x != c:%08x != i:%08x\n", jbytes, jchars, ints));
jbytes = murmur3_32(SIX_BYTE, 6);
jchars = murmur3_32(THREE_CHAR, 3);
assert (jbytes == jchars,
err_msg("Hashes did not match. b:%08x != c:%08x\n", jbytes, jchars));
jbytes = murmur3_32(EIGHT_BYTE, 8);
jchars = murmur3_32(FOUR_CHAR, 4);
ints = murmur3_32(TWO_INT, 2);
assert ((jbytes == jchars) && (jbytes == ints),
err_msg("Hashes did not match. b:%08x != c:%08x != i:%08x\n", jbytes, jchars, ints));
}
// Returns true if the alternate hashcode is correct
void AltHashing::test_alt_hash() {
testMurmur3_32_ByteArray();
testEquivalentHashes();
}
#endif // PRODUCT

View File

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

View File

@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "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) {

View File

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

View File

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

View File

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

View File

@ -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") \

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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;

View File

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

View File

@ -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") \
\

View File

@ -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.");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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

View File

@ -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);
}
}

View File

@ -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];
}

View File

@ -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") \
\

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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)

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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 )

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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++)

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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).

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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()));

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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",

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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"

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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.

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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))) ) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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 {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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!

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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; }

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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",

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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

View File

@ -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");
}
}

View File

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

View File

@ -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()) {

View File

@ -100,6 +100,7 @@ class fieldDescriptor VALUE_OBJ_CLASS_SPEC {
bool is_field_access_watched() const { return access_flags().is_field_access_watched(); }
bool is_field_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);

View File

@ -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") \
\

View File

@ -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();
}
}

View File

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

View File

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

View File

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

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