Merge
This commit is contained in:
commit
890a1517be
@ -1,5 +1,6 @@
|
|||||||
^build/
|
^build/
|
||||||
^dist/
|
^dist/
|
||||||
|
^webrev
|
||||||
/nbproject/private/
|
/nbproject/private/
|
||||||
^src/share/tools/hsdis/build/
|
^src/share/tools/hsdis/build/
|
||||||
^src/share/tools/IdealGraphVisualizer/[a-zA-Z0-9]*/build/
|
^src/share/tools/IdealGraphVisualizer/[a-zA-Z0-9]*/build/
|
||||||
|
@ -64,7 +64,10 @@ static jmethodID listAdd_ID = 0;
|
|||||||
#define THROW_NEW_DEBUGGER_EXCEPTION(str) { throw_new_debugger_exception(env, str); return;}
|
#define THROW_NEW_DEBUGGER_EXCEPTION(str) { throw_new_debugger_exception(env, str); return;}
|
||||||
|
|
||||||
void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) {
|
void throw_new_debugger_exception(JNIEnv* env, const char* errMsg) {
|
||||||
(*env)->ThrowNew(env, (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException"), errMsg);
|
jclass clazz;
|
||||||
|
clazz = (*env)->FindClass(env, "sun/jvm/hotspot/debugger/DebuggerException");
|
||||||
|
CHECK_EXCEPTION;
|
||||||
|
(*env)->ThrowNew(env, clazz, errMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) {
|
struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj) {
|
||||||
@ -149,11 +152,14 @@ static void fillThreadsAndLoadObjects(JNIEnv* env, jobject this_obj, struct ps_p
|
|||||||
const char* name;
|
const char* name;
|
||||||
jobject loadObject;
|
jobject loadObject;
|
||||||
jobject loadObjectList;
|
jobject loadObjectList;
|
||||||
|
jstring str;
|
||||||
|
|
||||||
base = get_lib_base(ph, i);
|
base = get_lib_base(ph, i);
|
||||||
name = get_lib_name(ph, i);
|
name = get_lib_name(ph, i);
|
||||||
loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID,
|
|
||||||
(*env)->NewStringUTF(env, name), (jlong)0, (jlong)base);
|
str = (*env)->NewStringUTF(env, name);
|
||||||
|
CHECK_EXCEPTION;
|
||||||
|
loadObject = (*env)->CallObjectMethod(env, this_obj, createLoadObject_ID, str, (jlong)0, (jlong)base);
|
||||||
CHECK_EXCEPTION;
|
CHECK_EXCEPTION;
|
||||||
loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID);
|
loadObjectList = (*env)->GetObjectField(env, this_obj, loadObjectList_ID);
|
||||||
CHECK_EXCEPTION;
|
CHECK_EXCEPTION;
|
||||||
@ -298,13 +304,18 @@ JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_l
|
|||||||
JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_lookupByAddress0
|
JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_lookupByAddress0
|
||||||
(JNIEnv *env, jobject this_obj, jlong addr) {
|
(JNIEnv *env, jobject this_obj, jlong addr) {
|
||||||
uintptr_t offset;
|
uintptr_t offset;
|
||||||
|
jobject obj;
|
||||||
|
jstring str;
|
||||||
const char* sym = NULL;
|
const char* sym = NULL;
|
||||||
|
|
||||||
struct ps_prochandle* ph = get_proc_handle(env, this_obj);
|
struct ps_prochandle* ph = get_proc_handle(env, this_obj);
|
||||||
sym = symbol_for_pc(ph, (uintptr_t) addr, &offset);
|
sym = symbol_for_pc(ph, (uintptr_t) addr, &offset);
|
||||||
if (sym == NULL) return 0;
|
if (sym == NULL) return 0;
|
||||||
return (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID,
|
str = (*env)->NewStringUTF(env, sym);
|
||||||
(*env)->NewStringUTF(env, sym), (jlong)offset);
|
CHECK_EXCEPTION_(NULL);
|
||||||
|
obj = (*env)->CallObjectMethod(env, this_obj, createClosestSymbol_ID, str, (jlong)offset);
|
||||||
|
CHECK_EXCEPTION_(NULL);
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -90,7 +90,9 @@ struct DebuggerWith2Objects : DebuggerWithObject {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static void throwNewDebuggerException(JNIEnv* env, const char* errMsg) {
|
static void throwNewDebuggerException(JNIEnv* env, const char* errMsg) {
|
||||||
env->ThrowNew(env->FindClass("sun/jvm/hotspot/debugger/DebuggerException"), errMsg);
|
jclass clazz = env->FindClass("sun/jvm/hotspot/debugger/DebuggerException");
|
||||||
|
CHECK_EXCEPTION;
|
||||||
|
env->ThrowNew(clazz, errMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// JNI ids for some fields, methods
|
// JNI ids for some fields, methods
|
||||||
@ -962,6 +964,7 @@ JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLoca
|
|||||||
CHECK_EXCEPTION_(0);
|
CHECK_EXCEPTION_(0);
|
||||||
jboolean isCopy;
|
jboolean isCopy;
|
||||||
jlong* ptr = env->GetLongArrayElements(res, &isCopy);
|
jlong* ptr = env->GetLongArrayElements(res, &isCopy);
|
||||||
|
CHECK_EXCEPTION_(NULL);
|
||||||
for (int i = 0; i < NPRGREG; i++) {
|
for (int i = 0; i < NPRGREG; i++) {
|
||||||
ptr[i] = (jlong) (uintptr_t) gregs[i];
|
ptr[i] = (jlong) (uintptr_t) gregs[i];
|
||||||
}
|
}
|
||||||
@ -1253,6 +1256,7 @@ JNIEXPORT jstring JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_d
|
|||||||
(JNIEnv *env, jobject this_object, jstring name) {
|
(JNIEnv *env, jobject this_object, jstring name) {
|
||||||
jboolean isCopy;
|
jboolean isCopy;
|
||||||
const char* ptr = env->GetStringUTFChars(name, &isCopy);
|
const char* ptr = env->GetStringUTFChars(name, &isCopy);
|
||||||
|
CHECK_EXCEPTION_(NULL);
|
||||||
char buf[2*SYMBOL_BUF_SIZE + 1];
|
char buf[2*SYMBOL_BUF_SIZE + 1];
|
||||||
jstring res = 0;
|
jstring res = 0;
|
||||||
if (cplus_demangle((char*) ptr, buf, sizeof(buf)) != DEMANGLE_ESPACE) {
|
if (cplus_demangle((char*) ptr, buf, sizeof(buf)) != DEMANGLE_ESPACE) {
|
||||||
@ -1439,7 +1443,9 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_init
|
|||||||
"createClosestSymbol", "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;");
|
"createClosestSymbol", "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;");
|
||||||
CHECK_EXCEPTION;
|
CHECK_EXCEPTION;
|
||||||
|
|
||||||
listAdd_ID = env->GetMethodID(env->FindClass("java/util/List"), "add", "(Ljava/lang/Object;)Z");
|
jclass list_clazz = env->FindClass("java/util/List");
|
||||||
|
CHECK_EXCEPTION;
|
||||||
|
listAdd_ID = env->GetMethodID(list_clazz, "add", "(Ljava/lang/Object;)Z");
|
||||||
CHECK_EXCEPTION;
|
CHECK_EXCEPTION;
|
||||||
|
|
||||||
// part of the class sharing workaround
|
// part of the class sharing workaround
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -49,7 +49,6 @@ public class ArrayKlass extends Klass {
|
|||||||
higherDimension = new MetadataField(type.getAddressField("_higher_dimension"), 0);
|
higherDimension = new MetadataField(type.getAddressField("_higher_dimension"), 0);
|
||||||
lowerDimension = new MetadataField(type.getAddressField("_lower_dimension"), 0);
|
lowerDimension = new MetadataField(type.getAddressField("_lower_dimension"), 0);
|
||||||
vtableLen = new CIntField(type.getCIntegerField("_vtable_len"), 0);
|
vtableLen = new CIntField(type.getCIntegerField("_vtable_len"), 0);
|
||||||
componentMirror = new OopField(type.getOopField("_component_mirror"), 0);
|
|
||||||
javaLangCloneableName = null;
|
javaLangCloneableName = null;
|
||||||
javaLangObjectName = null;
|
javaLangObjectName = null;
|
||||||
javaIoSerializableName = null;
|
javaIoSerializableName = null;
|
||||||
@ -63,7 +62,6 @@ public class ArrayKlass extends Klass {
|
|||||||
private static MetadataField higherDimension;
|
private static MetadataField higherDimension;
|
||||||
private static MetadataField lowerDimension;
|
private static MetadataField lowerDimension;
|
||||||
private static CIntField vtableLen;
|
private static CIntField vtableLen;
|
||||||
private static OopField componentMirror;
|
|
||||||
|
|
||||||
public Klass getJavaSuper() {
|
public Klass getJavaSuper() {
|
||||||
SystemDictionary sysDict = VM.getVM().getSystemDictionary();
|
SystemDictionary sysDict = VM.getVM().getSystemDictionary();
|
||||||
@ -74,7 +72,6 @@ public class ArrayKlass extends Klass {
|
|||||||
public Klass getHigherDimension() { return (Klass) higherDimension.getValue(this); }
|
public Klass getHigherDimension() { return (Klass) higherDimension.getValue(this); }
|
||||||
public Klass getLowerDimension() { return (Klass) lowerDimension.getValue(this); }
|
public Klass getLowerDimension() { return (Klass) lowerDimension.getValue(this); }
|
||||||
public long getVtableLen() { return vtableLen.getValue(this); }
|
public long getVtableLen() { return vtableLen.getValue(this); }
|
||||||
public Oop getComponentMirror() { return componentMirror.getValue(this); }
|
|
||||||
|
|
||||||
// constant class names - javaLangCloneable, javaIoSerializable, javaLangObject
|
// constant class names - javaLangCloneable, javaIoSerializable, javaLangObject
|
||||||
// Initialized lazily to avoid initialization ordering dependencies between ArrayKlass and SymbolTable
|
// Initialized lazily to avoid initialization ordering dependencies between ArrayKlass and SymbolTable
|
||||||
@ -144,6 +141,5 @@ public class ArrayKlass extends Klass {
|
|||||||
visitor.doMetadata(higherDimension, true);
|
visitor.doMetadata(higherDimension, true);
|
||||||
visitor.doMetadata(lowerDimension, true);
|
visitor.doMetadata(lowerDimension, true);
|
||||||
visitor.doCInt(vtableLen, true);
|
visitor.doCInt(vtableLen, true);
|
||||||
visitor.doOop(componentMirror, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -337,7 +337,7 @@ export_optimized:
|
|||||||
export_product_jdk::
|
export_product_jdk::
|
||||||
$(MAKE) BUILD_FLAVOR=$(@:export_%_jdk=%) ALT_EXPORT_PATH=$(JDK_IMAGE_DIR) generic_export
|
$(MAKE) BUILD_FLAVOR=$(@:export_%_jdk=%) ALT_EXPORT_PATH=$(JDK_IMAGE_DIR) generic_export
|
||||||
export_optimized_jdk::
|
export_optimized_jdk::
|
||||||
$(MAKE) BUILD_FLAVOR=$(@:export_%_jdk=%) ALT_EXPORT_PATH=$(JDK_IMAGE_DIR) generic_export
|
$(MAKE) BUILD_FLAVOR=$(@:export_%_jdk=%) ALT_EXPORT_PATH=$(JDK_IMAGE_DIR)/$(@:export_%_jdk=%) generic_export
|
||||||
export_fastdebug_jdk::
|
export_fastdebug_jdk::
|
||||||
$(MAKE) BUILD_FLAVOR=$(@:export_%_jdk=%) ALT_EXPORT_PATH=$(JDK_IMAGE_DIR)/$(@:export_%_jdk=%) generic_export
|
$(MAKE) BUILD_FLAVOR=$(@:export_%_jdk=%) ALT_EXPORT_PATH=$(JDK_IMAGE_DIR)/$(@:export_%_jdk=%) generic_export
|
||||||
export_debug_jdk::
|
export_debug_jdk::
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -125,7 +125,6 @@ SUNWprivate_1.1 {
|
|||||||
JVM_GetClassSignature;
|
JVM_GetClassSignature;
|
||||||
JVM_GetClassSigners;
|
JVM_GetClassSigners;
|
||||||
JVM_GetClassTypeAnnotations;
|
JVM_GetClassTypeAnnotations;
|
||||||
JVM_GetComponentType;
|
|
||||||
JVM_GetDeclaredClasses;
|
JVM_GetDeclaredClasses;
|
||||||
JVM_GetDeclaringClass;
|
JVM_GetDeclaringClass;
|
||||||
JVM_GetEnclosingMethodInfo;
|
JVM_GetEnclosingMethodInfo;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -125,7 +125,6 @@ SUNWprivate_1.1 {
|
|||||||
JVM_GetClassSignature;
|
JVM_GetClassSignature;
|
||||||
JVM_GetClassSigners;
|
JVM_GetClassSigners;
|
||||||
JVM_GetClassTypeAnnotations;
|
JVM_GetClassTypeAnnotations;
|
||||||
JVM_GetComponentType;
|
|
||||||
JVM_GetDeclaredClasses;
|
JVM_GetDeclaredClasses;
|
||||||
JVM_GetDeclaringClass;
|
JVM_GetDeclaringClass;
|
||||||
JVM_GetEnclosingMethodInfo;
|
JVM_GetEnclosingMethodInfo;
|
||||||
|
@ -325,6 +325,10 @@ ifeq ($(USE_CLANG), true)
|
|||||||
else ifeq ($(shell expr $(CC_VER_MAJOR) = 5 \& $(CC_VER_MINOR) = 1), 1)
|
else ifeq ($(shell expr $(CC_VER_MAJOR) = 5 \& $(CC_VER_MINOR) = 1), 1)
|
||||||
OPT_CFLAGS/loopTransform.o += $(OPT_CFLAGS/NOOPT)
|
OPT_CFLAGS/loopTransform.o += $(OPT_CFLAGS/NOOPT)
|
||||||
OPT_CFLAGS/unsafe.o += -O1
|
OPT_CFLAGS/unsafe.o += -O1
|
||||||
|
# Clang 6.0
|
||||||
|
else ifeq ($(shell expr $(CC_VER_MAJOR) = 6 \& $(CC_VER_MINOR) = 0), 1)
|
||||||
|
OPT_CFLAGS/loopTransform.o += $(OPT_CFLAGS/NOOPT)
|
||||||
|
OPT_CFLAGS/unsafe.o += -O1
|
||||||
else
|
else
|
||||||
$(error "Update compiler workarounds for Clang $(CC_VER_MAJOR).$(CC_VER_MINOR)")
|
$(error "Update compiler workarounds for Clang $(CC_VER_MAJOR).$(CC_VER_MINOR)")
|
||||||
endif
|
endif
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -123,7 +123,6 @@
|
|||||||
_JVM_GetClassSignature
|
_JVM_GetClassSignature
|
||||||
_JVM_GetClassSigners
|
_JVM_GetClassSigners
|
||||||
_JVM_GetClassTypeAnnotations
|
_JVM_GetClassTypeAnnotations
|
||||||
_JVM_GetComponentType
|
|
||||||
_JVM_GetDeclaredClasses
|
_JVM_GetDeclaredClasses
|
||||||
_JVM_GetDeclaringClass
|
_JVM_GetDeclaringClass
|
||||||
_JVM_GetEnclosingMethodInfo
|
_JVM_GetEnclosingMethodInfo
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -123,7 +123,6 @@
|
|||||||
_JVM_GetClassSignature
|
_JVM_GetClassSignature
|
||||||
_JVM_GetClassSigners
|
_JVM_GetClassSigners
|
||||||
_JVM_GetClassTypeAnnotations
|
_JVM_GetClassTypeAnnotations
|
||||||
_JVM_GetComponentType
|
|
||||||
_JVM_GetDeclaredClasses
|
_JVM_GetDeclaredClasses
|
||||||
_JVM_GetDeclaringClass
|
_JVM_GetDeclaringClass
|
||||||
_JVM_GetEnclosingMethodInfo
|
_JVM_GetEnclosingMethodInfo
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -125,7 +125,6 @@ SUNWprivate_1.1 {
|
|||||||
JVM_GetClassSignature;
|
JVM_GetClassSignature;
|
||||||
JVM_GetClassSigners;
|
JVM_GetClassSigners;
|
||||||
JVM_GetClassTypeAnnotations;
|
JVM_GetClassTypeAnnotations;
|
||||||
JVM_GetComponentType;
|
|
||||||
JVM_GetDeclaredClasses;
|
JVM_GetDeclaredClasses;
|
||||||
JVM_GetDeclaringClass;
|
JVM_GetDeclaringClass;
|
||||||
JVM_GetEnclosingMethodInfo;
|
JVM_GetEnclosingMethodInfo;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -125,7 +125,6 @@ SUNWprivate_1.1 {
|
|||||||
JVM_GetClassSignature;
|
JVM_GetClassSignature;
|
||||||
JVM_GetClassSigners;
|
JVM_GetClassSigners;
|
||||||
JVM_GetClassTypeAnnotations;
|
JVM_GetClassTypeAnnotations;
|
||||||
JVM_GetComponentType;
|
|
||||||
JVM_GetDeclaredClasses;
|
JVM_GetDeclaredClasses;
|
||||||
JVM_GetDeclaringClass;
|
JVM_GetDeclaringClass;
|
||||||
JVM_GetEnclosingMethodInfo;
|
JVM_GetEnclosingMethodInfo;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -125,7 +125,6 @@ SUNWprivate_1.1 {
|
|||||||
JVM_GetClassSignature;
|
JVM_GetClassSignature;
|
||||||
JVM_GetClassSigners;
|
JVM_GetClassSigners;
|
||||||
JVM_GetClassTypeAnnotations;
|
JVM_GetClassTypeAnnotations;
|
||||||
JVM_GetComponentType;
|
|
||||||
JVM_GetDeclaredClasses;
|
JVM_GetDeclaredClasses;
|
||||||
JVM_GetDeclaringClass;
|
JVM_GetDeclaringClass;
|
||||||
JVM_GetEnclosingMethodInfo;
|
JVM_GetEnclosingMethodInfo;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -125,7 +125,6 @@ SUNWprivate_1.1 {
|
|||||||
JVM_GetClassSignature;
|
JVM_GetClassSignature;
|
||||||
JVM_GetClassSigners;
|
JVM_GetClassSigners;
|
||||||
JVM_GetClassTypeAnnotations;
|
JVM_GetClassTypeAnnotations;
|
||||||
JVM_GetComponentType;
|
|
||||||
JVM_GetDeclaredClasses;
|
JVM_GetDeclaredClasses;
|
||||||
JVM_GetDeclaringClass;
|
JVM_GetDeclaringClass;
|
||||||
JVM_GetEnclosingMethodInfo;
|
JVM_GetEnclosingMethodInfo;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -124,7 +124,6 @@ SUNWprivate_1.1 {
|
|||||||
JVM_GetClassNameUTF;
|
JVM_GetClassNameUTF;
|
||||||
JVM_GetClassSignature;
|
JVM_GetClassSignature;
|
||||||
JVM_GetClassSigners;
|
JVM_GetClassSigners;
|
||||||
JVM_GetComponentType;
|
|
||||||
JVM_GetClassTypeAnnotations;
|
JVM_GetClassTypeAnnotations;
|
||||||
JVM_GetDeclaredClasses;
|
JVM_GetDeclaredClasses;
|
||||||
JVM_GetDeclaringClass;
|
JVM_GetDeclaringClass;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
#
|
#
|
||||||
# This code is free software; you can redistribute it and/or modify it
|
# This code is free software; you can redistribute it and/or modify it
|
||||||
@ -53,9 +53,9 @@ ifeq ($(JRE_RELEASE_VER),1.6.0)
|
|||||||
VALIDATED_COMPILER_REVS := 5.8
|
VALIDATED_COMPILER_REVS := 5.8
|
||||||
VALIDATED_CC_COMPILER_REVS := 5.8
|
VALIDATED_CC_COMPILER_REVS := 5.8
|
||||||
else
|
else
|
||||||
# Validated compiler for JDK7 is SS12 update 1 + patches (5.10)
|
# Validated compiler for JDK9 is SS12.3 (5.12)
|
||||||
VALIDATED_COMPILER_REVS := 5.10
|
VALIDATED_COMPILER_REVS := 5.12
|
||||||
VALIDATED_CC_COMPILER_REVS := 5.10
|
VALIDATED_CC_COMPILER_REVS := 5.12
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Warning messages about not using the above validated versions
|
# Warning messages about not using the above validated versions
|
||||||
|
@ -4937,6 +4937,26 @@ void Assembler::addq(Register dst, Register src) {
|
|||||||
emit_arith(0x03, 0xC0, dst, src);
|
emit_arith(0x03, 0xC0, dst, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Assembler::adcxq(Register dst, Register src) {
|
||||||
|
//assert(VM_Version::supports_adx(), "adx instructions not supported");
|
||||||
|
emit_int8((unsigned char)0x66);
|
||||||
|
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
|
||||||
|
emit_int8(0x0F);
|
||||||
|
emit_int8(0x38);
|
||||||
|
emit_int8((unsigned char)0xF6);
|
||||||
|
emit_int8((unsigned char)(0xC0 | encode));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::adoxq(Register dst, Register src) {
|
||||||
|
//assert(VM_Version::supports_adx(), "adx instructions not supported");
|
||||||
|
emit_int8((unsigned char)0xF3);
|
||||||
|
int encode = prefixq_and_encode(dst->encoding(), src->encoding());
|
||||||
|
emit_int8(0x0F);
|
||||||
|
emit_int8(0x38);
|
||||||
|
emit_int8((unsigned char)0xF6);
|
||||||
|
emit_int8((unsigned char)(0xC0 | encode));
|
||||||
|
}
|
||||||
|
|
||||||
void Assembler::andq(Address dst, int32_t imm32) {
|
void Assembler::andq(Address dst, int32_t imm32) {
|
||||||
InstructionMark im(this);
|
InstructionMark im(this);
|
||||||
prefixq(dst);
|
prefixq(dst);
|
||||||
@ -5444,6 +5464,26 @@ void Assembler::movzwq(Register dst, Register src) {
|
|||||||
emit_int8((unsigned char)(0xC0 | encode));
|
emit_int8((unsigned char)(0xC0 | encode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Assembler::mulq(Address src) {
|
||||||
|
InstructionMark im(this);
|
||||||
|
prefixq(src);
|
||||||
|
emit_int8((unsigned char)0xF7);
|
||||||
|
emit_operand(rsp, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::mulq(Register src) {
|
||||||
|
int encode = prefixq_and_encode(src->encoding());
|
||||||
|
emit_int8((unsigned char)0xF7);
|
||||||
|
emit_int8((unsigned char)(0xE0 | encode));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::mulxq(Register dst1, Register dst2, Register src) {
|
||||||
|
assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported");
|
||||||
|
int encode = vex_prefix_and_encode(dst1->encoding(), dst2->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, true, false);
|
||||||
|
emit_int8((unsigned char)0xF6);
|
||||||
|
emit_int8((unsigned char)(0xC0 | encode));
|
||||||
|
}
|
||||||
|
|
||||||
void Assembler::negq(Register dst) {
|
void Assembler::negq(Register dst) {
|
||||||
int encode = prefixq_and_encode(dst->encoding());
|
int encode = prefixq_and_encode(dst->encoding());
|
||||||
emit_int8((unsigned char)0xF7);
|
emit_int8((unsigned char)0xF7);
|
||||||
@ -5572,6 +5612,28 @@ void Assembler::rclq(Register dst, int imm8) {
|
|||||||
emit_int8(imm8);
|
emit_int8(imm8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Assembler::rorq(Register dst, int imm8) {
|
||||||
|
assert(isShiftCount(imm8 >> 1), "illegal shift count");
|
||||||
|
int encode = prefixq_and_encode(dst->encoding());
|
||||||
|
if (imm8 == 1) {
|
||||||
|
emit_int8((unsigned char)0xD1);
|
||||||
|
emit_int8((unsigned char)(0xC8 | encode));
|
||||||
|
} else {
|
||||||
|
emit_int8((unsigned char)0xC1);
|
||||||
|
emit_int8((unsigned char)(0xc8 | encode));
|
||||||
|
emit_int8(imm8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Assembler::rorxq(Register dst, Register src, int imm8) {
|
||||||
|
assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported");
|
||||||
|
int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, true, false);
|
||||||
|
emit_int8((unsigned char)0xF0);
|
||||||
|
emit_int8((unsigned char)(0xC0 | encode));
|
||||||
|
emit_int8(imm8);
|
||||||
|
}
|
||||||
|
|
||||||
void Assembler::sarq(Register dst, int imm8) {
|
void Assembler::sarq(Register dst, int imm8) {
|
||||||
assert(isShiftCount(imm8 >> 1), "illegal shift count");
|
assert(isShiftCount(imm8 >> 1), "illegal shift count");
|
||||||
int encode = prefixq_and_encode(dst->encoding());
|
int encode = prefixq_and_encode(dst->encoding());
|
||||||
|
@ -888,6 +888,14 @@ private:
|
|||||||
void addq(Register dst, Address src);
|
void addq(Register dst, Address src);
|
||||||
void addq(Register dst, Register src);
|
void addq(Register dst, Register src);
|
||||||
|
|
||||||
|
#ifdef _LP64
|
||||||
|
//Add Unsigned Integers with Carry Flag
|
||||||
|
void adcxq(Register dst, Register src);
|
||||||
|
|
||||||
|
//Add Unsigned Integers with Overflow Flag
|
||||||
|
void adoxq(Register dst, Register src);
|
||||||
|
#endif
|
||||||
|
|
||||||
void addr_nop_4();
|
void addr_nop_4();
|
||||||
void addr_nop_5();
|
void addr_nop_5();
|
||||||
void addr_nop_7();
|
void addr_nop_7();
|
||||||
@ -1204,19 +1212,20 @@ private:
|
|||||||
void idivl(Register src);
|
void idivl(Register src);
|
||||||
void divl(Register src); // Unsigned division
|
void divl(Register src); // Unsigned division
|
||||||
|
|
||||||
|
#ifdef _LP64
|
||||||
void idivq(Register src);
|
void idivq(Register src);
|
||||||
|
#endif
|
||||||
|
|
||||||
void imull(Register dst, Register src);
|
void imull(Register dst, Register src);
|
||||||
void imull(Register dst, Register src, int value);
|
void imull(Register dst, Register src, int value);
|
||||||
void imull(Register dst, Address src);
|
void imull(Register dst, Address src);
|
||||||
|
|
||||||
|
#ifdef _LP64
|
||||||
void imulq(Register dst, Register src);
|
void imulq(Register dst, Register src);
|
||||||
void imulq(Register dst, Register src, int value);
|
void imulq(Register dst, Register src, int value);
|
||||||
#ifdef _LP64
|
|
||||||
void imulq(Register dst, Address src);
|
void imulq(Register dst, Address src);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// jcc is the generic conditional branch generator to run-
|
// jcc is the generic conditional branch generator to run-
|
||||||
// time routines, jcc is used for branches to labels. jcc
|
// time routines, jcc is used for branches to labels. jcc
|
||||||
// takes a branch opcode (cc) and a label (L) and generates
|
// takes a branch opcode (cc) and a label (L) and generates
|
||||||
@ -1408,9 +1417,16 @@ private:
|
|||||||
void movzwq(Register dst, Register src);
|
void movzwq(Register dst, Register src);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Unsigned multiply with RAX destination register
|
||||||
void mull(Address src);
|
void mull(Address src);
|
||||||
void mull(Register src);
|
void mull(Register src);
|
||||||
|
|
||||||
|
#ifdef _LP64
|
||||||
|
void mulq(Address src);
|
||||||
|
void mulq(Register src);
|
||||||
|
void mulxq(Register dst1, Register dst2, Register src);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Multiply Scalar Double-Precision Floating-Point Values
|
// Multiply Scalar Double-Precision Floating-Point Values
|
||||||
void mulsd(XMMRegister dst, Address src);
|
void mulsd(XMMRegister dst, Address src);
|
||||||
void mulsd(XMMRegister dst, XMMRegister src);
|
void mulsd(XMMRegister dst, XMMRegister src);
|
||||||
@ -1541,6 +1557,11 @@ private:
|
|||||||
|
|
||||||
void ret(int imm16);
|
void ret(int imm16);
|
||||||
|
|
||||||
|
#ifdef _LP64
|
||||||
|
void rorq(Register dst, int imm8);
|
||||||
|
void rorxq(Register dst, Register src, int imm8);
|
||||||
|
#endif
|
||||||
|
|
||||||
void sahf();
|
void sahf();
|
||||||
|
|
||||||
void sarl(Register dst, int imm8);
|
void sarl(Register dst, int imm8);
|
||||||
|
@ -176,6 +176,8 @@ define_pd_global(uintx, TypeProfileLevel, 111);
|
|||||||
"Use count trailing zeros instruction") \
|
"Use count trailing zeros instruction") \
|
||||||
\
|
\
|
||||||
product(bool, UseBMI1Instructions, false, \
|
product(bool, UseBMI1Instructions, false, \
|
||||||
"Use BMI instructions")
|
"Use BMI1 instructions") \
|
||||||
|
\
|
||||||
|
product(bool, UseBMI2Instructions, false, \
|
||||||
|
"Use BMI2 instructions")
|
||||||
#endif // CPU_X86_VM_GLOBALS_X86_HPP
|
#endif // CPU_X86_VM_GLOBALS_X86_HPP
|
||||||
|
@ -7293,6 +7293,467 @@ void MacroAssembler::encode_iso_array(Register src, Register dst, Register len,
|
|||||||
bind(L_done);
|
bind(L_done);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _LP64
|
||||||
|
/**
|
||||||
|
* Helper for multiply_to_len().
|
||||||
|
*/
|
||||||
|
void MacroAssembler::add2_with_carry(Register dest_hi, Register dest_lo, Register src1, Register src2) {
|
||||||
|
addq(dest_lo, src1);
|
||||||
|
adcq(dest_hi, 0);
|
||||||
|
addq(dest_lo, src2);
|
||||||
|
adcq(dest_hi, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiply 64 bit by 64 bit first loop.
|
||||||
|
*/
|
||||||
|
void MacroAssembler::multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart,
|
||||||
|
Register y, Register y_idx, Register z,
|
||||||
|
Register carry, Register product,
|
||||||
|
Register idx, Register kdx) {
|
||||||
|
//
|
||||||
|
// jlong carry, x[], y[], z[];
|
||||||
|
// for (int idx=ystart, kdx=ystart+1+xstart; idx >= 0; idx-, kdx--) {
|
||||||
|
// huge_128 product = y[idx] * x[xstart] + carry;
|
||||||
|
// z[kdx] = (jlong)product;
|
||||||
|
// carry = (jlong)(product >>> 64);
|
||||||
|
// }
|
||||||
|
// z[xstart] = carry;
|
||||||
|
//
|
||||||
|
|
||||||
|
Label L_first_loop, L_first_loop_exit;
|
||||||
|
Label L_one_x, L_one_y, L_multiply;
|
||||||
|
|
||||||
|
decrementl(xstart);
|
||||||
|
jcc(Assembler::negative, L_one_x);
|
||||||
|
|
||||||
|
movq(x_xstart, Address(x, xstart, Address::times_4, 0));
|
||||||
|
rorq(x_xstart, 32); // convert big-endian to little-endian
|
||||||
|
|
||||||
|
bind(L_first_loop);
|
||||||
|
decrementl(idx);
|
||||||
|
jcc(Assembler::negative, L_first_loop_exit);
|
||||||
|
decrementl(idx);
|
||||||
|
jcc(Assembler::negative, L_one_y);
|
||||||
|
movq(y_idx, Address(y, idx, Address::times_4, 0));
|
||||||
|
rorq(y_idx, 32); // convert big-endian to little-endian
|
||||||
|
bind(L_multiply);
|
||||||
|
movq(product, x_xstart);
|
||||||
|
mulq(y_idx); // product(rax) * y_idx -> rdx:rax
|
||||||
|
addq(product, carry);
|
||||||
|
adcq(rdx, 0);
|
||||||
|
subl(kdx, 2);
|
||||||
|
movl(Address(z, kdx, Address::times_4, 4), product);
|
||||||
|
shrq(product, 32);
|
||||||
|
movl(Address(z, kdx, Address::times_4, 0), product);
|
||||||
|
movq(carry, rdx);
|
||||||
|
jmp(L_first_loop);
|
||||||
|
|
||||||
|
bind(L_one_y);
|
||||||
|
movl(y_idx, Address(y, 0));
|
||||||
|
jmp(L_multiply);
|
||||||
|
|
||||||
|
bind(L_one_x);
|
||||||
|
movl(x_xstart, Address(x, 0));
|
||||||
|
jmp(L_first_loop);
|
||||||
|
|
||||||
|
bind(L_first_loop_exit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiply 64 bit by 64 bit and add 128 bit.
|
||||||
|
*/
|
||||||
|
void MacroAssembler::multiply_add_128_x_128(Register x_xstart, Register y, Register z,
|
||||||
|
Register yz_idx, Register idx,
|
||||||
|
Register carry, Register product, int offset) {
|
||||||
|
// huge_128 product = (y[idx] * x_xstart) + z[kdx] + carry;
|
||||||
|
// z[kdx] = (jlong)product;
|
||||||
|
|
||||||
|
movq(yz_idx, Address(y, idx, Address::times_4, offset));
|
||||||
|
rorq(yz_idx, 32); // convert big-endian to little-endian
|
||||||
|
movq(product, x_xstart);
|
||||||
|
mulq(yz_idx); // product(rax) * yz_idx -> rdx:product(rax)
|
||||||
|
movq(yz_idx, Address(z, idx, Address::times_4, offset));
|
||||||
|
rorq(yz_idx, 32); // convert big-endian to little-endian
|
||||||
|
|
||||||
|
add2_with_carry(rdx, product, carry, yz_idx);
|
||||||
|
|
||||||
|
movl(Address(z, idx, Address::times_4, offset+4), product);
|
||||||
|
shrq(product, 32);
|
||||||
|
movl(Address(z, idx, Address::times_4, offset), product);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiply 128 bit by 128 bit. Unrolled inner loop.
|
||||||
|
*/
|
||||||
|
void MacroAssembler::multiply_128_x_128_loop(Register x_xstart, Register y, Register z,
|
||||||
|
Register yz_idx, Register idx, Register jdx,
|
||||||
|
Register carry, Register product,
|
||||||
|
Register carry2) {
|
||||||
|
// jlong carry, x[], y[], z[];
|
||||||
|
// int kdx = ystart+1;
|
||||||
|
// for (int idx=ystart-2; idx >= 0; idx -= 2) { // Third loop
|
||||||
|
// huge_128 product = (y[idx+1] * x_xstart) + z[kdx+idx+1] + carry;
|
||||||
|
// z[kdx+idx+1] = (jlong)product;
|
||||||
|
// jlong carry2 = (jlong)(product >>> 64);
|
||||||
|
// product = (y[idx] * x_xstart) + z[kdx+idx] + carry2;
|
||||||
|
// z[kdx+idx] = (jlong)product;
|
||||||
|
// carry = (jlong)(product >>> 64);
|
||||||
|
// }
|
||||||
|
// idx += 2;
|
||||||
|
// if (idx > 0) {
|
||||||
|
// product = (y[idx] * x_xstart) + z[kdx+idx] + carry;
|
||||||
|
// z[kdx+idx] = (jlong)product;
|
||||||
|
// carry = (jlong)(product >>> 64);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
|
||||||
|
Label L_third_loop, L_third_loop_exit, L_post_third_loop_done;
|
||||||
|
|
||||||
|
movl(jdx, idx);
|
||||||
|
andl(jdx, 0xFFFFFFFC);
|
||||||
|
shrl(jdx, 2);
|
||||||
|
|
||||||
|
bind(L_third_loop);
|
||||||
|
subl(jdx, 1);
|
||||||
|
jcc(Assembler::negative, L_third_loop_exit);
|
||||||
|
subl(idx, 4);
|
||||||
|
|
||||||
|
multiply_add_128_x_128(x_xstart, y, z, yz_idx, idx, carry, product, 8);
|
||||||
|
movq(carry2, rdx);
|
||||||
|
|
||||||
|
multiply_add_128_x_128(x_xstart, y, z, yz_idx, idx, carry2, product, 0);
|
||||||
|
movq(carry, rdx);
|
||||||
|
jmp(L_third_loop);
|
||||||
|
|
||||||
|
bind (L_third_loop_exit);
|
||||||
|
|
||||||
|
andl (idx, 0x3);
|
||||||
|
jcc(Assembler::zero, L_post_third_loop_done);
|
||||||
|
|
||||||
|
Label L_check_1;
|
||||||
|
subl(idx, 2);
|
||||||
|
jcc(Assembler::negative, L_check_1);
|
||||||
|
|
||||||
|
multiply_add_128_x_128(x_xstart, y, z, yz_idx, idx, carry, product, 0);
|
||||||
|
movq(carry, rdx);
|
||||||
|
|
||||||
|
bind (L_check_1);
|
||||||
|
addl (idx, 0x2);
|
||||||
|
andl (idx, 0x1);
|
||||||
|
subl(idx, 1);
|
||||||
|
jcc(Assembler::negative, L_post_third_loop_done);
|
||||||
|
|
||||||
|
movl(yz_idx, Address(y, idx, Address::times_4, 0));
|
||||||
|
movq(product, x_xstart);
|
||||||
|
mulq(yz_idx); // product(rax) * yz_idx -> rdx:product(rax)
|
||||||
|
movl(yz_idx, Address(z, idx, Address::times_4, 0));
|
||||||
|
|
||||||
|
add2_with_carry(rdx, product, yz_idx, carry);
|
||||||
|
|
||||||
|
movl(Address(z, idx, Address::times_4, 0), product);
|
||||||
|
shrq(product, 32);
|
||||||
|
|
||||||
|
shlq(rdx, 32);
|
||||||
|
orq(product, rdx);
|
||||||
|
movq(carry, product);
|
||||||
|
|
||||||
|
bind(L_post_third_loop_done);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiply 128 bit by 128 bit using BMI2. Unrolled inner loop.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void MacroAssembler::multiply_128_x_128_bmi2_loop(Register y, Register z,
|
||||||
|
Register carry, Register carry2,
|
||||||
|
Register idx, Register jdx,
|
||||||
|
Register yz_idx1, Register yz_idx2,
|
||||||
|
Register tmp, Register tmp3, Register tmp4) {
|
||||||
|
assert(UseBMI2Instructions, "should be used only when BMI2 is available");
|
||||||
|
|
||||||
|
// jlong carry, x[], y[], z[];
|
||||||
|
// int kdx = ystart+1;
|
||||||
|
// for (int idx=ystart-2; idx >= 0; idx -= 2) { // Third loop
|
||||||
|
// huge_128 tmp3 = (y[idx+1] * rdx) + z[kdx+idx+1] + carry;
|
||||||
|
// jlong carry2 = (jlong)(tmp3 >>> 64);
|
||||||
|
// huge_128 tmp4 = (y[idx] * rdx) + z[kdx+idx] + carry2;
|
||||||
|
// carry = (jlong)(tmp4 >>> 64);
|
||||||
|
// z[kdx+idx+1] = (jlong)tmp3;
|
||||||
|
// z[kdx+idx] = (jlong)tmp4;
|
||||||
|
// }
|
||||||
|
// idx += 2;
|
||||||
|
// if (idx > 0) {
|
||||||
|
// yz_idx1 = (y[idx] * rdx) + z[kdx+idx] + carry;
|
||||||
|
// z[kdx+idx] = (jlong)yz_idx1;
|
||||||
|
// carry = (jlong)(yz_idx1 >>> 64);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
|
||||||
|
Label L_third_loop, L_third_loop_exit, L_post_third_loop_done;
|
||||||
|
|
||||||
|
movl(jdx, idx);
|
||||||
|
andl(jdx, 0xFFFFFFFC);
|
||||||
|
shrl(jdx, 2);
|
||||||
|
|
||||||
|
bind(L_third_loop);
|
||||||
|
subl(jdx, 1);
|
||||||
|
jcc(Assembler::negative, L_third_loop_exit);
|
||||||
|
subl(idx, 4);
|
||||||
|
|
||||||
|
movq(yz_idx1, Address(y, idx, Address::times_4, 8));
|
||||||
|
rorxq(yz_idx1, yz_idx1, 32); // convert big-endian to little-endian
|
||||||
|
movq(yz_idx2, Address(y, idx, Address::times_4, 0));
|
||||||
|
rorxq(yz_idx2, yz_idx2, 32);
|
||||||
|
|
||||||
|
mulxq(tmp4, tmp3, yz_idx1); // yz_idx1 * rdx -> tmp4:tmp3
|
||||||
|
mulxq(carry2, tmp, yz_idx2); // yz_idx2 * rdx -> carry2:tmp
|
||||||
|
|
||||||
|
movq(yz_idx1, Address(z, idx, Address::times_4, 8));
|
||||||
|
rorxq(yz_idx1, yz_idx1, 32);
|
||||||
|
movq(yz_idx2, Address(z, idx, Address::times_4, 0));
|
||||||
|
rorxq(yz_idx2, yz_idx2, 32);
|
||||||
|
|
||||||
|
if (VM_Version::supports_adx()) {
|
||||||
|
adcxq(tmp3, carry);
|
||||||
|
adoxq(tmp3, yz_idx1);
|
||||||
|
|
||||||
|
adcxq(tmp4, tmp);
|
||||||
|
adoxq(tmp4, yz_idx2);
|
||||||
|
|
||||||
|
movl(carry, 0); // does not affect flags
|
||||||
|
adcxq(carry2, carry);
|
||||||
|
adoxq(carry2, carry);
|
||||||
|
} else {
|
||||||
|
add2_with_carry(tmp4, tmp3, carry, yz_idx1);
|
||||||
|
add2_with_carry(carry2, tmp4, tmp, yz_idx2);
|
||||||
|
}
|
||||||
|
movq(carry, carry2);
|
||||||
|
|
||||||
|
movl(Address(z, idx, Address::times_4, 12), tmp3);
|
||||||
|
shrq(tmp3, 32);
|
||||||
|
movl(Address(z, idx, Address::times_4, 8), tmp3);
|
||||||
|
|
||||||
|
movl(Address(z, idx, Address::times_4, 4), tmp4);
|
||||||
|
shrq(tmp4, 32);
|
||||||
|
movl(Address(z, idx, Address::times_4, 0), tmp4);
|
||||||
|
|
||||||
|
jmp(L_third_loop);
|
||||||
|
|
||||||
|
bind (L_third_loop_exit);
|
||||||
|
|
||||||
|
andl (idx, 0x3);
|
||||||
|
jcc(Assembler::zero, L_post_third_loop_done);
|
||||||
|
|
||||||
|
Label L_check_1;
|
||||||
|
subl(idx, 2);
|
||||||
|
jcc(Assembler::negative, L_check_1);
|
||||||
|
|
||||||
|
movq(yz_idx1, Address(y, idx, Address::times_4, 0));
|
||||||
|
rorxq(yz_idx1, yz_idx1, 32);
|
||||||
|
mulxq(tmp4, tmp3, yz_idx1); // yz_idx1 * rdx -> tmp4:tmp3
|
||||||
|
movq(yz_idx2, Address(z, idx, Address::times_4, 0));
|
||||||
|
rorxq(yz_idx2, yz_idx2, 32);
|
||||||
|
|
||||||
|
add2_with_carry(tmp4, tmp3, carry, yz_idx2);
|
||||||
|
|
||||||
|
movl(Address(z, idx, Address::times_4, 4), tmp3);
|
||||||
|
shrq(tmp3, 32);
|
||||||
|
movl(Address(z, idx, Address::times_4, 0), tmp3);
|
||||||
|
movq(carry, tmp4);
|
||||||
|
|
||||||
|
bind (L_check_1);
|
||||||
|
addl (idx, 0x2);
|
||||||
|
andl (idx, 0x1);
|
||||||
|
subl(idx, 1);
|
||||||
|
jcc(Assembler::negative, L_post_third_loop_done);
|
||||||
|
movl(tmp4, Address(y, idx, Address::times_4, 0));
|
||||||
|
mulxq(carry2, tmp3, tmp4); // tmp4 * rdx -> carry2:tmp3
|
||||||
|
movl(tmp4, Address(z, idx, Address::times_4, 0));
|
||||||
|
|
||||||
|
add2_with_carry(carry2, tmp3, tmp4, carry);
|
||||||
|
|
||||||
|
movl(Address(z, idx, Address::times_4, 0), tmp3);
|
||||||
|
shrq(tmp3, 32);
|
||||||
|
|
||||||
|
shlq(carry2, 32);
|
||||||
|
orq(tmp3, carry2);
|
||||||
|
movq(carry, tmp3);
|
||||||
|
|
||||||
|
bind(L_post_third_loop_done);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Code for BigInteger::multiplyToLen() instrinsic.
|
||||||
|
*
|
||||||
|
* rdi: x
|
||||||
|
* rax: xlen
|
||||||
|
* rsi: y
|
||||||
|
* rcx: ylen
|
||||||
|
* r8: z
|
||||||
|
* r11: zlen
|
||||||
|
* r12: tmp1
|
||||||
|
* r13: tmp2
|
||||||
|
* r14: tmp3
|
||||||
|
* r15: tmp4
|
||||||
|
* rbx: tmp5
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, Register zlen,
|
||||||
|
Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5) {
|
||||||
|
ShortBranchVerifier sbv(this);
|
||||||
|
assert_different_registers(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, rdx);
|
||||||
|
|
||||||
|
push(tmp1);
|
||||||
|
push(tmp2);
|
||||||
|
push(tmp3);
|
||||||
|
push(tmp4);
|
||||||
|
push(tmp5);
|
||||||
|
|
||||||
|
push(xlen);
|
||||||
|
push(zlen);
|
||||||
|
|
||||||
|
const Register idx = tmp1;
|
||||||
|
const Register kdx = tmp2;
|
||||||
|
const Register xstart = tmp3;
|
||||||
|
|
||||||
|
const Register y_idx = tmp4;
|
||||||
|
const Register carry = tmp5;
|
||||||
|
const Register product = xlen;
|
||||||
|
const Register x_xstart = zlen; // reuse register
|
||||||
|
|
||||||
|
// First Loop.
|
||||||
|
//
|
||||||
|
// final static long LONG_MASK = 0xffffffffL;
|
||||||
|
// int xstart = xlen - 1;
|
||||||
|
// int ystart = ylen - 1;
|
||||||
|
// long carry = 0;
|
||||||
|
// for (int idx=ystart, kdx=ystart+1+xstart; idx >= 0; idx-, kdx--) {
|
||||||
|
// long product = (y[idx] & LONG_MASK) * (x[xstart] & LONG_MASK) + carry;
|
||||||
|
// z[kdx] = (int)product;
|
||||||
|
// carry = product >>> 32;
|
||||||
|
// }
|
||||||
|
// z[xstart] = (int)carry;
|
||||||
|
//
|
||||||
|
|
||||||
|
movl(idx, ylen); // idx = ylen;
|
||||||
|
movl(kdx, zlen); // kdx = xlen+ylen;
|
||||||
|
xorq(carry, carry); // carry = 0;
|
||||||
|
|
||||||
|
Label L_done;
|
||||||
|
|
||||||
|
movl(xstart, xlen);
|
||||||
|
decrementl(xstart);
|
||||||
|
jcc(Assembler::negative, L_done);
|
||||||
|
|
||||||
|
multiply_64_x_64_loop(x, xstart, x_xstart, y, y_idx, z, carry, product, idx, kdx);
|
||||||
|
|
||||||
|
Label L_second_loop;
|
||||||
|
testl(kdx, kdx);
|
||||||
|
jcc(Assembler::zero, L_second_loop);
|
||||||
|
|
||||||
|
Label L_carry;
|
||||||
|
subl(kdx, 1);
|
||||||
|
jcc(Assembler::zero, L_carry);
|
||||||
|
|
||||||
|
movl(Address(z, kdx, Address::times_4, 0), carry);
|
||||||
|
shrq(carry, 32);
|
||||||
|
subl(kdx, 1);
|
||||||
|
|
||||||
|
bind(L_carry);
|
||||||
|
movl(Address(z, kdx, Address::times_4, 0), carry);
|
||||||
|
|
||||||
|
// Second and third (nested) loops.
|
||||||
|
//
|
||||||
|
// for (int i = xstart-1; i >= 0; i--) { // Second loop
|
||||||
|
// carry = 0;
|
||||||
|
// for (int jdx=ystart, k=ystart+1+i; jdx >= 0; jdx--, k--) { // Third loop
|
||||||
|
// long product = (y[jdx] & LONG_MASK) * (x[i] & LONG_MASK) +
|
||||||
|
// (z[k] & LONG_MASK) + carry;
|
||||||
|
// z[k] = (int)product;
|
||||||
|
// carry = product >>> 32;
|
||||||
|
// }
|
||||||
|
// z[i] = (int)carry;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// i = xlen, j = tmp1, k = tmp2, carry = tmp5, x[i] = rdx
|
||||||
|
|
||||||
|
const Register jdx = tmp1;
|
||||||
|
|
||||||
|
bind(L_second_loop);
|
||||||
|
xorl(carry, carry); // carry = 0;
|
||||||
|
movl(jdx, ylen); // j = ystart+1
|
||||||
|
|
||||||
|
subl(xstart, 1); // i = xstart-1;
|
||||||
|
jcc(Assembler::negative, L_done);
|
||||||
|
|
||||||
|
push (z);
|
||||||
|
|
||||||
|
Label L_last_x;
|
||||||
|
lea(z, Address(z, xstart, Address::times_4, 4)); // z = z + k - j
|
||||||
|
subl(xstart, 1); // i = xstart-1;
|
||||||
|
jcc(Assembler::negative, L_last_x);
|
||||||
|
|
||||||
|
if (UseBMI2Instructions) {
|
||||||
|
movq(rdx, Address(x, xstart, Address::times_4, 0));
|
||||||
|
rorxq(rdx, rdx, 32); // convert big-endian to little-endian
|
||||||
|
} else {
|
||||||
|
movq(x_xstart, Address(x, xstart, Address::times_4, 0));
|
||||||
|
rorq(x_xstart, 32); // convert big-endian to little-endian
|
||||||
|
}
|
||||||
|
|
||||||
|
Label L_third_loop_prologue;
|
||||||
|
bind(L_third_loop_prologue);
|
||||||
|
|
||||||
|
push (x);
|
||||||
|
push (xstart);
|
||||||
|
push (ylen);
|
||||||
|
|
||||||
|
|
||||||
|
if (UseBMI2Instructions) {
|
||||||
|
multiply_128_x_128_bmi2_loop(y, z, carry, x, jdx, ylen, product, tmp2, x_xstart, tmp3, tmp4);
|
||||||
|
} else { // !UseBMI2Instructions
|
||||||
|
multiply_128_x_128_loop(x_xstart, y, z, y_idx, jdx, ylen, carry, product, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
pop(ylen);
|
||||||
|
pop(xlen);
|
||||||
|
pop(x);
|
||||||
|
pop(z);
|
||||||
|
|
||||||
|
movl(tmp3, xlen);
|
||||||
|
addl(tmp3, 1);
|
||||||
|
movl(Address(z, tmp3, Address::times_4, 0), carry);
|
||||||
|
subl(tmp3, 1);
|
||||||
|
jccb(Assembler::negative, L_done);
|
||||||
|
|
||||||
|
shrq(carry, 32);
|
||||||
|
movl(Address(z, tmp3, Address::times_4, 0), carry);
|
||||||
|
jmp(L_second_loop);
|
||||||
|
|
||||||
|
// Next infrequent code is moved outside loops.
|
||||||
|
bind(L_last_x);
|
||||||
|
if (UseBMI2Instructions) {
|
||||||
|
movl(rdx, Address(x, 0));
|
||||||
|
} else {
|
||||||
|
movl(x_xstart, Address(x, 0));
|
||||||
|
}
|
||||||
|
jmp(L_third_loop_prologue);
|
||||||
|
|
||||||
|
bind(L_done);
|
||||||
|
|
||||||
|
pop(zlen);
|
||||||
|
pop(xlen);
|
||||||
|
|
||||||
|
pop(tmp5);
|
||||||
|
pop(tmp4);
|
||||||
|
pop(tmp3);
|
||||||
|
pop(tmp2);
|
||||||
|
pop(tmp1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emits code to update CRC-32 with a byte value according to constants in table
|
* Emits code to update CRC-32 with a byte value according to constants in table
|
||||||
*
|
*
|
||||||
|
@ -1221,6 +1221,28 @@ public:
|
|||||||
XMMRegister tmp1, XMMRegister tmp2, XMMRegister tmp3,
|
XMMRegister tmp1, XMMRegister tmp2, XMMRegister tmp3,
|
||||||
XMMRegister tmp4, Register tmp5, Register result);
|
XMMRegister tmp4, Register tmp5, Register result);
|
||||||
|
|
||||||
|
#ifdef _LP64
|
||||||
|
void add2_with_carry(Register dest_hi, Register dest_lo, Register src1, Register src2);
|
||||||
|
void multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart,
|
||||||
|
Register y, Register y_idx, Register z,
|
||||||
|
Register carry, Register product,
|
||||||
|
Register idx, Register kdx);
|
||||||
|
void multiply_add_128_x_128(Register x_xstart, Register y, Register z,
|
||||||
|
Register yz_idx, Register idx,
|
||||||
|
Register carry, Register product, int offset);
|
||||||
|
void multiply_128_x_128_bmi2_loop(Register y, Register z,
|
||||||
|
Register carry, Register carry2,
|
||||||
|
Register idx, Register jdx,
|
||||||
|
Register yz_idx1, Register yz_idx2,
|
||||||
|
Register tmp, Register tmp3, Register tmp4);
|
||||||
|
void multiply_128_x_128_loop(Register x_xstart, Register y, Register z,
|
||||||
|
Register yz_idx, Register idx, Register jdx,
|
||||||
|
Register carry, Register product,
|
||||||
|
Register carry2);
|
||||||
|
void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, Register zlen,
|
||||||
|
Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5);
|
||||||
|
#endif
|
||||||
|
|
||||||
// CRC32 code for java.util.zip.CRC32::updateBytes() instrinsic.
|
// CRC32 code for java.util.zip.CRC32::updateBytes() instrinsic.
|
||||||
void update_byte_crc32(Register crc, Register val, Register table);
|
void update_byte_crc32(Register crc, Register val, Register table);
|
||||||
void kernel_crc32(Register crc, Register buf, Register len, Register table, Register tmp);
|
void kernel_crc32(Register crc, Register buf, Register len, Register table, Register tmp);
|
||||||
|
@ -3677,6 +3677,70 @@ class StubGenerator: public StubCodeGenerator {
|
|||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Arguments:
|
||||||
|
*
|
||||||
|
* Input:
|
||||||
|
* c_rarg0 - x address
|
||||||
|
* c_rarg1 - x length
|
||||||
|
* c_rarg2 - y address
|
||||||
|
* c_rarg3 - y lenth
|
||||||
|
* not Win64
|
||||||
|
* c_rarg4 - z address
|
||||||
|
* c_rarg5 - z length
|
||||||
|
* Win64
|
||||||
|
* rsp+40 - z address
|
||||||
|
* rsp+48 - z length
|
||||||
|
*/
|
||||||
|
address generate_multiplyToLen() {
|
||||||
|
__ align(CodeEntryAlignment);
|
||||||
|
StubCodeMark mark(this, "StubRoutines", "multiplyToLen");
|
||||||
|
|
||||||
|
address start = __ pc();
|
||||||
|
// Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...)
|
||||||
|
// Unix: rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...)
|
||||||
|
const Register x = rdi;
|
||||||
|
const Register xlen = rax;
|
||||||
|
const Register y = rsi;
|
||||||
|
const Register ylen = rcx;
|
||||||
|
const Register z = r8;
|
||||||
|
const Register zlen = r11;
|
||||||
|
|
||||||
|
// Next registers will be saved on stack in multiply_to_len().
|
||||||
|
const Register tmp1 = r12;
|
||||||
|
const Register tmp2 = r13;
|
||||||
|
const Register tmp3 = r14;
|
||||||
|
const Register tmp4 = r15;
|
||||||
|
const Register tmp5 = rbx;
|
||||||
|
|
||||||
|
BLOCK_COMMENT("Entry:");
|
||||||
|
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
||||||
|
|
||||||
|
#ifndef _WIN64
|
||||||
|
__ movptr(zlen, r9); // Save r9 in r11 - zlen
|
||||||
|
#endif
|
||||||
|
setup_arg_regs(4); // x => rdi, xlen => rsi, y => rdx
|
||||||
|
// ylen => rcx, z => r8, zlen => r11
|
||||||
|
// r9 and r10 may be used to save non-volatile registers
|
||||||
|
#ifdef _WIN64
|
||||||
|
// last 2 arguments (#4, #5) are on stack on Win64
|
||||||
|
__ movptr(z, Address(rsp, 6 * wordSize));
|
||||||
|
__ movptr(zlen, Address(rsp, 7 * wordSize));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__ movptr(xlen, rsi);
|
||||||
|
__ movptr(y, rdx);
|
||||||
|
__ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5);
|
||||||
|
|
||||||
|
restore_arg_regs();
|
||||||
|
|
||||||
|
__ leave(); // required for proper stackwalking of RuntimeStub frame
|
||||||
|
__ ret(0);
|
||||||
|
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
#undef __
|
#undef __
|
||||||
#define __ masm->
|
#define __ masm->
|
||||||
|
|
||||||
@ -3917,6 +3981,11 @@ class StubGenerator: public StubCodeGenerator {
|
|||||||
generate_safefetch("SafeFetchN", sizeof(intptr_t), &StubRoutines::_safefetchN_entry,
|
generate_safefetch("SafeFetchN", sizeof(intptr_t), &StubRoutines::_safefetchN_entry,
|
||||||
&StubRoutines::_safefetchN_fault_pc,
|
&StubRoutines::_safefetchN_fault_pc,
|
||||||
&StubRoutines::_safefetchN_continuation_pc);
|
&StubRoutines::_safefetchN_continuation_pc);
|
||||||
|
#ifdef COMPILER2
|
||||||
|
if (UseMultiplyToLenIntrinsic) {
|
||||||
|
StubRoutines::_multiplyToLen = generate_multiplyToLen();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -485,7 +485,7 @@ void VM_Version::get_processor_features() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char buf[256];
|
char buf[256];
|
||||||
jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
|
||||||
cores_per_cpu(), threads_per_core(),
|
cores_per_cpu(), threads_per_core(),
|
||||||
cpu_family(), _model, _stepping,
|
cpu_family(), _model, _stepping,
|
||||||
(supports_cmov() ? ", cmov" : ""),
|
(supports_cmov() ? ", cmov" : ""),
|
||||||
@ -514,7 +514,8 @@ void VM_Version::get_processor_features() {
|
|||||||
(supports_tscinv_bit() ? ", tscinvbit": ""),
|
(supports_tscinv_bit() ? ", tscinvbit": ""),
|
||||||
(supports_tscinv() ? ", tscinv": ""),
|
(supports_tscinv() ? ", tscinv": ""),
|
||||||
(supports_bmi1() ? ", bmi1" : ""),
|
(supports_bmi1() ? ", bmi1" : ""),
|
||||||
(supports_bmi2() ? ", bmi2" : ""));
|
(supports_bmi2() ? ", bmi2" : ""),
|
||||||
|
(supports_adx() ? ", adx" : ""));
|
||||||
_features_str = os::strdup(buf);
|
_features_str = os::strdup(buf);
|
||||||
|
|
||||||
// UseSSE is set to the smaller of what hardware supports and what
|
// UseSSE is set to the smaller of what hardware supports and what
|
||||||
@ -566,7 +567,7 @@ void VM_Version::get_processor_features() {
|
|||||||
}
|
}
|
||||||
} else if (UseCRC32Intrinsics) {
|
} else if (UseCRC32Intrinsics) {
|
||||||
if (!FLAG_IS_DEFAULT(UseCRC32Intrinsics))
|
if (!FLAG_IS_DEFAULT(UseCRC32Intrinsics))
|
||||||
warning("CRC32 Intrinsics requires AVX and CLMUL instructions (not available on this CPU)");
|
warning("CRC32 Intrinsics requires CLMUL instructions (not available on this CPU)");
|
||||||
FLAG_SET_DEFAULT(UseCRC32Intrinsics, false);
|
FLAG_SET_DEFAULT(UseCRC32Intrinsics, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -689,7 +690,20 @@ void VM_Version::get_processor_features() {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _LP64
|
||||||
|
if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
|
||||||
|
UseMultiplyToLenIntrinsic = true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (UseMultiplyToLenIntrinsic) {
|
||||||
|
if (!FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
|
||||||
|
warning("multiplyToLen intrinsic is not available in 32-bit VM");
|
||||||
|
}
|
||||||
|
FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, false);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
#endif // COMPILER2
|
||||||
|
|
||||||
// On new cpus instructions which update whole XMM register should be used
|
// On new cpus instructions which update whole XMM register should be used
|
||||||
// to prevent partial register stall due to dependencies on high half.
|
// to prevent partial register stall due to dependencies on high half.
|
||||||
@ -832,6 +846,9 @@ void VM_Version::get_processor_features() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(FLAG_IS_DEFAULT(AllocatePrefetchInstr) && supports_3dnow_prefetch()) {
|
||||||
|
AllocatePrefetchInstr = 3;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use count leading zeros count instruction if available.
|
// Use count leading zeros count instruction if available.
|
||||||
@ -844,25 +861,37 @@ void VM_Version::get_processor_features() {
|
|||||||
FLAG_SET_DEFAULT(UseCountLeadingZerosInstruction, false);
|
FLAG_SET_DEFAULT(UseCountLeadingZerosInstruction, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (supports_bmi1()) {
|
|
||||||
if (FLAG_IS_DEFAULT(UseBMI1Instructions)) {
|
|
||||||
UseBMI1Instructions = true;
|
|
||||||
}
|
|
||||||
} else if (UseBMI1Instructions) {
|
|
||||||
warning("BMI1 instructions are not available on this CPU");
|
|
||||||
FLAG_SET_DEFAULT(UseBMI1Instructions, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use count trailing zeros instruction if available
|
// Use count trailing zeros instruction if available
|
||||||
if (supports_bmi1()) {
|
if (supports_bmi1()) {
|
||||||
|
// tzcnt does not require VEX prefix
|
||||||
if (FLAG_IS_DEFAULT(UseCountTrailingZerosInstruction)) {
|
if (FLAG_IS_DEFAULT(UseCountTrailingZerosInstruction)) {
|
||||||
UseCountTrailingZerosInstruction = UseBMI1Instructions;
|
UseCountTrailingZerosInstruction = true;
|
||||||
}
|
}
|
||||||
} else if (UseCountTrailingZerosInstruction) {
|
} else if (UseCountTrailingZerosInstruction) {
|
||||||
warning("tzcnt instruction is not available on this CPU");
|
warning("tzcnt instruction is not available on this CPU");
|
||||||
FLAG_SET_DEFAULT(UseCountTrailingZerosInstruction, false);
|
FLAG_SET_DEFAULT(UseCountTrailingZerosInstruction, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// BMI instructions use an encoding with VEX prefix.
|
||||||
|
// VEX prefix is generated only when AVX > 0.
|
||||||
|
if (supports_bmi1() && supports_avx()) {
|
||||||
|
if (FLAG_IS_DEFAULT(UseBMI1Instructions)) {
|
||||||
|
UseBMI1Instructions = true;
|
||||||
|
}
|
||||||
|
} else if (UseBMI1Instructions) {
|
||||||
|
warning("BMI1 instructions are not available on this CPU (AVX is also required)");
|
||||||
|
FLAG_SET_DEFAULT(UseBMI1Instructions, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (supports_bmi2() && supports_avx()) {
|
||||||
|
if (FLAG_IS_DEFAULT(UseBMI2Instructions)) {
|
||||||
|
UseBMI2Instructions = true;
|
||||||
|
}
|
||||||
|
} else if (UseBMI2Instructions) {
|
||||||
|
warning("BMI2 instructions are not available on this CPU (AVX is also required)");
|
||||||
|
FLAG_SET_DEFAULT(UseBMI2Instructions, false);
|
||||||
|
}
|
||||||
|
|
||||||
// Use population count instruction if available.
|
// Use population count instruction if available.
|
||||||
if (supports_popcnt()) {
|
if (supports_popcnt()) {
|
||||||
if (FLAG_IS_DEFAULT(UsePopCountInstruction)) {
|
if (FLAG_IS_DEFAULT(UsePopCountInstruction)) {
|
||||||
|
@ -209,7 +209,9 @@ public:
|
|||||||
erms : 1,
|
erms : 1,
|
||||||
: 1,
|
: 1,
|
||||||
rtm : 1,
|
rtm : 1,
|
||||||
: 20;
|
: 7,
|
||||||
|
adx : 1,
|
||||||
|
: 12;
|
||||||
} bits;
|
} bits;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -260,7 +262,8 @@ protected:
|
|||||||
CPU_CLMUL = (1 << 21), // carryless multiply for CRC
|
CPU_CLMUL = (1 << 21), // carryless multiply for CRC
|
||||||
CPU_BMI1 = (1 << 22),
|
CPU_BMI1 = (1 << 22),
|
||||||
CPU_BMI2 = (1 << 23),
|
CPU_BMI2 = (1 << 23),
|
||||||
CPU_RTM = (1 << 24) // Restricted Transactional Memory instructions
|
CPU_RTM = (1 << 24), // Restricted Transactional Memory instructions
|
||||||
|
CPU_ADX = (1 << 25)
|
||||||
} cpuFeatureFlags;
|
} cpuFeatureFlags;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -465,10 +468,16 @@ protected:
|
|||||||
}
|
}
|
||||||
// Intel features.
|
// Intel features.
|
||||||
if(is_intel()) {
|
if(is_intel()) {
|
||||||
|
if(_cpuid_info.sef_cpuid7_ebx.bits.adx != 0)
|
||||||
|
result |= CPU_ADX;
|
||||||
if(_cpuid_info.sef_cpuid7_ebx.bits.bmi2 != 0)
|
if(_cpuid_info.sef_cpuid7_ebx.bits.bmi2 != 0)
|
||||||
result |= CPU_BMI2;
|
result |= CPU_BMI2;
|
||||||
if(_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0)
|
if(_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0)
|
||||||
result |= CPU_LZCNT;
|
result |= CPU_LZCNT;
|
||||||
|
// for Intel, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw
|
||||||
|
if (_cpuid_info.ext_cpuid1_ecx.bits.misalignsse != 0) {
|
||||||
|
result |= CPU_3DNOW_PREFETCH;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -625,6 +634,7 @@ public:
|
|||||||
static bool supports_rtm() { return (_cpuFeatures & CPU_RTM) != 0; }
|
static bool supports_rtm() { return (_cpuFeatures & CPU_RTM) != 0; }
|
||||||
static bool supports_bmi1() { return (_cpuFeatures & CPU_BMI1) != 0; }
|
static bool supports_bmi1() { return (_cpuFeatures & CPU_BMI1) != 0; }
|
||||||
static bool supports_bmi2() { return (_cpuFeatures & CPU_BMI2) != 0; }
|
static bool supports_bmi2() { return (_cpuFeatures & CPU_BMI2) != 0; }
|
||||||
|
static bool supports_adx() { return (_cpuFeatures & CPU_ADX) != 0; }
|
||||||
// Intel features
|
// Intel features
|
||||||
static bool is_intel_family_core() { return is_intel() &&
|
static bool is_intel_family_core() { return is_intel() &&
|
||||||
extended_cpu_family() == CPU_FAMILY_INTEL_CORE; }
|
extended_cpu_family() == CPU_FAMILY_INTEL_CORE; }
|
||||||
|
@ -1678,14 +1678,9 @@ void os::print_dll_info(outputStream *st) {
|
|||||||
|
|
||||||
dlclose(handle);
|
dlclose(handle);
|
||||||
#elif defined(__APPLE__)
|
#elif defined(__APPLE__)
|
||||||
uint32_t count;
|
for (uint32_t i = 1; i < _dyld_image_count(); i++) {
|
||||||
uint32_t i;
|
st->print_cr(PTR_FORMAT " \t%s", _dyld_get_image_header(i),
|
||||||
|
_dyld_get_image_name(i));
|
||||||
count = _dyld_image_count();
|
|
||||||
for (i = 1; i < count; i++) {
|
|
||||||
const char *name = _dyld_get_image_name(i);
|
|
||||||
intptr_t slide = _dyld_get_image_vmaddr_slide(i);
|
|
||||||
st->print_cr(PTR_FORMAT " \t%s", slide, name);
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
st->print_cr("Error: Cannot print dynamic libraries.");
|
st->print_cr("Error: Cannot print dynamic libraries.");
|
||||||
|
@ -134,6 +134,10 @@ CodeBuffer::~CodeBuffer() {
|
|||||||
// free any overflow storage
|
// free any overflow storage
|
||||||
delete _overflow_arena;
|
delete _overflow_arena;
|
||||||
|
|
||||||
|
// Claim is that stack allocation ensures resources are cleaned up.
|
||||||
|
// This is resource clean up, let's hope that all were properly copied out.
|
||||||
|
free_strings();
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
// Save allocation type to execute assert in ~ResourceObj()
|
// Save allocation type to execute assert in ~ResourceObj()
|
||||||
// which is called after this destructor.
|
// which is called after this destructor.
|
||||||
@ -705,7 +709,7 @@ void CodeBuffer::copy_code_to(CodeBlob* dest_blob) {
|
|||||||
relocate_code_to(&dest);
|
relocate_code_to(&dest);
|
||||||
|
|
||||||
// transfer strings and comments from buffer to blob
|
// transfer strings and comments from buffer to blob
|
||||||
dest_blob->set_strings(_strings);
|
dest_blob->set_strings(_code_strings);
|
||||||
|
|
||||||
// Done moving code bytes; were they the right size?
|
// Done moving code bytes; were they the right size?
|
||||||
assert(round_to(dest.total_content_size(), oopSize) == dest_blob->content_size(), "sanity");
|
assert(round_to(dest.total_content_size(), oopSize) == dest_blob->content_size(), "sanity");
|
||||||
@ -1005,11 +1009,11 @@ void CodeSection::decode() {
|
|||||||
|
|
||||||
|
|
||||||
void CodeBuffer::block_comment(intptr_t offset, const char * comment) {
|
void CodeBuffer::block_comment(intptr_t offset, const char * comment) {
|
||||||
_strings.add_comment(offset, comment);
|
_code_strings.add_comment(offset, comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* CodeBuffer::code_string(const char* str) {
|
const char* CodeBuffer::code_string(const char* str) {
|
||||||
return _strings.add_string(str);
|
return _code_strings.add_string(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
class CodeString: public CHeapObj<mtCode> {
|
class CodeString: public CHeapObj<mtCode> {
|
||||||
@ -1075,6 +1079,7 @@ CodeString* CodeStrings::find_last(intptr_t offset) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CodeStrings::add_comment(intptr_t offset, const char * comment) {
|
void CodeStrings::add_comment(intptr_t offset, const char * comment) {
|
||||||
|
check_valid();
|
||||||
CodeString* c = new CodeString(comment, offset);
|
CodeString* c = new CodeString(comment, offset);
|
||||||
CodeString* inspos = (_strings == NULL) ? NULL : find_last(offset);
|
CodeString* inspos = (_strings == NULL) ? NULL : find_last(offset);
|
||||||
|
|
||||||
@ -1090,11 +1095,32 @@ void CodeStrings::add_comment(intptr_t offset, const char * comment) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CodeStrings::assign(CodeStrings& other) {
|
void CodeStrings::assign(CodeStrings& other) {
|
||||||
|
other.check_valid();
|
||||||
|
// Cannot do following because CodeStrings constructor is not alway run!
|
||||||
|
assert(is_null(), "Cannot assign onto non-empty CodeStrings");
|
||||||
_strings = other._strings;
|
_strings = other._strings;
|
||||||
|
other.set_null_and_invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deep copy of CodeStrings for consistent memory management.
|
||||||
|
// Only used for actual disassembly so this is cheaper than reference counting
|
||||||
|
// for the "normal" fastdebug case.
|
||||||
|
void CodeStrings::copy(CodeStrings& other) {
|
||||||
|
other.check_valid();
|
||||||
|
check_valid();
|
||||||
|
assert(is_null(), "Cannot copy onto non-empty CodeStrings");
|
||||||
|
CodeString* n = other._strings;
|
||||||
|
CodeString** ps = &_strings;
|
||||||
|
while (n != NULL) {
|
||||||
|
*ps = new CodeString(n->string(),n->offset());
|
||||||
|
ps = &((*ps)->_next);
|
||||||
|
n = n->next();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeStrings::print_block_comment(outputStream* stream, intptr_t offset) const {
|
void CodeStrings::print_block_comment(outputStream* stream, intptr_t offset) const {
|
||||||
if (_strings != NULL) {
|
check_valid();
|
||||||
|
if (_strings != NULL) {
|
||||||
CodeString* c = find(offset);
|
CodeString* c = find(offset);
|
||||||
while (c && c->offset() == offset) {
|
while (c && c->offset() == offset) {
|
||||||
stream->bol();
|
stream->bol();
|
||||||
@ -1105,7 +1131,7 @@ void CodeStrings::print_block_comment(outputStream* stream, intptr_t offset) con
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also sets isNull()
|
||||||
void CodeStrings::free() {
|
void CodeStrings::free() {
|
||||||
CodeString* n = _strings;
|
CodeString* n = _strings;
|
||||||
while (n) {
|
while (n) {
|
||||||
@ -1115,10 +1141,11 @@ void CodeStrings::free() {
|
|||||||
delete n;
|
delete n;
|
||||||
n = p;
|
n = p;
|
||||||
}
|
}
|
||||||
_strings = NULL;
|
set_null_and_invalidate();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* CodeStrings::add_string(const char * string) {
|
const char* CodeStrings::add_string(const char * string) {
|
||||||
|
check_valid();
|
||||||
CodeString* s = new CodeString(string);
|
CodeString* s = new CodeString(string);
|
||||||
s->set_next(_strings);
|
s->set_next(_strings);
|
||||||
_strings = s;
|
_strings = s;
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "code/oopRecorder.hpp"
|
#include "code/oopRecorder.hpp"
|
||||||
#include "code/relocInfo.hpp"
|
#include "code/relocInfo.hpp"
|
||||||
|
#include "utilities/debug.hpp"
|
||||||
|
|
||||||
class CodeStrings;
|
class CodeStrings;
|
||||||
class PhaseCFG;
|
class PhaseCFG;
|
||||||
@ -245,15 +246,39 @@ class CodeStrings VALUE_OBJ_CLASS_SPEC {
|
|||||||
private:
|
private:
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
CodeString* _strings;
|
CodeString* _strings;
|
||||||
|
#ifdef ASSERT
|
||||||
|
// Becomes true after copy-out, forbids further use.
|
||||||
|
bool _defunct; // Zero bit pattern is "valid", see memset call in decode_env::decode_env
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CodeString* find(intptr_t offset) const;
|
CodeString* find(intptr_t offset) const;
|
||||||
CodeString* find_last(intptr_t offset) const;
|
CodeString* find_last(intptr_t offset) const;
|
||||||
|
|
||||||
|
void set_null_and_invalidate() {
|
||||||
|
#ifndef PRODUCT
|
||||||
|
_strings = NULL;
|
||||||
|
#ifdef ASSERT
|
||||||
|
_defunct = true;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CodeStrings() {
|
CodeStrings() {
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
_strings = NULL;
|
_strings = NULL;
|
||||||
|
#ifdef ASSERT
|
||||||
|
_defunct = false;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_null() {
|
||||||
|
#ifdef ASSERT
|
||||||
|
return _strings == NULL;
|
||||||
|
#else
|
||||||
|
return true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,8 +286,17 @@ public:
|
|||||||
|
|
||||||
void add_comment(intptr_t offset, const char * comment) PRODUCT_RETURN;
|
void add_comment(intptr_t offset, const char * comment) PRODUCT_RETURN;
|
||||||
void print_block_comment(outputStream* stream, intptr_t offset) const PRODUCT_RETURN;
|
void print_block_comment(outputStream* stream, intptr_t offset) const PRODUCT_RETURN;
|
||||||
|
// MOVE strings from other to this; invalidate other.
|
||||||
void assign(CodeStrings& other) PRODUCT_RETURN;
|
void assign(CodeStrings& other) PRODUCT_RETURN;
|
||||||
|
// COPY strings from other to this; leave other valid.
|
||||||
|
void copy(CodeStrings& other) PRODUCT_RETURN;
|
||||||
void free() PRODUCT_RETURN;
|
void free() PRODUCT_RETURN;
|
||||||
|
// Guarantee that _strings are used at most once; assign invalidates a buffer.
|
||||||
|
inline void check_valid() const {
|
||||||
|
#ifdef ASSERT
|
||||||
|
assert(!_defunct, "Use of invalid CodeStrings");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// A CodeBuffer describes a memory space into which assembly
|
// A CodeBuffer describes a memory space into which assembly
|
||||||
@ -330,7 +364,7 @@ class CodeBuffer: public StackObj {
|
|||||||
csize_t _total_size; // size in bytes of combined memory buffer
|
csize_t _total_size; // size in bytes of combined memory buffer
|
||||||
|
|
||||||
OopRecorder* _oop_recorder;
|
OopRecorder* _oop_recorder;
|
||||||
CodeStrings _strings;
|
CodeStrings _code_strings;
|
||||||
OopRecorder _default_oop_recorder; // override with initialize_oop_recorder
|
OopRecorder _default_oop_recorder; // override with initialize_oop_recorder
|
||||||
Arena* _overflow_arena;
|
Arena* _overflow_arena;
|
||||||
|
|
||||||
@ -531,7 +565,13 @@ class CodeBuffer: public StackObj {
|
|||||||
void initialize_oop_recorder(OopRecorder* r);
|
void initialize_oop_recorder(OopRecorder* r);
|
||||||
|
|
||||||
OopRecorder* oop_recorder() const { return _oop_recorder; }
|
OopRecorder* oop_recorder() const { return _oop_recorder; }
|
||||||
CodeStrings& strings() { return _strings; }
|
CodeStrings& strings() { return _code_strings; }
|
||||||
|
|
||||||
|
void free_strings() {
|
||||||
|
if (!_code_strings.is_null()) {
|
||||||
|
_code_strings.free(); // sets _strings Null as a side-effect.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Code generation
|
// Code generation
|
||||||
void relocate(address at, RelocationHolder const& rspec, int format = 0) {
|
void relocate(address at, RelocationHolder const& rspec, int format = 0) {
|
||||||
|
@ -275,4 +275,101 @@ inline void assert_different_registers(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void assert_different_registers(
|
||||||
|
AbstractRegister a,
|
||||||
|
AbstractRegister b,
|
||||||
|
AbstractRegister c,
|
||||||
|
AbstractRegister d,
|
||||||
|
AbstractRegister e,
|
||||||
|
AbstractRegister f,
|
||||||
|
AbstractRegister g,
|
||||||
|
AbstractRegister h,
|
||||||
|
AbstractRegister i,
|
||||||
|
AbstractRegister j
|
||||||
|
) {
|
||||||
|
assert(
|
||||||
|
a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i && a != j
|
||||||
|
&& b != c && b != d && b != e && b != f && b != g && b != h && b != i && b != j
|
||||||
|
&& c != d && c != e && c != f && c != g && c != h && c != i && c != j
|
||||||
|
&& d != e && d != f && d != g && d != h && d != i && d != j
|
||||||
|
&& e != f && e != g && e != h && e != i && e != j
|
||||||
|
&& f != g && f != h && f != i && f != j
|
||||||
|
&& g != h && g != i && g != j
|
||||||
|
&& h != i && h != j
|
||||||
|
&& i != j,
|
||||||
|
err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT
|
||||||
|
", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT
|
||||||
|
", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT
|
||||||
|
", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT "",
|
||||||
|
p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void assert_different_registers(
|
||||||
|
AbstractRegister a,
|
||||||
|
AbstractRegister b,
|
||||||
|
AbstractRegister c,
|
||||||
|
AbstractRegister d,
|
||||||
|
AbstractRegister e,
|
||||||
|
AbstractRegister f,
|
||||||
|
AbstractRegister g,
|
||||||
|
AbstractRegister h,
|
||||||
|
AbstractRegister i,
|
||||||
|
AbstractRegister j,
|
||||||
|
AbstractRegister k
|
||||||
|
) {
|
||||||
|
assert(
|
||||||
|
a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i && a != j && a !=k
|
||||||
|
&& b != c && b != d && b != e && b != f && b != g && b != h && b != i && b != j && b !=k
|
||||||
|
&& c != d && c != e && c != f && c != g && c != h && c != i && c != j && c !=k
|
||||||
|
&& d != e && d != f && d != g && d != h && d != i && d != j && d !=k
|
||||||
|
&& e != f && e != g && e != h && e != i && e != j && e !=k
|
||||||
|
&& f != g && f != h && f != i && f != j && f !=k
|
||||||
|
&& g != h && g != i && g != j && g !=k
|
||||||
|
&& h != i && h != j && h !=k
|
||||||
|
&& i != j && i !=k
|
||||||
|
&& j !=k,
|
||||||
|
err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT
|
||||||
|
", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT
|
||||||
|
", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT
|
||||||
|
", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT ", k=" INTPTR_FORMAT "",
|
||||||
|
p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j), p2i(k))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void assert_different_registers(
|
||||||
|
AbstractRegister a,
|
||||||
|
AbstractRegister b,
|
||||||
|
AbstractRegister c,
|
||||||
|
AbstractRegister d,
|
||||||
|
AbstractRegister e,
|
||||||
|
AbstractRegister f,
|
||||||
|
AbstractRegister g,
|
||||||
|
AbstractRegister h,
|
||||||
|
AbstractRegister i,
|
||||||
|
AbstractRegister j,
|
||||||
|
AbstractRegister k,
|
||||||
|
AbstractRegister l
|
||||||
|
) {
|
||||||
|
assert(
|
||||||
|
a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i && a != j && a !=k && a !=l
|
||||||
|
&& b != c && b != d && b != e && b != f && b != g && b != h && b != i && b != j && b !=k && b !=l
|
||||||
|
&& c != d && c != e && c != f && c != g && c != h && c != i && c != j && c !=k && c !=l
|
||||||
|
&& d != e && d != f && d != g && d != h && d != i && d != j && d !=k && d !=l
|
||||||
|
&& e != f && e != g && e != h && e != i && e != j && e !=k && e !=l
|
||||||
|
&& f != g && f != h && f != i && f != j && f !=k && f !=l
|
||||||
|
&& g != h && g != i && g != j && g !=k && g !=l
|
||||||
|
&& h != i && h != j && h !=k && h !=l
|
||||||
|
&& i != j && i !=k && i !=l
|
||||||
|
&& j !=k && j !=l
|
||||||
|
&& k !=l,
|
||||||
|
err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT
|
||||||
|
", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT
|
||||||
|
", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT
|
||||||
|
", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT ", k=" INTPTR_FORMAT
|
||||||
|
", l=" INTPTR_FORMAT "",
|
||||||
|
p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j), p2i(k), p2i(l))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#endif // SHARE_VM_ASM_REGISTER_HPP
|
#endif // SHARE_VM_ASM_REGISTER_HPP
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -52,11 +52,6 @@ public:
|
|||||||
ciType* base_element_type(); // JLS calls this the "element type"
|
ciType* base_element_type(); // JLS calls this the "element type"
|
||||||
bool is_leaf_type(); // No subtypes of this array type.
|
bool is_leaf_type(); // No subtypes of this array type.
|
||||||
|
|
||||||
ciInstance* component_mirror() {
|
|
||||||
// This is a real field in ArrayKlass, but we derive it from element_type.
|
|
||||||
return element_type()->java_mirror();
|
|
||||||
}
|
|
||||||
|
|
||||||
// What kind of vmObject is this?
|
// What kind of vmObject is this?
|
||||||
bool is_array_klass() const { return true; }
|
bool is_array_klass() const { return true; }
|
||||||
bool is_java_klass() const { return true; }
|
bool is_java_klass() const { return true; }
|
||||||
|
@ -1101,6 +1101,22 @@ bool ciMethod::has_option(const char* option) {
|
|||||||
return CompilerOracle::has_option_string(mh, option);
|
return CompilerOracle::has_option_string(mh, option);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------
|
||||||
|
// ciMethod::has_option_value
|
||||||
|
//
|
||||||
|
template<typename T>
|
||||||
|
bool ciMethod::has_option_value(const char* option, T& value) {
|
||||||
|
check_is_loaded();
|
||||||
|
VM_ENTRY_MARK;
|
||||||
|
methodHandle mh(THREAD, get_Method());
|
||||||
|
return CompilerOracle::has_option_value(mh, option, value);
|
||||||
|
}
|
||||||
|
// Explicit instantiation for all OptionTypes supported.
|
||||||
|
template bool ciMethod::has_option_value<intx>(const char* option, intx& value);
|
||||||
|
template bool ciMethod::has_option_value<uintx>(const char* option, uintx& value);
|
||||||
|
template bool ciMethod::has_option_value<bool>(const char* option, bool& value);
|
||||||
|
template bool ciMethod::has_option_value<ccstr>(const char* option, ccstr& value);
|
||||||
|
|
||||||
// ------------------------------------------------------------------
|
// ------------------------------------------------------------------
|
||||||
// ciMethod::can_be_compiled
|
// ciMethod::can_be_compiled
|
||||||
//
|
//
|
||||||
|
@ -269,6 +269,8 @@ class ciMethod : public ciMetadata {
|
|||||||
bool should_print_assembly();
|
bool should_print_assembly();
|
||||||
bool break_at_execute();
|
bool break_at_execute();
|
||||||
bool has_option(const char *option);
|
bool has_option(const char *option);
|
||||||
|
template<typename T>
|
||||||
|
bool has_option_value(const char* option, T& value);
|
||||||
bool can_be_compiled();
|
bool can_be_compiled();
|
||||||
bool can_be_osr_compiled(int entry_bci);
|
bool can_be_osr_compiled(int entry_bci);
|
||||||
void set_not_compilable(const char* reason = NULL);
|
void set_not_compilable(const char* reason = NULL);
|
||||||
|
@ -81,19 +81,38 @@ ciMethodData::ciMethodData() : ciMetadata(NULL) {
|
|||||||
void ciMethodData::load_extra_data() {
|
void ciMethodData::load_extra_data() {
|
||||||
MethodData* mdo = get_MethodData();
|
MethodData* mdo = get_MethodData();
|
||||||
|
|
||||||
|
MutexLocker(mdo->extra_data_lock());
|
||||||
|
|
||||||
// speculative trap entries also hold a pointer to a Method so need to be translated
|
// speculative trap entries also hold a pointer to a Method so need to be translated
|
||||||
DataLayout* dp_src = mdo->extra_data_base();
|
DataLayout* dp_src = mdo->extra_data_base();
|
||||||
DataLayout* end_src = mdo->extra_data_limit();
|
DataLayout* end_src = mdo->args_data_limit();
|
||||||
DataLayout* dp_dst = extra_data_base();
|
DataLayout* dp_dst = extra_data_base();
|
||||||
for (;; dp_src = MethodData::next_extra(dp_src), dp_dst = MethodData::next_extra(dp_dst)) {
|
for (;; dp_src = MethodData::next_extra(dp_src), dp_dst = MethodData::next_extra(dp_dst)) {
|
||||||
assert(dp_src < end_src, "moved past end of extra data");
|
assert(dp_src < end_src, "moved past end of extra data");
|
||||||
// New traps in the MDO can be added as we translate the copy so
|
assert(((intptr_t)dp_dst) - ((intptr_t)extra_data_base()) == ((intptr_t)dp_src) - ((intptr_t)mdo->extra_data_base()), "source and destination don't match");
|
||||||
// look at the entries in the copy.
|
|
||||||
switch(dp_dst->tag()) {
|
// New traps in the MDO may have been added since we copied the
|
||||||
|
// data (concurrent deoptimizations before we acquired
|
||||||
|
// extra_data_lock above) or can be removed (a safepoint may occur
|
||||||
|
// in the translate_from call below) as we translate the copy:
|
||||||
|
// update the copy as we go.
|
||||||
|
int tag = dp_src->tag();
|
||||||
|
if (tag != DataLayout::arg_info_data_tag) {
|
||||||
|
memcpy(dp_dst, dp_src, ((intptr_t)MethodData::next_extra(dp_src)) - ((intptr_t)dp_src));
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(tag) {
|
||||||
case DataLayout::speculative_trap_data_tag: {
|
case DataLayout::speculative_trap_data_tag: {
|
||||||
ciSpeculativeTrapData* data_dst = new ciSpeculativeTrapData(dp_dst);
|
ciSpeculativeTrapData* data_dst = new ciSpeculativeTrapData(dp_dst);
|
||||||
SpeculativeTrapData* data_src = new SpeculativeTrapData(dp_src);
|
SpeculativeTrapData* data_src = new SpeculativeTrapData(dp_src);
|
||||||
|
|
||||||
data_dst->translate_from(data_src);
|
data_dst->translate_from(data_src);
|
||||||
|
|
||||||
|
#ifdef ASSERT
|
||||||
|
SpeculativeTrapData* data_src2 = new SpeculativeTrapData(dp_src);
|
||||||
|
assert(data_src2->method() == data_src->method() && data_src2->bci() == data_src->bci(), "entries changed while translating");
|
||||||
|
#endif
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DataLayout::bit_data_tag:
|
case DataLayout::bit_data_tag:
|
||||||
@ -244,8 +263,8 @@ ciProfileData* ciMethodData::next_data(ciProfileData* current) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ciProfileData* ciMethodData::bci_to_extra_data(int bci, ciMethod* m, bool& two_free_slots) {
|
ciProfileData* ciMethodData::bci_to_extra_data(int bci, ciMethod* m, bool& two_free_slots) {
|
||||||
DataLayout* dp = data_layout_at(data_size());
|
DataLayout* dp = extra_data_base();
|
||||||
DataLayout* end = data_layout_at(data_size() + extra_data_size());
|
DataLayout* end = args_data_limit();
|
||||||
two_free_slots = false;
|
two_free_slots = false;
|
||||||
for (;dp < end; dp = MethodData::next_extra(dp)) {
|
for (;dp < end; dp = MethodData::next_extra(dp)) {
|
||||||
switch(dp->tag()) {
|
switch(dp->tag()) {
|
||||||
@ -492,8 +511,8 @@ ByteSize ciMethodData::offset_of_slot(ciProfileData* data, ByteSize slot_offset_
|
|||||||
|
|
||||||
ciArgInfoData *ciMethodData::arg_info() const {
|
ciArgInfoData *ciMethodData::arg_info() const {
|
||||||
// Should be last, have to skip all traps.
|
// Should be last, have to skip all traps.
|
||||||
DataLayout* dp = data_layout_at(data_size());
|
DataLayout* dp = extra_data_base();
|
||||||
DataLayout* end = data_layout_at(data_size() + extra_data_size());
|
DataLayout* end = args_data_limit();
|
||||||
for (; dp < end; dp = MethodData::next_extra(dp)) {
|
for (; dp < end; dp = MethodData::next_extra(dp)) {
|
||||||
if (dp->tag() == DataLayout::arg_info_data_tag)
|
if (dp->tag() == DataLayout::arg_info_data_tag)
|
||||||
return new ciArgInfoData(dp);
|
return new ciArgInfoData(dp);
|
||||||
@ -535,8 +554,8 @@ template<class T> void ciMethodData::dump_replay_data_call_type_helper(outputStr
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ciMethodData::dump_replay_data_extra_data_helper(outputStream* out, int round, int& count) {
|
void ciMethodData::dump_replay_data_extra_data_helper(outputStream* out, int round, int& count) {
|
||||||
DataLayout* dp = data_layout_at(data_size());
|
DataLayout* dp = extra_data_base();
|
||||||
DataLayout* end = data_layout_at(data_size() + extra_data_size());
|
DataLayout* end = args_data_limit();
|
||||||
|
|
||||||
for (;dp < end; dp = MethodData::next_extra(dp)) {
|
for (;dp < end; dp = MethodData::next_extra(dp)) {
|
||||||
switch(dp->tag()) {
|
switch(dp->tag()) {
|
||||||
@ -653,8 +672,8 @@ void ciMethodData::print_data_on(outputStream* st) {
|
|||||||
data->print_data_on(st);
|
data->print_data_on(st);
|
||||||
}
|
}
|
||||||
st->print_cr("--- Extra data:");
|
st->print_cr("--- Extra data:");
|
||||||
DataLayout* dp = data_layout_at(data_size());
|
DataLayout* dp = extra_data_base();
|
||||||
DataLayout* end = data_layout_at(data_size() + extra_data_size());
|
DataLayout* end = args_data_limit();
|
||||||
for (;; dp = MethodData::next_extra(dp)) {
|
for (;; dp = MethodData::next_extra(dp)) {
|
||||||
assert(dp < end, "moved past end of extra data");
|
assert(dp < end, "moved past end of extra data");
|
||||||
switch (dp->tag()) {
|
switch (dp->tag()) {
|
||||||
|
@ -410,6 +410,9 @@ private:
|
|||||||
// Area dedicated to parameters. NULL if no parameter profiling for
|
// Area dedicated to parameters. NULL if no parameter profiling for
|
||||||
// this method.
|
// this method.
|
||||||
DataLayout* _parameters;
|
DataLayout* _parameters;
|
||||||
|
int parameters_size() const {
|
||||||
|
return _parameters == NULL ? 0 : parameters_type_data()->size_in_bytes();
|
||||||
|
}
|
||||||
|
|
||||||
ciMethodData(MethodData* md);
|
ciMethodData(MethodData* md);
|
||||||
ciMethodData();
|
ciMethodData();
|
||||||
@ -461,9 +464,6 @@ private:
|
|||||||
address data_base() const {
|
address data_base() const {
|
||||||
return (address) _data;
|
return (address) _data;
|
||||||
}
|
}
|
||||||
DataLayout* limit_data_position() const {
|
|
||||||
return (DataLayout*)((address)data_base() + _data_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void load_extra_data();
|
void load_extra_data();
|
||||||
ciProfileData* bci_to_extra_data(int bci, ciMethod* m, bool& two_free_slots);
|
ciProfileData* bci_to_extra_data(int bci, ciMethod* m, bool& two_free_slots);
|
||||||
@ -524,7 +524,9 @@ public:
|
|||||||
ciProfileData* next_data(ciProfileData* current);
|
ciProfileData* next_data(ciProfileData* current);
|
||||||
bool is_valid(ciProfileData* current) { return current != NULL; }
|
bool is_valid(ciProfileData* current) { return current != NULL; }
|
||||||
|
|
||||||
DataLayout* extra_data_base() const { return limit_data_position(); }
|
DataLayout* extra_data_base() const { return data_layout_at(data_size()); }
|
||||||
|
DataLayout* args_data_limit() const { return data_layout_at(data_size() + extra_data_size() -
|
||||||
|
parameters_size()); }
|
||||||
|
|
||||||
// Get the data at an arbitrary bci, or NULL if there is none. If m
|
// Get the data at an arbitrary bci, or NULL if there is none. If m
|
||||||
// is not NULL look for a SpeculativeTrapData if any first.
|
// is not NULL look for a SpeculativeTrapData if any first.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -30,7 +30,7 @@ void ClassFileStream::truncated_file_error(TRAPS) {
|
|||||||
THROW_MSG(vmSymbols::java_lang_ClassFormatError(), "Truncated class file");
|
THROW_MSG(vmSymbols::java_lang_ClassFormatError(), "Truncated class file");
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassFileStream::ClassFileStream(u1* buffer, int length, char* source) {
|
ClassFileStream::ClassFileStream(u1* buffer, int length, const char* source) {
|
||||||
_buffer_start = buffer;
|
_buffer_start = buffer;
|
||||||
_buffer_end = buffer + length;
|
_buffer_end = buffer + length;
|
||||||
_current = buffer;
|
_current = buffer;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -39,20 +39,20 @@ class ClassFileStream: public ResourceObj {
|
|||||||
u1* _buffer_start; // Buffer bottom
|
u1* _buffer_start; // Buffer bottom
|
||||||
u1* _buffer_end; // Buffer top (one past last element)
|
u1* _buffer_end; // Buffer top (one past last element)
|
||||||
u1* _current; // Current buffer position
|
u1* _current; // Current buffer position
|
||||||
char* _source; // Source of stream (directory name, ZIP/JAR archive name)
|
const char* _source; // Source of stream (directory name, ZIP/JAR archive name)
|
||||||
bool _need_verify; // True if verification is on for the class file
|
bool _need_verify; // True if verification is on for the class file
|
||||||
|
|
||||||
void truncated_file_error(TRAPS);
|
void truncated_file_error(TRAPS);
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
ClassFileStream(u1* buffer, int length, char* source);
|
ClassFileStream(u1* buffer, int length, const char* source);
|
||||||
|
|
||||||
// Buffer access
|
// Buffer access
|
||||||
u1* buffer() const { return _buffer_start; }
|
u1* buffer() const { return _buffer_start; }
|
||||||
int length() const { return _buffer_end - _buffer_start; }
|
int length() const { return _buffer_end - _buffer_start; }
|
||||||
u1* current() const { return _current; }
|
u1* current() const { return _current; }
|
||||||
void set_current(u1* pos) { _current = pos; }
|
void set_current(u1* pos) { _current = pos; }
|
||||||
char* source() const { return _source; }
|
const char* source() const { return _source; }
|
||||||
void set_verify(bool flag) { _need_verify = flag; }
|
void set_verify(bool flag) { _need_verify = flag; }
|
||||||
|
|
||||||
void check_truncated_file(bool b, TRAPS) {
|
void check_truncated_file(bool b, TRAPS) {
|
||||||
|
@ -189,9 +189,10 @@ bool ClassPathEntry::is_lazy() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassPathDirEntry::ClassPathDirEntry(char* dir) : ClassPathEntry() {
|
ClassPathDirEntry::ClassPathDirEntry(const char* dir) : ClassPathEntry() {
|
||||||
_dir = NEW_C_HEAP_ARRAY(char, strlen(dir)+1, mtClass);
|
char* copy = NEW_C_HEAP_ARRAY(char, strlen(dir)+1, mtClass);
|
||||||
strcpy(_dir, dir);
|
strcpy(copy, dir);
|
||||||
|
_dir = copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -235,8 +236,9 @@ ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) {
|
|||||||
|
|
||||||
ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name) : ClassPathEntry() {
|
ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name) : ClassPathEntry() {
|
||||||
_zip = zip;
|
_zip = zip;
|
||||||
_zip_name = NEW_C_HEAP_ARRAY(char, strlen(zip_name)+1, mtClass);
|
char *copy = NEW_C_HEAP_ARRAY(char, strlen(zip_name)+1, mtClass);
|
||||||
strcpy(_zip_name, zip_name);
|
strcpy(copy, zip_name);
|
||||||
|
_zip_name = copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassPathZipEntry::~ClassPathZipEntry() {
|
ClassPathZipEntry::~ClassPathZipEntry() {
|
||||||
@ -304,7 +306,7 @@ void ClassPathZipEntry::contents_do(void f(const char* name, void* context), voi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LazyClassPathEntry::LazyClassPathEntry(char* path, const struct stat* st, bool throw_exception) : ClassPathEntry() {
|
LazyClassPathEntry::LazyClassPathEntry(const char* path, const struct stat* st, bool throw_exception) : ClassPathEntry() {
|
||||||
_path = os::strdup_check_oom(path);
|
_path = os::strdup_check_oom(path);
|
||||||
_st = *st;
|
_st = *st;
|
||||||
_meta_index = NULL;
|
_meta_index = NULL;
|
||||||
@ -314,7 +316,7 @@ LazyClassPathEntry::LazyClassPathEntry(char* path, const struct stat* st, bool t
|
|||||||
}
|
}
|
||||||
|
|
||||||
LazyClassPathEntry::~LazyClassPathEntry() {
|
LazyClassPathEntry::~LazyClassPathEntry() {
|
||||||
os::free(_path);
|
os::free((void*)_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LazyClassPathEntry::is_jar_file() {
|
bool LazyClassPathEntry::is_jar_file() {
|
||||||
@ -563,17 +565,19 @@ void ClassLoader::check_shared_classpath(const char *path) {
|
|||||||
|
|
||||||
void ClassLoader::setup_bootstrap_search_path() {
|
void ClassLoader::setup_bootstrap_search_path() {
|
||||||
assert(_first_entry == NULL, "should not setup bootstrap class search path twice");
|
assert(_first_entry == NULL, "should not setup bootstrap class search path twice");
|
||||||
char* sys_class_path = os::strdup_check_oom(Arguments::get_sysclasspath());
|
const char* sys_class_path = Arguments::get_sysclasspath();
|
||||||
if (!PrintSharedArchiveAndExit) {
|
if (PrintSharedArchiveAndExit) {
|
||||||
|
// Don't print sys_class_path - this is the bootcp of this current VM process, not necessarily
|
||||||
|
// the same as the bootcp of the shared archive.
|
||||||
|
} else {
|
||||||
trace_class_path("[Bootstrap loader class path=", sys_class_path);
|
trace_class_path("[Bootstrap loader class path=", sys_class_path);
|
||||||
}
|
}
|
||||||
#if INCLUDE_CDS
|
#if INCLUDE_CDS
|
||||||
if (DumpSharedSpaces) {
|
if (DumpSharedSpaces) {
|
||||||
_shared_paths_misc_info->add_boot_classpath(Arguments::get_sysclasspath());
|
_shared_paths_misc_info->add_boot_classpath(sys_class_path);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
setup_search_path(sys_class_path);
|
setup_search_path(sys_class_path);
|
||||||
os::free(sys_class_path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if INCLUDE_CDS
|
#if INCLUDE_CDS
|
||||||
@ -593,7 +597,7 @@ bool ClassLoader::check_shared_paths_misc_info(void *buf, int size) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void ClassLoader::setup_search_path(char *class_path) {
|
void ClassLoader::setup_search_path(const char *class_path) {
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int len = (int)strlen(class_path);
|
int len = (int)strlen(class_path);
|
||||||
int end = 0;
|
int end = 0;
|
||||||
@ -620,7 +624,7 @@ void ClassLoader::setup_search_path(char *class_path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassPathEntry* ClassLoader::create_class_path_entry(char *path, const struct stat* st,
|
ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const struct stat* st,
|
||||||
bool lazy, bool throw_exception, TRAPS) {
|
bool lazy, bool throw_exception, TRAPS) {
|
||||||
JavaThread* thread = JavaThread::current();
|
JavaThread* thread = JavaThread::current();
|
||||||
if (lazy) {
|
if (lazy) {
|
||||||
@ -687,11 +691,8 @@ ClassPathZipEntry* ClassLoader::create_class_path_zip_entry(const char *path) {
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
if (os::stat(path, &st) == 0) {
|
if (os::stat(path, &st) == 0) {
|
||||||
if ((st.st_mode & S_IFREG) == S_IFREG) {
|
if ((st.st_mode & S_IFREG) == S_IFREG) {
|
||||||
char orig_path[JVM_MAXPATHLEN];
|
|
||||||
char canonical_path[JVM_MAXPATHLEN];
|
char canonical_path[JVM_MAXPATHLEN];
|
||||||
|
if (get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) {
|
||||||
strcpy(orig_path, path);
|
|
||||||
if (get_canonical_path(orig_path, canonical_path, JVM_MAXPATHLEN)) {
|
|
||||||
char* error_msg = NULL;
|
char* error_msg = NULL;
|
||||||
jzfile* zip;
|
jzfile* zip;
|
||||||
{
|
{
|
||||||
@ -737,7 +738,7 @@ void ClassLoader::add_to_list(ClassPathEntry *new_entry) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns true IFF the file/dir exists and the entry was successfully created.
|
// Returns true IFF the file/dir exists and the entry was successfully created.
|
||||||
bool ClassLoader::update_class_path_entry_list(char *path,
|
bool ClassLoader::update_class_path_entry_list(const char *path,
|
||||||
bool check_for_duplicates,
|
bool check_for_duplicates,
|
||||||
bool throw_exception) {
|
bool throw_exception) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
@ -762,8 +763,8 @@ bool ClassLoader::update_class_path_entry_list(char *path,
|
|||||||
if (DumpSharedSpaces) {
|
if (DumpSharedSpaces) {
|
||||||
_shared_paths_misc_info->add_nonexist_path(path);
|
_shared_paths_misc_info->add_nonexist_path(path);
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
#endif
|
#endif
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1269,11 +1270,17 @@ void classLoader_init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ClassLoader::get_canonical_path(char* orig, char* out, int len) {
|
bool ClassLoader::get_canonical_path(const char* orig, char* out, int len) {
|
||||||
assert(orig != NULL && out != NULL && len > 0, "bad arguments");
|
assert(orig != NULL && out != NULL && len > 0, "bad arguments");
|
||||||
if (CanonicalizeEntry != NULL) {
|
if (CanonicalizeEntry != NULL) {
|
||||||
JNIEnv* env = JavaThread::current()->jni_environment();
|
JavaThread* THREAD = JavaThread::current();
|
||||||
if ((CanonicalizeEntry)(env, os::native_path(orig), out, len) < 0) {
|
JNIEnv* env = THREAD->jni_environment();
|
||||||
|
ResourceMark rm(THREAD);
|
||||||
|
|
||||||
|
// os::native_path writes into orig_copy
|
||||||
|
char* orig_copy = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, strlen(orig)+1);
|
||||||
|
strcpy(orig_copy, orig);
|
||||||
|
if ((CanonicalizeEntry)(env, os::native_path(orig_copy), out, len) < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -72,11 +72,11 @@ class ClassPathEntry: public CHeapObj<mtClass> {
|
|||||||
|
|
||||||
class ClassPathDirEntry: public ClassPathEntry {
|
class ClassPathDirEntry: public ClassPathEntry {
|
||||||
private:
|
private:
|
||||||
char* _dir; // Name of directory
|
const char* _dir; // Name of directory
|
||||||
public:
|
public:
|
||||||
bool is_jar_file() { return false; }
|
bool is_jar_file() { return false; }
|
||||||
const char* name() { return _dir; }
|
const char* name() { return _dir; }
|
||||||
ClassPathDirEntry(char* dir);
|
ClassPathDirEntry(const char* dir);
|
||||||
ClassFileStream* open_stream(const char* name, TRAPS);
|
ClassFileStream* open_stream(const char* name, TRAPS);
|
||||||
// Debugging
|
// Debugging
|
||||||
NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);)
|
NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);)
|
||||||
@ -100,8 +100,8 @@ typedef struct {
|
|||||||
|
|
||||||
class ClassPathZipEntry: public ClassPathEntry {
|
class ClassPathZipEntry: public ClassPathEntry {
|
||||||
private:
|
private:
|
||||||
jzfile* _zip; // The zip archive
|
jzfile* _zip; // The zip archive
|
||||||
char* _zip_name; // Name of zip archive
|
const char* _zip_name; // Name of zip archive
|
||||||
public:
|
public:
|
||||||
bool is_jar_file() { return true; }
|
bool is_jar_file() { return true; }
|
||||||
const char* name() { return _zip_name; }
|
const char* name() { return _zip_name; }
|
||||||
@ -119,7 +119,7 @@ class ClassPathZipEntry: public ClassPathEntry {
|
|||||||
// For lazier loading of boot class path entries
|
// For lazier loading of boot class path entries
|
||||||
class LazyClassPathEntry: public ClassPathEntry {
|
class LazyClassPathEntry: public ClassPathEntry {
|
||||||
private:
|
private:
|
||||||
char* _path; // dir or file
|
const char* _path; // dir or file
|
||||||
struct stat _st;
|
struct stat _st;
|
||||||
MetaIndex* _meta_index;
|
MetaIndex* _meta_index;
|
||||||
bool _has_error;
|
bool _has_error;
|
||||||
@ -129,7 +129,7 @@ class LazyClassPathEntry: public ClassPathEntry {
|
|||||||
public:
|
public:
|
||||||
bool is_jar_file();
|
bool is_jar_file();
|
||||||
const char* name() { return _path; }
|
const char* name() { return _path; }
|
||||||
LazyClassPathEntry(char* path, const struct stat* st, bool throw_exception);
|
LazyClassPathEntry(const char* path, const struct stat* st, bool throw_exception);
|
||||||
virtual ~LazyClassPathEntry();
|
virtual ~LazyClassPathEntry();
|
||||||
u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS);
|
u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS);
|
||||||
|
|
||||||
@ -216,17 +216,17 @@ class ClassLoader: AllStatic {
|
|||||||
static void setup_meta_index(const char* meta_index_path, const char* meta_index_dir,
|
static void setup_meta_index(const char* meta_index_path, const char* meta_index_dir,
|
||||||
int start_index);
|
int start_index);
|
||||||
static void setup_bootstrap_search_path();
|
static void setup_bootstrap_search_path();
|
||||||
static void setup_search_path(char *class_path);
|
static void setup_search_path(const char *class_path);
|
||||||
|
|
||||||
static void load_zip_library();
|
static void load_zip_library();
|
||||||
static ClassPathEntry* create_class_path_entry(char *path, const struct stat* st,
|
static ClassPathEntry* create_class_path_entry(const char *path, const struct stat* st,
|
||||||
bool lazy, bool throw_exception, TRAPS);
|
bool lazy, bool throw_exception, TRAPS);
|
||||||
|
|
||||||
// Canonicalizes path names, so strcmp will work properly. This is mainly
|
// Canonicalizes path names, so strcmp will work properly. This is mainly
|
||||||
// to avoid confusing the zip library
|
// to avoid confusing the zip library
|
||||||
static bool get_canonical_path(char* orig, char* out, int len);
|
static bool get_canonical_path(const char* orig, char* out, int len);
|
||||||
public:
|
public:
|
||||||
static bool update_class_path_entry_list(char *path,
|
static bool update_class_path_entry_list(const char *path,
|
||||||
bool check_for_duplicates,
|
bool check_for_duplicates,
|
||||||
bool throw_exception=true);
|
bool throw_exception=true);
|
||||||
static void print_bootclasspath();
|
static void print_bootclasspath();
|
||||||
|
@ -332,27 +332,6 @@ void ClassLoaderData::unload() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ASSERT
|
|
||||||
class AllAliveClosure : public OopClosure {
|
|
||||||
BoolObjectClosure* _is_alive_closure;
|
|
||||||
bool _found_dead;
|
|
||||||
public:
|
|
||||||
AllAliveClosure(BoolObjectClosure* is_alive_closure) : _is_alive_closure(is_alive_closure), _found_dead(false) {}
|
|
||||||
template <typename T> void do_oop_work(T* p) {
|
|
||||||
T heap_oop = oopDesc::load_heap_oop(p);
|
|
||||||
if (!oopDesc::is_null(heap_oop)) {
|
|
||||||
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
|
|
||||||
if (!_is_alive_closure->do_object_b(obj)) {
|
|
||||||
_found_dead = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void do_oop(oop* p) { do_oop_work<oop>(p); }
|
|
||||||
void do_oop(narrowOop* p) { do_oop_work<narrowOop>(p); }
|
|
||||||
bool found_dead() { return _found_dead; }
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
oop ClassLoaderData::keep_alive_object() const {
|
oop ClassLoaderData::keep_alive_object() const {
|
||||||
assert(!keep_alive(), "Don't use with CLDs that are artificially kept alive");
|
assert(!keep_alive(), "Don't use with CLDs that are artificially kept alive");
|
||||||
return is_anonymous() ? _klasses->java_mirror() : class_loader();
|
return is_anonymous() ? _klasses->java_mirror() : class_loader();
|
||||||
@ -362,15 +341,6 @@ bool ClassLoaderData::is_alive(BoolObjectClosure* is_alive_closure) const {
|
|||||||
bool alive = keep_alive() // null class loader and incomplete anonymous klasses.
|
bool alive = keep_alive() // null class loader and incomplete anonymous klasses.
|
||||||
|| is_alive_closure->do_object_b(keep_alive_object());
|
|| is_alive_closure->do_object_b(keep_alive_object());
|
||||||
|
|
||||||
#ifdef ASSERT
|
|
||||||
if (alive) {
|
|
||||||
AllAliveClosure all_alive_closure(is_alive_closure);
|
|
||||||
KlassToOopClosure klass_closure(&all_alive_closure);
|
|
||||||
const_cast<ClassLoaderData*>(this)->oops_do(&all_alive_closure, &klass_closure, false);
|
|
||||||
assert(!all_alive_closure.found_dead(), err_msg("Found dead oop in alive cld: " PTR_FORMAT, p2i(this)));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return alive;
|
return alive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,8 +59,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void add_class_path_entry(char* path, bool check_for_duplicates,
|
static void add_class_path_entry(const char* path, bool check_for_duplicates,
|
||||||
ClassPathEntry* new_entry) {
|
ClassPathEntry* new_entry) {
|
||||||
ClassLoader::add_to_list(new_entry);
|
ClassLoader::add_to_list(new_entry);
|
||||||
}
|
}
|
||||||
static void setup_search_paths() {}
|
static void setup_search_paths() {}
|
||||||
|
@ -620,7 +620,6 @@ void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader,
|
|||||||
// Two-way link between the array klass and its component mirror:
|
// Two-way link between the array klass and its component mirror:
|
||||||
// (array_klass) k -> mirror -> component_mirror -> array_klass -> k
|
// (array_klass) k -> mirror -> component_mirror -> array_klass -> k
|
||||||
set_component_mirror(mirror(), comp_mirror());
|
set_component_mirror(mirror(), comp_mirror());
|
||||||
ArrayKlass::cast(k())->set_component_mirror(comp_mirror());
|
|
||||||
set_array_klass(comp_mirror(), k());
|
set_array_klass(comp_mirror(), k());
|
||||||
} else {
|
} else {
|
||||||
assert(k->oop_is_instance(), "Must be");
|
assert(k->oop_is_instance(), "Must be");
|
||||||
@ -682,10 +681,9 @@ void java_lang_Class::set_protection_domain(oop java_class, oop pd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void java_lang_Class::set_component_mirror(oop java_class, oop comp_mirror) {
|
void java_lang_Class::set_component_mirror(oop java_class, oop comp_mirror) {
|
||||||
if (_component_mirror_offset != 0) {
|
assert(_component_mirror_offset != 0, "must be set");
|
||||||
java_class->obj_field_put(_component_mirror_offset, comp_mirror);
|
java_class->obj_field_put(_component_mirror_offset, comp_mirror);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
oop java_lang_Class::component_mirror(oop java_class) {
|
oop java_lang_Class::component_mirror(oop java_class) {
|
||||||
assert(_component_mirror_offset != 0, "must be set");
|
assert(_component_mirror_offset != 0, "must be set");
|
||||||
return java_class->obj_field(_component_mirror_offset);
|
return java_class->obj_field(_component_mirror_offset);
|
||||||
@ -875,22 +873,27 @@ void java_lang_Class::compute_offsets() {
|
|||||||
assert(!offsets_computed, "offsets should be initialized only once");
|
assert(!offsets_computed, "offsets should be initialized only once");
|
||||||
offsets_computed = true;
|
offsets_computed = true;
|
||||||
|
|
||||||
Klass* klass_oop = SystemDictionary::Class_klass();
|
Klass* k = SystemDictionary::Class_klass();
|
||||||
// The classRedefinedCount field is only present starting in 1.5,
|
// The classRedefinedCount field is only present starting in 1.5,
|
||||||
// so don't go fatal.
|
// so don't go fatal.
|
||||||
compute_optional_offset(classRedefinedCount_offset,
|
compute_optional_offset(classRedefinedCount_offset,
|
||||||
klass_oop, vmSymbols::classRedefinedCount_name(), vmSymbols::int_signature());
|
k, vmSymbols::classRedefinedCount_name(), vmSymbols::int_signature());
|
||||||
|
|
||||||
// Needs to be optional because the old build runs Queens during bootstrapping
|
// Needs to be optional because the old build runs Queens during bootstrapping
|
||||||
// and jdk8-9 doesn't have coordinated pushes yet.
|
// and jdk8-9 doesn't have coordinated pushes yet.
|
||||||
compute_optional_offset(_class_loader_offset,
|
compute_optional_offset(_class_loader_offset,
|
||||||
klass_oop, vmSymbols::classLoader_name(),
|
k, vmSymbols::classLoader_name(),
|
||||||
vmSymbols::classloader_signature());
|
vmSymbols::classloader_signature());
|
||||||
|
|
||||||
compute_optional_offset(_component_mirror_offset,
|
compute_offset(_component_mirror_offset,
|
||||||
klass_oop, vmSymbols::componentType_name(),
|
k, vmSymbols::componentType_name(),
|
||||||
vmSymbols::class_signature());
|
vmSymbols::class_signature());
|
||||||
|
|
||||||
|
// Init lock is a C union with component_mirror. Only instanceKlass mirrors have
|
||||||
|
// init_lock and only ArrayKlass mirrors have component_mirror. Since both are oops
|
||||||
|
// GC treats them the same.
|
||||||
|
_init_lock_offset = _component_mirror_offset;
|
||||||
|
|
||||||
CLASS_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
|
CLASS_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +222,6 @@ class java_lang_String : AllStatic {
|
|||||||
macro(java_lang_Class, oop_size, int_signature, false) \
|
macro(java_lang_Class, oop_size, int_signature, false) \
|
||||||
macro(java_lang_Class, static_oop_field_count, int_signature, false) \
|
macro(java_lang_Class, static_oop_field_count, int_signature, false) \
|
||||||
macro(java_lang_Class, protection_domain, object_signature, false) \
|
macro(java_lang_Class, protection_domain, object_signature, false) \
|
||||||
macro(java_lang_Class, init_lock, object_signature, false) \
|
|
||||||
macro(java_lang_Class, signers, object_signature, false)
|
macro(java_lang_Class, signers, object_signature, false)
|
||||||
|
|
||||||
class java_lang_Class : AllStatic {
|
class java_lang_Class : AllStatic {
|
||||||
|
@ -139,7 +139,7 @@ bool SharedPathsMiscInfo::check(jint type, const char* path) {
|
|||||||
if (timestamp != st.st_mtime) {
|
if (timestamp != st.st_mtime) {
|
||||||
return fail("Timestamp mismatch");
|
return fail("Timestamp mismatch");
|
||||||
}
|
}
|
||||||
if (filesize != st.st_size) {
|
if (filesize != st.st_size) {
|
||||||
return fail("File size mismatch");
|
return fail("File size mismatch");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,7 +165,7 @@ public:
|
|||||||
out->print("Expecting that %s does not exist", path);
|
out->print("Expecting that %s does not exist", path);
|
||||||
break;
|
break;
|
||||||
case REQUIRED:
|
case REQUIRED:
|
||||||
out->print("Expecting that file %s must exist and not altered", path);
|
out->print("Expecting that file %s must exist and is not altered", path);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ShouldNotReachHere();
|
ShouldNotReachHere();
|
||||||
|
@ -109,7 +109,7 @@ oop StringTable::lookup(int index, jchar* name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the bucket size is too deep check if this hash code is insufficient.
|
// If the bucket size is too deep check if this hash code is insufficient.
|
||||||
if (count >= BasicHashtable<mtSymbol>::rehash_count && !needs_rehashing()) {
|
if (count >= rehash_count && !needs_rehashing()) {
|
||||||
_needs_rehashing = check_rehash_table(count);
|
_needs_rehashing = check_rehash_table(count);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "utilities/hashtable.hpp"
|
#include "utilities/hashtable.hpp"
|
||||||
|
|
||||||
class StringTable : public Hashtable<oop, mtSymbol> {
|
class StringTable : public RehashableHashtable<oop, mtSymbol> {
|
||||||
friend class VMStructs;
|
friend class VMStructs;
|
||||||
friend class Symbol;
|
friend class Symbol;
|
||||||
|
|
||||||
@ -55,11 +55,11 @@ private:
|
|||||||
// in the range [start_idx, end_idx).
|
// in the range [start_idx, end_idx).
|
||||||
static void buckets_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int start_idx, int end_idx, int* processed, int* removed);
|
static void buckets_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f, int start_idx, int end_idx, int* processed, int* removed);
|
||||||
|
|
||||||
StringTable() : Hashtable<oop, mtSymbol>((int)StringTableSize,
|
StringTable() : RehashableHashtable<oop, mtSymbol>((int)StringTableSize,
|
||||||
sizeof (HashtableEntry<oop, mtSymbol>)) {}
|
sizeof (HashtableEntry<oop, mtSymbol>)) {}
|
||||||
|
|
||||||
StringTable(HashtableBucket<mtSymbol>* t, int number_of_entries)
|
StringTable(HashtableBucket<mtSymbol>* t, int number_of_entries)
|
||||||
: Hashtable<oop, mtSymbol>((int)StringTableSize, sizeof (HashtableEntry<oop, mtSymbol>), t,
|
: RehashableHashtable<oop, mtSymbol>((int)StringTableSize, sizeof (HashtableEntry<oop, mtSymbol>), t,
|
||||||
number_of_entries) {}
|
number_of_entries) {}
|
||||||
public:
|
public:
|
||||||
// The string table
|
// The string table
|
||||||
|
@ -201,7 +201,7 @@ Symbol* SymbolTable::lookup(int index, const char* name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If the bucket size is too deep check if this hash code is insufficient.
|
// If the bucket size is too deep check if this hash code is insufficient.
|
||||||
if (count >= BasicHashtable<mtSymbol>::rehash_count && !needs_rehashing()) {
|
if (count >= rehash_count && !needs_rehashing()) {
|
||||||
_needs_rehashing = check_rehash_table(count);
|
_needs_rehashing = check_rehash_table(count);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -73,7 +73,7 @@ class TempNewSymbol : public StackObj {
|
|||||||
operator Symbol*() { return _temp; }
|
operator Symbol*() { return _temp; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class SymbolTable : public Hashtable<Symbol*, mtSymbol> {
|
class SymbolTable : public RehashableHashtable<Symbol*, mtSymbol> {
|
||||||
friend class VMStructs;
|
friend class VMStructs;
|
||||||
friend class ClassFileParser;
|
friend class ClassFileParser;
|
||||||
|
|
||||||
@ -109,10 +109,10 @@ private:
|
|||||||
Symbol* lookup(int index, const char* name, int len, unsigned int hash);
|
Symbol* lookup(int index, const char* name, int len, unsigned int hash);
|
||||||
|
|
||||||
SymbolTable()
|
SymbolTable()
|
||||||
: Hashtable<Symbol*, mtSymbol>(SymbolTableSize, sizeof (HashtableEntry<Symbol*, mtSymbol>)) {}
|
: RehashableHashtable<Symbol*, mtSymbol>(SymbolTableSize, sizeof (HashtableEntry<Symbol*, mtSymbol>)) {}
|
||||||
|
|
||||||
SymbolTable(HashtableBucket<mtSymbol>* t, int number_of_entries)
|
SymbolTable(HashtableBucket<mtSymbol>* t, int number_of_entries)
|
||||||
: Hashtable<Symbol*, mtSymbol>(SymbolTableSize, sizeof (HashtableEntry<Symbol*, mtSymbol>), t,
|
: RehashableHashtable<Symbol*, mtSymbol>(SymbolTableSize, sizeof (HashtableEntry<Symbol*, mtSymbol>), t,
|
||||||
number_of_entries) {}
|
number_of_entries) {}
|
||||||
|
|
||||||
// Arena for permanent symbols (null class loader) that are never unloaded
|
// Arena for permanent symbols (null class loader) that are never unloaded
|
||||||
|
@ -1243,7 +1243,6 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik,
|
|||||||
tty->print_cr("]");
|
tty->print_cr("]");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if INCLUDE_CDS
|
|
||||||
if (DumpLoadedClassList != NULL && classlist_file->is_open()) {
|
if (DumpLoadedClassList != NULL && classlist_file->is_open()) {
|
||||||
// Only dump the classes that can be stored into CDS archive
|
// Only dump the classes that can be stored into CDS archive
|
||||||
if (SystemDictionaryShared::is_sharing_possible(loader_data)) {
|
if (SystemDictionaryShared::is_sharing_possible(loader_data)) {
|
||||||
@ -1252,7 +1251,6 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik,
|
|||||||
classlist_file->flush();
|
classlist_file->flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// notify a class loaded from shared object
|
// notify a class loaded from shared object
|
||||||
ClassLoadingService::notify_class_loaded(InstanceKlass::cast(ik()),
|
ClassLoadingService::notify_class_loaded(InstanceKlass::cast(ik()),
|
||||||
@ -1260,7 +1258,7 @@ instanceKlassHandle SystemDictionary::load_shared_class(instanceKlassHandle ik,
|
|||||||
}
|
}
|
||||||
return ik;
|
return ik;
|
||||||
}
|
}
|
||||||
#endif
|
#endif // INCLUDE_CDS
|
||||||
|
|
||||||
instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) {
|
instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Handle class_loader, TRAPS) {
|
||||||
instanceKlassHandle nh = instanceKlassHandle(); // null Handle
|
instanceKlassHandle nh = instanceKlassHandle(); // null Handle
|
||||||
|
@ -399,7 +399,6 @@
|
|||||||
template(oop_size_name, "oop_size") \
|
template(oop_size_name, "oop_size") \
|
||||||
template(static_oop_field_count_name, "static_oop_field_count") \
|
template(static_oop_field_count_name, "static_oop_field_count") \
|
||||||
template(protection_domain_name, "protection_domain") \
|
template(protection_domain_name, "protection_domain") \
|
||||||
template(init_lock_name, "init_lock") \
|
|
||||||
template(signers_name, "signers_name") \
|
template(signers_name, "signers_name") \
|
||||||
template(loader_data_name, "loader_data") \
|
template(loader_data_name, "loader_data") \
|
||||||
template(dependencies_name, "dependencies") \
|
template(dependencies_name, "dependencies") \
|
||||||
@ -747,8 +746,6 @@
|
|||||||
do_name( isPrimitive_name, "isPrimitive") \
|
do_name( isPrimitive_name, "isPrimitive") \
|
||||||
do_intrinsic(_getSuperclass, java_lang_Class, getSuperclass_name, void_class_signature, F_RN) \
|
do_intrinsic(_getSuperclass, java_lang_Class, getSuperclass_name, void_class_signature, F_RN) \
|
||||||
do_name( getSuperclass_name, "getSuperclass") \
|
do_name( getSuperclass_name, "getSuperclass") \
|
||||||
do_intrinsic(_getComponentType, java_lang_Class, getComponentType_name, void_class_signature, F_RN) \
|
|
||||||
do_name( getComponentType_name, "getComponentType") \
|
|
||||||
\
|
\
|
||||||
do_intrinsic(_getClassAccessFlags, sun_reflect_Reflection, getClassAccessFlags_name, class_int_signature, F_SN) \
|
do_intrinsic(_getClassAccessFlags, sun_reflect_Reflection, getClassAccessFlags_name, class_int_signature, F_SN) \
|
||||||
do_name( getClassAccessFlags_name, "getClassAccessFlags") \
|
do_name( getClassAccessFlags_name, "getClassAccessFlags") \
|
||||||
@ -788,6 +785,11 @@
|
|||||||
do_name( encodeISOArray_name, "encodeISOArray") \
|
do_name( encodeISOArray_name, "encodeISOArray") \
|
||||||
do_signature(encodeISOArray_signature, "([CI[BII)I") \
|
do_signature(encodeISOArray_signature, "([CI[BII)I") \
|
||||||
\
|
\
|
||||||
|
do_class(java_math_BigInteger, "java/math/BigInteger") \
|
||||||
|
do_intrinsic(_multiplyToLen, java_math_BigInteger, multiplyToLen_name, multiplyToLen_signature, F_R) \
|
||||||
|
do_name( multiplyToLen_name, "multiplyToLen") \
|
||||||
|
do_signature(multiplyToLen_signature, "([II[II[I)[I") \
|
||||||
|
\
|
||||||
/* java/lang/ref/Reference */ \
|
/* java/lang/ref/Reference */ \
|
||||||
do_intrinsic(_Reference_get, java_lang_ref_Reference, get_name, void_object_signature, F_R) \
|
do_intrinsic(_Reference_get, java_lang_ref_Reference, get_name, void_object_signature, F_R) \
|
||||||
\
|
\
|
||||||
|
@ -238,6 +238,7 @@ void* BufferBlob::operator new(size_t s, unsigned size, bool is_critical) throw(
|
|||||||
|
|
||||||
void BufferBlob::free( BufferBlob *blob ) {
|
void BufferBlob::free( BufferBlob *blob ) {
|
||||||
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
|
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
|
||||||
|
blob->flush();
|
||||||
{
|
{
|
||||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||||
CodeCache::free((CodeBlob*)blob);
|
CodeCache::free((CodeBlob*)blob);
|
||||||
|
@ -168,48 +168,134 @@ bool MethodMatcher::match(Symbol* candidate, Symbol* match, Mode match_mode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum OptionType {
|
||||||
|
IntxType,
|
||||||
|
UintxType,
|
||||||
|
BoolType,
|
||||||
|
CcstrType,
|
||||||
|
UnknownType
|
||||||
|
};
|
||||||
|
|
||||||
class MethodOptionMatcher: public MethodMatcher {
|
/* Methods to map real type names to OptionType */
|
||||||
const char * option;
|
template<typename T>
|
||||||
public:
|
static OptionType get_type_for() {
|
||||||
MethodOptionMatcher(Symbol* class_name, Mode class_mode,
|
return UnknownType;
|
||||||
Symbol* method_name, Mode method_mode,
|
};
|
||||||
Symbol* signature, const char * opt, MethodMatcher* next):
|
|
||||||
MethodMatcher(class_name, class_mode, method_name, method_mode, signature, next) {
|
template<> OptionType get_type_for<intx>() {
|
||||||
option = os::strdup_check_oom(opt);
|
return IntxType;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> OptionType get_type_for<uintx>() {
|
||||||
|
return UintxType;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> OptionType get_type_for<bool>() {
|
||||||
|
return BoolType;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> OptionType get_type_for<ccstr>() {
|
||||||
|
return CcstrType;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static const T copy_value(const T value) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<> const ccstr copy_value<ccstr>(const ccstr value) {
|
||||||
|
return (const ccstr)os::strdup_check_oom(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class TypedMethodOptionMatcher : public MethodMatcher {
|
||||||
|
const char* _option;
|
||||||
|
OptionType _type;
|
||||||
|
const T _value;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TypedMethodOptionMatcher(Symbol* class_name, Mode class_mode,
|
||||||
|
Symbol* method_name, Mode method_mode,
|
||||||
|
Symbol* signature, const char* opt,
|
||||||
|
const T value, MethodMatcher* next) :
|
||||||
|
MethodMatcher(class_name, class_mode, method_name, method_mode, signature, next),
|
||||||
|
_type(get_type_for<T>()), _value(copy_value<T>(value)) {
|
||||||
|
_option = os::strdup_check_oom(opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~MethodOptionMatcher() {
|
~TypedMethodOptionMatcher() {
|
||||||
os::free((void*)option);
|
os::free((void*)_option);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool match(methodHandle method, const char* opt) {
|
TypedMethodOptionMatcher* match(methodHandle method, const char* opt) {
|
||||||
MethodOptionMatcher* current = this;
|
TypedMethodOptionMatcher* current = this;
|
||||||
while (current != NULL) {
|
while (current != NULL) {
|
||||||
current = (MethodOptionMatcher*)current->find(method);
|
current = (TypedMethodOptionMatcher*)current->find(method);
|
||||||
if (current == NULL) {
|
if (current == NULL) {
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (strcmp(current->option, opt) == 0) {
|
if (strcmp(current->_option, opt) == 0) {
|
||||||
return true;
|
return current;
|
||||||
}
|
}
|
||||||
current = current->next();
|
current = current->next();
|
||||||
}
|
}
|
||||||
return false;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
MethodOptionMatcher* next() {
|
TypedMethodOptionMatcher* next() {
|
||||||
return (MethodOptionMatcher*)_next;
|
return (TypedMethodOptionMatcher*)_next;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void print() {
|
OptionType get_type(void) {
|
||||||
|
return _type;
|
||||||
|
};
|
||||||
|
|
||||||
|
T value() { return _value; }
|
||||||
|
|
||||||
|
void print() {
|
||||||
|
ttyLocker ttyl;
|
||||||
print_base();
|
print_base();
|
||||||
tty->print(" %s", option);
|
tty->print(" %s", _option);
|
||||||
|
tty->print(" <unknown option type>");
|
||||||
tty->cr();
|
tty->cr();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void TypedMethodOptionMatcher<intx>::print() {
|
||||||
|
ttyLocker ttyl;
|
||||||
|
print_base();
|
||||||
|
tty->print(" intx %s", _option);
|
||||||
|
tty->print(" = " INTX_FORMAT, _value);
|
||||||
|
tty->cr();
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void TypedMethodOptionMatcher<uintx>::print() {
|
||||||
|
ttyLocker ttyl;
|
||||||
|
print_base();
|
||||||
|
tty->print(" uintx %s", _option);
|
||||||
|
tty->print(" = " UINTX_FORMAT, _value);
|
||||||
|
tty->cr();
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void TypedMethodOptionMatcher<bool>::print() {
|
||||||
|
ttyLocker ttyl;
|
||||||
|
print_base();
|
||||||
|
tty->print(" bool %s", _option);
|
||||||
|
tty->print(" = %s", _value ? "true" : "false");
|
||||||
|
tty->cr();
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void TypedMethodOptionMatcher<ccstr>::print() {
|
||||||
|
ttyLocker ttyl;
|
||||||
|
print_base();
|
||||||
|
tty->print(" const char* %s", _option);
|
||||||
|
tty->print(" = '%s'", _value);
|
||||||
|
tty->cr();
|
||||||
|
};
|
||||||
|
|
||||||
// this must parallel the command_names below
|
// this must parallel the command_names below
|
||||||
enum OracleCommand {
|
enum OracleCommand {
|
||||||
@ -264,23 +350,46 @@ static MethodMatcher* add_predicate(OracleCommand command,
|
|||||||
return lists[command];
|
return lists[command];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
|
||||||
static MethodMatcher* add_option_string(Symbol* class_name, MethodMatcher::Mode c_mode,
|
static MethodMatcher* add_option_string(Symbol* class_name, MethodMatcher::Mode c_mode,
|
||||||
Symbol* method_name, MethodMatcher::Mode m_mode,
|
Symbol* method_name, MethodMatcher::Mode m_mode,
|
||||||
Symbol* signature,
|
Symbol* signature,
|
||||||
const char* option) {
|
const char* option,
|
||||||
lists[OptionCommand] = new MethodOptionMatcher(class_name, c_mode, method_name, m_mode,
|
T value) {
|
||||||
signature, option, lists[OptionCommand]);
|
lists[OptionCommand] = new TypedMethodOptionMatcher<T>(class_name, c_mode, method_name, m_mode,
|
||||||
|
signature, option, value, lists[OptionCommand]);
|
||||||
return lists[OptionCommand];
|
return lists[OptionCommand];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
bool CompilerOracle::has_option_string(methodHandle method, const char* option) {
|
static bool get_option_value(methodHandle method, const char* option, T& value) {
|
||||||
return lists[OptionCommand] != NULL &&
|
TypedMethodOptionMatcher<T>* m;
|
||||||
((MethodOptionMatcher*)lists[OptionCommand])->match(method, option);
|
if (lists[OptionCommand] != NULL
|
||||||
|
&& (m = ((TypedMethodOptionMatcher<T>*)lists[OptionCommand])->match(method, option)) != NULL
|
||||||
|
&& m->get_type() == get_type_for<T>()) {
|
||||||
|
value = m->value();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CompilerOracle::has_option_string(methodHandle method, const char* option) {
|
||||||
|
bool value = false;
|
||||||
|
get_option_value(method, option, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
bool CompilerOracle::has_option_value(methodHandle method, const char* option, T& value) {
|
||||||
|
return ::get_option_value(method, option, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explicit instantiation for all OptionTypes supported.
|
||||||
|
template bool CompilerOracle::has_option_value<intx>(methodHandle method, const char* option, intx& value);
|
||||||
|
template bool CompilerOracle::has_option_value<uintx>(methodHandle method, const char* option, uintx& value);
|
||||||
|
template bool CompilerOracle::has_option_value<bool>(methodHandle method, const char* option, bool& value);
|
||||||
|
template bool CompilerOracle::has_option_value<ccstr>(methodHandle method, const char* option, ccstr& value);
|
||||||
|
|
||||||
bool CompilerOracle::should_exclude(methodHandle method, bool& quietly) {
|
bool CompilerOracle::should_exclude(methodHandle method, bool& quietly) {
|
||||||
quietly = true;
|
quietly = true;
|
||||||
@ -422,6 +531,94 @@ static bool scan_line(const char * line,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Scan next flag and value in line, return MethodMatcher object on success, NULL on failure.
|
||||||
|
// On failure, error_msg contains description for the first error.
|
||||||
|
// For future extensions: set error_msg on first error.
|
||||||
|
static MethodMatcher* scan_flag_and_value(const char* type, const char* line, int& total_bytes_read,
|
||||||
|
Symbol* c_name, MethodMatcher::Mode c_match,
|
||||||
|
Symbol* m_name, MethodMatcher::Mode m_match,
|
||||||
|
Symbol* signature,
|
||||||
|
char* errorbuf, const int buf_size) {
|
||||||
|
total_bytes_read = 0;
|
||||||
|
int bytes_read = 0;
|
||||||
|
char flag[256];
|
||||||
|
|
||||||
|
// Read flag name.
|
||||||
|
if (sscanf(line, "%*[ \t]%255[a-zA-Z0-9]%n", flag, &bytes_read) == 1) {
|
||||||
|
line += bytes_read;
|
||||||
|
total_bytes_read += bytes_read;
|
||||||
|
|
||||||
|
// Read value.
|
||||||
|
if (strcmp(type, "intx") == 0) {
|
||||||
|
intx value;
|
||||||
|
if (sscanf(line, "%*[ \t]" INTX_FORMAT "%n", &value, &bytes_read) == 1) {
|
||||||
|
total_bytes_read += bytes_read;
|
||||||
|
return add_option_string(c_name, c_match, m_name, m_match, signature, flag, value);
|
||||||
|
} else {
|
||||||
|
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s ", flag, type);
|
||||||
|
}
|
||||||
|
} else if (strcmp(type, "uintx") == 0) {
|
||||||
|
uintx value;
|
||||||
|
if (sscanf(line, "%*[ \t]" UINTX_FORMAT "%n", &value, &bytes_read) == 1) {
|
||||||
|
total_bytes_read += bytes_read;
|
||||||
|
return add_option_string(c_name, c_match, m_name, m_match, signature, flag, value);
|
||||||
|
} else {
|
||||||
|
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type);
|
||||||
|
}
|
||||||
|
} else if (strcmp(type, "ccstr") == 0) {
|
||||||
|
ResourceMark rm;
|
||||||
|
char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1);
|
||||||
|
if (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n", value, &bytes_read) == 1) {
|
||||||
|
total_bytes_read += bytes_read;
|
||||||
|
return add_option_string(c_name, c_match, m_name, m_match, signature, flag, (ccstr)value);
|
||||||
|
} else {
|
||||||
|
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type);
|
||||||
|
}
|
||||||
|
} else if (strcmp(type, "ccstrlist") == 0) {
|
||||||
|
// Accumulates several strings into one. The internal type is ccstr.
|
||||||
|
ResourceMark rm;
|
||||||
|
char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1);
|
||||||
|
char* next_value = value;
|
||||||
|
if (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n", next_value, &bytes_read) == 1) {
|
||||||
|
total_bytes_read += bytes_read;
|
||||||
|
line += bytes_read;
|
||||||
|
next_value += bytes_read;
|
||||||
|
char* end_value = next_value-1;
|
||||||
|
while (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n", next_value, &bytes_read) == 1) {
|
||||||
|
total_bytes_read += bytes_read;
|
||||||
|
line += bytes_read;
|
||||||
|
*end_value = ' '; // override '\0'
|
||||||
|
next_value += bytes_read;
|
||||||
|
end_value = next_value-1;
|
||||||
|
}
|
||||||
|
return add_option_string(c_name, c_match, m_name, m_match, signature, flag, (ccstr)value);
|
||||||
|
} else {
|
||||||
|
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type);
|
||||||
|
}
|
||||||
|
} else if (strcmp(type, "bool") == 0) {
|
||||||
|
char value[256];
|
||||||
|
if (sscanf(line, "%*[ \t]%255[a-zA-Z]%n", value, &bytes_read) == 1) {
|
||||||
|
if (strcmp(value, "true") == 0) {
|
||||||
|
total_bytes_read += bytes_read;
|
||||||
|
return add_option_string(c_name, c_match, m_name, m_match, signature, flag, true);
|
||||||
|
} else if (strcmp(value, "false") == 0) {
|
||||||
|
total_bytes_read += bytes_read;
|
||||||
|
return add_option_string(c_name, c_match, m_name, m_match, signature, flag, false);
|
||||||
|
} else {
|
||||||
|
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
jio_snprintf(errorbuf, sizeof(errorbuf), " Value cannot be read for flag %s of type %s", flag, type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
jio_snprintf(errorbuf, sizeof(errorbuf), " Type %s not supported ", type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
jio_snprintf(errorbuf, sizeof(errorbuf), " Flag name for type %s should be alphanumeric ", type);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void CompilerOracle::parse_from_line(char* line) {
|
void CompilerOracle::parse_from_line(char* line) {
|
||||||
if (line[0] == '\0') return;
|
if (line[0] == '\0') return;
|
||||||
if (line[0] == '#') return;
|
if (line[0] == '#') return;
|
||||||
@ -451,8 +648,10 @@ void CompilerOracle::parse_from_line(char* line) {
|
|||||||
int bytes_read;
|
int bytes_read;
|
||||||
OracleCommand command = parse_command_name(line, &bytes_read);
|
OracleCommand command = parse_command_name(line, &bytes_read);
|
||||||
line += bytes_read;
|
line += bytes_read;
|
||||||
|
ResourceMark rm;
|
||||||
|
|
||||||
if (command == UnknownCommand) {
|
if (command == UnknownCommand) {
|
||||||
|
ttyLocker ttyl;
|
||||||
tty->print_cr("CompilerOracle: unrecognized line");
|
tty->print_cr("CompilerOracle: unrecognized line");
|
||||||
tty->print_cr(" \"%s\"", original_line);
|
tty->print_cr(" \"%s\"", original_line);
|
||||||
return;
|
return;
|
||||||
@ -474,7 +673,7 @@ void CompilerOracle::parse_from_line(char* line) {
|
|||||||
char method_name[256];
|
char method_name[256];
|
||||||
char sig[1024];
|
char sig[1024];
|
||||||
char errorbuf[1024];
|
char errorbuf[1024];
|
||||||
const char* error_msg = NULL;
|
const char* error_msg = NULL; // description of first error that appears
|
||||||
MethodMatcher* match = NULL;
|
MethodMatcher* match = NULL;
|
||||||
|
|
||||||
if (scan_line(line, class_name, &c_match, method_name, &m_match, &bytes_read, error_msg)) {
|
if (scan_line(line, class_name, &c_match, method_name, &m_match, &bytes_read, error_msg)) {
|
||||||
@ -493,43 +692,77 @@ void CompilerOracle::parse_from_line(char* line) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (command == OptionCommand) {
|
if (command == OptionCommand) {
|
||||||
// Look for trailing options to support
|
// Look for trailing options.
|
||||||
// ciMethod::has_option("string") to control features in the
|
//
|
||||||
// compiler. Multiple options may follow the method name.
|
// Two types of trailing options are
|
||||||
char option[256];
|
// supported:
|
||||||
|
//
|
||||||
|
// (1) CompileCommand=option,Klass::method,flag
|
||||||
|
// (2) CompileCommand=option,Klass::method,type,flag,value
|
||||||
|
//
|
||||||
|
// Type (1) is used to support ciMethod::has_option("someflag")
|
||||||
|
// (i.e., to check if a flag "someflag" is enabled for a method).
|
||||||
|
//
|
||||||
|
// Type (2) is used to support options with a value. Values can have the
|
||||||
|
// the following types: intx, uintx, bool, ccstr, and ccstrlist.
|
||||||
|
//
|
||||||
|
// For future extensions: extend scan_flag_and_value()
|
||||||
|
char option[256]; // stores flag for Type (1) and type of Type (2)
|
||||||
while (sscanf(line, "%*[ \t]%255[a-zA-Z0-9]%n", option, &bytes_read) == 1) {
|
while (sscanf(line, "%*[ \t]%255[a-zA-Z0-9]%n", option, &bytes_read) == 1) {
|
||||||
if (match != NULL && !_quiet) {
|
if (match != NULL && !_quiet) {
|
||||||
// Print out the last match added
|
// Print out the last match added
|
||||||
|
ttyLocker ttyl;
|
||||||
tty->print("CompilerOracle: %s ", command_names[command]);
|
tty->print("CompilerOracle: %s ", command_names[command]);
|
||||||
match->print();
|
match->print();
|
||||||
}
|
}
|
||||||
match = add_option_string(c_name, c_match, m_name, m_match, signature, option);
|
|
||||||
line += bytes_read;
|
line += bytes_read;
|
||||||
}
|
|
||||||
|
if (strcmp(option, "intx") == 0
|
||||||
|
|| strcmp(option, "uintx") == 0
|
||||||
|
|| strcmp(option, "bool") == 0
|
||||||
|
|| strcmp(option, "ccstr") == 0
|
||||||
|
|| strcmp(option, "ccstrlist") == 0
|
||||||
|
) {
|
||||||
|
|
||||||
|
// Type (2) option: parse flag name and value.
|
||||||
|
match = scan_flag_and_value(option, line, bytes_read,
|
||||||
|
c_name, c_match, m_name, m_match, signature,
|
||||||
|
errorbuf, sizeof(errorbuf));
|
||||||
|
if (match == NULL) {
|
||||||
|
error_msg = errorbuf;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
line += bytes_read;
|
||||||
|
} else {
|
||||||
|
// Type (1) option
|
||||||
|
match = add_option_string(c_name, c_match, m_name, m_match, signature, option, true);
|
||||||
|
}
|
||||||
|
} // while(
|
||||||
} else {
|
} else {
|
||||||
bytes_read = 0;
|
match = add_predicate(command, c_name, c_match, m_name, m_match, signature);
|
||||||
sscanf(line, "%*[ \t]%n", &bytes_read);
|
|
||||||
if (line[bytes_read] != '\0') {
|
|
||||||
jio_snprintf(errorbuf, sizeof(errorbuf), " Unrecognized text after command: %s", line);
|
|
||||||
error_msg = errorbuf;
|
|
||||||
} else {
|
|
||||||
match = add_predicate(command, c_name, c_match, m_name, m_match, signature);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (match != NULL) {
|
ttyLocker ttyl;
|
||||||
if (!_quiet) {
|
if (error_msg != NULL) {
|
||||||
ResourceMark rm;
|
// an error has happened
|
||||||
tty->print("CompilerOracle: %s ", command_names[command]);
|
|
||||||
match->print();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tty->print_cr("CompilerOracle: unrecognized line");
|
tty->print_cr("CompilerOracle: unrecognized line");
|
||||||
tty->print_cr(" \"%s\"", original_line);
|
tty->print_cr(" \"%s\"", original_line);
|
||||||
if (error_msg != NULL) {
|
if (error_msg != NULL) {
|
||||||
tty->print_cr("%s", error_msg);
|
tty->print_cr("%s", error_msg);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// check for remaining characters
|
||||||
|
bytes_read = 0;
|
||||||
|
sscanf(line, "%*[ \t]%n", &bytes_read);
|
||||||
|
if (line[bytes_read] != '\0') {
|
||||||
|
tty->print_cr("CompilerOracle: unrecognized line");
|
||||||
|
tty->print_cr(" \"%s\"", original_line);
|
||||||
|
tty->print_cr(" Unrecognized text %s after command ", line);
|
||||||
|
} else if (match != NULL && !_quiet) {
|
||||||
|
tty->print("CompilerOracle: %s ", command_names[command]);
|
||||||
|
match->print();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,6 +64,11 @@ class CompilerOracle : AllStatic {
|
|||||||
// Check to see if this method has option set for it
|
// Check to see if this method has option set for it
|
||||||
static bool has_option_string(methodHandle method, const char * option);
|
static bool has_option_string(methodHandle method, const char * option);
|
||||||
|
|
||||||
|
// Check if method has option and value set. If yes, overwrite value and return true,
|
||||||
|
// otherwise leave value unchanged and return false.
|
||||||
|
template<typename T>
|
||||||
|
static bool has_option_value(methodHandle method, const char* option, T& value);
|
||||||
|
|
||||||
// Reads from string instead of file
|
// Reads from string instead of file
|
||||||
static void parse_from_string(const char* command_string, void (*parser)(char*));
|
static void parse_from_string(const char* command_string, void (*parser)(char*));
|
||||||
|
|
||||||
|
@ -246,12 +246,12 @@ class decode_env {
|
|||||||
};
|
};
|
||||||
|
|
||||||
decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c) {
|
decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c) {
|
||||||
memset(this, 0, sizeof(*this));
|
memset(this, 0, sizeof(*this)); // Beware, this zeroes bits of fields.
|
||||||
_output = output ? output : tty;
|
_output = output ? output : tty;
|
||||||
_code = code;
|
_code = code;
|
||||||
if (code != NULL && code->is_nmethod())
|
if (code != NULL && code->is_nmethod())
|
||||||
_nm = (nmethod*) code;
|
_nm = (nmethod*) code;
|
||||||
_strings.assign(c);
|
_strings.copy(c);
|
||||||
|
|
||||||
// by default, output pc but not bytes:
|
// by default, output pc but not bytes:
|
||||||
_print_pc = true;
|
_print_pc = true;
|
||||||
|
@ -22,372 +22,375 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "code/codeCache.hpp"
|
||||||
#include "code/nmethod.hpp"
|
#include "code/nmethod.hpp"
|
||||||
#include "gc_implementation/g1/g1CodeCacheRemSet.hpp"
|
#include "gc_implementation/g1/g1CodeCacheRemSet.hpp"
|
||||||
|
#include "gc_implementation/g1/heapRegion.hpp"
|
||||||
|
#include "memory/heap.hpp"
|
||||||
#include "memory/iterator.hpp"
|
#include "memory/iterator.hpp"
|
||||||
|
#include "oops/oop.inline.hpp"
|
||||||
|
#include "utilities/hashtable.inline.hpp"
|
||||||
|
#include "utilities/stack.inline.hpp"
|
||||||
|
|
||||||
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
|
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
|
||||||
|
|
||||||
G1CodeRootChunk::G1CodeRootChunk() : _top(NULL), _next(NULL), _prev(NULL), _free(NULL) {
|
class CodeRootSetTable : public Hashtable<nmethod*, mtGC> {
|
||||||
_top = bottom();
|
friend class G1CodeRootSetTest;
|
||||||
|
typedef HashtableEntry<nmethod*, mtGC> Entry;
|
||||||
|
|
||||||
|
static CodeRootSetTable* volatile _purge_list;
|
||||||
|
|
||||||
|
CodeRootSetTable* _purge_next;
|
||||||
|
|
||||||
|
unsigned int compute_hash(nmethod* nm) {
|
||||||
|
uintptr_t hash = (uintptr_t)nm;
|
||||||
|
return hash ^ (hash >> 7); // code heap blocks are 128byte aligned
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry* new_entry(nmethod* nm);
|
||||||
|
|
||||||
|
public:
|
||||||
|
CodeRootSetTable(int size) : Hashtable<nmethod*, mtGC>(size, sizeof(Entry)), _purge_next(NULL) {}
|
||||||
|
~CodeRootSetTable();
|
||||||
|
|
||||||
|
// Needs to be protected locks
|
||||||
|
bool add(nmethod* nm);
|
||||||
|
bool remove(nmethod* nm);
|
||||||
|
|
||||||
|
// Can be called without locking
|
||||||
|
bool contains(nmethod* nm);
|
||||||
|
|
||||||
|
int entry_size() const { return BasicHashtable<mtGC>::entry_size(); }
|
||||||
|
|
||||||
|
void copy_to(CodeRootSetTable* new_table);
|
||||||
|
void nmethods_do(CodeBlobClosure* blk);
|
||||||
|
|
||||||
|
template<typename CB>
|
||||||
|
void remove_if(CB& should_remove);
|
||||||
|
|
||||||
|
static void purge_list_append(CodeRootSetTable* tbl);
|
||||||
|
static void purge();
|
||||||
|
|
||||||
|
static size_t static_mem_size() {
|
||||||
|
return sizeof(_purge_list);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CodeRootSetTable* volatile CodeRootSetTable::_purge_list = NULL;
|
||||||
|
|
||||||
|
CodeRootSetTable::Entry* CodeRootSetTable::new_entry(nmethod* nm) {
|
||||||
|
unsigned int hash = compute_hash(nm);
|
||||||
|
Entry* entry = (Entry*) new_entry_free_list();
|
||||||
|
if (entry == NULL) {
|
||||||
|
entry = (Entry*) NEW_C_HEAP_ARRAY2(char, entry_size(), mtGC, CURRENT_PC);
|
||||||
|
}
|
||||||
|
entry->set_next(NULL);
|
||||||
|
entry->set_hash(hash);
|
||||||
|
entry->set_literal(nm);
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
void G1CodeRootChunk::reset() {
|
CodeRootSetTable::~CodeRootSetTable() {
|
||||||
_next = _prev = NULL;
|
for (int index = 0; index < table_size(); ++index) {
|
||||||
_free = NULL;
|
for (Entry* e = bucket(index); e != NULL; ) {
|
||||||
_top = bottom();
|
Entry* to_remove = e;
|
||||||
}
|
// read next before freeing.
|
||||||
|
e = e->next();
|
||||||
void G1CodeRootChunk::nmethods_do(CodeBlobClosure* cl) {
|
unlink_entry(to_remove);
|
||||||
NmethodOrLink* cur = bottom();
|
FREE_C_HEAP_ARRAY(char, to_remove, mtGC);
|
||||||
while (cur != _top) {
|
|
||||||
if (is_nmethod(cur)) {
|
|
||||||
cl->do_code_blob(cur->_nmethod);
|
|
||||||
}
|
}
|
||||||
cur++;
|
}
|
||||||
|
assert(number_of_entries() == 0, "should have removed all entries");
|
||||||
|
free_buckets();
|
||||||
|
for (BasicHashtableEntry<mtGC>* e = new_entry_free_list(); e != NULL; e = new_entry_free_list()) {
|
||||||
|
FREE_C_HEAP_ARRAY(char, e, mtGC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool G1CodeRootChunk::remove_lock_free(nmethod* method) {
|
bool CodeRootSetTable::add(nmethod* nm) {
|
||||||
NmethodOrLink* cur = bottom();
|
if (!contains(nm)) {
|
||||||
|
Entry* e = new_entry(nm);
|
||||||
for (NmethodOrLink* cur = bottom(); cur != _top; cur++) {
|
int index = hash_to_index(e->hash());
|
||||||
if (cur->_nmethod == method) {
|
add_entry(index, e);
|
||||||
bool result = Atomic::cmpxchg_ptr(NULL, &cur->_nmethod, method) == method;
|
return true;
|
||||||
|
|
||||||
if (!result) {
|
|
||||||
// Someone else cleared out this entry.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The method was cleared. Time to link it into the free list.
|
|
||||||
NmethodOrLink* prev_free;
|
|
||||||
do {
|
|
||||||
prev_free = (NmethodOrLink*)_free;
|
|
||||||
cur->_link = prev_free;
|
|
||||||
} while (Atomic::cmpxchg_ptr(cur, &_free, prev_free) != prev_free);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
G1CodeRootChunkManager::G1CodeRootChunkManager() : _free_list(), _num_chunks_handed_out(0) {
|
bool CodeRootSetTable::contains(nmethod* nm) {
|
||||||
_free_list.initialize();
|
int index = hash_to_index(compute_hash(nm));
|
||||||
_free_list.set_size(G1CodeRootChunk::word_size());
|
for (Entry* e = bucket(index); e != NULL; e = e->next()) {
|
||||||
}
|
if (e->literal() == nm) {
|
||||||
|
return true;
|
||||||
size_t G1CodeRootChunkManager::fl_mem_size() {
|
}
|
||||||
return _free_list.count() * _free_list.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void G1CodeRootChunkManager::free_all_chunks(FreeList<G1CodeRootChunk>* list) {
|
|
||||||
_num_chunks_handed_out -= list->count();
|
|
||||||
_free_list.prepend(list);
|
|
||||||
}
|
|
||||||
|
|
||||||
void G1CodeRootChunkManager::free_chunk(G1CodeRootChunk* chunk) {
|
|
||||||
_free_list.return_chunk_at_head(chunk);
|
|
||||||
_num_chunks_handed_out--;
|
|
||||||
}
|
|
||||||
|
|
||||||
void G1CodeRootChunkManager::purge_chunks(size_t keep_ratio) {
|
|
||||||
size_t keep = _num_chunks_handed_out * keep_ratio / 100;
|
|
||||||
if (keep >= (size_t)_free_list.count()) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
FreeList<G1CodeRootChunk> temp;
|
bool CodeRootSetTable::remove(nmethod* nm) {
|
||||||
temp.initialize();
|
int index = hash_to_index(compute_hash(nm));
|
||||||
temp.set_size(G1CodeRootChunk::word_size());
|
Entry* previous = NULL;
|
||||||
|
for (Entry* e = bucket(index); e != NULL; previous = e, e = e->next()) {
|
||||||
|
if (e->literal() == nm) {
|
||||||
|
if (previous != NULL) {
|
||||||
|
previous->set_next(e->next());
|
||||||
|
} else {
|
||||||
|
set_entry(index, e->next());
|
||||||
|
}
|
||||||
|
free_entry(e);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
_free_list.getFirstNChunksFromList((size_t)_free_list.count() - keep, &temp);
|
void CodeRootSetTable::copy_to(CodeRootSetTable* new_table) {
|
||||||
|
for (int index = 0; index < table_size(); ++index) {
|
||||||
|
for (Entry* e = bucket(index); e != NULL; e = e->next()) {
|
||||||
|
new_table->add(e->literal());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
new_table->copy_freelist(this);
|
||||||
|
}
|
||||||
|
|
||||||
G1CodeRootChunk* cur = temp.get_chunk_at_head();
|
void CodeRootSetTable::nmethods_do(CodeBlobClosure* blk) {
|
||||||
while (cur != NULL) {
|
for (int index = 0; index < table_size(); ++index) {
|
||||||
delete cur;
|
for (Entry* e = bucket(index); e != NULL; e = e->next()) {
|
||||||
cur = temp.get_chunk_at_head();
|
blk->do_code_blob(e->literal());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t G1CodeRootChunkManager::static_mem_size() {
|
template<typename CB>
|
||||||
return sizeof(G1CodeRootChunkManager);
|
void CodeRootSetTable::remove_if(CB& should_remove) {
|
||||||
}
|
for (int index = 0; index < table_size(); ++index) {
|
||||||
|
Entry* previous = NULL;
|
||||||
|
Entry* e = bucket(index);
|
||||||
G1CodeRootChunk* G1CodeRootChunkManager::new_chunk() {
|
while (e != NULL) {
|
||||||
G1CodeRootChunk* result = _free_list.get_chunk_at_head();
|
Entry* next = e->next();
|
||||||
if (result == NULL) {
|
if (should_remove(e->literal())) {
|
||||||
result = new G1CodeRootChunk();
|
if (previous != NULL) {
|
||||||
|
previous->set_next(next);
|
||||||
|
} else {
|
||||||
|
set_entry(index, next);
|
||||||
|
}
|
||||||
|
free_entry(e);
|
||||||
|
} else {
|
||||||
|
previous = e;
|
||||||
|
}
|
||||||
|
e = next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_num_chunks_handed_out++;
|
|
||||||
result->reset();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
|
|
||||||
size_t G1CodeRootChunkManager::num_chunks_handed_out() const {
|
|
||||||
return _num_chunks_handed_out;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t G1CodeRootChunkManager::num_free_chunks() const {
|
|
||||||
return (size_t)_free_list.count();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
G1CodeRootChunkManager G1CodeRootSet::_default_chunk_manager;
|
|
||||||
|
|
||||||
void G1CodeRootSet::purge_chunks(size_t keep_ratio) {
|
|
||||||
_default_chunk_manager.purge_chunks(keep_ratio);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t G1CodeRootSet::free_chunks_static_mem_size() {
|
|
||||||
return _default_chunk_manager.static_mem_size();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t G1CodeRootSet::free_chunks_mem_size() {
|
|
||||||
return _default_chunk_manager.fl_mem_size();
|
|
||||||
}
|
|
||||||
|
|
||||||
G1CodeRootSet::G1CodeRootSet(G1CodeRootChunkManager* manager) : _manager(manager), _list(), _length(0) {
|
|
||||||
if (_manager == NULL) {
|
|
||||||
_manager = &_default_chunk_manager;
|
|
||||||
}
|
|
||||||
_list.initialize();
|
|
||||||
_list.set_size(G1CodeRootChunk::word_size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
G1CodeRootSet::~G1CodeRootSet() {
|
G1CodeRootSet::~G1CodeRootSet() {
|
||||||
clear();
|
delete _table;
|
||||||
}
|
}
|
||||||
|
|
||||||
void G1CodeRootSet::add(nmethod* method) {
|
CodeRootSetTable* G1CodeRootSet::load_acquire_table() {
|
||||||
if (!contains(method)) {
|
return (CodeRootSetTable*) OrderAccess::load_ptr_acquire(&_table);
|
||||||
// Find the first chunk that isn't full.
|
|
||||||
G1CodeRootChunk* cur = _list.head();
|
|
||||||
while (cur != NULL) {
|
|
||||||
if (!cur->is_full()) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cur = cur->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// All chunks are full, get a new chunk.
|
|
||||||
if (cur == NULL) {
|
|
||||||
cur = new_chunk();
|
|
||||||
_list.return_chunk_at_head(cur);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the nmethod.
|
|
||||||
bool result = cur->add(method);
|
|
||||||
|
|
||||||
guarantee(result, err_msg("Not able to add nmethod "PTR_FORMAT" to newly allocated chunk.", method));
|
|
||||||
|
|
||||||
_length++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void G1CodeRootSet::remove_lock_free(nmethod* method) {
|
void G1CodeRootSet::allocate_small_table() {
|
||||||
G1CodeRootChunk* found = find(method);
|
_table = new CodeRootSetTable(SmallSize);
|
||||||
if (found != NULL) {
|
|
||||||
bool result = found->remove_lock_free(method);
|
|
||||||
if (result) {
|
|
||||||
Atomic::dec_ptr((volatile intptr_t*)&_length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(!contains(method), err_msg(PTR_FORMAT" still contains nmethod "PTR_FORMAT, this, method));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nmethod* G1CodeRootSet::pop() {
|
void CodeRootSetTable::purge_list_append(CodeRootSetTable* table) {
|
||||||
while (true) {
|
for (;;) {
|
||||||
G1CodeRootChunk* cur = _list.head();
|
table->_purge_next = _purge_list;
|
||||||
if (cur == NULL) {
|
CodeRootSetTable* old = (CodeRootSetTable*) Atomic::cmpxchg_ptr(table, &_purge_list, table->_purge_next);
|
||||||
assert(_length == 0, "when there are no chunks, there should be no elements");
|
if (old == table->_purge_next) {
|
||||||
return NULL;
|
break;
|
||||||
}
|
|
||||||
nmethod* result = cur->pop();
|
|
||||||
if (result != NULL) {
|
|
||||||
_length--;
|
|
||||||
return result;
|
|
||||||
} else {
|
|
||||||
free(_list.get_chunk_at_head());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
G1CodeRootChunk* G1CodeRootSet::find(nmethod* method) {
|
void CodeRootSetTable::purge() {
|
||||||
G1CodeRootChunk* cur = _list.head();
|
CodeRootSetTable* table = _purge_list;
|
||||||
while (cur != NULL) {
|
_purge_list = NULL;
|
||||||
if (cur->contains(method)) {
|
while (table != NULL) {
|
||||||
return cur;
|
CodeRootSetTable* to_purge = table;
|
||||||
}
|
table = table->_purge_next;
|
||||||
cur = (G1CodeRootChunk*)cur->next();
|
delete to_purge;
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void G1CodeRootSet::free(G1CodeRootChunk* chunk) {
|
void G1CodeRootSet::move_to_large() {
|
||||||
free_chunk(chunk);
|
CodeRootSetTable* temp = new CodeRootSetTable(LargeSize);
|
||||||
|
|
||||||
|
_table->copy_to(temp);
|
||||||
|
|
||||||
|
CodeRootSetTable::purge_list_append(_table);
|
||||||
|
|
||||||
|
OrderAccess::release_store_ptr(&_table, temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool G1CodeRootSet::contains(nmethod* method) {
|
|
||||||
return find(method) != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void G1CodeRootSet::clear() {
|
void G1CodeRootSet::purge() {
|
||||||
free_all_chunks(&_list);
|
CodeRootSetTable::purge();
|
||||||
_length = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void G1CodeRootSet::nmethods_do(CodeBlobClosure* blk) const {
|
|
||||||
G1CodeRootChunk* cur = _list.head();
|
|
||||||
while (cur != NULL) {
|
|
||||||
cur->nmethods_do(blk);
|
|
||||||
cur = (G1CodeRootChunk*)cur->next();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t G1CodeRootSet::static_mem_size() {
|
size_t G1CodeRootSet::static_mem_size() {
|
||||||
return sizeof(G1CodeRootSet);
|
return CodeRootSetTable::static_mem_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void G1CodeRootSet::add(nmethod* method) {
|
||||||
|
bool added = false;
|
||||||
|
if (is_empty()) {
|
||||||
|
allocate_small_table();
|
||||||
|
}
|
||||||
|
added = _table->add(method);
|
||||||
|
if (_length == Threshold) {
|
||||||
|
move_to_large();
|
||||||
|
}
|
||||||
|
if (added) {
|
||||||
|
++_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool G1CodeRootSet::remove(nmethod* method) {
|
||||||
|
bool removed = false;
|
||||||
|
if (_table != NULL) {
|
||||||
|
removed = _table->remove(method);
|
||||||
|
}
|
||||||
|
if (removed) {
|
||||||
|
_length--;
|
||||||
|
if (_length == 0) {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool G1CodeRootSet::contains(nmethod* method) {
|
||||||
|
CodeRootSetTable* table = load_acquire_table();
|
||||||
|
if (table != NULL) {
|
||||||
|
return table->contains(method);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void G1CodeRootSet::clear() {
|
||||||
|
delete _table;
|
||||||
|
_table = NULL;
|
||||||
|
_length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t G1CodeRootSet::mem_size() {
|
size_t G1CodeRootSet::mem_size() {
|
||||||
return G1CodeRootSet::static_mem_size() + _list.count() * _list.size();
|
return sizeof(*this) +
|
||||||
|
(_table != NULL ? sizeof(CodeRootSetTable) + _table->entry_size() * _length : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void G1CodeRootSet::nmethods_do(CodeBlobClosure* blk) const {
|
||||||
|
if (_table != NULL) {
|
||||||
|
_table->nmethods_do(blk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CleanCallback : public StackObj {
|
||||||
|
class PointsIntoHRDetectionClosure : public OopClosure {
|
||||||
|
HeapRegion* _hr;
|
||||||
|
public:
|
||||||
|
bool _points_into;
|
||||||
|
PointsIntoHRDetectionClosure(HeapRegion* hr) : _hr(hr), _points_into(false) {}
|
||||||
|
|
||||||
|
void do_oop(narrowOop* o) {
|
||||||
|
do_oop_work(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_oop(oop* o) {
|
||||||
|
do_oop_work(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void do_oop_work(T* p) {
|
||||||
|
if (_hr->is_in(oopDesc::load_decode_heap_oop(p))) {
|
||||||
|
_points_into = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
PointsIntoHRDetectionClosure _detector;
|
||||||
|
CodeBlobToOopClosure _blobs;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CleanCallback(HeapRegion* hr) : _detector(hr), _blobs(&_detector, !CodeBlobToOopClosure::FixRelocations) {}
|
||||||
|
|
||||||
|
bool operator() (nmethod* nm) {
|
||||||
|
_detector._points_into = false;
|
||||||
|
_blobs.do_code_blob(nm);
|
||||||
|
return _detector._points_into;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void G1CodeRootSet::clean(HeapRegion* owner) {
|
||||||
|
CleanCallback should_clean(owner);
|
||||||
|
if (_table != NULL) {
|
||||||
|
_table->remove_if(should_clean);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
|
|
||||||
void G1CodeRootSet::test() {
|
class G1CodeRootSetTest {
|
||||||
G1CodeRootChunkManager mgr;
|
public:
|
||||||
|
static void test() {
|
||||||
assert(mgr.num_chunks_handed_out() == 0, "Must not have handed out chunks yet");
|
|
||||||
|
|
||||||
assert(G1CodeRootChunkManager::static_mem_size() > sizeof(void*),
|
|
||||||
err_msg("The chunk manager's static memory usage seems too small, is only "SIZE_FORMAT" bytes.", G1CodeRootChunkManager::static_mem_size()));
|
|
||||||
|
|
||||||
// The number of chunks that we allocate for purge testing.
|
|
||||||
size_t const num_chunks = 10;
|
|
||||||
|
|
||||||
{
|
|
||||||
G1CodeRootSet set1(&mgr);
|
|
||||||
assert(set1.is_empty(), "Code root set must be initially empty but is not.");
|
|
||||||
|
|
||||||
assert(G1CodeRootSet::static_mem_size() > sizeof(void*),
|
|
||||||
err_msg("The code root set's static memory usage seems too small, is only "SIZE_FORMAT" bytes", G1CodeRootSet::static_mem_size()));
|
|
||||||
|
|
||||||
set1.add((nmethod*)1);
|
|
||||||
assert(mgr.num_chunks_handed_out() == 1,
|
|
||||||
err_msg("Must have allocated and handed out one chunk, but handed out "
|
|
||||||
SIZE_FORMAT" chunks", mgr.num_chunks_handed_out()));
|
|
||||||
assert(set1.length() == 1, err_msg("Added exactly one element, but set contains "
|
|
||||||
SIZE_FORMAT" elements", set1.length()));
|
|
||||||
|
|
||||||
// G1CodeRootChunk::word_size() is larger than G1CodeRootChunk::num_entries which
|
|
||||||
// we cannot access.
|
|
||||||
for (uint i = 0; i < G1CodeRootChunk::word_size() + 1; i++) {
|
|
||||||
set1.add((nmethod*)1);
|
|
||||||
}
|
|
||||||
assert(mgr.num_chunks_handed_out() == 1,
|
|
||||||
err_msg("Duplicate detection must have prevented allocation of further "
|
|
||||||
"chunks but allocated "SIZE_FORMAT, mgr.num_chunks_handed_out()));
|
|
||||||
assert(set1.length() == 1,
|
|
||||||
err_msg("Duplicate detection should not have increased the set size but "
|
|
||||||
"is "SIZE_FORMAT, set1.length()));
|
|
||||||
|
|
||||||
size_t num_total_after_add = G1CodeRootChunk::word_size() + 1;
|
|
||||||
for (size_t i = 0; i < num_total_after_add - 1; i++) {
|
|
||||||
set1.add((nmethod*)(uintptr_t)(2 + i));
|
|
||||||
}
|
|
||||||
assert(mgr.num_chunks_handed_out() > 1,
|
|
||||||
"After adding more code roots, more than one additional chunk should have been handed out");
|
|
||||||
assert(set1.length() == num_total_after_add,
|
|
||||||
err_msg("After adding in total "SIZE_FORMAT" distinct code roots, they "
|
|
||||||
"need to be in the set, but there are only "SIZE_FORMAT,
|
|
||||||
num_total_after_add, set1.length()));
|
|
||||||
|
|
||||||
size_t num_popped = 0;
|
|
||||||
while (set1.pop() != NULL) {
|
|
||||||
num_popped++;
|
|
||||||
}
|
|
||||||
assert(num_popped == num_total_after_add,
|
|
||||||
err_msg("Managed to pop "SIZE_FORMAT" code roots, but only "SIZE_FORMAT" "
|
|
||||||
"were added", num_popped, num_total_after_add));
|
|
||||||
assert(mgr.num_chunks_handed_out() == 0,
|
|
||||||
err_msg("After popping all elements, all chunks must have been returned "
|
|
||||||
"but there are still "SIZE_FORMAT" additional", mgr.num_chunks_handed_out()));
|
|
||||||
|
|
||||||
mgr.purge_chunks(0);
|
|
||||||
assert(mgr.num_free_chunks() == 0,
|
|
||||||
err_msg("After purging everything, the free list must be empty but still "
|
|
||||||
"contains "SIZE_FORMAT" chunks", mgr.num_free_chunks()));
|
|
||||||
|
|
||||||
// Add some more handed out chunks.
|
|
||||||
size_t i = 0;
|
|
||||||
while (mgr.num_chunks_handed_out() < num_chunks) {
|
|
||||||
set1.add((nmethod*)i);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// Generate chunks on the free list.
|
G1CodeRootSet set1;
|
||||||
G1CodeRootSet set2(&mgr);
|
assert(set1.is_empty(), "Code root set must be initially empty but is not.");
|
||||||
size_t i = 0;
|
|
||||||
while (mgr.num_chunks_handed_out() < (num_chunks * 2)) {
|
assert(G1CodeRootSet::static_mem_size() == sizeof(void*),
|
||||||
set2.add((nmethod*)i);
|
err_msg("The code root set's static memory usage is incorrect, "SIZE_FORMAT" bytes", G1CodeRootSet::static_mem_size()));
|
||||||
i++;
|
|
||||||
|
set1.add((nmethod*)1);
|
||||||
|
assert(set1.length() == 1, err_msg("Added exactly one element, but set contains "
|
||||||
|
SIZE_FORMAT" elements", set1.length()));
|
||||||
|
|
||||||
|
const size_t num_to_add = (size_t)G1CodeRootSet::Threshold + 1;
|
||||||
|
|
||||||
|
for (size_t i = 1; i <= num_to_add; i++) {
|
||||||
|
set1.add((nmethod*)1);
|
||||||
}
|
}
|
||||||
// Exit of the scope of the set2 object will call the destructor that generates
|
assert(set1.length() == 1,
|
||||||
// num_chunks elements on the free list.
|
err_msg("Duplicate detection should not have increased the set size but "
|
||||||
|
"is "SIZE_FORMAT, set1.length()));
|
||||||
|
|
||||||
|
for (size_t i = 2; i <= num_to_add; i++) {
|
||||||
|
set1.add((nmethod*)(uintptr_t)(i));
|
||||||
|
}
|
||||||
|
assert(set1.length() == num_to_add,
|
||||||
|
err_msg("After adding in total "SIZE_FORMAT" distinct code roots, they "
|
||||||
|
"need to be in the set, but there are only "SIZE_FORMAT,
|
||||||
|
num_to_add, set1.length()));
|
||||||
|
|
||||||
|
assert(CodeRootSetTable::_purge_list != NULL, "should have grown to large hashtable");
|
||||||
|
|
||||||
|
size_t num_popped = 0;
|
||||||
|
for (size_t i = 1; i <= num_to_add; i++) {
|
||||||
|
bool removed = set1.remove((nmethod*)i);
|
||||||
|
if (removed) {
|
||||||
|
num_popped += 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(num_popped == num_to_add,
|
||||||
|
err_msg("Managed to pop "SIZE_FORMAT" code roots, but only "SIZE_FORMAT" "
|
||||||
|
"were added", num_popped, num_to_add));
|
||||||
|
assert(CodeRootSetTable::_purge_list != NULL, "should have grown to large hashtable");
|
||||||
|
|
||||||
|
G1CodeRootSet::purge();
|
||||||
|
|
||||||
|
assert(CodeRootSetTable::_purge_list == NULL, "should have purged old small tables");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(mgr.num_chunks_handed_out() == num_chunks,
|
}
|
||||||
err_msg("Deletion of the second set must have resulted in giving back "
|
};
|
||||||
"those, but there are still "SIZE_FORMAT" additional handed out, expecting "
|
|
||||||
SIZE_FORMAT, mgr.num_chunks_handed_out(), num_chunks));
|
|
||||||
assert(mgr.num_free_chunks() == num_chunks,
|
|
||||||
err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list "
|
|
||||||
"but there are only "SIZE_FORMAT, num_chunks, mgr.num_free_chunks()));
|
|
||||||
|
|
||||||
size_t const test_percentage = 50;
|
|
||||||
mgr.purge_chunks(test_percentage);
|
|
||||||
assert(mgr.num_chunks_handed_out() == num_chunks,
|
|
||||||
err_msg("Purging must not hand out chunks but there are "SIZE_FORMAT,
|
|
||||||
mgr.num_chunks_handed_out()));
|
|
||||||
assert(mgr.num_free_chunks() == (size_t)(mgr.num_chunks_handed_out() * test_percentage / 100),
|
|
||||||
err_msg("Must have purged "SIZE_FORMAT" percent of "SIZE_FORMAT" chunks"
|
|
||||||
"but there are "SIZE_FORMAT, test_percentage, num_chunks,
|
|
||||||
mgr.num_free_chunks()));
|
|
||||||
// Purge the remainder of the chunks on the free list.
|
|
||||||
mgr.purge_chunks(0);
|
|
||||||
assert(mgr.num_free_chunks() == 0, "Free List must be empty");
|
|
||||||
assert(mgr.num_chunks_handed_out() == num_chunks,
|
|
||||||
err_msg("Expected to be "SIZE_FORMAT" chunks handed out from the first set "
|
|
||||||
"but there are "SIZE_FORMAT, num_chunks, mgr.num_chunks_handed_out()));
|
|
||||||
|
|
||||||
// Exit of the scope of the set1 object will call the destructor that generates
|
|
||||||
// num_chunks additional elements on the free list.
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(mgr.num_chunks_handed_out() == 0,
|
|
||||||
err_msg("Deletion of the only set must have resulted in no chunks handed "
|
|
||||||
"out, but there is still "SIZE_FORMAT" handed out", mgr.num_chunks_handed_out()));
|
|
||||||
assert(mgr.num_free_chunks() == num_chunks,
|
|
||||||
err_msg("After freeing "SIZE_FORMAT" chunks, they must be on the free list "
|
|
||||||
"but there are only "SIZE_FORMAT, num_chunks, mgr.num_free_chunks()));
|
|
||||||
|
|
||||||
// Restore initial state.
|
|
||||||
mgr.purge_chunks(0);
|
|
||||||
assert(mgr.num_free_chunks() == 0, "Free List must be empty");
|
|
||||||
assert(mgr.num_chunks_handed_out() == 0, "No additional elements must have been handed out yet");
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestCodeCacheRemSet_test() {
|
void TestCodeCacheRemSet_test() {
|
||||||
G1CodeRootSet::test();
|
G1CodeRootSetTest::test();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -26,222 +26,64 @@
|
|||||||
#define SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP
|
#define SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP
|
||||||
|
|
||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
#include "memory/freeList.hpp"
|
|
||||||
#include "runtime/globals.hpp"
|
|
||||||
|
|
||||||
class CodeBlobClosure;
|
class CodeBlobClosure;
|
||||||
|
class CodeRootSetTable;
|
||||||
// The elements of the G1CodeRootChunk is either:
|
class HeapRegion;
|
||||||
// 1) nmethod pointers
|
class nmethod;
|
||||||
// 2) nodes in an internally chained free list
|
|
||||||
typedef union {
|
|
||||||
nmethod* _nmethod;
|
|
||||||
void* _link;
|
|
||||||
} NmethodOrLink;
|
|
||||||
|
|
||||||
class G1CodeRootChunk : public CHeapObj<mtGC> {
|
|
||||||
private:
|
|
||||||
static const int NUM_ENTRIES = 32;
|
|
||||||
public:
|
|
||||||
G1CodeRootChunk* _next;
|
|
||||||
G1CodeRootChunk* _prev;
|
|
||||||
|
|
||||||
NmethodOrLink* _top;
|
|
||||||
// First free position within the chunk.
|
|
||||||
volatile NmethodOrLink* _free;
|
|
||||||
|
|
||||||
NmethodOrLink _data[NUM_ENTRIES];
|
|
||||||
|
|
||||||
NmethodOrLink* bottom() const {
|
|
||||||
return (NmethodOrLink*) &(_data[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
NmethodOrLink* end() const {
|
|
||||||
return (NmethodOrLink*) &(_data[NUM_ENTRIES]);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_link(NmethodOrLink* nmethod_or_link) {
|
|
||||||
return nmethod_or_link->_link == NULL ||
|
|
||||||
(bottom() <= nmethod_or_link->_link
|
|
||||||
&& nmethod_or_link->_link < end());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_nmethod(NmethodOrLink* nmethod_or_link) {
|
|
||||||
return !is_link(nmethod_or_link);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
G1CodeRootChunk();
|
|
||||||
~G1CodeRootChunk() {}
|
|
||||||
|
|
||||||
static size_t word_size() { return (size_t)(align_size_up_(sizeof(G1CodeRootChunk), HeapWordSize) / HeapWordSize); }
|
|
||||||
|
|
||||||
// FreeList "interface" methods
|
|
||||||
|
|
||||||
G1CodeRootChunk* next() const { return _next; }
|
|
||||||
G1CodeRootChunk* prev() const { return _prev; }
|
|
||||||
void set_next(G1CodeRootChunk* v) { _next = v; assert(v != this, "Boom");}
|
|
||||||
void set_prev(G1CodeRootChunk* v) { _prev = v; assert(v != this, "Boom");}
|
|
||||||
void clear_next() { set_next(NULL); }
|
|
||||||
void clear_prev() { set_prev(NULL); }
|
|
||||||
|
|
||||||
size_t size() const { return word_size(); }
|
|
||||||
|
|
||||||
void link_next(G1CodeRootChunk* ptr) { set_next(ptr); }
|
|
||||||
void link_prev(G1CodeRootChunk* ptr) { set_prev(ptr); }
|
|
||||||
void link_after(G1CodeRootChunk* ptr) {
|
|
||||||
link_next(ptr);
|
|
||||||
if (ptr != NULL) ptr->link_prev((G1CodeRootChunk*)this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_free() { return true; }
|
|
||||||
|
|
||||||
// New G1CodeRootChunk routines
|
|
||||||
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
bool is_empty() const {
|
|
||||||
return _top == bottom();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_full() const {
|
|
||||||
return _top == end() && _free == NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool contains(nmethod* method) {
|
|
||||||
NmethodOrLink* cur = bottom();
|
|
||||||
while (cur != _top) {
|
|
||||||
if (cur->_nmethod == method) return true;
|
|
||||||
cur++;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool add(nmethod* method) {
|
|
||||||
if (is_full()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_free != NULL) {
|
|
||||||
// Take from internally chained free list
|
|
||||||
NmethodOrLink* first_free = (NmethodOrLink*)_free;
|
|
||||||
_free = (NmethodOrLink*)_free->_link;
|
|
||||||
first_free->_nmethod = method;
|
|
||||||
} else {
|
|
||||||
// Take from top.
|
|
||||||
_top->_nmethod = method;
|
|
||||||
_top++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool remove_lock_free(nmethod* method);
|
|
||||||
|
|
||||||
void nmethods_do(CodeBlobClosure* blk);
|
|
||||||
|
|
||||||
nmethod* pop() {
|
|
||||||
if (_free != NULL) {
|
|
||||||
// Kill the free list.
|
|
||||||
_free = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (!is_empty()) {
|
|
||||||
_top--;
|
|
||||||
if (is_nmethod(_top)) {
|
|
||||||
return _top->_nmethod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Manages free chunks.
|
|
||||||
class G1CodeRootChunkManager VALUE_OBJ_CLASS_SPEC {
|
|
||||||
private:
|
|
||||||
// Global free chunk list management
|
|
||||||
FreeList<G1CodeRootChunk> _free_list;
|
|
||||||
// Total number of chunks handed out
|
|
||||||
size_t _num_chunks_handed_out;
|
|
||||||
|
|
||||||
public:
|
|
||||||
G1CodeRootChunkManager();
|
|
||||||
|
|
||||||
G1CodeRootChunk* new_chunk();
|
|
||||||
void free_chunk(G1CodeRootChunk* chunk);
|
|
||||||
// Free all elements of the given list.
|
|
||||||
void free_all_chunks(FreeList<G1CodeRootChunk>* list);
|
|
||||||
|
|
||||||
void initialize();
|
|
||||||
void purge_chunks(size_t keep_ratio);
|
|
||||||
|
|
||||||
static size_t static_mem_size();
|
|
||||||
size_t fl_mem_size();
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
size_t num_chunks_handed_out() const;
|
|
||||||
size_t num_free_chunks() const;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
// Implements storage for a set of code roots.
|
// Implements storage for a set of code roots.
|
||||||
// All methods that modify the set are not thread-safe except if otherwise noted.
|
// All methods that modify the set are not thread-safe except if otherwise noted.
|
||||||
class G1CodeRootSet VALUE_OBJ_CLASS_SPEC {
|
class G1CodeRootSet VALUE_OBJ_CLASS_SPEC {
|
||||||
|
friend class G1CodeRootSetTest;
|
||||||
private:
|
private:
|
||||||
// Global default free chunk manager instance.
|
|
||||||
static G1CodeRootChunkManager _default_chunk_manager;
|
|
||||||
|
|
||||||
G1CodeRootChunk* new_chunk() { return _manager->new_chunk(); }
|
const static size_t SmallSize = 32;
|
||||||
void free_chunk(G1CodeRootChunk* chunk) { _manager->free_chunk(chunk); }
|
const static size_t Threshold = 24;
|
||||||
// Free all elements of the given list.
|
const static size_t LargeSize = 512;
|
||||||
void free_all_chunks(FreeList<G1CodeRootChunk>* list) { _manager->free_all_chunks(list); }
|
|
||||||
|
|
||||||
// Return the chunk that contains the given nmethod, NULL otherwise.
|
CodeRootSetTable* _table;
|
||||||
// Scans the list of chunks backwards, as this method is used to add new
|
CodeRootSetTable* load_acquire_table();
|
||||||
// entries, which are typically added in bulk for a single nmethod.
|
|
||||||
G1CodeRootChunk* find(nmethod* method);
|
|
||||||
void free(G1CodeRootChunk* chunk);
|
|
||||||
|
|
||||||
size_t _length;
|
size_t _length;
|
||||||
FreeList<G1CodeRootChunk> _list;
|
|
||||||
G1CodeRootChunkManager* _manager;
|
void move_to_large();
|
||||||
|
void allocate_small_table();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// If an instance is initialized with a chunk manager of NULL, use the global
|
G1CodeRootSet() : _table(NULL), _length(0) {}
|
||||||
// default one.
|
|
||||||
G1CodeRootSet(G1CodeRootChunkManager* manager = NULL);
|
|
||||||
~G1CodeRootSet();
|
~G1CodeRootSet();
|
||||||
|
|
||||||
static void purge_chunks(size_t keep_ratio);
|
static void purge();
|
||||||
|
|
||||||
static size_t free_chunks_static_mem_size();
|
static size_t static_mem_size();
|
||||||
static size_t free_chunks_mem_size();
|
|
||||||
|
|
||||||
// Search for the code blob from the recently allocated ones to find duplicates more quickly, as this
|
|
||||||
// method is likely to be repeatedly called with the same nmethod.
|
|
||||||
void add(nmethod* method);
|
void add(nmethod* method);
|
||||||
|
|
||||||
void remove_lock_free(nmethod* method);
|
bool remove(nmethod* method);
|
||||||
nmethod* pop();
|
|
||||||
|
|
||||||
|
// Safe to call without synchronization, but may return false negatives.
|
||||||
bool contains(nmethod* method);
|
bool contains(nmethod* method);
|
||||||
|
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
void nmethods_do(CodeBlobClosure* blk) const;
|
void nmethods_do(CodeBlobClosure* blk) const;
|
||||||
|
|
||||||
bool is_empty() { return length() == 0; }
|
// Remove all nmethods which no longer contain pointers into our "owner" region
|
||||||
|
void clean(HeapRegion* owner);
|
||||||
|
|
||||||
|
bool is_empty() {
|
||||||
|
bool empty = length() == 0;
|
||||||
|
assert(empty == (_table == NULL), "is empty only if table is deallocated");
|
||||||
|
return empty;
|
||||||
|
}
|
||||||
|
|
||||||
// Length in elements
|
// Length in elements
|
||||||
size_t length() const { return _length; }
|
size_t length() const { return _length; }
|
||||||
|
|
||||||
// Static data memory size in bytes of this set.
|
|
||||||
static size_t static_mem_size();
|
|
||||||
// Memory size in bytes taken by this set.
|
// Memory size in bytes taken by this set.
|
||||||
size_t mem_size();
|
size_t mem_size();
|
||||||
|
|
||||||
static void test() PRODUCT_RETURN;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP
|
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1CODECACHEREMSET_HPP
|
||||||
|
@ -4670,6 +4670,56 @@ class G1KlassScanClosure : public KlassClosure {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class G1CodeBlobClosure : public CodeBlobClosure {
|
||||||
|
class HeapRegionGatheringOopClosure : public OopClosure {
|
||||||
|
G1CollectedHeap* _g1h;
|
||||||
|
OopClosure* _work;
|
||||||
|
nmethod* _nm;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void do_oop_work(T* p) {
|
||||||
|
_work->do_oop(p);
|
||||||
|
T oop_or_narrowoop = oopDesc::load_heap_oop(p);
|
||||||
|
if (!oopDesc::is_null(oop_or_narrowoop)) {
|
||||||
|
oop o = oopDesc::decode_heap_oop_not_null(oop_or_narrowoop);
|
||||||
|
HeapRegion* hr = _g1h->heap_region_containing_raw(o);
|
||||||
|
assert(!_g1h->obj_in_cs(o) || hr->rem_set()->strong_code_roots_list_contains(_nm), "if o still in CS then evacuation failed and nm must already be in the remset");
|
||||||
|
hr->add_strong_code_root(_nm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
HeapRegionGatheringOopClosure(OopClosure* oc) : _g1h(G1CollectedHeap::heap()), _work(oc), _nm(NULL) {}
|
||||||
|
|
||||||
|
void do_oop(oop* o) {
|
||||||
|
do_oop_work(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_oop(narrowOop* o) {
|
||||||
|
do_oop_work(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_nm(nmethod* nm) {
|
||||||
|
_nm = nm;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
HeapRegionGatheringOopClosure _oc;
|
||||||
|
public:
|
||||||
|
G1CodeBlobClosure(OopClosure* oc) : _oc(oc) {}
|
||||||
|
|
||||||
|
void do_code_blob(CodeBlob* cb) {
|
||||||
|
nmethod* nm = cb->as_nmethod_or_null();
|
||||||
|
if (nm != NULL) {
|
||||||
|
if (!nm->test_set_oops_do_mark()) {
|
||||||
|
_oc.set_nm(nm);
|
||||||
|
nm->oops_do(&_oc);
|
||||||
|
nm->fix_oop_relocations();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class G1ParTask : public AbstractGangTask {
|
class G1ParTask : public AbstractGangTask {
|
||||||
protected:
|
protected:
|
||||||
G1CollectedHeap* _g1h;
|
G1CollectedHeap* _g1h;
|
||||||
@ -4738,22 +4788,6 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class G1CodeBlobClosure: public CodeBlobClosure {
|
|
||||||
OopClosure* _f;
|
|
||||||
|
|
||||||
public:
|
|
||||||
G1CodeBlobClosure(OopClosure* f) : _f(f) {}
|
|
||||||
void do_code_blob(CodeBlob* blob) {
|
|
||||||
nmethod* that = blob->as_nmethod_or_null();
|
|
||||||
if (that != NULL) {
|
|
||||||
if (!that->test_set_oops_do_mark()) {
|
|
||||||
that->oops_do(_f);
|
|
||||||
that->fix_oop_relocations();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void work(uint worker_id) {
|
void work(uint worker_id) {
|
||||||
if (worker_id >= _n_workers) return; // no work needed this round
|
if (worker_id >= _n_workers) return; // no work needed this round
|
||||||
|
|
||||||
@ -4944,7 +4978,7 @@ g1_process_roots(OopClosure* scan_non_heap_roots,
|
|||||||
g1_policy()->phase_times()->record_satb_filtering_time(worker_i, satb_filtering_ms);
|
g1_policy()->phase_times()->record_satb_filtering_time(worker_i, satb_filtering_ms);
|
||||||
|
|
||||||
// Now scan the complement of the collection set.
|
// Now scan the complement of the collection set.
|
||||||
MarkingCodeBlobClosure scavenge_cs_nmethods(scan_non_heap_weak_roots, CodeBlobToOopClosure::FixRelocations);
|
G1CodeBlobClosure scavenge_cs_nmethods(scan_non_heap_weak_roots);
|
||||||
|
|
||||||
g1_rem_set()->oops_into_collection_set_do(scan_rs, &scavenge_cs_nmethods, worker_i);
|
g1_rem_set()->oops_into_collection_set_do(scan_rs, &scavenge_cs_nmethods, worker_i);
|
||||||
|
|
||||||
@ -5991,12 +6025,6 @@ void G1CollectedHeap::evacuate_collection_set(EvacuationInfo& evacuation_info) {
|
|||||||
hot_card_cache->reset_hot_cache();
|
hot_card_cache->reset_hot_cache();
|
||||||
hot_card_cache->set_use_cache(true);
|
hot_card_cache->set_use_cache(true);
|
||||||
|
|
||||||
// Migrate the strong code roots attached to each region in
|
|
||||||
// the collection set. Ideally we would like to do this
|
|
||||||
// after we have finished the scanning/evacuation of the
|
|
||||||
// strong code roots for a particular heap region.
|
|
||||||
migrate_strong_code_roots();
|
|
||||||
|
|
||||||
purge_code_root_memory();
|
purge_code_root_memory();
|
||||||
|
|
||||||
if (g1_policy()->during_initial_mark_pause()) {
|
if (g1_policy()->during_initial_mark_pause()) {
|
||||||
@ -7049,13 +7077,8 @@ class RegisterNMethodOopClosure: public OopClosure {
|
|||||||
" starting at "HR_FORMAT,
|
" starting at "HR_FORMAT,
|
||||||
_nm, HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region())));
|
_nm, HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region())));
|
||||||
|
|
||||||
// HeapRegion::add_strong_code_root() avoids adding duplicate
|
// HeapRegion::add_strong_code_root_locked() avoids adding duplicate entries.
|
||||||
// entries but having duplicates is OK since we "mark" nmethods
|
hr->add_strong_code_root_locked(_nm);
|
||||||
// as visited when we scan the strong code root lists during the GC.
|
|
||||||
hr->add_strong_code_root(_nm);
|
|
||||||
assert(hr->rem_set()->strong_code_roots_list_contains(_nm),
|
|
||||||
err_msg("failed to add code root "PTR_FORMAT" to remembered set of region "HR_FORMAT,
|
|
||||||
_nm, HR_FORMAT_PARAMS(hr)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7082,9 +7105,6 @@ class UnregisterNMethodOopClosure: public OopClosure {
|
|||||||
_nm, HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region())));
|
_nm, HR_FORMAT_PARAMS(hr), HR_FORMAT_PARAMS(hr->humongous_start_region())));
|
||||||
|
|
||||||
hr->remove_strong_code_root(_nm);
|
hr->remove_strong_code_root(_nm);
|
||||||
assert(!hr->rem_set()->strong_code_roots_list_contains(_nm),
|
|
||||||
err_msg("failed to remove code root "PTR_FORMAT" of region "HR_FORMAT,
|
|
||||||
_nm, HR_FORMAT_PARAMS(hr)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7112,28 +7132,9 @@ void G1CollectedHeap::unregister_nmethod(nmethod* nm) {
|
|||||||
nm->oops_do(®_cl, true);
|
nm->oops_do(®_cl, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
class MigrateCodeRootsHeapRegionClosure: public HeapRegionClosure {
|
|
||||||
public:
|
|
||||||
bool doHeapRegion(HeapRegion *hr) {
|
|
||||||
assert(!hr->isHumongous(),
|
|
||||||
err_msg("humongous region "HR_FORMAT" should not have been added to collection set",
|
|
||||||
HR_FORMAT_PARAMS(hr)));
|
|
||||||
hr->migrate_strong_code_roots();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void G1CollectedHeap::migrate_strong_code_roots() {
|
|
||||||
MigrateCodeRootsHeapRegionClosure cl;
|
|
||||||
double migrate_start = os::elapsedTime();
|
|
||||||
collection_set_iterate(&cl);
|
|
||||||
double migration_time_ms = (os::elapsedTime() - migrate_start) * 1000.0;
|
|
||||||
g1_policy()->phase_times()->record_strong_code_root_migration_time(migration_time_ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
void G1CollectedHeap::purge_code_root_memory() {
|
void G1CollectedHeap::purge_code_root_memory() {
|
||||||
double purge_start = os::elapsedTime();
|
double purge_start = os::elapsedTime();
|
||||||
G1CodeRootSet::purge_chunks(G1CodeRootsChunkCacheKeepPercent);
|
G1CodeRootSet::purge();
|
||||||
double purge_time_ms = (os::elapsedTime() - purge_start) * 1000.0;
|
double purge_time_ms = (os::elapsedTime() - purge_start) * 1000.0;
|
||||||
g1_policy()->phase_times()->record_strong_code_root_purge_time(purge_time_ms);
|
g1_policy()->phase_times()->record_strong_code_root_purge_time(purge_time_ms);
|
||||||
}
|
}
|
||||||
|
@ -1662,12 +1662,6 @@ public:
|
|||||||
// Unregister the given nmethod from the G1 heap.
|
// Unregister the given nmethod from the G1 heap.
|
||||||
virtual void unregister_nmethod(nmethod* nm);
|
virtual void unregister_nmethod(nmethod* nm);
|
||||||
|
|
||||||
// Migrate the nmethods in the code root lists of the regions
|
|
||||||
// in the collection set to regions in to-space. In the event
|
|
||||||
// of an evacuation failure, nmethods that reference objects
|
|
||||||
// that were not successfully evacuated are not migrated.
|
|
||||||
void migrate_strong_code_roots();
|
|
||||||
|
|
||||||
// Free up superfluous code root memory.
|
// Free up superfluous code root memory.
|
||||||
void purge_code_root_memory();
|
void purge_code_root_memory();
|
||||||
|
|
||||||
|
@ -217,6 +217,8 @@ public:
|
|||||||
_update_rset_cl->set_region(hr);
|
_update_rset_cl->set_region(hr);
|
||||||
hr->object_iterate(&rspc);
|
hr->object_iterate(&rspc);
|
||||||
|
|
||||||
|
hr->rem_set()->clean_strong_code_roots(hr);
|
||||||
|
|
||||||
hr->note_self_forwarding_removal_end(during_initial_mark,
|
hr->note_self_forwarding_removal_end(during_initial_mark,
|
||||||
during_conc_mark,
|
during_conc_mark,
|
||||||
rspc.marked_bytes());
|
rspc.marked_bytes());
|
||||||
|
@ -275,9 +275,6 @@ double G1GCPhaseTimes::accounted_time_ms() {
|
|||||||
// Now subtract the time taken to fix up roots in generated code
|
// Now subtract the time taken to fix up roots in generated code
|
||||||
misc_time_ms += _cur_collection_code_root_fixup_time_ms;
|
misc_time_ms += _cur_collection_code_root_fixup_time_ms;
|
||||||
|
|
||||||
// Strong code root migration time
|
|
||||||
misc_time_ms += _cur_strong_code_root_migration_time_ms;
|
|
||||||
|
|
||||||
// Strong code root purge time
|
// Strong code root purge time
|
||||||
misc_time_ms += _cur_strong_code_root_purge_time_ms;
|
misc_time_ms += _cur_strong_code_root_purge_time_ms;
|
||||||
|
|
||||||
@ -328,7 +325,6 @@ void G1GCPhaseTimes::print(double pause_time_sec) {
|
|||||||
_last_obj_copy_times_ms.print(1, "Object Copy (ms)");
|
_last_obj_copy_times_ms.print(1, "Object Copy (ms)");
|
||||||
}
|
}
|
||||||
print_stats(1, "Code Root Fixup", _cur_collection_code_root_fixup_time_ms);
|
print_stats(1, "Code Root Fixup", _cur_collection_code_root_fixup_time_ms);
|
||||||
print_stats(1, "Code Root Migration", _cur_strong_code_root_migration_time_ms);
|
|
||||||
print_stats(1, "Code Root Purge", _cur_strong_code_root_purge_time_ms);
|
print_stats(1, "Code Root Purge", _cur_strong_code_root_purge_time_ms);
|
||||||
if (G1StringDedup::is_enabled()) {
|
if (G1StringDedup::is_enabled()) {
|
||||||
print_stats(1, "String Dedup Fixup", _cur_string_dedup_fixup_time_ms, _active_gc_threads);
|
print_stats(1, "String Dedup Fixup", _cur_string_dedup_fixup_time_ms, _active_gc_threads);
|
||||||
|
@ -129,7 +129,6 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
|||||||
|
|
||||||
double _cur_collection_par_time_ms;
|
double _cur_collection_par_time_ms;
|
||||||
double _cur_collection_code_root_fixup_time_ms;
|
double _cur_collection_code_root_fixup_time_ms;
|
||||||
double _cur_strong_code_root_migration_time_ms;
|
|
||||||
double _cur_strong_code_root_purge_time_ms;
|
double _cur_strong_code_root_purge_time_ms;
|
||||||
|
|
||||||
double _cur_evac_fail_recalc_used;
|
double _cur_evac_fail_recalc_used;
|
||||||
@ -233,10 +232,6 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
|||||||
_cur_collection_code_root_fixup_time_ms = ms;
|
_cur_collection_code_root_fixup_time_ms = ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
void record_strong_code_root_migration_time(double ms) {
|
|
||||||
_cur_strong_code_root_migration_time_ms = ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
void record_strong_code_root_purge_time(double ms) {
|
void record_strong_code_root_purge_time(double ms) {
|
||||||
_cur_strong_code_root_purge_time_ms = ms;
|
_cur_strong_code_root_purge_time_ms = ms;
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ class ScanRSClosure : public HeapRegionClosure {
|
|||||||
G1CollectedHeap* _g1h;
|
G1CollectedHeap* _g1h;
|
||||||
|
|
||||||
OopsInHeapRegionClosure* _oc;
|
OopsInHeapRegionClosure* _oc;
|
||||||
CodeBlobToOopClosure* _code_root_cl;
|
CodeBlobClosure* _code_root_cl;
|
||||||
|
|
||||||
G1BlockOffsetSharedArray* _bot_shared;
|
G1BlockOffsetSharedArray* _bot_shared;
|
||||||
G1SATBCardTableModRefBS *_ct_bs;
|
G1SATBCardTableModRefBS *_ct_bs;
|
||||||
@ -122,7 +122,7 @@ class ScanRSClosure : public HeapRegionClosure {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
ScanRSClosure(OopsInHeapRegionClosure* oc,
|
ScanRSClosure(OopsInHeapRegionClosure* oc,
|
||||||
CodeBlobToOopClosure* code_root_cl,
|
CodeBlobClosure* code_root_cl,
|
||||||
uint worker_i) :
|
uint worker_i) :
|
||||||
_oc(oc),
|
_oc(oc),
|
||||||
_code_root_cl(code_root_cl),
|
_code_root_cl(code_root_cl),
|
||||||
@ -242,7 +242,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
void G1RemSet::scanRS(OopsInHeapRegionClosure* oc,
|
void G1RemSet::scanRS(OopsInHeapRegionClosure* oc,
|
||||||
CodeBlobToOopClosure* code_root_cl,
|
CodeBlobClosure* code_root_cl,
|
||||||
uint worker_i) {
|
uint worker_i) {
|
||||||
double rs_time_start = os::elapsedTime();
|
double rs_time_start = os::elapsedTime();
|
||||||
HeapRegion *startRegion = _g1->start_cset_region_for_worker(worker_i);
|
HeapRegion *startRegion = _g1->start_cset_region_for_worker(worker_i);
|
||||||
@ -321,7 +321,7 @@ void G1RemSet::cleanupHRRS() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc,
|
void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc,
|
||||||
CodeBlobToOopClosure* code_root_cl,
|
CodeBlobClosure* code_root_cl,
|
||||||
uint worker_i) {
|
uint worker_i) {
|
||||||
#if CARD_REPEAT_HISTO
|
#if CARD_REPEAT_HISTO
|
||||||
ct_freq_update_histo_and_reset();
|
ct_freq_update_histo_and_reset();
|
||||||
|
@ -96,7 +96,7 @@ public:
|
|||||||
// the "i" passed to the calling thread's work(i) function.
|
// the "i" passed to the calling thread's work(i) function.
|
||||||
// In the sequential case this param will be ignored.
|
// In the sequential case this param will be ignored.
|
||||||
void oops_into_collection_set_do(OopsInHeapRegionClosure* blk,
|
void oops_into_collection_set_do(OopsInHeapRegionClosure* blk,
|
||||||
CodeBlobToOopClosure* code_root_cl,
|
CodeBlobClosure* code_root_cl,
|
||||||
uint worker_i);
|
uint worker_i);
|
||||||
|
|
||||||
// Prepare for and cleanup after an oops_into_collection_set_do
|
// Prepare for and cleanup after an oops_into_collection_set_do
|
||||||
@ -108,7 +108,7 @@ public:
|
|||||||
void cleanup_after_oops_into_collection_set_do();
|
void cleanup_after_oops_into_collection_set_do();
|
||||||
|
|
||||||
void scanRS(OopsInHeapRegionClosure* oc,
|
void scanRS(OopsInHeapRegionClosure* oc,
|
||||||
CodeBlobToOopClosure* code_root_cl,
|
CodeBlobClosure* code_root_cl,
|
||||||
uint worker_i);
|
uint worker_i);
|
||||||
|
|
||||||
void updateRS(DirtyCardQueue* into_cset_dcq, uint worker_i);
|
void updateRS(DirtyCardQueue* into_cset_dcq, uint worker_i);
|
||||||
|
@ -253,6 +253,7 @@ public:
|
|||||||
size_t occupied_cards = hrrs->occupied();
|
size_t occupied_cards = hrrs->occupied();
|
||||||
size_t code_root_mem_sz = hrrs->strong_code_roots_mem_size();
|
size_t code_root_mem_sz = hrrs->strong_code_roots_mem_size();
|
||||||
if (code_root_mem_sz > max_code_root_mem_sz()) {
|
if (code_root_mem_sz > max_code_root_mem_sz()) {
|
||||||
|
_max_code_root_mem_sz = code_root_mem_sz;
|
||||||
_max_code_root_mem_sz_region = r;
|
_max_code_root_mem_sz_region = r;
|
||||||
}
|
}
|
||||||
size_t code_root_elems = hrrs->strong_code_roots_list_length();
|
size_t code_root_elems = hrrs->strong_code_roots_list_length();
|
||||||
|
@ -277,10 +277,6 @@
|
|||||||
product(uintx, G1MixedGCCountTarget, 8, \
|
product(uintx, G1MixedGCCountTarget, 8, \
|
||||||
"The target number of mixed GCs after a marking cycle.") \
|
"The target number of mixed GCs after a marking cycle.") \
|
||||||
\
|
\
|
||||||
experimental(uintx, G1CodeRootsChunkCacheKeepPercent, 10, \
|
|
||||||
"The amount of code root chunks that should be kept at most " \
|
|
||||||
"as percentage of already allocated.") \
|
|
||||||
\
|
|
||||||
experimental(bool, G1ReclaimDeadHumongousObjectsAtYoungGC, true, \
|
experimental(bool, G1ReclaimDeadHumongousObjectsAtYoungGC, true, \
|
||||||
"Try to reclaim dead large objects at every young GC.") \
|
"Try to reclaim dead large objects at every young GC.") \
|
||||||
\
|
\
|
||||||
|
@ -540,21 +540,17 @@ void HeapRegion::add_strong_code_root(nmethod* nm) {
|
|||||||
hrrs->add_strong_code_root(nm);
|
hrrs->add_strong_code_root(nm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HeapRegion::add_strong_code_root_locked(nmethod* nm) {
|
||||||
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
|
HeapRegionRemSet* hrrs = rem_set();
|
||||||
|
hrrs->add_strong_code_root_locked(nm);
|
||||||
|
}
|
||||||
|
|
||||||
void HeapRegion::remove_strong_code_root(nmethod* nm) {
|
void HeapRegion::remove_strong_code_root(nmethod* nm) {
|
||||||
HeapRegionRemSet* hrrs = rem_set();
|
HeapRegionRemSet* hrrs = rem_set();
|
||||||
hrrs->remove_strong_code_root(nm);
|
hrrs->remove_strong_code_root(nm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HeapRegion::migrate_strong_code_roots() {
|
|
||||||
assert(in_collection_set(), "only collection set regions");
|
|
||||||
assert(!isHumongous(),
|
|
||||||
err_msg("humongous region "HR_FORMAT" should not have been added to collection set",
|
|
||||||
HR_FORMAT_PARAMS(this)));
|
|
||||||
|
|
||||||
HeapRegionRemSet* hrrs = rem_set();
|
|
||||||
hrrs->migrate_strong_code_roots();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HeapRegion::strong_code_roots_do(CodeBlobClosure* blk) const {
|
void HeapRegion::strong_code_roots_do(CodeBlobClosure* blk) const {
|
||||||
HeapRegionRemSet* hrrs = rem_set();
|
HeapRegionRemSet* hrrs = rem_set();
|
||||||
hrrs->strong_code_roots_do(blk);
|
hrrs->strong_code_roots_do(blk);
|
||||||
|
@ -756,14 +756,9 @@ class HeapRegion: public G1OffsetTableContigSpace {
|
|||||||
// Routines for managing a list of code roots (attached to the
|
// Routines for managing a list of code roots (attached to the
|
||||||
// this region's RSet) that point into this heap region.
|
// this region's RSet) that point into this heap region.
|
||||||
void add_strong_code_root(nmethod* nm);
|
void add_strong_code_root(nmethod* nm);
|
||||||
|
void add_strong_code_root_locked(nmethod* nm);
|
||||||
void remove_strong_code_root(nmethod* nm);
|
void remove_strong_code_root(nmethod* nm);
|
||||||
|
|
||||||
// During a collection, migrate the successfully evacuated
|
|
||||||
// strong code roots that referenced into this region to the
|
|
||||||
// new regions that they now point into. Unsuccessfully
|
|
||||||
// evacuated code roots are not migrated.
|
|
||||||
void migrate_strong_code_roots();
|
|
||||||
|
|
||||||
// Applies blk->do_code_blob() to each of the entries in
|
// Applies blk->do_code_blob() to each of the entries in
|
||||||
// the strong code roots list for this region
|
// the strong code roots list for this region
|
||||||
void strong_code_roots_do(CodeBlobClosure* blk) const;
|
void strong_code_roots_do(CodeBlobClosure* blk) const;
|
||||||
|
@ -448,10 +448,10 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
|
|||||||
|
|
||||||
// Note that this may be a continued H region.
|
// Note that this may be a continued H region.
|
||||||
HeapRegion* from_hr = _g1h->heap_region_containing_raw(from);
|
HeapRegion* from_hr = _g1h->heap_region_containing_raw(from);
|
||||||
RegionIdx_t from_hrs_ind = (RegionIdx_t) from_hr->hrm_index();
|
RegionIdx_t from_hrm_ind = (RegionIdx_t) from_hr->hrm_index();
|
||||||
|
|
||||||
// If the region is already coarsened, return.
|
// If the region is already coarsened, return.
|
||||||
if (_coarse_map.at(from_hrs_ind)) {
|
if (_coarse_map.at(from_hrm_ind)) {
|
||||||
if (G1TraceHeapRegionRememberedSet) {
|
if (G1TraceHeapRegionRememberedSet) {
|
||||||
gclog_or_tty->print_cr(" coarse map hit.");
|
gclog_or_tty->print_cr(" coarse map hit.");
|
||||||
}
|
}
|
||||||
@ -460,7 +460,7 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise find a per-region table to add it to.
|
// Otherwise find a per-region table to add it to.
|
||||||
size_t ind = from_hrs_ind & _mod_max_fine_entries_mask;
|
size_t ind = from_hrm_ind & _mod_max_fine_entries_mask;
|
||||||
PerRegionTable* prt = find_region_table(ind, from_hr);
|
PerRegionTable* prt = find_region_table(ind, from_hr);
|
||||||
if (prt == NULL) {
|
if (prt == NULL) {
|
||||||
MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
|
MutexLockerEx x(_m, Mutex::_no_safepoint_check_flag);
|
||||||
@ -475,7 +475,7 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
|
|||||||
assert(0 <= card_index && (size_t)card_index < HeapRegion::CardsPerRegion,
|
assert(0 <= card_index && (size_t)card_index < HeapRegion::CardsPerRegion,
|
||||||
"Must be in range.");
|
"Must be in range.");
|
||||||
if (G1HRRSUseSparseTable &&
|
if (G1HRRSUseSparseTable &&
|
||||||
_sparse_table.add_card(from_hrs_ind, card_index)) {
|
_sparse_table.add_card(from_hrm_ind, card_index)) {
|
||||||
if (G1RecordHRRSOops) {
|
if (G1RecordHRRSOops) {
|
||||||
HeapRegionRemSet::record(hr(), from);
|
HeapRegionRemSet::record(hr(), from);
|
||||||
if (G1TraceHeapRegionRememberedSet) {
|
if (G1TraceHeapRegionRememberedSet) {
|
||||||
@ -495,7 +495,7 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
|
|||||||
if (G1TraceHeapRegionRememberedSet) {
|
if (G1TraceHeapRegionRememberedSet) {
|
||||||
gclog_or_tty->print_cr(" [tid %d] sparse table entry "
|
gclog_or_tty->print_cr(" [tid %d] sparse table entry "
|
||||||
"overflow(f: %d, t: %u)",
|
"overflow(f: %d, t: %u)",
|
||||||
tid, from_hrs_ind, cur_hrm_ind);
|
tid, from_hrm_ind, cur_hrm_ind);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -516,7 +516,7 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
|
|||||||
|
|
||||||
if (G1HRRSUseSparseTable) {
|
if (G1HRRSUseSparseTable) {
|
||||||
// Transfer from sparse to fine-grain.
|
// Transfer from sparse to fine-grain.
|
||||||
SparsePRTEntry *sprt_entry = _sparse_table.get_entry(from_hrs_ind);
|
SparsePRTEntry *sprt_entry = _sparse_table.get_entry(from_hrm_ind);
|
||||||
assert(sprt_entry != NULL, "There should have been an entry");
|
assert(sprt_entry != NULL, "There should have been an entry");
|
||||||
for (int i = 0; i < SparsePRTEntry::cards_num(); i++) {
|
for (int i = 0; i < SparsePRTEntry::cards_num(); i++) {
|
||||||
CardIdx_t c = sprt_entry->card(i);
|
CardIdx_t c = sprt_entry->card(i);
|
||||||
@ -525,7 +525,7 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Now we can delete the sparse entry.
|
// Now we can delete the sparse entry.
|
||||||
bool res = _sparse_table.delete_entry(from_hrs_ind);
|
bool res = _sparse_table.delete_entry(from_hrm_ind);
|
||||||
assert(res, "It should have been there.");
|
assert(res, "It should have been there.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -926,8 +926,24 @@ void HeapRegionRemSet::scrub(CardTableModRefBS* ctbs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Code roots support
|
// Code roots support
|
||||||
|
//
|
||||||
|
// The code root set is protected by two separate locking schemes
|
||||||
|
// When at safepoint the per-hrrs lock must be held during modifications
|
||||||
|
// except when doing a full gc.
|
||||||
|
// When not at safepoint the CodeCache_lock must be held during modifications.
|
||||||
|
// When concurrent readers access the contains() function
|
||||||
|
// (during the evacuation phase) no removals are allowed.
|
||||||
|
|
||||||
void HeapRegionRemSet::add_strong_code_root(nmethod* nm) {
|
void HeapRegionRemSet::add_strong_code_root(nmethod* nm) {
|
||||||
|
assert(nm != NULL, "sanity");
|
||||||
|
// Optimistic unlocked contains-check
|
||||||
|
if (!_code_roots.contains(nm)) {
|
||||||
|
MutexLockerEx ml(&_m, Mutex::_no_safepoint_check_flag);
|
||||||
|
add_strong_code_root_locked(nm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HeapRegionRemSet::add_strong_code_root_locked(nmethod* nm) {
|
||||||
assert(nm != NULL, "sanity");
|
assert(nm != NULL, "sanity");
|
||||||
_code_roots.add(nm);
|
_code_roots.add(nm);
|
||||||
}
|
}
|
||||||
@ -936,98 +952,21 @@ void HeapRegionRemSet::remove_strong_code_root(nmethod* nm) {
|
|||||||
assert(nm != NULL, "sanity");
|
assert(nm != NULL, "sanity");
|
||||||
assert_locked_or_safepoint(CodeCache_lock);
|
assert_locked_or_safepoint(CodeCache_lock);
|
||||||
|
|
||||||
_code_roots.remove_lock_free(nm);
|
MutexLockerEx ml(CodeCache_lock->owned_by_self() ? NULL : &_m, Mutex::_no_safepoint_check_flag);
|
||||||
|
_code_roots.remove(nm);
|
||||||
|
|
||||||
// Check that there were no duplicates
|
// Check that there were no duplicates
|
||||||
guarantee(!_code_roots.contains(nm), "duplicate entry found");
|
guarantee(!_code_roots.contains(nm), "duplicate entry found");
|
||||||
}
|
}
|
||||||
|
|
||||||
class NMethodMigrationOopClosure : public OopClosure {
|
|
||||||
G1CollectedHeap* _g1h;
|
|
||||||
HeapRegion* _from;
|
|
||||||
nmethod* _nm;
|
|
||||||
|
|
||||||
uint _num_self_forwarded;
|
|
||||||
|
|
||||||
template <class T> void do_oop_work(T* p) {
|
|
||||||
T heap_oop = oopDesc::load_heap_oop(p);
|
|
||||||
if (!oopDesc::is_null(heap_oop)) {
|
|
||||||
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
|
|
||||||
if (_from->is_in(obj)) {
|
|
||||||
// Reference still points into the source region.
|
|
||||||
// Since roots are immediately evacuated this means that
|
|
||||||
// we must have self forwarded the object
|
|
||||||
assert(obj->is_forwarded(),
|
|
||||||
err_msg("code roots should be immediately evacuated. "
|
|
||||||
"Ref: "PTR_FORMAT", "
|
|
||||||
"Obj: "PTR_FORMAT", "
|
|
||||||
"Region: "HR_FORMAT,
|
|
||||||
p, (void*) obj, HR_FORMAT_PARAMS(_from)));
|
|
||||||
assert(obj->forwardee() == obj,
|
|
||||||
err_msg("not self forwarded? obj = "PTR_FORMAT, (void*)obj));
|
|
||||||
|
|
||||||
// The object has been self forwarded.
|
|
||||||
// Note, if we're during an initial mark pause, there is
|
|
||||||
// no need to explicitly mark object. It will be marked
|
|
||||||
// during the regular evacuation failure handling code.
|
|
||||||
_num_self_forwarded++;
|
|
||||||
} else {
|
|
||||||
// The reference points into a promotion or to-space region
|
|
||||||
HeapRegion* to = _g1h->heap_region_containing(obj);
|
|
||||||
to->rem_set()->add_strong_code_root(_nm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
NMethodMigrationOopClosure(G1CollectedHeap* g1h, HeapRegion* from, nmethod* nm):
|
|
||||||
_g1h(g1h), _from(from), _nm(nm), _num_self_forwarded(0) {}
|
|
||||||
|
|
||||||
void do_oop(narrowOop* p) { do_oop_work(p); }
|
|
||||||
void do_oop(oop* p) { do_oop_work(p); }
|
|
||||||
|
|
||||||
uint retain() { return _num_self_forwarded > 0; }
|
|
||||||
};
|
|
||||||
|
|
||||||
void HeapRegionRemSet::migrate_strong_code_roots() {
|
|
||||||
assert(hr()->in_collection_set(), "only collection set regions");
|
|
||||||
assert(!hr()->isHumongous(),
|
|
||||||
err_msg("humongous region "HR_FORMAT" should not have been added to the collection set",
|
|
||||||
HR_FORMAT_PARAMS(hr())));
|
|
||||||
|
|
||||||
ResourceMark rm;
|
|
||||||
|
|
||||||
// List of code blobs to retain for this region
|
|
||||||
GrowableArray<nmethod*> to_be_retained(10);
|
|
||||||
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
|
||||||
|
|
||||||
while (!_code_roots.is_empty()) {
|
|
||||||
nmethod *nm = _code_roots.pop();
|
|
||||||
if (nm != NULL) {
|
|
||||||
NMethodMigrationOopClosure oop_cl(g1h, hr(), nm);
|
|
||||||
nm->oops_do(&oop_cl);
|
|
||||||
if (oop_cl.retain()) {
|
|
||||||
to_be_retained.push(nm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now push any code roots we need to retain
|
|
||||||
assert(to_be_retained.is_empty() || hr()->evacuation_failed(),
|
|
||||||
"Retained nmethod list must be empty or "
|
|
||||||
"evacuation of this region failed");
|
|
||||||
|
|
||||||
while (to_be_retained.is_nonempty()) {
|
|
||||||
nmethod* nm = to_be_retained.pop();
|
|
||||||
assert(nm != NULL, "sanity");
|
|
||||||
add_strong_code_root(nm);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HeapRegionRemSet::strong_code_roots_do(CodeBlobClosure* blk) const {
|
void HeapRegionRemSet::strong_code_roots_do(CodeBlobClosure* blk) const {
|
||||||
_code_roots.nmethods_do(blk);
|
_code_roots.nmethods_do(blk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HeapRegionRemSet::clean_strong_code_roots(HeapRegion* hr) {
|
||||||
|
_code_roots.clean(hr);
|
||||||
|
}
|
||||||
|
|
||||||
size_t HeapRegionRemSet::strong_code_roots_mem_size() {
|
size_t HeapRegionRemSet::strong_code_roots_mem_size() {
|
||||||
return _code_roots.mem_size();
|
return _code_roots.mem_size();
|
||||||
}
|
}
|
||||||
|
@ -349,13 +349,13 @@ public:
|
|||||||
// Returns the memory occupancy of all static data structures associated
|
// Returns the memory occupancy of all static data structures associated
|
||||||
// with remembered sets.
|
// with remembered sets.
|
||||||
static size_t static_mem_size() {
|
static size_t static_mem_size() {
|
||||||
return OtherRegionsTable::static_mem_size() + G1CodeRootSet::free_chunks_static_mem_size();
|
return OtherRegionsTable::static_mem_size() + G1CodeRootSet::static_mem_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the memory occupancy of all free_list data structures associated
|
// Returns the memory occupancy of all free_list data structures associated
|
||||||
// with remembered sets.
|
// with remembered sets.
|
||||||
static size_t fl_mem_size() {
|
static size_t fl_mem_size() {
|
||||||
return OtherRegionsTable::fl_mem_size() + G1CodeRootSet::free_chunks_mem_size();
|
return OtherRegionsTable::fl_mem_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool contains_reference(OopOrNarrowOopStar from) const {
|
bool contains_reference(OopOrNarrowOopStar from) const {
|
||||||
@ -365,18 +365,15 @@ public:
|
|||||||
// Routines for managing the list of code roots that point into
|
// Routines for managing the list of code roots that point into
|
||||||
// the heap region that owns this RSet.
|
// the heap region that owns this RSet.
|
||||||
void add_strong_code_root(nmethod* nm);
|
void add_strong_code_root(nmethod* nm);
|
||||||
|
void add_strong_code_root_locked(nmethod* nm);
|
||||||
void remove_strong_code_root(nmethod* nm);
|
void remove_strong_code_root(nmethod* nm);
|
||||||
|
|
||||||
// During a collection, migrate the successfully evacuated strong
|
|
||||||
// code roots that referenced into the region that owns this RSet
|
|
||||||
// to the RSets of the new regions that they now point into.
|
|
||||||
// Unsuccessfully evacuated code roots are not migrated.
|
|
||||||
void migrate_strong_code_roots();
|
|
||||||
|
|
||||||
// Applies blk->do_code_blob() to each of the entries in
|
// Applies blk->do_code_blob() to each of the entries in
|
||||||
// the strong code roots list
|
// the strong code roots list
|
||||||
void strong_code_roots_do(CodeBlobClosure* blk) const;
|
void strong_code_roots_do(CodeBlobClosure* blk) const;
|
||||||
|
|
||||||
|
void clean_strong_code_roots(HeapRegion* hr);
|
||||||
|
|
||||||
// Returns the number of elements in the strong code roots list
|
// Returns the number of elements in the strong code roots list
|
||||||
size_t strong_code_roots_list_length() const {
|
size_t strong_code_roots_list_length() const {
|
||||||
return _code_roots.length();
|
return _code_roots.length();
|
||||||
|
@ -55,7 +55,9 @@ class InterpreterCodelet: public Stub {
|
|||||||
public:
|
public:
|
||||||
// Initialization/finalization
|
// Initialization/finalization
|
||||||
void initialize(int size,
|
void initialize(int size,
|
||||||
CodeStrings& strings) { _size = size; DEBUG_ONLY(_strings.assign(strings);) }
|
CodeStrings& strings) { _size = size;
|
||||||
|
DEBUG_ONLY(::new(&_strings) CodeStrings();)
|
||||||
|
DEBUG_ONLY(_strings.assign(strings);) }
|
||||||
void finalize() { ShouldNotCallThis(); }
|
void finalize() { ShouldNotCallThis(); }
|
||||||
|
|
||||||
// General info/converters
|
// General info/converters
|
||||||
|
@ -34,7 +34,6 @@
|
|||||||
|
|
||||||
#if INCLUDE_ALL_GCS
|
#if INCLUDE_ALL_GCS
|
||||||
#include "gc_implementation/concurrentMarkSweep/freeChunk.hpp"
|
#include "gc_implementation/concurrentMarkSweep/freeChunk.hpp"
|
||||||
#include "gc_implementation/g1/g1CodeCacheRemSet.hpp"
|
|
||||||
#endif // INCLUDE_ALL_GCS
|
#endif // INCLUDE_ALL_GCS
|
||||||
|
|
||||||
// Free list. A FreeList is used to access a linked list of chunks
|
// Free list. A FreeList is used to access a linked list of chunks
|
||||||
@ -333,5 +332,4 @@ template class FreeList<Metablock>;
|
|||||||
template class FreeList<Metachunk>;
|
template class FreeList<Metachunk>;
|
||||||
#if INCLUDE_ALL_GCS
|
#if INCLUDE_ALL_GCS
|
||||||
template class FreeList<FreeChunk>;
|
template class FreeList<FreeChunk>;
|
||||||
template class FreeList<G1CodeRootChunk>;
|
|
||||||
#endif // INCLUDE_ALL_GCS
|
#endif // INCLUDE_ALL_GCS
|
||||||
|
@ -41,7 +41,7 @@
|
|||||||
|
|
||||||
#define SET_ESTIMATED_SIZE(type, region) \
|
#define SET_ESTIMATED_SIZE(type, region) \
|
||||||
Shared ##region## Size = FLAG_IS_DEFAULT(Shared ##region## Size) ? \
|
Shared ##region## Size = FLAG_IS_DEFAULT(Shared ##region## Size) ? \
|
||||||
(type ## SharedArchiveSize * region ## RegionPercentage) : Shared ## region ## Size
|
(uintx)(type ## SharedArchiveSize * region ## RegionPercentage) : Shared ## region ## Size
|
||||||
|
|
||||||
class FileMapInfo;
|
class FileMapInfo;
|
||||||
|
|
||||||
|
@ -78,7 +78,6 @@ ArrayKlass::ArrayKlass(Symbol* name) {
|
|||||||
set_dimension(1);
|
set_dimension(1);
|
||||||
set_higher_dimension(NULL);
|
set_higher_dimension(NULL);
|
||||||
set_lower_dimension(NULL);
|
set_lower_dimension(NULL);
|
||||||
set_component_mirror(NULL);
|
|
||||||
// Arrays don't add any new methods, so their vtable is the same size as
|
// Arrays don't add any new methods, so their vtable is the same size as
|
||||||
// the vtable of klass Object.
|
// the vtable of klass Object.
|
||||||
int vtable_size = Universe::base_vtable_size();
|
int vtable_size = Universe::base_vtable_size();
|
||||||
@ -160,14 +159,6 @@ void ArrayKlass::array_klasses_do(void f(Klass* k)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GC support
|
|
||||||
|
|
||||||
void ArrayKlass::oops_do(OopClosure* cl) {
|
|
||||||
Klass::oops_do(cl);
|
|
||||||
|
|
||||||
cl->do_oop(adr_component_mirror());
|
|
||||||
}
|
|
||||||
|
|
||||||
// JVM support
|
// JVM support
|
||||||
|
|
||||||
jint ArrayKlass::compute_modifier_flags(TRAPS) const {
|
jint ArrayKlass::compute_modifier_flags(TRAPS) const {
|
||||||
@ -182,8 +173,6 @@ jint ArrayKlass::jvmti_class_status() const {
|
|||||||
|
|
||||||
void ArrayKlass::remove_unshareable_info() {
|
void ArrayKlass::remove_unshareable_info() {
|
||||||
Klass::remove_unshareable_info();
|
Klass::remove_unshareable_info();
|
||||||
// Clear the java mirror
|
|
||||||
set_component_mirror(NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArrayKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
|
void ArrayKlass::restore_unshareable_info(ClassLoaderData* loader_data, Handle protection_domain, TRAPS) {
|
||||||
@ -217,10 +206,6 @@ void ArrayKlass::oop_print_on(oop obj, outputStream* st) {
|
|||||||
|
|
||||||
void ArrayKlass::verify_on(outputStream* st) {
|
void ArrayKlass::verify_on(outputStream* st) {
|
||||||
Klass::verify_on(st);
|
Klass::verify_on(st);
|
||||||
|
|
||||||
if (component_mirror() != NULL) {
|
|
||||||
guarantee(component_mirror()->klass() != NULL, "should have a class");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArrayKlass::oop_verify_on(oop obj, outputStream* st) {
|
void ArrayKlass::oop_verify_on(oop obj, outputStream* st) {
|
||||||
|
@ -39,7 +39,6 @@ class ArrayKlass: public Klass {
|
|||||||
Klass* volatile _higher_dimension; // Refers the (n+1)'th-dimensional array (if present).
|
Klass* volatile _higher_dimension; // Refers the (n+1)'th-dimensional array (if present).
|
||||||
Klass* volatile _lower_dimension; // Refers the (n-1)'th-dimensional array (if present).
|
Klass* volatile _lower_dimension; // Refers the (n-1)'th-dimensional array (if present).
|
||||||
int _vtable_len; // size of vtable for this klass
|
int _vtable_len; // size of vtable for this klass
|
||||||
oop _component_mirror; // component type, as a java/lang/Class
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Constructors
|
// Constructors
|
||||||
@ -70,13 +69,6 @@ class ArrayKlass: public Klass {
|
|||||||
// type of elements (T_OBJECT for both oop arrays and array-arrays)
|
// type of elements (T_OBJECT for both oop arrays and array-arrays)
|
||||||
BasicType element_type() const { return layout_helper_element_type(layout_helper()); }
|
BasicType element_type() const { return layout_helper_element_type(layout_helper()); }
|
||||||
|
|
||||||
oop component_mirror() const { return _component_mirror; }
|
|
||||||
void set_component_mirror(oop m) { klass_oop_store(&_component_mirror, m); }
|
|
||||||
oop* adr_component_mirror() { return (oop*)&this->_component_mirror;}
|
|
||||||
|
|
||||||
// Compiler/Interpreter offset
|
|
||||||
static ByteSize component_mirror_offset() { return in_ByteSize(offset_of(ArrayKlass, _component_mirror)); }
|
|
||||||
|
|
||||||
virtual Klass* java_super() const;//{ return SystemDictionary::Object_klass(); }
|
virtual Klass* java_super() const;//{ return SystemDictionary::Object_klass(); }
|
||||||
|
|
||||||
// Allocation
|
// Allocation
|
||||||
@ -122,9 +114,6 @@ class ArrayKlass: public Klass {
|
|||||||
void array_klasses_do(void f(Klass* k));
|
void array_klasses_do(void f(Klass* k));
|
||||||
void array_klasses_do(void f(Klass* k, TRAPS), TRAPS);
|
void array_klasses_do(void f(Klass* k, TRAPS), TRAPS);
|
||||||
|
|
||||||
// GC support
|
|
||||||
virtual void oops_do(OopClosure* cl);
|
|
||||||
|
|
||||||
// Return a handle.
|
// Return a handle.
|
||||||
static void complete_create_array_klass(ArrayKlass* k, KlassHandle super_klass, TRAPS);
|
static void complete_create_array_klass(ArrayKlass* k, KlassHandle super_klass, TRAPS);
|
||||||
|
|
||||||
|
@ -565,7 +565,7 @@ protected:
|
|||||||
TRACE_DEFINE_KLASS_METHODS;
|
TRACE_DEFINE_KLASS_METHODS;
|
||||||
|
|
||||||
// garbage collection support
|
// garbage collection support
|
||||||
virtual void oops_do(OopClosure* cl);
|
void oops_do(OopClosure* cl);
|
||||||
|
|
||||||
// Iff the class loader (or mirror for anonymous classes) is alive the
|
// Iff the class loader (or mirror for anonymous classes) is alive the
|
||||||
// Klass is considered alive.
|
// Klass is considered alive.
|
||||||
|
@ -86,7 +86,7 @@ ProfileData::ProfileData() {
|
|||||||
|
|
||||||
char* ProfileData::print_data_on_helper(const MethodData* md) const {
|
char* ProfileData::print_data_on_helper(const MethodData* md) const {
|
||||||
DataLayout* dp = md->extra_data_base();
|
DataLayout* dp = md->extra_data_base();
|
||||||
DataLayout* end = md->extra_data_limit();
|
DataLayout* end = md->args_data_limit();
|
||||||
stringStream ss;
|
stringStream ss;
|
||||||
for (;; dp = MethodData::next_extra(dp)) {
|
for (;; dp = MethodData::next_extra(dp)) {
|
||||||
assert(dp < end, "moved past end of extra data");
|
assert(dp < end, "moved past end of extra data");
|
||||||
@ -1048,14 +1048,15 @@ void MethodData::post_initialize(BytecodeStream* stream) {
|
|||||||
stream->next();
|
stream->next();
|
||||||
data->post_initialize(stream, this);
|
data->post_initialize(stream, this);
|
||||||
}
|
}
|
||||||
if (_parameters_type_data_di != -1) {
|
if (_parameters_type_data_di != no_parameters) {
|
||||||
parameters_type_data()->post_initialize(NULL, this);
|
parameters_type_data()->post_initialize(NULL, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the MethodData* corresponding to a given method.
|
// Initialize the MethodData* corresponding to a given method.
|
||||||
MethodData::MethodData(methodHandle method, int size, TRAPS)
|
MethodData::MethodData(methodHandle method, int size, TRAPS)
|
||||||
: _extra_data_lock(Monitor::leaf, "MDO extra data lock") {
|
: _extra_data_lock(Monitor::leaf, "MDO extra data lock"),
|
||||||
|
_parameters_type_data_di(parameters_uninitialized) {
|
||||||
No_Safepoint_Verifier no_safepoint; // init function atomic wrt GC
|
No_Safepoint_Verifier no_safepoint; // init function atomic wrt GC
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
// Set the method back-pointer.
|
// Set the method back-pointer.
|
||||||
@ -1111,7 +1112,7 @@ MethodData::MethodData(methodHandle method, int size, TRAPS)
|
|||||||
DataLayout *dp = data_layout_at(data_size + extra_size + arg_data_size);
|
DataLayout *dp = data_layout_at(data_size + extra_size + arg_data_size);
|
||||||
dp->initialize(DataLayout::parameters_type_data_tag, 0, parms_cell);
|
dp->initialize(DataLayout::parameters_type_data_tag, 0, parms_cell);
|
||||||
} else {
|
} else {
|
||||||
_parameters_type_data_di = -1;
|
_parameters_type_data_di = no_parameters;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set an initial hint. Don't use set_hint_di() because
|
// Set an initial hint. Don't use set_hint_di() because
|
||||||
@ -1236,7 +1237,7 @@ DataLayout* MethodData::next_extra(DataLayout* dp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ProfileData* MethodData::bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp, bool concurrent) {
|
ProfileData* MethodData::bci_to_extra_data_helper(int bci, Method* m, DataLayout*& dp, bool concurrent) {
|
||||||
DataLayout* end = extra_data_limit();
|
DataLayout* end = args_data_limit();
|
||||||
|
|
||||||
for (;; dp = next_extra(dp)) {
|
for (;; dp = next_extra(dp)) {
|
||||||
assert(dp < end, "moved past end of extra data");
|
assert(dp < end, "moved past end of extra data");
|
||||||
@ -1285,7 +1286,7 @@ ProfileData* MethodData::bci_to_extra_data(int bci, Method* m, bool create_if_mi
|
|||||||
"code needs to be adjusted");
|
"code needs to be adjusted");
|
||||||
|
|
||||||
DataLayout* dp = extra_data_base();
|
DataLayout* dp = extra_data_base();
|
||||||
DataLayout* end = extra_data_limit();
|
DataLayout* end = args_data_limit();
|
||||||
|
|
||||||
// Allocation in the extra data space has to be atomic because not
|
// Allocation in the extra data space has to be atomic because not
|
||||||
// all entries have the same size and non atomic concurrent
|
// all entries have the same size and non atomic concurrent
|
||||||
@ -1330,7 +1331,7 @@ ProfileData* MethodData::bci_to_extra_data(int bci, Method* m, bool create_if_mi
|
|||||||
|
|
||||||
ArgInfoData *MethodData::arg_info() {
|
ArgInfoData *MethodData::arg_info() {
|
||||||
DataLayout* dp = extra_data_base();
|
DataLayout* dp = extra_data_base();
|
||||||
DataLayout* end = extra_data_limit();
|
DataLayout* end = args_data_limit();
|
||||||
for (; dp < end; dp = next_extra(dp)) {
|
for (; dp < end; dp = next_extra(dp)) {
|
||||||
if (dp->tag() == DataLayout::arg_info_data_tag)
|
if (dp->tag() == DataLayout::arg_info_data_tag)
|
||||||
return new ArgInfoData(dp);
|
return new ArgInfoData(dp);
|
||||||
@ -1357,7 +1358,7 @@ void MethodData::print_value_on(outputStream* st) const {
|
|||||||
void MethodData::print_data_on(outputStream* st) const {
|
void MethodData::print_data_on(outputStream* st) const {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
ProfileData* data = first_data();
|
ProfileData* data = first_data();
|
||||||
if (_parameters_type_data_di != -1) {
|
if (_parameters_type_data_di != no_parameters) {
|
||||||
parameters_type_data()->print_data_on(st);
|
parameters_type_data()->print_data_on(st);
|
||||||
}
|
}
|
||||||
for ( ; is_valid(data); data = next_data(data)) {
|
for ( ; is_valid(data); data = next_data(data)) {
|
||||||
@ -1367,7 +1368,7 @@ void MethodData::print_data_on(outputStream* st) const {
|
|||||||
}
|
}
|
||||||
st->print_cr("--- Extra data:");
|
st->print_cr("--- Extra data:");
|
||||||
DataLayout* dp = extra_data_base();
|
DataLayout* dp = extra_data_base();
|
||||||
DataLayout* end = extra_data_limit();
|
DataLayout* end = args_data_limit();
|
||||||
for (;; dp = next_extra(dp)) {
|
for (;; dp = next_extra(dp)) {
|
||||||
assert(dp < end, "moved past end of extra data");
|
assert(dp < end, "moved past end of extra data");
|
||||||
// No need for "OrderAccess::load_acquire" ops,
|
// No need for "OrderAccess::load_acquire" ops,
|
||||||
@ -1565,7 +1566,7 @@ public:
|
|||||||
// redefined method
|
// redefined method
|
||||||
void MethodData::clean_extra_data(CleanExtraDataClosure* cl) {
|
void MethodData::clean_extra_data(CleanExtraDataClosure* cl) {
|
||||||
DataLayout* dp = extra_data_base();
|
DataLayout* dp = extra_data_base();
|
||||||
DataLayout* end = extra_data_limit();
|
DataLayout* end = args_data_limit();
|
||||||
|
|
||||||
int shift = 0;
|
int shift = 0;
|
||||||
for (; dp < end; dp = next_extra(dp)) {
|
for (; dp < end; dp = next_extra(dp)) {
|
||||||
@ -1610,7 +1611,7 @@ void MethodData::clean_extra_data(CleanExtraDataClosure* cl) {
|
|||||||
void MethodData::verify_extra_data_clean(CleanExtraDataClosure* cl) {
|
void MethodData::verify_extra_data_clean(CleanExtraDataClosure* cl) {
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
DataLayout* dp = extra_data_base();
|
DataLayout* dp = extra_data_base();
|
||||||
DataLayout* end = extra_data_limit();
|
DataLayout* end = args_data_limit();
|
||||||
|
|
||||||
for (; dp < end; dp = next_extra(dp)) {
|
for (; dp < end; dp = next_extra(dp)) {
|
||||||
switch(dp->tag()) {
|
switch(dp->tag()) {
|
||||||
|
@ -2107,7 +2107,12 @@ private:
|
|||||||
|
|
||||||
// data index for the area dedicated to parameters. -1 if no
|
// data index for the area dedicated to parameters. -1 if no
|
||||||
// parameter profiling.
|
// parameter profiling.
|
||||||
|
enum { no_parameters = -2, parameters_uninitialized = -1 };
|
||||||
int _parameters_type_data_di;
|
int _parameters_type_data_di;
|
||||||
|
int parameters_size_in_bytes() const {
|
||||||
|
ParametersTypeData* param = parameters_type_data();
|
||||||
|
return param == NULL ? 0 : param->size_in_bytes();
|
||||||
|
}
|
||||||
|
|
||||||
// Beginning of the data entries
|
// Beginning of the data entries
|
||||||
intptr_t _data[1];
|
intptr_t _data[1];
|
||||||
@ -2130,7 +2135,7 @@ private:
|
|||||||
|
|
||||||
// Helper for data_at
|
// Helper for data_at
|
||||||
DataLayout* limit_data_position() const {
|
DataLayout* limit_data_position() const {
|
||||||
return (DataLayout*)((address)data_base() + _data_size);
|
return data_layout_at(_data_size);
|
||||||
}
|
}
|
||||||
bool out_of_bounds(int data_index) const {
|
bool out_of_bounds(int data_index) const {
|
||||||
return data_index >= data_size();
|
return data_index >= data_size();
|
||||||
@ -2371,10 +2376,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add a handful of extra data records, for trap tracking.
|
// Add a handful of extra data records, for trap tracking.
|
||||||
DataLayout* extra_data_base() const { return limit_data_position(); }
|
DataLayout* extra_data_base() const { return limit_data_position(); }
|
||||||
DataLayout* extra_data_limit() const { return (DataLayout*)((address)this + size_in_bytes()); }
|
DataLayout* extra_data_limit() const { return (DataLayout*)((address)this + size_in_bytes()); }
|
||||||
int extra_data_size() const { return (address)extra_data_limit()
|
DataLayout* args_data_limit() const { return (DataLayout*)((address)this + size_in_bytes() -
|
||||||
- (address)extra_data_base(); }
|
parameters_size_in_bytes()); }
|
||||||
|
int extra_data_size() const { return (address)extra_data_limit() - (address)extra_data_base(); }
|
||||||
static DataLayout* next_extra(DataLayout* dp);
|
static DataLayout* next_extra(DataLayout* dp);
|
||||||
|
|
||||||
// Return (uint)-1 for overflow.
|
// Return (uint)-1 for overflow.
|
||||||
@ -2429,11 +2435,12 @@ public:
|
|||||||
|
|
||||||
// Return pointer to area dedicated to parameters in MDO
|
// Return pointer to area dedicated to parameters in MDO
|
||||||
ParametersTypeData* parameters_type_data() const {
|
ParametersTypeData* parameters_type_data() const {
|
||||||
return _parameters_type_data_di != -1 ? data_layout_at(_parameters_type_data_di)->data_in()->as_ParametersTypeData() : NULL;
|
assert(_parameters_type_data_di != parameters_uninitialized, "called too early");
|
||||||
|
return _parameters_type_data_di != no_parameters ? data_layout_at(_parameters_type_data_di)->data_in()->as_ParametersTypeData() : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int parameters_type_data_di() const {
|
int parameters_type_data_di() const {
|
||||||
assert(_parameters_type_data_di != -1, "no args type data");
|
assert(_parameters_type_data_di != parameters_uninitialized && _parameters_type_data_di != no_parameters, "no args type data");
|
||||||
return _parameters_type_data_di;
|
return _parameters_type_data_di;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2480,8 +2487,8 @@ public:
|
|||||||
static bool profile_return_jsr292_only();
|
static bool profile_return_jsr292_only();
|
||||||
|
|
||||||
void clean_method_data(BoolObjectClosure* is_alive);
|
void clean_method_data(BoolObjectClosure* is_alive);
|
||||||
|
|
||||||
void clean_weak_method_links();
|
void clean_weak_method_links();
|
||||||
|
Mutex* extra_data_lock() { return &_extra_data_lock; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHARE_VM_OOPS_METHODDATAOOP_HPP
|
#endif // SHARE_VM_OOPS_METHODDATAOOP_HPP
|
||||||
|
@ -650,6 +650,9 @@
|
|||||||
product(bool, UseMathExactIntrinsics, true, \
|
product(bool, UseMathExactIntrinsics, true, \
|
||||||
"Enables intrinsification of various java.lang.Math functions") \
|
"Enables intrinsification of various java.lang.Math functions") \
|
||||||
\
|
\
|
||||||
|
product(bool, UseMultiplyToLenIntrinsic, false, \
|
||||||
|
"Enables intrinsification of BigInteger.multiplyToLen()") \
|
||||||
|
\
|
||||||
product(bool, UseTypeSpeculation, true, \
|
product(bool, UseTypeSpeculation, true, \
|
||||||
"Speculatively propagate types from profiles") \
|
"Speculatively propagate types from profiles") \
|
||||||
\
|
\
|
||||||
|
@ -1830,8 +1830,8 @@ ArrayCopyNode* ArrayCopyNode::make(GraphKit* kit, bool may_throw,
|
|||||||
Node* dest, Node* dest_offset,
|
Node* dest, Node* dest_offset,
|
||||||
Node* length,
|
Node* length,
|
||||||
bool alloc_tightly_coupled,
|
bool alloc_tightly_coupled,
|
||||||
Node* src_length, Node* dest_length,
|
Node* src_klass, Node* dest_klass,
|
||||||
Node* src_klass, Node* dest_klass) {
|
Node* src_length, Node* dest_length) {
|
||||||
|
|
||||||
ArrayCopyNode* ac = new ArrayCopyNode(kit->C, alloc_tightly_coupled);
|
ArrayCopyNode* ac = new ArrayCopyNode(kit->C, alloc_tightly_coupled);
|
||||||
Node* prev_mem = kit->set_predefined_input_for_runtime_call(ac);
|
Node* prev_mem = kit->set_predefined_input_for_runtime_call(ac);
|
||||||
|
@ -1138,8 +1138,8 @@ public:
|
|||||||
Node* dest, Node* dest_offset,
|
Node* dest, Node* dest_offset,
|
||||||
Node* length,
|
Node* length,
|
||||||
bool alloc_tightly_coupled,
|
bool alloc_tightly_coupled,
|
||||||
Node* src_length = NULL, Node* dest_length = NULL,
|
Node* src_klass = NULL, Node* dest_klass = NULL,
|
||||||
Node* src_klass = NULL, Node* dest_klass = NULL);
|
Node* src_length = NULL, Node* dest_length = NULL);
|
||||||
|
|
||||||
void connect_outputs(GraphKit* kit);
|
void connect_outputs(GraphKit* kit);
|
||||||
|
|
||||||
|
@ -601,6 +601,10 @@ class Compile : public Phase {
|
|||||||
bool method_has_option(const char * option) {
|
bool method_has_option(const char * option) {
|
||||||
return method() != NULL && method()->has_option(option);
|
return method() != NULL && method()->has_option(option);
|
||||||
}
|
}
|
||||||
|
template<typename T>
|
||||||
|
bool method_has_option_value(const char * option, T& value) {
|
||||||
|
return method() != NULL && method()->has_option_value(option, value);
|
||||||
|
}
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
bool trace_opto_output() const { return _trace_opto_output; }
|
bool trace_opto_output() const { return _trace_opto_output; }
|
||||||
bool parsed_irreducible_loop() const { return _parsed_irreducible_loop; }
|
bool parsed_irreducible_loop() const { return _parsed_irreducible_loop; }
|
||||||
|
@ -945,7 +945,8 @@ void ConnectionGraph::process_call_arguments(CallNode *call) {
|
|||||||
strcmp(call->as_CallLeaf()->_name, "sha256_implCompress") == 0 ||
|
strcmp(call->as_CallLeaf()->_name, "sha256_implCompress") == 0 ||
|
||||||
strcmp(call->as_CallLeaf()->_name, "sha256_implCompressMB") == 0 ||
|
strcmp(call->as_CallLeaf()->_name, "sha256_implCompressMB") == 0 ||
|
||||||
strcmp(call->as_CallLeaf()->_name, "sha512_implCompress") == 0 ||
|
strcmp(call->as_CallLeaf()->_name, "sha512_implCompress") == 0 ||
|
||||||
strcmp(call->as_CallLeaf()->_name, "sha512_implCompressMB") == 0)
|
strcmp(call->as_CallLeaf()->_name, "sha512_implCompressMB") == 0 ||
|
||||||
|
strcmp(call->as_CallLeaf()->_name, "multiplyToLen") == 0)
|
||||||
))) {
|
))) {
|
||||||
call->dump();
|
call->dump();
|
||||||
fatal(err_msg_res("EA unexpected CallLeaf %s", call->as_CallLeaf()->_name));
|
fatal(err_msg_res("EA unexpected CallLeaf %s", call->as_CallLeaf()->_name));
|
||||||
|
@ -285,6 +285,7 @@ class LibraryCallKit : public GraphKit {
|
|||||||
bool inline_updateCRC32();
|
bool inline_updateCRC32();
|
||||||
bool inline_updateBytesCRC32();
|
bool inline_updateBytesCRC32();
|
||||||
bool inline_updateByteBufferCRC32();
|
bool inline_updateByteBufferCRC32();
|
||||||
|
bool inline_multiplyToLen();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -293,8 +294,12 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) {
|
|||||||
vmIntrinsics::ID id = m->intrinsic_id();
|
vmIntrinsics::ID id = m->intrinsic_id();
|
||||||
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
|
assert(id != vmIntrinsics::_none, "must be a VM intrinsic");
|
||||||
|
|
||||||
if (DisableIntrinsic[0] != '\0'
|
ccstr disable_intr = NULL;
|
||||||
&& strstr(DisableIntrinsic, vmIntrinsics::name_at(id)) != NULL) {
|
|
||||||
|
if ((DisableIntrinsic[0] != '\0'
|
||||||
|
&& strstr(DisableIntrinsic, vmIntrinsics::name_at(id)) != NULL) ||
|
||||||
|
(method_has_option_value("DisableIntrinsic", disable_intr)
|
||||||
|
&& strstr(disable_intr, vmIntrinsics::name_at(id)) != NULL)) {
|
||||||
// disabled by a user request on the command line:
|
// disabled by a user request on the command line:
|
||||||
// example: -XX:DisableIntrinsic=_hashCode,_getClass
|
// example: -XX:DisableIntrinsic=_hashCode,_getClass
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -477,6 +482,10 @@ CallGenerator* Compile::make_vm_intrinsic(ciMethod* m, bool is_virtual) {
|
|||||||
if (!UseAESIntrinsics) return NULL;
|
if (!UseAESIntrinsics) return NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case vmIntrinsics::_multiplyToLen:
|
||||||
|
if (!UseMultiplyToLenIntrinsic) return NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt:
|
case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt:
|
||||||
case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt:
|
case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt:
|
||||||
if (!UseAESIntrinsics) return NULL;
|
if (!UseAESIntrinsics) return NULL;
|
||||||
@ -836,7 +845,6 @@ bool LibraryCallKit::try_to_inline(int predicate) {
|
|||||||
case vmIntrinsics::_isArray:
|
case vmIntrinsics::_isArray:
|
||||||
case vmIntrinsics::_isPrimitive:
|
case vmIntrinsics::_isPrimitive:
|
||||||
case vmIntrinsics::_getSuperclass:
|
case vmIntrinsics::_getSuperclass:
|
||||||
case vmIntrinsics::_getComponentType:
|
|
||||||
case vmIntrinsics::_getClassAccessFlags: return inline_native_Class_query(intrinsic_id());
|
case vmIntrinsics::_getClassAccessFlags: return inline_native_Class_query(intrinsic_id());
|
||||||
|
|
||||||
case vmIntrinsics::_floatToRawIntBits:
|
case vmIntrinsics::_floatToRawIntBits:
|
||||||
@ -876,6 +884,9 @@ bool LibraryCallKit::try_to_inline(int predicate) {
|
|||||||
case vmIntrinsics::_digestBase_implCompressMB:
|
case vmIntrinsics::_digestBase_implCompressMB:
|
||||||
return inline_digestBase_implCompressMB(predicate);
|
return inline_digestBase_implCompressMB(predicate);
|
||||||
|
|
||||||
|
case vmIntrinsics::_multiplyToLen:
|
||||||
|
return inline_multiplyToLen();
|
||||||
|
|
||||||
case vmIntrinsics::_encodeISOArray:
|
case vmIntrinsics::_encodeISOArray:
|
||||||
return inline_encodeISOArray();
|
return inline_encodeISOArray();
|
||||||
|
|
||||||
@ -3400,10 +3411,6 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) {
|
|||||||
prim_return_value = null();
|
prim_return_value = null();
|
||||||
return_type = TypeInstPtr::MIRROR->cast_to_ptr_type(TypePtr::BotPTR);
|
return_type = TypeInstPtr::MIRROR->cast_to_ptr_type(TypePtr::BotPTR);
|
||||||
break;
|
break;
|
||||||
case vmIntrinsics::_getComponentType:
|
|
||||||
prim_return_value = null();
|
|
||||||
return_type = TypeInstPtr::MIRROR->cast_to_ptr_type(TypePtr::BotPTR);
|
|
||||||
break;
|
|
||||||
case vmIntrinsics::_getClassAccessFlags:
|
case vmIntrinsics::_getClassAccessFlags:
|
||||||
prim_return_value = intcon(JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC);
|
prim_return_value = intcon(JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC);
|
||||||
return_type = TypeInt::INT; // not bool! 6297094
|
return_type = TypeInt::INT; // not bool! 6297094
|
||||||
@ -3520,17 +3527,6 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case vmIntrinsics::_getComponentType:
|
|
||||||
if (generate_array_guard(kls, region) != NULL) {
|
|
||||||
// Be sure to pin the oop load to the guard edge just created:
|
|
||||||
Node* is_array_ctrl = region->in(region->req()-1);
|
|
||||||
Node* cma = basic_plus_adr(kls, in_bytes(ArrayKlass::component_mirror_offset()));
|
|
||||||
Node* cmo = make_load(is_array_ctrl, cma, TypeInstPtr::MIRROR, T_OBJECT, MemNode::unordered);
|
|
||||||
phi->add_req(cmo);
|
|
||||||
}
|
|
||||||
query_value = null(); // non-array case is null
|
|
||||||
break;
|
|
||||||
|
|
||||||
case vmIntrinsics::_getClassAccessFlags:
|
case vmIntrinsics::_getClassAccessFlags:
|
||||||
p = basic_plus_adr(kls, in_bytes(Klass::access_flags_offset()));
|
p = basic_plus_adr(kls, in_bytes(Klass::access_flags_offset()));
|
||||||
query_value = make_load(NULL, p, TypeInt::INT, T_INT, MemNode::unordered);
|
query_value = make_load(NULL, p, TypeInt::INT, T_INT, MemNode::unordered);
|
||||||
@ -3859,7 +3855,7 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) {
|
|||||||
Node* orig_tail = _gvn.transform(new SubINode(orig_length, start));
|
Node* orig_tail = _gvn.transform(new SubINode(orig_length, start));
|
||||||
Node* moved = generate_min_max(vmIntrinsics::_min, orig_tail, length);
|
Node* moved = generate_min_max(vmIntrinsics::_min, orig_tail, length);
|
||||||
|
|
||||||
newcopy = new_array(klass_node, length, 0); // no argments to push
|
newcopy = new_array(klass_node, length, 0); // no arguments to push
|
||||||
|
|
||||||
// Generate a direct call to the right arraycopy function(s).
|
// Generate a direct call to the right arraycopy function(s).
|
||||||
// We know the copy is disjoint but we might not know if the
|
// We know the copy is disjoint but we might not know if the
|
||||||
@ -3869,7 +3865,8 @@ bool LibraryCallKit::inline_array_copyOf(bool is_copyOfRange) {
|
|||||||
|
|
||||||
Node* alloc = tightly_coupled_allocation(newcopy, NULL);
|
Node* alloc = tightly_coupled_allocation(newcopy, NULL);
|
||||||
|
|
||||||
ArrayCopyNode* ac = ArrayCopyNode::make(this, true, original, start, newcopy, intcon(0), moved, alloc != NULL);
|
ArrayCopyNode* ac = ArrayCopyNode::make(this, true, original, start, newcopy, intcon(0), moved, alloc != NULL,
|
||||||
|
load_object_klass(original), klass_node);
|
||||||
if (!is_copyOfRange) {
|
if (!is_copyOfRange) {
|
||||||
ac->set_copyof();
|
ac->set_copyof();
|
||||||
} else {
|
} else {
|
||||||
@ -4792,8 +4789,8 @@ bool LibraryCallKit::inline_arraycopy() {
|
|||||||
// Create LoadRange and LoadKlass nodes for use during macro expansion here
|
// Create LoadRange and LoadKlass nodes for use during macro expansion here
|
||||||
// so the compiler has a chance to eliminate them: during macro expansion,
|
// so the compiler has a chance to eliminate them: during macro expansion,
|
||||||
// we have to set their control (CastPP nodes are eliminated).
|
// we have to set their control (CastPP nodes are eliminated).
|
||||||
load_array_length(src), load_array_length(dest),
|
load_object_klass(src), load_object_klass(dest),
|
||||||
load_object_klass(src), load_object_klass(dest));
|
load_array_length(src), load_array_length(dest));
|
||||||
|
|
||||||
if (notest) {
|
if (notest) {
|
||||||
ac->set_arraycopy_notest();
|
ac->set_arraycopy_notest();
|
||||||
@ -4924,6 +4921,106 @@ bool LibraryCallKit::inline_encodeISOArray() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//-------------inline_multiplyToLen-----------------------------------
|
||||||
|
bool LibraryCallKit::inline_multiplyToLen() {
|
||||||
|
assert(UseMultiplyToLenIntrinsic, "not implementated on this platform");
|
||||||
|
|
||||||
|
address stubAddr = StubRoutines::multiplyToLen();
|
||||||
|
if (stubAddr == NULL) {
|
||||||
|
return false; // Intrinsic's stub is not implemented on this platform
|
||||||
|
}
|
||||||
|
const char* stubName = "multiplyToLen";
|
||||||
|
|
||||||
|
assert(callee()->signature()->size() == 5, "multiplyToLen has 5 parameters");
|
||||||
|
|
||||||
|
Node* x = argument(1);
|
||||||
|
Node* xlen = argument(2);
|
||||||
|
Node* y = argument(3);
|
||||||
|
Node* ylen = argument(4);
|
||||||
|
Node* z = argument(5);
|
||||||
|
|
||||||
|
const Type* x_type = x->Value(&_gvn);
|
||||||
|
const Type* y_type = y->Value(&_gvn);
|
||||||
|
const TypeAryPtr* top_x = x_type->isa_aryptr();
|
||||||
|
const TypeAryPtr* top_y = y_type->isa_aryptr();
|
||||||
|
if (top_x == NULL || top_x->klass() == NULL ||
|
||||||
|
top_y == NULL || top_y->klass() == NULL) {
|
||||||
|
// failed array check
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
BasicType x_elem = x_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
|
||||||
|
BasicType y_elem = y_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type();
|
||||||
|
if (x_elem != T_INT || y_elem != T_INT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the original stack and the reexecute bit for the interpreter to reexecute
|
||||||
|
// the bytecode that invokes BigInteger.multiplyToLen() if deoptimization happens
|
||||||
|
// on the return from z array allocation in runtime.
|
||||||
|
{ PreserveReexecuteState preexecs(this);
|
||||||
|
jvms()->set_should_reexecute(true);
|
||||||
|
|
||||||
|
Node* x_start = array_element_address(x, intcon(0), x_elem);
|
||||||
|
Node* y_start = array_element_address(y, intcon(0), y_elem);
|
||||||
|
// 'x_start' points to x array + scaled xlen
|
||||||
|
// 'y_start' points to y array + scaled ylen
|
||||||
|
|
||||||
|
// Allocate the result array
|
||||||
|
Node* zlen = _gvn.transform(new AddINode(xlen, ylen));
|
||||||
|
Node* klass_node = makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_INT)));
|
||||||
|
|
||||||
|
IdealKit ideal(this);
|
||||||
|
|
||||||
|
#define __ ideal.
|
||||||
|
Node* one = __ ConI(1);
|
||||||
|
Node* zero = __ ConI(0);
|
||||||
|
IdealVariable need_alloc(ideal), z_alloc(ideal); __ declarations_done();
|
||||||
|
__ set(need_alloc, zero);
|
||||||
|
__ set(z_alloc, z);
|
||||||
|
__ if_then(z, BoolTest::eq, null()); {
|
||||||
|
__ increment (need_alloc, one);
|
||||||
|
} __ else_(); {
|
||||||
|
// Update graphKit memory and control from IdealKit.
|
||||||
|
sync_kit(ideal);
|
||||||
|
Node* zlen_arg = load_array_length(z);
|
||||||
|
// Update IdealKit memory and control from graphKit.
|
||||||
|
__ sync_kit(this);
|
||||||
|
__ if_then(zlen_arg, BoolTest::lt, zlen); {
|
||||||
|
__ increment (need_alloc, one);
|
||||||
|
} __ end_if();
|
||||||
|
} __ end_if();
|
||||||
|
|
||||||
|
__ if_then(__ value(need_alloc), BoolTest::ne, zero); {
|
||||||
|
// Update graphKit memory and control from IdealKit.
|
||||||
|
sync_kit(ideal);
|
||||||
|
Node * narr = new_array(klass_node, zlen, 1);
|
||||||
|
// Update IdealKit memory and control from graphKit.
|
||||||
|
__ sync_kit(this);
|
||||||
|
__ set(z_alloc, narr);
|
||||||
|
} __ end_if();
|
||||||
|
|
||||||
|
sync_kit(ideal);
|
||||||
|
z = __ value(z_alloc);
|
||||||
|
_gvn.set_type(z, TypeAryPtr::INTS);
|
||||||
|
// Final sync IdealKit and GraphKit.
|
||||||
|
final_sync(ideal);
|
||||||
|
#undef __
|
||||||
|
|
||||||
|
Node* z_start = array_element_address(z, intcon(0), T_INT);
|
||||||
|
|
||||||
|
Node* call = make_runtime_call(RC_LEAF|RC_NO_FP,
|
||||||
|
OptoRuntime::multiplyToLen_Type(),
|
||||||
|
stubAddr, stubName, TypePtr::BOTTOM,
|
||||||
|
x_start, xlen, y_start, ylen, z_start, zlen);
|
||||||
|
} // original reexecute is set back here
|
||||||
|
|
||||||
|
C->set_has_split_ifs(true); // Has chance for split-if optimization
|
||||||
|
set_result(z);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate CRC32 for byte.
|
* Calculate CRC32 for byte.
|
||||||
* int java.util.zip.CRC32.update(int crc, int b)
|
* int java.util.zip.CRC32.update(int crc, int b)
|
||||||
|
@ -506,6 +506,8 @@ Node* PhaseMacroExpand::generate_arraycopy(ArrayCopyNode *ac, AllocateArrayNode*
|
|||||||
Node* src_klass = ac->in(ArrayCopyNode::SrcKlass);
|
Node* src_klass = ac->in(ArrayCopyNode::SrcKlass);
|
||||||
Node* dest_klass = ac->in(ArrayCopyNode::DestKlass);
|
Node* dest_klass = ac->in(ArrayCopyNode::DestKlass);
|
||||||
|
|
||||||
|
assert(src_klass != NULL && dest_klass != NULL, "should have klasses");
|
||||||
|
|
||||||
// Generate the subtype check.
|
// Generate the subtype check.
|
||||||
// This might fold up statically, or then again it might not.
|
// This might fold up statically, or then again it might not.
|
||||||
//
|
//
|
||||||
@ -1209,6 +1211,7 @@ void PhaseMacroExpand::expand_arraycopy_node(ArrayCopyNode *ac) {
|
|||||||
|
|
||||||
// (7) src_offset + length must not exceed length of src.
|
// (7) src_offset + length must not exceed length of src.
|
||||||
Node* alen = ac->in(ArrayCopyNode::SrcLen);
|
Node* alen = ac->in(ArrayCopyNode::SrcLen);
|
||||||
|
assert(alen != NULL, "need src len");
|
||||||
generate_limit_guard(&ctrl,
|
generate_limit_guard(&ctrl,
|
||||||
src_offset, length,
|
src_offset, length,
|
||||||
alen,
|
alen,
|
||||||
@ -1216,6 +1219,7 @@ void PhaseMacroExpand::expand_arraycopy_node(ArrayCopyNode *ac) {
|
|||||||
|
|
||||||
// (8) dest_offset + length must not exceed length of dest.
|
// (8) dest_offset + length must not exceed length of dest.
|
||||||
alen = ac->in(ArrayCopyNode::DestLen);
|
alen = ac->in(ArrayCopyNode::DestLen);
|
||||||
|
assert(alen != NULL, "need dest len");
|
||||||
generate_limit_guard(&ctrl,
|
generate_limit_guard(&ctrl,
|
||||||
dest_offset, length,
|
dest_offset, length,
|
||||||
alen,
|
alen,
|
||||||
|
@ -1799,13 +1799,6 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const {
|
|||||||
}
|
}
|
||||||
const Type* aift = load_array_final_field(tkls, klass);
|
const Type* aift = load_array_final_field(tkls, klass);
|
||||||
if (aift != NULL) return aift;
|
if (aift != NULL) return aift;
|
||||||
if (tkls->offset() == in_bytes(ArrayKlass::component_mirror_offset())
|
|
||||||
&& klass->is_array_klass()) {
|
|
||||||
// The field is ArrayKlass::_component_mirror. Return its (constant) value.
|
|
||||||
// (Folds up aClassConstant.getComponentType, common in Arrays.copyOf.)
|
|
||||||
assert(Opcode() == Op_LoadP, "must load an oop from _component_mirror");
|
|
||||||
return TypeInstPtr::make(klass->as_array_klass()->component_mirror());
|
|
||||||
}
|
|
||||||
if (tkls->offset() == in_bytes(Klass::java_mirror_offset())) {
|
if (tkls->offset() == in_bytes(Klass::java_mirror_offset())) {
|
||||||
// The field is Klass::_java_mirror. Return its (constant) value.
|
// The field is Klass::_java_mirror. Return its (constant) value.
|
||||||
// (Folds up the 2nd indirection in anObjConstant.getClass().)
|
// (Folds up the 2nd indirection in anObjConstant.getClass().)
|
||||||
@ -2200,18 +2193,15 @@ Node* LoadNode::klass_identity_common(PhaseTransform *phase ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Simplify k.java_mirror.as_klass to plain k, where k is a Klass*.
|
// Simplify k.java_mirror.as_klass to plain k, where k is a Klass*.
|
||||||
// Simplify ak.component_mirror.array_klass to plain ak, ak an ArrayKlass.
|
|
||||||
// See inline_native_Class_query for occurrences of these patterns.
|
// See inline_native_Class_query for occurrences of these patterns.
|
||||||
// Java Example: x.getClass().isAssignableFrom(y)
|
// Java Example: x.getClass().isAssignableFrom(y)
|
||||||
// Java Example: Array.newInstance(x.getClass().getComponentType(), n)
|
|
||||||
//
|
//
|
||||||
// This improves reflective code, often making the Class
|
// This improves reflective code, often making the Class
|
||||||
// mirror go completely dead. (Current exception: Class
|
// mirror go completely dead. (Current exception: Class
|
||||||
// mirrors may appear in debug info, but we could clean them out by
|
// mirrors may appear in debug info, but we could clean them out by
|
||||||
// introducing a new debug info operator for Klass*.java_mirror).
|
// introducing a new debug info operator for Klass*.java_mirror).
|
||||||
if (toop->isa_instptr() && toop->klass() == phase->C->env()->Class_klass()
|
if (toop->isa_instptr() && toop->klass() == phase->C->env()->Class_klass()
|
||||||
&& (offset == java_lang_Class::klass_offset_in_bytes() ||
|
&& offset == java_lang_Class::klass_offset_in_bytes()) {
|
||||||
offset == java_lang_Class::array_klass_offset_in_bytes())) {
|
|
||||||
// We are loading a special hidden field from a Class mirror,
|
// We are loading a special hidden field from a Class mirror,
|
||||||
// the field which points to its Klass or ArrayKlass metaobject.
|
// the field which points to its Klass or ArrayKlass metaobject.
|
||||||
if (base->is_Load()) {
|
if (base->is_Load()) {
|
||||||
@ -2223,9 +2213,6 @@ Node* LoadNode::klass_identity_common(PhaseTransform *phase ) {
|
|||||||
&& adr2->is_AddP()
|
&& adr2->is_AddP()
|
||||||
) {
|
) {
|
||||||
int mirror_field = in_bytes(Klass::java_mirror_offset());
|
int mirror_field = in_bytes(Klass::java_mirror_offset());
|
||||||
if (offset == java_lang_Class::array_klass_offset_in_bytes()) {
|
|
||||||
mirror_field = in_bytes(ArrayKlass::component_mirror_offset());
|
|
||||||
}
|
|
||||||
if (tkls->offset() == mirror_field) {
|
if (tkls->offset() == mirror_field) {
|
||||||
return adr2->in(AddPNode::Base);
|
return adr2->in(AddPNode::Base);
|
||||||
}
|
}
|
||||||
@ -2799,9 +2786,10 @@ bool ClearArrayNode::step_through(Node** np, uint instance_id, PhaseTransform* p
|
|||||||
assert(n->is_ClearArray(), "sanity");
|
assert(n->is_ClearArray(), "sanity");
|
||||||
intptr_t offset;
|
intptr_t offset;
|
||||||
AllocateNode* alloc = AllocateNode::Ideal_allocation(n->in(3), phase, offset);
|
AllocateNode* alloc = AllocateNode::Ideal_allocation(n->in(3), phase, offset);
|
||||||
// This method is called only before Allocate nodes are expanded during
|
// This method is called only before Allocate nodes are expanded
|
||||||
// macro nodes expansion. Before that ClearArray nodes are only generated
|
// during macro nodes expansion. Before that ClearArray nodes are
|
||||||
// in LibraryCallKit::generate_arraycopy() which follows allocations.
|
// only generated in PhaseMacroExpand::generate_arraycopy() (before
|
||||||
|
// Allocate nodes are expanded) which follows allocations.
|
||||||
assert(alloc != NULL, "should have allocation");
|
assert(alloc != NULL, "should have allocation");
|
||||||
if (alloc->_idx == instance_id) {
|
if (alloc->_idx == instance_id) {
|
||||||
// Can not bypass initialization of the instance we are looking for.
|
// Can not bypass initialization of the instance we are looking for.
|
||||||
|
@ -42,10 +42,14 @@ NodeHash::NodeHash(uint est_max_size) :
|
|||||||
_max( round_up(est_max_size < NODE_HASH_MINIMUM_SIZE ? NODE_HASH_MINIMUM_SIZE : est_max_size) ),
|
_max( round_up(est_max_size < NODE_HASH_MINIMUM_SIZE ? NODE_HASH_MINIMUM_SIZE : est_max_size) ),
|
||||||
_a(Thread::current()->resource_area()),
|
_a(Thread::current()->resource_area()),
|
||||||
_table( NEW_ARENA_ARRAY( _a , Node* , _max ) ), // (Node**)_a->Amalloc(_max * sizeof(Node*)) ),
|
_table( NEW_ARENA_ARRAY( _a , Node* , _max ) ), // (Node**)_a->Amalloc(_max * sizeof(Node*)) ),
|
||||||
_inserts(0), _insert_limit( insert_limit() ),
|
_inserts(0), _insert_limit( insert_limit() )
|
||||||
_look_probes(0), _lookup_hits(0), _lookup_misses(0),
|
#ifndef PRODUCT
|
||||||
|
,_look_probes(0), _lookup_hits(0), _lookup_misses(0),
|
||||||
|
_delete_probes(0), _delete_hits(0), _delete_misses(0),
|
||||||
_total_insert_probes(0), _total_inserts(0),
|
_total_insert_probes(0), _total_inserts(0),
|
||||||
_insert_probes(0), _grows(0) {
|
_insert_probes(0), _grows(0)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
// _sentinel must be in the current node space
|
// _sentinel must be in the current node space
|
||||||
_sentinel = new ProjNode(NULL, TypeFunc::Control);
|
_sentinel = new ProjNode(NULL, TypeFunc::Control);
|
||||||
memset(_table,0,sizeof(Node*)*_max);
|
memset(_table,0,sizeof(Node*)*_max);
|
||||||
@ -56,11 +60,14 @@ NodeHash::NodeHash(Arena *arena, uint est_max_size) :
|
|||||||
_max( round_up(est_max_size < NODE_HASH_MINIMUM_SIZE ? NODE_HASH_MINIMUM_SIZE : est_max_size) ),
|
_max( round_up(est_max_size < NODE_HASH_MINIMUM_SIZE ? NODE_HASH_MINIMUM_SIZE : est_max_size) ),
|
||||||
_a(arena),
|
_a(arena),
|
||||||
_table( NEW_ARENA_ARRAY( _a , Node* , _max ) ),
|
_table( NEW_ARENA_ARRAY( _a , Node* , _max ) ),
|
||||||
_inserts(0), _insert_limit( insert_limit() ),
|
_inserts(0), _insert_limit( insert_limit() )
|
||||||
_look_probes(0), _lookup_hits(0), _lookup_misses(0),
|
#ifndef PRODUCT
|
||||||
|
,_look_probes(0), _lookup_hits(0), _lookup_misses(0),
|
||||||
_delete_probes(0), _delete_hits(0), _delete_misses(0),
|
_delete_probes(0), _delete_hits(0), _delete_misses(0),
|
||||||
_total_insert_probes(0), _total_inserts(0),
|
_total_insert_probes(0), _total_inserts(0),
|
||||||
_insert_probes(0), _grows(0) {
|
_insert_probes(0), _grows(0)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
// _sentinel must be in the current node space
|
// _sentinel must be in the current node space
|
||||||
_sentinel = new ProjNode(NULL, TypeFunc::Control);
|
_sentinel = new ProjNode(NULL, TypeFunc::Control);
|
||||||
memset(_table,0,sizeof(Node*)*_max);
|
memset(_table,0,sizeof(Node*)*_max);
|
||||||
@ -87,15 +94,15 @@ Node *NodeHash::hash_find( const Node *n ) {
|
|||||||
// ((Node*)n)->set_hash( n->hash() );
|
// ((Node*)n)->set_hash( n->hash() );
|
||||||
uint hash = n->hash();
|
uint hash = n->hash();
|
||||||
if (hash == Node::NO_HASH) {
|
if (hash == Node::NO_HASH) {
|
||||||
debug_only( _lookup_misses++ );
|
NOT_PRODUCT( _lookup_misses++ );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
uint key = hash & (_max-1);
|
uint key = hash & (_max-1);
|
||||||
uint stride = key | 0x01;
|
uint stride = key | 0x01;
|
||||||
debug_only( _look_probes++ );
|
NOT_PRODUCT( _look_probes++ );
|
||||||
Node *k = _table[key]; // Get hashed value
|
Node *k = _table[key]; // Get hashed value
|
||||||
if( !k ) { // ?Miss?
|
if( !k ) { // ?Miss?
|
||||||
debug_only( _lookup_misses++ );
|
NOT_PRODUCT( _lookup_misses++ );
|
||||||
return NULL; // Miss!
|
return NULL; // Miss!
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,16 +115,16 @@ Node *NodeHash::hash_find( const Node *n ) {
|
|||||||
if( n->in(i)!=k->in(i)) // Different inputs?
|
if( n->in(i)!=k->in(i)) // Different inputs?
|
||||||
goto collision; // "goto" is a speed hack...
|
goto collision; // "goto" is a speed hack...
|
||||||
if( n->cmp(*k) ) { // Check for any special bits
|
if( n->cmp(*k) ) { // Check for any special bits
|
||||||
debug_only( _lookup_hits++ );
|
NOT_PRODUCT( _lookup_hits++ );
|
||||||
return k; // Hit!
|
return k; // Hit!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
collision:
|
collision:
|
||||||
debug_only( _look_probes++ );
|
NOT_PRODUCT( _look_probes++ );
|
||||||
key = (key + stride/*7*/) & (_max-1); // Stride through table with relative prime
|
key = (key + stride/*7*/) & (_max-1); // Stride through table with relative prime
|
||||||
k = _table[key]; // Get hashed value
|
k = _table[key]; // Get hashed value
|
||||||
if( !k ) { // ?Miss?
|
if( !k ) { // ?Miss?
|
||||||
debug_only( _lookup_misses++ );
|
NOT_PRODUCT( _lookup_misses++ );
|
||||||
return NULL; // Miss!
|
return NULL; // Miss!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -132,16 +139,16 @@ Node *NodeHash::hash_find_insert( Node *n ) {
|
|||||||
// n->set_hash( );
|
// n->set_hash( );
|
||||||
uint hash = n->hash();
|
uint hash = n->hash();
|
||||||
if (hash == Node::NO_HASH) {
|
if (hash == Node::NO_HASH) {
|
||||||
debug_only( _lookup_misses++ );
|
NOT_PRODUCT( _lookup_misses++ );
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
uint key = hash & (_max-1);
|
uint key = hash & (_max-1);
|
||||||
uint stride = key | 0x01; // stride must be relatively prime to table siz
|
uint stride = key | 0x01; // stride must be relatively prime to table siz
|
||||||
uint first_sentinel = 0; // replace a sentinel if seen.
|
uint first_sentinel = 0; // replace a sentinel if seen.
|
||||||
debug_only( _look_probes++ );
|
NOT_PRODUCT( _look_probes++ );
|
||||||
Node *k = _table[key]; // Get hashed value
|
Node *k = _table[key]; // Get hashed value
|
||||||
if( !k ) { // ?Miss?
|
if( !k ) { // ?Miss?
|
||||||
debug_only( _lookup_misses++ );
|
NOT_PRODUCT( _lookup_misses++ );
|
||||||
_table[key] = n; // Insert into table!
|
_table[key] = n; // Insert into table!
|
||||||
debug_only(n->enter_hash_lock()); // Lock down the node while in the table.
|
debug_only(n->enter_hash_lock()); // Lock down the node while in the table.
|
||||||
check_grow(); // Grow table if insert hit limit
|
check_grow(); // Grow table if insert hit limit
|
||||||
@ -160,16 +167,16 @@ Node *NodeHash::hash_find_insert( Node *n ) {
|
|||||||
if( n->in(i)!=k->in(i)) // Different inputs?
|
if( n->in(i)!=k->in(i)) // Different inputs?
|
||||||
goto collision; // "goto" is a speed hack...
|
goto collision; // "goto" is a speed hack...
|
||||||
if( n->cmp(*k) ) { // Check for any special bits
|
if( n->cmp(*k) ) { // Check for any special bits
|
||||||
debug_only( _lookup_hits++ );
|
NOT_PRODUCT( _lookup_hits++ );
|
||||||
return k; // Hit!
|
return k; // Hit!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
collision:
|
collision:
|
||||||
debug_only( _look_probes++ );
|
NOT_PRODUCT( _look_probes++ );
|
||||||
key = (key + stride) & (_max-1); // Stride through table w/ relative prime
|
key = (key + stride) & (_max-1); // Stride through table w/ relative prime
|
||||||
k = _table[key]; // Get hashed value
|
k = _table[key]; // Get hashed value
|
||||||
if( !k ) { // ?Miss?
|
if( !k ) { // ?Miss?
|
||||||
debug_only( _lookup_misses++ );
|
NOT_PRODUCT( _lookup_misses++ );
|
||||||
key = (first_sentinel == 0) ? key : first_sentinel; // ?saw sentinel?
|
key = (first_sentinel == 0) ? key : first_sentinel; // ?saw sentinel?
|
||||||
_table[key] = n; // Insert into table!
|
_table[key] = n; // Insert into table!
|
||||||
debug_only(n->enter_hash_lock()); // Lock down the node while in the table.
|
debug_only(n->enter_hash_lock()); // Lock down the node while in the table.
|
||||||
@ -200,7 +207,7 @@ void NodeHash::hash_insert( Node *n ) {
|
|||||||
uint stride = key | 0x01;
|
uint stride = key | 0x01;
|
||||||
|
|
||||||
while( 1 ) { // While probing hash table
|
while( 1 ) { // While probing hash table
|
||||||
debug_only( _insert_probes++ );
|
NOT_PRODUCT( _insert_probes++ );
|
||||||
Node *k = _table[key]; // Get hashed value
|
Node *k = _table[key]; // Get hashed value
|
||||||
if( !k || (k == _sentinel) ) break; // Found a slot
|
if( !k || (k == _sentinel) ) break; // Found a slot
|
||||||
assert( k != n, "already inserted" );
|
assert( k != n, "already inserted" );
|
||||||
@ -218,7 +225,7 @@ bool NodeHash::hash_delete( const Node *n ) {
|
|||||||
Node *k;
|
Node *k;
|
||||||
uint hash = n->hash();
|
uint hash = n->hash();
|
||||||
if (hash == Node::NO_HASH) {
|
if (hash == Node::NO_HASH) {
|
||||||
debug_only( _delete_misses++ );
|
NOT_PRODUCT( _delete_misses++ );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint key = hash & (_max-1);
|
uint key = hash & (_max-1);
|
||||||
@ -226,10 +233,10 @@ bool NodeHash::hash_delete( const Node *n ) {
|
|||||||
debug_only( uint counter = 0; );
|
debug_only( uint counter = 0; );
|
||||||
for( ; /* (k != NULL) && (k != _sentinel) */; ) {
|
for( ; /* (k != NULL) && (k != _sentinel) */; ) {
|
||||||
debug_only( counter++ );
|
debug_only( counter++ );
|
||||||
debug_only( _delete_probes++ );
|
NOT_PRODUCT( _delete_probes++ );
|
||||||
k = _table[key]; // Get hashed value
|
k = _table[key]; // Get hashed value
|
||||||
if( !k ) { // Miss?
|
if( !k ) { // Miss?
|
||||||
debug_only( _delete_misses++ );
|
NOT_PRODUCT( _delete_misses++ );
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
if( VerifyOpto ) {
|
if( VerifyOpto ) {
|
||||||
for( uint i=0; i < _max; i++ )
|
for( uint i=0; i < _max; i++ )
|
||||||
@ -239,7 +246,7 @@ bool NodeHash::hash_delete( const Node *n ) {
|
|||||||
return false; // Miss! Not in chain
|
return false; // Miss! Not in chain
|
||||||
}
|
}
|
||||||
else if( n == k ) {
|
else if( n == k ) {
|
||||||
debug_only( _delete_hits++ );
|
NOT_PRODUCT( _delete_hits++ );
|
||||||
_table[key] = _sentinel; // Hit! Label as deleted entry
|
_table[key] = _sentinel; // Hit! Label as deleted entry
|
||||||
debug_only(((Node*)n)->exit_hash_lock()); // Unlock the node upon removal from table.
|
debug_only(((Node*)n)->exit_hash_lock()); // Unlock the node upon removal from table.
|
||||||
return true;
|
return true;
|
||||||
@ -271,11 +278,13 @@ void NodeHash::grow() {
|
|||||||
uint old_max = _max;
|
uint old_max = _max;
|
||||||
Node **old_table = _table;
|
Node **old_table = _table;
|
||||||
// Construct new table with twice the space
|
// Construct new table with twice the space
|
||||||
|
#ifndef PRODUCT
|
||||||
_grows++;
|
_grows++;
|
||||||
_total_inserts += _inserts;
|
_total_inserts += _inserts;
|
||||||
_total_insert_probes += _insert_probes;
|
_total_insert_probes += _insert_probes;
|
||||||
_inserts = 0;
|
|
||||||
_insert_probes = 0;
|
_insert_probes = 0;
|
||||||
|
#endif
|
||||||
|
_inserts = 0;
|
||||||
_max = _max << 1;
|
_max = _max << 1;
|
||||||
_table = NEW_ARENA_ARRAY( _a , Node* , _max ); // (Node**)_a->Amalloc( _max * sizeof(Node*) );
|
_table = NEW_ARENA_ARRAY( _a , Node* , _max ); // (Node**)_a->Amalloc( _max * sizeof(Node*) );
|
||||||
memset(_table,0,sizeof(Node*)*_max);
|
memset(_table,0,sizeof(Node*)*_max);
|
||||||
|
@ -100,7 +100,6 @@ public:
|
|||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
Node *find_index(uint idx); // For debugging
|
Node *find_index(uint idx); // For debugging
|
||||||
void dump(); // For debugging, dump statistics
|
void dump(); // For debugging, dump statistics
|
||||||
#endif
|
|
||||||
uint _grows; // For debugging, count of table grow()s
|
uint _grows; // For debugging, count of table grow()s
|
||||||
uint _look_probes; // For debugging, count of hash probes
|
uint _look_probes; // For debugging, count of hash probes
|
||||||
uint _lookup_hits; // For debugging, count of hash_finds
|
uint _lookup_hits; // For debugging, count of hash_finds
|
||||||
@ -111,6 +110,7 @@ public:
|
|||||||
uint _delete_misses; // For debugging, count of hash probes for deletes
|
uint _delete_misses; // For debugging, count of hash probes for deletes
|
||||||
uint _total_inserts; // For debugging, total inserts into hash table
|
uint _total_inserts; // For debugging, total inserts into hash table
|
||||||
uint _total_insert_probes; // For debugging, total probes while inserting
|
uint _total_insert_probes; // For debugging, total probes while inserting
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -922,6 +922,30 @@ const TypeFunc* OptoRuntime::digestBase_implCompressMB_Type() {
|
|||||||
return TypeFunc::make(domain, range);
|
return TypeFunc::make(domain, range);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TypeFunc* OptoRuntime::multiplyToLen_Type() {
|
||||||
|
// create input type (domain)
|
||||||
|
int num_args = 6;
|
||||||
|
int argcnt = num_args;
|
||||||
|
const Type** fields = TypeTuple::fields(argcnt);
|
||||||
|
int argp = TypeFunc::Parms;
|
||||||
|
fields[argp++] = TypePtr::NOTNULL; // x
|
||||||
|
fields[argp++] = TypeInt::INT; // xlen
|
||||||
|
fields[argp++] = TypePtr::NOTNULL; // y
|
||||||
|
fields[argp++] = TypeInt::INT; // ylen
|
||||||
|
fields[argp++] = TypePtr::NOTNULL; // z
|
||||||
|
fields[argp++] = TypeInt::INT; // zlen
|
||||||
|
assert(argp == TypeFunc::Parms+argcnt, "correct decoding");
|
||||||
|
const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+argcnt, fields);
|
||||||
|
|
||||||
|
// no result type needed
|
||||||
|
fields = TypeTuple::fields(1);
|
||||||
|
fields[TypeFunc::Parms+0] = NULL;
|
||||||
|
const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields);
|
||||||
|
return TypeFunc::make(domain, range);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//------------- Interpreter state access for on stack replacement
|
//------------- Interpreter state access for on stack replacement
|
||||||
const TypeFunc* OptoRuntime::osr_end_Type() {
|
const TypeFunc* OptoRuntime::osr_end_Type() {
|
||||||
// create input type (domain)
|
// create input type (domain)
|
||||||
|
@ -310,6 +310,8 @@ private:
|
|||||||
static const TypeFunc* sha_implCompress_Type();
|
static const TypeFunc* sha_implCompress_Type();
|
||||||
static const TypeFunc* digestBase_implCompressMB_Type();
|
static const TypeFunc* digestBase_implCompressMB_Type();
|
||||||
|
|
||||||
|
static const TypeFunc* multiplyToLen_Type();
|
||||||
|
|
||||||
static const TypeFunc* updateBytesCRC32_Type();
|
static const TypeFunc* updateBytesCRC32_Type();
|
||||||
|
|
||||||
// leaf on stack replacement interpreter accessor types
|
// leaf on stack replacement interpreter accessor types
|
||||||
|
@ -1403,14 +1403,6 @@ JVM_QUICK_ENTRY(jboolean, JVM_IsPrimitiveClass(JNIEnv *env, jclass cls))
|
|||||||
JVM_END
|
JVM_END
|
||||||
|
|
||||||
|
|
||||||
JVM_ENTRY(jclass, JVM_GetComponentType(JNIEnv *env, jclass cls))
|
|
||||||
JVMWrapper("JVM_GetComponentType");
|
|
||||||
oop mirror = JNIHandles::resolve_non_null(cls);
|
|
||||||
oop result = Reflection::array_component_type(mirror, CHECK_NULL);
|
|
||||||
return (jclass) JNIHandles::make_local(env, result);
|
|
||||||
JVM_END
|
|
||||||
|
|
||||||
|
|
||||||
JVM_ENTRY(jint, JVM_GetClassModifiers(JNIEnv *env, jclass cls))
|
JVM_ENTRY(jint, JVM_GetClassModifiers(JNIEnv *env, jclass cls))
|
||||||
JVMWrapper("JVM_GetClassModifiers");
|
JVMWrapper("JVM_GetClassModifiers");
|
||||||
if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(cls))) {
|
if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(cls))) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -483,9 +483,6 @@ JVM_IsArrayClass(JNIEnv *env, jclass cls);
|
|||||||
JNIEXPORT jboolean JNICALL
|
JNIEXPORT jboolean JNICALL
|
||||||
JVM_IsPrimitiveClass(JNIEnv *env, jclass cls);
|
JVM_IsPrimitiveClass(JNIEnv *env, jclass cls);
|
||||||
|
|
||||||
JNIEXPORT jclass JNICALL
|
|
||||||
JVM_GetComponentType(JNIEnv *env, jclass cls);
|
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL
|
JNIEXPORT jint JNICALL
|
||||||
JVM_GetClassModifiers(JNIEnv *env, jclass cls);
|
JVM_GetClassModifiers(JNIEnv *env, jclass cls);
|
||||||
|
|
||||||
|
@ -191,7 +191,8 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
|
|||||||
// It is not guaranteed that we can get such information here only
|
// It is not guaranteed that we can get such information here only
|
||||||
// by analyzing bytecode in deoptimized frames. This is why this flag
|
// by analyzing bytecode in deoptimized frames. This is why this flag
|
||||||
// is set during method compilation (see Compile::Process_OopMap_Node()).
|
// is set during method compilation (see Compile::Process_OopMap_Node()).
|
||||||
bool save_oop_result = chunk->at(0)->scope()->return_oop();
|
// If the previous frame was popped, we don't have a result.
|
||||||
|
bool save_oop_result = chunk->at(0)->scope()->return_oop() && !thread->popframe_forcing_deopt_reexecution();
|
||||||
Handle return_value;
|
Handle return_value;
|
||||||
if (save_oop_result) {
|
if (save_oop_result) {
|
||||||
// Reallocation may trigger GC. If deoptimization happened on return from
|
// Reallocation may trigger GC. If deoptimization happened on return from
|
||||||
|
@ -390,7 +390,7 @@ oop Reflection::array_component_type(oop mirror, TRAPS) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
oop result = ArrayKlass::cast(klass)->component_mirror();
|
oop result = java_lang_Class::component_mirror(mirror);
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
oop result2 = NULL;
|
oop result2 = NULL;
|
||||||
if (ArrayKlass::cast(klass)->dimension() == 1) {
|
if (ArrayKlass::cast(klass)->dimension() == 1) {
|
||||||
|
@ -135,6 +135,8 @@ address StubRoutines::_sha512_implCompressMB = NULL;
|
|||||||
address StubRoutines::_updateBytesCRC32 = NULL;
|
address StubRoutines::_updateBytesCRC32 = NULL;
|
||||||
address StubRoutines::_crc_table_adr = NULL;
|
address StubRoutines::_crc_table_adr = NULL;
|
||||||
|
|
||||||
|
address StubRoutines::_multiplyToLen = NULL;
|
||||||
|
|
||||||
double (* StubRoutines::_intrinsic_log )(double) = NULL;
|
double (* StubRoutines::_intrinsic_log )(double) = NULL;
|
||||||
double (* StubRoutines::_intrinsic_log10 )(double) = NULL;
|
double (* StubRoutines::_intrinsic_log10 )(double) = NULL;
|
||||||
double (* StubRoutines::_intrinsic_exp )(double) = NULL;
|
double (* StubRoutines::_intrinsic_exp )(double) = NULL;
|
||||||
|
@ -202,6 +202,8 @@ class StubRoutines: AllStatic {
|
|||||||
static address _updateBytesCRC32;
|
static address _updateBytesCRC32;
|
||||||
static address _crc_table_adr;
|
static address _crc_table_adr;
|
||||||
|
|
||||||
|
static address _multiplyToLen;
|
||||||
|
|
||||||
// These are versions of the java.lang.Math methods which perform
|
// These are versions of the java.lang.Math methods which perform
|
||||||
// the same operations as the intrinsic version. They are used for
|
// the same operations as the intrinsic version. They are used for
|
||||||
// constant folding in the compiler to ensure equivalence. If the
|
// constant folding in the compiler to ensure equivalence. If the
|
||||||
@ -358,6 +360,8 @@ class StubRoutines: AllStatic {
|
|||||||
static address updateBytesCRC32() { return _updateBytesCRC32; }
|
static address updateBytesCRC32() { return _updateBytesCRC32; }
|
||||||
static address crc_table_addr() { return _crc_table_adr; }
|
static address crc_table_addr() { return _crc_table_adr; }
|
||||||
|
|
||||||
|
static address multiplyToLen() {return _multiplyToLen; }
|
||||||
|
|
||||||
static address select_fill_function(BasicType t, bool aligned, const char* &name);
|
static address select_fill_function(BasicType t, bool aligned, const char* &name);
|
||||||
|
|
||||||
static address zero_aligned_words() { return _zero_aligned_words; }
|
static address zero_aligned_words() { return _zero_aligned_words; }
|
||||||
|
@ -274,7 +274,6 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
|
|||||||
volatile_nonstatic_field(ArrayKlass, _higher_dimension, Klass*) \
|
volatile_nonstatic_field(ArrayKlass, _higher_dimension, Klass*) \
|
||||||
volatile_nonstatic_field(ArrayKlass, _lower_dimension, Klass*) \
|
volatile_nonstatic_field(ArrayKlass, _lower_dimension, Klass*) \
|
||||||
nonstatic_field(ArrayKlass, _vtable_len, int) \
|
nonstatic_field(ArrayKlass, _vtable_len, int) \
|
||||||
nonstatic_field(ArrayKlass, _component_mirror, oop) \
|
|
||||||
nonstatic_field(CompiledICHolder, _holder_method, Method*) \
|
nonstatic_field(CompiledICHolder, _holder_method, Method*) \
|
||||||
nonstatic_field(CompiledICHolder, _holder_klass, Klass*) \
|
nonstatic_field(CompiledICHolder, _holder_klass, Klass*) \
|
||||||
nonstatic_field(ConstantPool, _tags, Array<u1>*) \
|
nonstatic_field(ConstantPool, _tags, Array<u1>*) \
|
||||||
@ -811,6 +810,7 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
|
|||||||
static_field(StubRoutines, _cipherBlockChaining_decryptAESCrypt, address) \
|
static_field(StubRoutines, _cipherBlockChaining_decryptAESCrypt, address) \
|
||||||
static_field(StubRoutines, _updateBytesCRC32, address) \
|
static_field(StubRoutines, _updateBytesCRC32, address) \
|
||||||
static_field(StubRoutines, _crc_table_adr, address) \
|
static_field(StubRoutines, _crc_table_adr, address) \
|
||||||
|
static_field(StubRoutines, _multiplyToLen, address) \
|
||||||
\
|
\
|
||||||
/*****************/ \
|
/*****************/ \
|
||||||
/* SharedRuntime */ \
|
/* SharedRuntime */ \
|
||||||
|
@ -37,21 +37,22 @@
|
|||||||
#include "utilities/numberSeq.hpp"
|
#include "utilities/numberSeq.hpp"
|
||||||
|
|
||||||
|
|
||||||
// This is a generic hashtable, designed to be used for the symbol
|
// This hashtable is implemented as an open hash table with a fixed number of buckets.
|
||||||
// and string tables.
|
|
||||||
//
|
|
||||||
// It is implemented as an open hash table with a fixed number of buckets.
|
|
||||||
//
|
|
||||||
// %note:
|
|
||||||
// - HashtableEntrys are allocated in blocks to reduce the space overhead.
|
|
||||||
|
|
||||||
template <MEMFLAGS F> BasicHashtableEntry<F>* BasicHashtable<F>::new_entry(unsigned int hashValue) {
|
template <MEMFLAGS F> BasicHashtableEntry<F>* BasicHashtable<F>::new_entry_free_list() {
|
||||||
BasicHashtableEntry<F>* entry;
|
BasicHashtableEntry<F>* entry = NULL;
|
||||||
|
if (_free_list != NULL) {
|
||||||
if (_free_list) {
|
|
||||||
entry = _free_list;
|
entry = _free_list;
|
||||||
_free_list = _free_list->next();
|
_free_list = _free_list->next();
|
||||||
} else {
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// HashtableEntrys are allocated in blocks to reduce the space overhead.
|
||||||
|
template <MEMFLAGS F> BasicHashtableEntry<F>* BasicHashtable<F>::new_entry(unsigned int hashValue) {
|
||||||
|
BasicHashtableEntry<F>* entry = new_entry_free_list();
|
||||||
|
|
||||||
|
if (entry == NULL) {
|
||||||
if (_first_free_entry + _entry_size >= _end_block) {
|
if (_first_free_entry + _entry_size >= _end_block) {
|
||||||
int block_size = MIN2(512, MAX2((int)_table_size / 2, (int)_number_of_entries));
|
int block_size = MIN2(512, MAX2((int)_table_size / 2, (int)_number_of_entries));
|
||||||
int len = _entry_size * block_size;
|
int len = _entry_size * block_size;
|
||||||
@ -84,9 +85,9 @@ template <class T, MEMFLAGS F> HashtableEntry<T, F>* Hashtable<T, F>::new_entry(
|
|||||||
// This is somewhat an arbitrary heuristic but if one bucket gets to
|
// This is somewhat an arbitrary heuristic but if one bucket gets to
|
||||||
// rehash_count which is currently 100, there's probably something wrong.
|
// rehash_count which is currently 100, there's probably something wrong.
|
||||||
|
|
||||||
template <MEMFLAGS F> bool BasicHashtable<F>::check_rehash_table(int count) {
|
template <class T, MEMFLAGS F> bool RehashableHashtable<T, F>::check_rehash_table(int count) {
|
||||||
assert(table_size() != 0, "underflow");
|
assert(this->table_size() != 0, "underflow");
|
||||||
if (count > (((double)number_of_entries()/(double)table_size())*rehash_multiple)) {
|
if (count > (((double)this->number_of_entries()/(double)this->table_size())*rehash_multiple)) {
|
||||||
// Set a flag for the next safepoint, which should be at some guaranteed
|
// Set a flag for the next safepoint, which should be at some guaranteed
|
||||||
// safepoint interval.
|
// safepoint interval.
|
||||||
return true;
|
return true;
|
||||||
@ -94,13 +95,13 @@ template <MEMFLAGS F> bool BasicHashtable<F>::check_rehash_table(int count) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, MEMFLAGS F> juint Hashtable<T, F>::_seed = 0;
|
template <class T, MEMFLAGS F> juint RehashableHashtable<T, F>::_seed = 0;
|
||||||
|
|
||||||
// Create a new table and using alternate hash code, populate the new table
|
// Create a new table and using alternate hash code, populate the new table
|
||||||
// with the existing elements. This can be used to change the hash code
|
// with the existing elements. This can be used to change the hash code
|
||||||
// and could in the future change the size of the table.
|
// and could in the future change the size of the table.
|
||||||
|
|
||||||
template <class T, MEMFLAGS F> void Hashtable<T, F>::move_to(Hashtable<T, F>* new_table) {
|
template <class T, MEMFLAGS F> void RehashableHashtable<T, F>::move_to(RehashableHashtable<T, F>* new_table) {
|
||||||
|
|
||||||
// Initialize the global seed for hashing.
|
// Initialize the global seed for hashing.
|
||||||
_seed = AltHashing::compute_seed();
|
_seed = AltHashing::compute_seed();
|
||||||
@ -110,7 +111,7 @@ template <class T, MEMFLAGS F> void Hashtable<T, F>::move_to(Hashtable<T, F>* ne
|
|||||||
|
|
||||||
// Iterate through the table and create a new entry for the new table
|
// Iterate through the table and create a new entry for the new table
|
||||||
for (int i = 0; i < new_table->table_size(); ++i) {
|
for (int i = 0; i < new_table->table_size(); ++i) {
|
||||||
for (HashtableEntry<T, F>* p = bucket(i); p != NULL; ) {
|
for (HashtableEntry<T, F>* p = this->bucket(i); p != NULL; ) {
|
||||||
HashtableEntry<T, F>* next = p->next();
|
HashtableEntry<T, F>* next = p->next();
|
||||||
T string = p->literal();
|
T string = p->literal();
|
||||||
// Use alternate hashing algorithm on the symbol in the first table
|
// Use alternate hashing algorithm on the symbol in the first table
|
||||||
@ -239,11 +240,11 @@ template <class T, MEMFLAGS F> void Hashtable<T, F>::reverse(void* boundary) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, MEMFLAGS F> int Hashtable<T, F>::literal_size(Symbol *symbol) {
|
template <class T, MEMFLAGS F> int RehashableHashtable<T, F>::literal_size(Symbol *symbol) {
|
||||||
return symbol->size() * HeapWordSize;
|
return symbol->size() * HeapWordSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class T, MEMFLAGS F> int Hashtable<T, F>::literal_size(oop oop) {
|
template <class T, MEMFLAGS F> int RehashableHashtable<T, F>::literal_size(oop oop) {
|
||||||
// NOTE: this would over-count if (pre-JDK8) java_lang_Class::has_offset_field() is true,
|
// NOTE: this would over-count if (pre-JDK8) java_lang_Class::has_offset_field() is true,
|
||||||
// and the String.value array is shared by several Strings. However, starting from JDK8,
|
// and the String.value array is shared by several Strings. However, starting from JDK8,
|
||||||
// the String.value array is not shared anymore.
|
// the String.value array is not shared anymore.
|
||||||
@ -256,12 +257,12 @@ template <class T, MEMFLAGS F> int Hashtable<T, F>::literal_size(oop oop) {
|
|||||||
// Note: if you create a new subclass of Hashtable<MyNewType, F>, you will need to
|
// Note: if you create a new subclass of Hashtable<MyNewType, F>, you will need to
|
||||||
// add a new function Hashtable<T, F>::literal_size(MyNewType lit)
|
// add a new function Hashtable<T, F>::literal_size(MyNewType lit)
|
||||||
|
|
||||||
template <class T, MEMFLAGS F> void Hashtable<T, F>::dump_table(outputStream* st, const char *table_name) {
|
template <class T, MEMFLAGS F> void RehashableHashtable<T, F>::dump_table(outputStream* st, const char *table_name) {
|
||||||
NumberSeq summary;
|
NumberSeq summary;
|
||||||
int literal_bytes = 0;
|
int literal_bytes = 0;
|
||||||
for (int i = 0; i < this->table_size(); ++i) {
|
for (int i = 0; i < this->table_size(); ++i) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (HashtableEntry<T, F>* e = bucket(i);
|
for (HashtableEntry<T, F>* e = this->bucket(i);
|
||||||
e != NULL; e = e->next()) {
|
e != NULL; e = e->next()) {
|
||||||
count++;
|
count++;
|
||||||
literal_bytes += literal_size(e->literal());
|
literal_bytes += literal_size(e->literal());
|
||||||
@ -271,7 +272,7 @@ template <class T, MEMFLAGS F> void Hashtable<T, F>::dump_table(outputStream* st
|
|||||||
double num_buckets = summary.num();
|
double num_buckets = summary.num();
|
||||||
double num_entries = summary.sum();
|
double num_entries = summary.sum();
|
||||||
|
|
||||||
int bucket_bytes = (int)num_buckets * sizeof(bucket(0));
|
int bucket_bytes = (int)num_buckets * sizeof(HashtableBucket<F>);
|
||||||
int entry_bytes = (int)num_entries * sizeof(HashtableEntry<T, F>);
|
int entry_bytes = (int)num_entries * sizeof(HashtableEntry<T, F>);
|
||||||
int total_bytes = literal_bytes + bucket_bytes + entry_bytes;
|
int total_bytes = literal_bytes + bucket_bytes + entry_bytes;
|
||||||
|
|
||||||
@ -354,12 +355,20 @@ template <MEMFLAGS F> void BasicHashtable<F>::verify_lookup_length(double load)
|
|||||||
|
|
||||||
|
|
||||||
// Explicitly instantiate these types
|
// Explicitly instantiate these types
|
||||||
|
#if INCLUDE_ALL_GCS
|
||||||
|
template class Hashtable<nmethod*, mtGC>;
|
||||||
|
template class HashtableEntry<nmethod*, mtGC>;
|
||||||
|
template class BasicHashtable<mtGC>;
|
||||||
|
#endif
|
||||||
template class Hashtable<ConstantPool*, mtClass>;
|
template class Hashtable<ConstantPool*, mtClass>;
|
||||||
|
template class RehashableHashtable<Symbol*, mtSymbol>;
|
||||||
|
template class RehashableHashtable<oopDesc*, mtSymbol>;
|
||||||
template class Hashtable<Symbol*, mtSymbol>;
|
template class Hashtable<Symbol*, mtSymbol>;
|
||||||
template class Hashtable<Klass*, mtClass>;
|
template class Hashtable<Klass*, mtClass>;
|
||||||
template class Hashtable<oop, mtClass>;
|
template class Hashtable<oop, mtClass>;
|
||||||
#if defined(SOLARIS) || defined(CHECK_UNHANDLED_OOPS)
|
#if defined(SOLARIS) || defined(CHECK_UNHANDLED_OOPS)
|
||||||
template class Hashtable<oop, mtSymbol>;
|
template class Hashtable<oop, mtSymbol>;
|
||||||
|
template class RehashableHashtable<oop, mtSymbol>;
|
||||||
#endif // SOLARIS || CHECK_UNHANDLED_OOPS
|
#endif // SOLARIS || CHECK_UNHANDLED_OOPS
|
||||||
template class Hashtable<oopDesc*, mtSymbol>;
|
template class Hashtable<oopDesc*, mtSymbol>;
|
||||||
template class Hashtable<Symbol*, mtClass>;
|
template class Hashtable<Symbol*, mtClass>;
|
||||||
|
@ -178,11 +178,6 @@ protected:
|
|||||||
void verify_lookup_length(double load);
|
void verify_lookup_length(double load);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
enum {
|
|
||||||
rehash_count = 100,
|
|
||||||
rehash_multiple = 60
|
|
||||||
};
|
|
||||||
|
|
||||||
void initialize(int table_size, int entry_size, int number_of_entries);
|
void initialize(int table_size, int entry_size, int number_of_entries);
|
||||||
|
|
||||||
// Accessor
|
// Accessor
|
||||||
@ -194,12 +189,12 @@ protected:
|
|||||||
// The following method is not MT-safe and must be done under lock.
|
// The following method is not MT-safe and must be done under lock.
|
||||||
BasicHashtableEntry<F>** bucket_addr(int i) { return _buckets[i].entry_addr(); }
|
BasicHashtableEntry<F>** bucket_addr(int i) { return _buckets[i].entry_addr(); }
|
||||||
|
|
||||||
|
// Attempt to get an entry from the free list
|
||||||
|
BasicHashtableEntry<F>* new_entry_free_list();
|
||||||
|
|
||||||
// Table entry management
|
// Table entry management
|
||||||
BasicHashtableEntry<F>* new_entry(unsigned int hashValue);
|
BasicHashtableEntry<F>* new_entry(unsigned int hashValue);
|
||||||
|
|
||||||
// Check that the table is unbalanced
|
|
||||||
bool check_rehash_table(int count);
|
|
||||||
|
|
||||||
// Used when moving the entry to another table
|
// Used when moving the entry to another table
|
||||||
// Clean up links, but do not add to free_list
|
// Clean up links, but do not add to free_list
|
||||||
void unlink_entry(BasicHashtableEntry<F>* entry) {
|
void unlink_entry(BasicHashtableEntry<F>* entry) {
|
||||||
@ -277,8 +272,30 @@ protected:
|
|||||||
return (HashtableEntry<T, F>**)BasicHashtable<F>::bucket_addr(i);
|
return (HashtableEntry<T, F>**)BasicHashtable<F>::bucket_addr(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T, MEMFLAGS F> class RehashableHashtable : public Hashtable<T, F> {
|
||||||
|
protected:
|
||||||
|
|
||||||
|
enum {
|
||||||
|
rehash_count = 100,
|
||||||
|
rehash_multiple = 60
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check that the table is unbalanced
|
||||||
|
bool check_rehash_table(int count);
|
||||||
|
|
||||||
|
public:
|
||||||
|
RehashableHashtable(int table_size, int entry_size)
|
||||||
|
: Hashtable<T, F>(table_size, entry_size) { }
|
||||||
|
|
||||||
|
RehashableHashtable(int table_size, int entry_size,
|
||||||
|
HashtableBucket<F>* buckets, int number_of_entries)
|
||||||
|
: Hashtable<T, F>(table_size, entry_size, buckets, number_of_entries) { }
|
||||||
|
|
||||||
|
|
||||||
// Function to move these elements into the new table.
|
// Function to move these elements into the new table.
|
||||||
void move_to(Hashtable<T, F>* new_table);
|
void move_to(RehashableHashtable<T, F>* new_table);
|
||||||
static bool use_alternate_hashcode() { return _seed != 0; }
|
static bool use_alternate_hashcode() { return _seed != 0; }
|
||||||
static juint seed() { return _seed; }
|
static juint seed() { return _seed; }
|
||||||
|
|
||||||
@ -292,7 +309,6 @@ protected:
|
|||||||
static int literal_size(ConstantPool *cp) {Unimplemented(); return 0;}
|
static int literal_size(ConstantPool *cp) {Unimplemented(); return 0;}
|
||||||
static int literal_size(Klass *k) {Unimplemented(); return 0;}
|
static int literal_size(Klass *k) {Unimplemented(); return 0;}
|
||||||
|
|
||||||
public:
|
|
||||||
void dump_table(outputStream* st, const char *table_name);
|
void dump_table(outputStream* st, const char *table_name);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
63
hotspot/test/compiler/arraycopy/TestArrayOfNoTypeCheck.java
Normal file
63
hotspot/test/compiler/arraycopy/TestArrayOfNoTypeCheck.java
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8055910
|
||||||
|
* @summary Arrays.copyOf doesn't perform subtype check
|
||||||
|
* @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement TestArrayOfNoTypeCheck
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public class TestArrayOfNoTypeCheck {
|
||||||
|
|
||||||
|
static class A {
|
||||||
|
}
|
||||||
|
|
||||||
|
static class B extends A {
|
||||||
|
}
|
||||||
|
|
||||||
|
static B[] test(A[] arr) {
|
||||||
|
return Arrays.copyOf(arr, 10, B[].class);
|
||||||
|
}
|
||||||
|
|
||||||
|
static public void main(String[] args) {
|
||||||
|
A[] arr = new A[20];
|
||||||
|
for (int i = 0; i < 20000; i++) {
|
||||||
|
test(arr);
|
||||||
|
}
|
||||||
|
A[] arr2 = new A[20];
|
||||||
|
arr2[0] = new A();
|
||||||
|
boolean exception = false;
|
||||||
|
try {
|
||||||
|
test(arr2);
|
||||||
|
} catch (ArrayStoreException ase) {
|
||||||
|
exception = true;
|
||||||
|
}
|
||||||
|
if (!exception) {
|
||||||
|
throw new RuntimeException("TEST FAILED: ArrayStoreException not thrown");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,7 @@
|
|||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @library /testlibrary /testlibrary/whitebox /compiler/whitebox
|
* @library /testlibrary /testlibrary/whitebox /compiler/whitebox
|
||||||
|
* /compiler/testlibrary
|
||||||
* @build AddExactIntTest
|
* @build AddExactIntTest
|
||||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||||
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||||
@ -35,7 +36,7 @@
|
|||||||
* -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation
|
||||||
* -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod
|
* -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod
|
||||||
* -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics AddExactIntTest
|
* -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics AddExactIntTest
|
||||||
* @run main Verifier hs_neg.log hs.log
|
* @run main intrinsics.Verifier hs_neg.log hs.log
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class AddExactIntTest {
|
public class AddExactIntTest {
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
/*
|
/*
|
||||||
* @test
|
* @test
|
||||||
* @library /testlibrary /testlibrary/whitebox /compiler/whitebox
|
* @library /testlibrary /testlibrary/whitebox /compiler/whitebox
|
||||||
|
* /compiler/testlibrary
|
||||||
* @build AddExactLongTest
|
* @build AddExactLongTest
|
||||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||||
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||||
@ -35,7 +36,7 @@
|
|||||||
* -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation
|
* -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation
|
||||||
* -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod
|
* -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod
|
||||||
* -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics AddExactLongTest
|
* -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics AddExactLongTest
|
||||||
* @run main Verifier hs_neg.log hs.log
|
* @run main intrinsics.Verifier hs_neg.log hs.log
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class AddExactLongTest {
|
public class AddExactLongTest {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user