Merge
This commit is contained in:
commit
568874f545
1
.hgtags
1
.hgtags
@ -481,3 +481,4 @@ f7363de371c9a1f668bd0a01b7df3d1ddb9cc58b jdk-11+7
|
|||||||
755e1b55a4dff510f9639cdb5c5e82549a7e09b3 jdk-11+8
|
755e1b55a4dff510f9639cdb5c5e82549a7e09b3 jdk-11+8
|
||||||
0c3e252cea44f06aef570ef464950ab97c669970 jdk-11+9
|
0c3e252cea44f06aef570ef464950ab97c669970 jdk-11+9
|
||||||
6fa770f9f8ab296e1ce255ec17ccf6d4e1051886 jdk-10+46
|
6fa770f9f8ab296e1ce255ec17ccf6d4e1051886 jdk-10+46
|
||||||
|
69d7398038c54774d9395b6810e0cca335edc02c jdk-11+10
|
||||||
|
@ -310,9 +310,13 @@ else # HAS_SPEC=true
|
|||||||
ifneq ($(PARALLEL_TARGETS), )
|
ifneq ($(PARALLEL_TARGETS), )
|
||||||
$(call StartGlobalTimer)
|
$(call StartGlobalTimer)
|
||||||
$(call PrepareSmartJavac)
|
$(call PrepareSmartJavac)
|
||||||
|
# JOBS will only be empty for a bootcycle-images recursive call
|
||||||
|
# or if specified via a make argument directly. In those cases
|
||||||
|
# treat it as NOT using jobs at all.
|
||||||
( cd $(TOPDIR) && \
|
( cd $(TOPDIR) && \
|
||||||
$(NICE) $(MAKE) $(MAKE_ARGS) $(OUTPUT_SYNC_FLAG) \
|
$(NICE) $(MAKE) $(MAKE_ARGS) $(OUTPUT_SYNC_FLAG) \
|
||||||
-j $(JOBS) -f make/Main.gmk $(USER_MAKE_VARS) \
|
$(if $(JOBS), -j $(JOBS)) \
|
||||||
|
-f make/Main.gmk $(USER_MAKE_VARS) \
|
||||||
$(PARALLEL_TARGETS) $(COMPARE_BUILD_MAKE) $(BUILD_LOG_PIPE) || \
|
$(PARALLEL_TARGETS) $(COMPARE_BUILD_MAKE) $(BUILD_LOG_PIPE) || \
|
||||||
( exitcode=$$? && \
|
( exitcode=$$? && \
|
||||||
$(PRINTF) "\nERROR: Build failed for $(TARGET_DESCRIPTION) (exit code $$exitcode) \n" \
|
$(PRINTF) "\nERROR: Build failed for $(TARGET_DESCRIPTION) (exit code $$exitcode) \n" \
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#
|
#
|
||||||
# Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
# Copyright (c) 2000, 2018, 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
|
||||||
@ -326,6 +326,8 @@ charset windows-1252 MS1252
|
|||||||
ascii true
|
ascii true
|
||||||
alias cp1252 # JDK historical
|
alias cp1252 # JDK historical
|
||||||
alias cp5348 # Euro IBM CCSID
|
alias cp5348 # Euro IBM CCSID
|
||||||
|
alias ibm-1252
|
||||||
|
alias ibm1252
|
||||||
|
|
||||||
charset windows-1253 MS1253
|
charset windows-1253 MS1253
|
||||||
package sun.nio.cs
|
package sun.nio.cs
|
||||||
@ -933,11 +935,16 @@ charset x-IBM942 IBM942 # IBM & PC/MSDOS encodings
|
|||||||
|
|
||||||
charset x-IBM942C IBM942C
|
charset x-IBM942C IBM942C
|
||||||
package sun.nio.cs.ext
|
package sun.nio.cs.ext
|
||||||
type source
|
type template
|
||||||
alias cp942C # JDK historical
|
alias cp942C # JDK historical
|
||||||
alias ibm942C
|
alias ibm942C
|
||||||
alias ibm-942C
|
alias ibm-942C
|
||||||
alias 942C
|
alias 942C
|
||||||
|
alias cp932
|
||||||
|
alias ibm932
|
||||||
|
alias ibm-932
|
||||||
|
alias 932
|
||||||
|
alias x-ibm932
|
||||||
|
|
||||||
charset x-IBM943 IBM943
|
charset x-IBM943 IBM943
|
||||||
package sun.nio.cs.ext
|
package sun.nio.cs.ext
|
||||||
@ -952,7 +959,7 @@ charset x-IBM943 IBM943
|
|||||||
|
|
||||||
charset x-IBM943C IBM943C
|
charset x-IBM943C IBM943C
|
||||||
package sun.nio.cs.ext
|
package sun.nio.cs.ext
|
||||||
type source
|
type template
|
||||||
alias cp943C # JDK historical
|
alias cp943C # JDK historical
|
||||||
alias ibm943C
|
alias ibm943C
|
||||||
alias ibm-943C
|
alias ibm-943C
|
||||||
@ -1519,6 +1526,9 @@ charset x-IBM1383 IBM1383
|
|||||||
alias ibm1383
|
alias ibm1383
|
||||||
alias ibm-1383
|
alias ibm-1383
|
||||||
alias 1383
|
alias 1383
|
||||||
|
alias ibmeuccn
|
||||||
|
alias ibm-euccn
|
||||||
|
alias cpeuccn
|
||||||
|
|
||||||
charset x-IBM970 IBM970
|
charset x-IBM970 IBM970
|
||||||
package sun.nio.cs.ext
|
package sun.nio.cs.ext
|
||||||
|
@ -1,6 +1,26 @@
|
|||||||
#
|
#
|
||||||
# generate these charsets into sun.nio.cs
|
# generate these charsets into sun.nio.cs
|
||||||
#
|
#
|
||||||
|
Big5
|
||||||
|
Big5_Solaris
|
||||||
|
Big5_HKSCS
|
||||||
EUC_CN
|
EUC_CN
|
||||||
EUC_KR
|
EUC_KR
|
||||||
GBK
|
GBK
|
||||||
|
GB18030
|
||||||
|
IBM856
|
||||||
|
IBM921
|
||||||
|
IBM922
|
||||||
|
IBM942
|
||||||
|
IBM942C
|
||||||
|
IBM943
|
||||||
|
IBM943C
|
||||||
|
IBM950
|
||||||
|
IBM970
|
||||||
|
IBM1046
|
||||||
|
IBM1124
|
||||||
|
IBM1383
|
||||||
|
ISO_8859_6
|
||||||
|
ISO_8859_8
|
||||||
|
MS1252
|
||||||
|
TIS_620
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -129,7 +129,7 @@ public class SPI {
|
|||||||
} else if (line.indexOf("_INCLUDE_ALIASES_MAP_") != -1) {
|
} else if (line.indexOf("_INCLUDE_ALIASES_MAP_") != -1) {
|
||||||
Hasher.genClass(out, aliasKeys, aliasValues,
|
Hasher.genClass(out, aliasKeys, aliasValues,
|
||||||
null, "Aliases", "String",
|
null, "Aliases", "String",
|
||||||
11, 3, true, false, false);
|
12, 3, true, false, false);
|
||||||
} else if (line.indexOf("_INCLUDE_CLASSES_MAP_") != -1) {
|
} else if (line.indexOf("_INCLUDE_CLASSES_MAP_") != -1) {
|
||||||
Hasher.genClass(out, clzKeys, clzValues,
|
Hasher.genClass(out, clzKeys, clzValues,
|
||||||
null, "Classes", "String",
|
null, "Classes", "String",
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2014, 2018, 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
|
||||||
@ -86,13 +86,17 @@ public interface MessageType {
|
|||||||
NAME("name", "Name", "com.sun.tools.javac.util"),
|
NAME("name", "Name", "com.sun.tools.javac.util"),
|
||||||
NUMBER("number", "int", null),
|
NUMBER("number", "int", null),
|
||||||
OPTION_NAME("option name", "Option", "com.sun.tools.javac.main"),
|
OPTION_NAME("option name", "Option", "com.sun.tools.javac.main"),
|
||||||
|
PROFILE("profile", "Profile", "com.sun.tools.javac.jvm"),
|
||||||
|
SOURCE("source", "Source", "com.sun.tools.javac.code"),
|
||||||
SOURCE_VERSION("source version", "SourceVersion", "javax.lang.model"),
|
SOURCE_VERSION("source version", "SourceVersion", "javax.lang.model"),
|
||||||
STRING("string", "String", null),
|
STRING("string", "String", null),
|
||||||
SYMBOL("symbol", "Symbol", "com.sun.tools.javac.code"),
|
SYMBOL("symbol", "Symbol", "com.sun.tools.javac.code"),
|
||||||
SYMBOL_KIND("symbol kind", "Kind", "com.sun.tools.javac.code.Kinds"),
|
SYMBOL_KIND("symbol kind", "Kind", "com.sun.tools.javac.code.Kinds"),
|
||||||
KIND_NAME("kind name", "KindName", "com.sun.tools.javac.code.Kinds"),
|
KIND_NAME("kind name", "KindName", "com.sun.tools.javac.code.Kinds"),
|
||||||
|
TARGET("target", "Target", "com.sun.tools.javac.jvm"),
|
||||||
TOKEN("token", "TokenKind", "com.sun.tools.javac.parser.Tokens"),
|
TOKEN("token", "TokenKind", "com.sun.tools.javac.parser.Tokens"),
|
||||||
TYPE("type", "Type", "com.sun.tools.javac.code"),
|
TYPE("type", "Type", "com.sun.tools.javac.code"),
|
||||||
|
URL("url", "URL", "java.net"),
|
||||||
SET("set", "Set", "java.util"),
|
SET("set", "Set", "java.util"),
|
||||||
LIST("list", "List", "java.util"),
|
LIST("list", "List", "java.util"),
|
||||||
OBJECT("object", "Object", null),
|
OBJECT("object", "Object", null),
|
||||||
|
@ -224,7 +224,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBAWT, \
|
|||||||
format-nonliteral parentheses, \
|
format-nonliteral parentheses, \
|
||||||
DISABLED_WARNINGS_clang := logical-op-parentheses extern-initializer, \
|
DISABLED_WARNINGS_clang := logical-op-parentheses extern-initializer, \
|
||||||
DISABLED_WARNINGS_solstudio := E_DECLARATION_IN_CODE, \
|
DISABLED_WARNINGS_solstudio := E_DECLARATION_IN_CODE, \
|
||||||
DISABLED_WARNINGS_microsoft := 4297 4244 4267 4996, \
|
DISABLED_WARNINGS_microsoft := 4297 4244 4267 4291 4302 4311 4996, \
|
||||||
ASFLAGS := $(LIBAWT_ASFLAGS), \
|
ASFLAGS := $(LIBAWT_ASFLAGS), \
|
||||||
LDFLAGS := $(LDFLAGS_JDKLIB) $(call SET_SHARED_LIBRARY_ORIGIN), \
|
LDFLAGS := $(LDFLAGS_JDKLIB) $(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||||
LDFLAGS_macosx := -L$(INSTALL_LIBRARIES_HERE), \
|
LDFLAGS_macosx := -L$(INSTALL_LIBRARIES_HERE), \
|
||||||
|
@ -44,12 +44,6 @@ void ModRefBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Decorat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ModRefBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
|
||||||
Address dst, Register val, Register tmp1, Register tmp2) {
|
|
||||||
BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||||
Address dst, Register val, Register tmp1, Register tmp2) {
|
Address dst, Register val, Register tmp1, Register tmp2) {
|
||||||
if (type == T_OBJECT || type == T_ARRAY) {
|
if (type == T_OBJECT || type == T_ARRAY) {
|
||||||
|
@ -40,7 +40,7 @@ protected:
|
|||||||
Register start, Register end, Register tmp, RegSet saved_regs) {}
|
Register start, Register end, Register tmp, RegSet saved_regs) {}
|
||||||
|
|
||||||
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||||
Address dst, Register val, Register tmp1, Register tmp2);
|
Address dst, Register val, Register tmp1, Register tmp2) = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
|
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
|
||||||
|
@ -56,12 +56,6 @@ void ModRefBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Decorat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModRefBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
|
||||||
Register base, RegisterOrConstant ind_or_offs, Register val,
|
|
||||||
Register tmp1, Register tmp2, Register tmp3, bool needs_frame) {
|
|
||||||
BarrierSetAssembler::store_at(masm, decorators, type, base, ind_or_offs, val, tmp1, tmp2, tmp3, needs_frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||||
Register base, RegisterOrConstant ind_or_offs, Register val,
|
Register base, RegisterOrConstant ind_or_offs, Register val,
|
||||||
Register tmp1, Register tmp2, Register tmp3, bool needs_frame) {
|
Register tmp1, Register tmp2, Register tmp3, bool needs_frame) {
|
||||||
|
@ -41,7 +41,7 @@ protected:
|
|||||||
|
|
||||||
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||||
Register base, RegisterOrConstant ind_or_offs, Register val,
|
Register base, RegisterOrConstant ind_or_offs, Register val,
|
||||||
Register tmp1, Register tmp2, Register tmp3, bool needs_frame);
|
Register tmp1, Register tmp2, Register tmp3, bool needs_frame) = 0;
|
||||||
public:
|
public:
|
||||||
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||||
Register src, Register dst, Register count, Register preserve1, Register preserve2);
|
Register src, Register dst, Register count, Register preserve1, Register preserve2);
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "asm/macroAssembler.inline.hpp"
|
||||||
#include "gc/shared/barrierSetAssembler.hpp"
|
#include "gc/shared/barrierSetAssembler.hpp"
|
||||||
#include "interpreter/interp_masm.hpp"
|
#include "interpreter/interp_masm.hpp"
|
||||||
|
|
||||||
|
@ -50,11 +50,6 @@ void ModRefBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, Decorat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModRefBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
|
||||||
const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
|
|
||||||
BarrierSetAssembler::store_at(masm, decorators, type, dst, val, tmp1, tmp2, tmp3);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||||
const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
|
const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3) {
|
||||||
if (type == T_OBJECT || type == T_ARRAY) {
|
if (type == T_OBJECT || type == T_ARRAY) {
|
||||||
|
@ -39,7 +39,7 @@ protected:
|
|||||||
virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count,
|
virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators, Register addr, Register count,
|
||||||
bool do_return);
|
bool do_return);
|
||||||
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||||
const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3);
|
const Address& dst, Register val, Register tmp1, Register tmp2, Register tmp3) = 0;
|
||||||
public:
|
public:
|
||||||
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
|
||||||
Register src, Register dst, Register count);
|
Register src, Register dst, Register count);
|
||||||
|
@ -445,6 +445,8 @@ void AOTCodeHeap::link_shared_runtime_symbols() {
|
|||||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_handle_wrong_method_stub", address, SharedRuntime::get_handle_wrong_method_stub());
|
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_handle_wrong_method_stub", address, SharedRuntime::get_handle_wrong_method_stub());
|
||||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_exception_handler_for_return_address", address, SharedRuntime::exception_handler_for_return_address);
|
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_exception_handler_for_return_address", address, SharedRuntime::exception_handler_for_return_address);
|
||||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_register_finalizer", address, SharedRuntime::register_finalizer);
|
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_register_finalizer", address, SharedRuntime::register_finalizer);
|
||||||
|
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_object_notify", address, JVMCIRuntime::object_notify);
|
||||||
|
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_object_notifyAll", address, JVMCIRuntime::object_notifyAll);
|
||||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_OSR_migration_end", address, SharedRuntime::OSR_migration_end);
|
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_OSR_migration_end", address, SharedRuntime::OSR_migration_end);
|
||||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_dynamic_invoke", address, CompilerRuntime::resolve_dynamic_invoke);
|
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_dynamic_invoke", address, CompilerRuntime::resolve_dynamic_invoke);
|
||||||
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_string_by_symbol", address, CompilerRuntime::resolve_string_by_symbol);
|
SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_resolve_string_by_symbol", address, CompilerRuntime::resolve_string_by_symbol);
|
||||||
|
@ -80,13 +80,13 @@
|
|||||||
|
|
||||||
// Entry points in zip.dll for loading zip/jar file entries
|
// Entry points in zip.dll for loading zip/jar file entries
|
||||||
|
|
||||||
typedef void * * (JNICALL *ZipOpen_t)(const char *name, char **pmsg);
|
typedef void * * (*ZipOpen_t)(const char *name, char **pmsg);
|
||||||
typedef void (JNICALL *ZipClose_t)(jzfile *zip);
|
typedef void (*ZipClose_t)(jzfile *zip);
|
||||||
typedef jzentry* (JNICALL *FindEntry_t)(jzfile *zip, const char *name, jint *sizeP, jint *nameLen);
|
typedef jzentry* (*FindEntry_t)(jzfile *zip, const char *name, jint *sizeP, jint *nameLen);
|
||||||
typedef jboolean (JNICALL *ReadEntry_t)(jzfile *zip, jzentry *entry, unsigned char *buf, char *namebuf);
|
typedef jboolean (*ReadEntry_t)(jzfile *zip, jzentry *entry, unsigned char *buf, char *namebuf);
|
||||||
typedef jzentry* (JNICALL *GetNextEntry_t)(jzfile *zip, jint n);
|
typedef jzentry* (*GetNextEntry_t)(jzfile *zip, jint n);
|
||||||
typedef jboolean (JNICALL *ZipInflateFully_t)(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pmsg);
|
typedef jboolean (*ZipInflateFully_t)(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pmsg);
|
||||||
typedef jint (JNICALL *Crc32_t)(jint crc, const jbyte *buf, jint len);
|
typedef jint (*Crc32_t)(jint crc, const jbyte *buf, jint len);
|
||||||
|
|
||||||
static ZipOpen_t ZipOpen = NULL;
|
static ZipOpen_t ZipOpen = NULL;
|
||||||
static ZipClose_t ZipClose = NULL;
|
static ZipClose_t ZipClose = NULL;
|
||||||
|
@ -54,6 +54,7 @@
|
|||||||
#include "classfile/metadataOnStackMark.hpp"
|
#include "classfile/metadataOnStackMark.hpp"
|
||||||
#include "classfile/moduleEntry.hpp"
|
#include "classfile/moduleEntry.hpp"
|
||||||
#include "classfile/packageEntry.hpp"
|
#include "classfile/packageEntry.hpp"
|
||||||
|
#include "classfile/symbolTable.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
#include "logging/logStream.hpp"
|
#include "logging/logStream.hpp"
|
||||||
@ -102,8 +103,25 @@ void ClassLoaderData::init_null_class_loader_data() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// JFR and logging support so that the name and klass are available after the
|
||||||
|
// class_loader oop is no longer alive, during unloading.
|
||||||
|
void ClassLoaderData::initialize_name_and_klass(Handle class_loader) {
|
||||||
|
_class_loader_klass = class_loader->klass();
|
||||||
|
oop class_loader_name = java_lang_ClassLoader::name(class_loader());
|
||||||
|
if (class_loader_name != NULL) {
|
||||||
|
Thread* THREAD = Thread::current();
|
||||||
|
ResourceMark rm(THREAD);
|
||||||
|
const char* class_loader_instance_name =
|
||||||
|
java_lang_String::as_utf8_string(class_loader_name);
|
||||||
|
|
||||||
|
if (class_loader_instance_name != NULL && class_loader_instance_name[0] != '\0') {
|
||||||
|
// Can't throw InternalError and SymbolTable doesn't throw OOM anymore.
|
||||||
|
_class_loader_name = SymbolTable::new_symbol(class_loader_instance_name, CATCH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) :
|
ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) :
|
||||||
_class_loader(h_class_loader()),
|
|
||||||
_is_anonymous(is_anonymous),
|
_is_anonymous(is_anonymous),
|
||||||
// An anonymous class loader data doesn't have anything to keep
|
// An anonymous class loader data doesn't have anything to keep
|
||||||
// it from being unloaded during parsing of the anonymous class.
|
// it from being unloaded during parsing of the anonymous class.
|
||||||
@ -114,9 +132,14 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous) :
|
|||||||
_claimed(0), _modified_oops(true), _accumulated_modified_oops(false),
|
_claimed(0), _modified_oops(true), _accumulated_modified_oops(false),
|
||||||
_jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
|
_jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
|
||||||
_next(NULL),
|
_next(NULL),
|
||||||
|
_class_loader_klass(NULL), _class_loader_name(NULL),
|
||||||
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
|
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
|
||||||
Monitor::_safepoint_check_never)) {
|
Monitor::_safepoint_check_never)) {
|
||||||
|
|
||||||
|
if (!h_class_loader.is_null()) {
|
||||||
|
_class_loader = _handles.add(h_class_loader());
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_anonymous) {
|
if (!is_anonymous) {
|
||||||
// The holder is initialized later for anonymous classes, and before calling anything
|
// The holder is initialized later for anonymous classes, and before calling anything
|
||||||
// that call class_loader().
|
// that call class_loader().
|
||||||
@ -269,7 +292,6 @@ void ClassLoaderData::oops_do(OopClosure* f, bool must_claim, bool clear_mod_oop
|
|||||||
clear_modified_oops();
|
clear_modified_oops();
|
||||||
}
|
}
|
||||||
|
|
||||||
f->do_oop(&_class_loader);
|
|
||||||
_handles.oops_do(f);
|
_handles.oops_do(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -556,7 +578,7 @@ void ClassLoaderData::unload() {
|
|||||||
if (lt.is_enabled()) {
|
if (lt.is_enabled()) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
LogStream ls(lt);
|
LogStream ls(lt);
|
||||||
ls.print("unload ");
|
ls.print("unload");
|
||||||
print_value_on(&ls);
|
print_value_on(&ls);
|
||||||
ls.cr();
|
ls.cr();
|
||||||
}
|
}
|
||||||
@ -631,7 +653,7 @@ oop ClassLoaderData::holder_phantom() const {
|
|||||||
// Unloading support
|
// Unloading support
|
||||||
bool ClassLoaderData::is_alive() const {
|
bool ClassLoaderData::is_alive() const {
|
||||||
bool alive = keep_alive() // null class loader and incomplete anonymous klasses.
|
bool alive = keep_alive() // null class loader and incomplete anonymous klasses.
|
||||||
|| (_holder.peek() != NULL); // not cleaned by weak reference processing
|
|| (_holder.peek() != NULL); // and not cleaned by the GC weak handle processing.
|
||||||
|
|
||||||
return alive;
|
return alive;
|
||||||
}
|
}
|
||||||
@ -887,13 +909,23 @@ ClassLoaderData* ClassLoaderData::anonymous_class_loader_data(Handle loader) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const char* ClassLoaderData::loader_name() const {
|
const char* ClassLoaderData::loader_name() const {
|
||||||
// Handles null class loader
|
if (is_unloading()) {
|
||||||
return SystemDictionary::loader_name(class_loader());
|
if (_class_loader_klass == NULL) {
|
||||||
|
return "<bootloader>";
|
||||||
|
} else if (_class_loader_name != NULL) {
|
||||||
|
return _class_loader_name->as_C_string();
|
||||||
|
} else {
|
||||||
|
return _class_loader_klass->name()->as_C_string();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Handles null class loader
|
||||||
|
return SystemDictionary::loader_name(class_loader());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ClassLoaderData::print_value_on(outputStream* out) const {
|
void ClassLoaderData::print_value_on(outputStream* out) const {
|
||||||
if (class_loader() != NULL) {
|
if (!is_unloading() && class_loader() != NULL) {
|
||||||
out->print("loader data: " INTPTR_FORMAT " for instance ", p2i(this));
|
out->print("loader data: " INTPTR_FORMAT " for instance ", p2i(this));
|
||||||
class_loader()->print_value_on(out); // includes loader_name() and address of class loader instance
|
class_loader()->print_value_on(out); // includes loader_name() and address of class loader instance
|
||||||
} else {
|
} else {
|
||||||
@ -908,7 +940,7 @@ void ClassLoaderData::print_value_on(outputStream* out) const {
|
|||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void ClassLoaderData::print_on(outputStream* out) const {
|
void ClassLoaderData::print_on(outputStream* out) const {
|
||||||
out->print("ClassLoaderData CLD: " PTR_FORMAT ", loader: " PTR_FORMAT ", loader_klass: %s {",
|
out->print("ClassLoaderData CLD: " PTR_FORMAT ", loader: " PTR_FORMAT ", loader_klass: %s {",
|
||||||
p2i(this), p2i((void *)class_loader()), loader_name());
|
p2i(this), p2i(_class_loader.ptr_raw()), loader_name());
|
||||||
if (is_anonymous()) out->print(" anonymous");
|
if (is_anonymous()) out->print(" anonymous");
|
||||||
if (claimed()) out->print(" claimed");
|
if (claimed()) out->print(" claimed");
|
||||||
if (is_unloading()) out->print(" unloading");
|
if (is_unloading()) out->print(" unloading");
|
||||||
@ -962,10 +994,10 @@ bool ClassLoaderDataGraph::_metaspace_oom = false;
|
|||||||
|
|
||||||
// Add a new class loader data node to the list. Assign the newly created
|
// Add a new class loader data node to the list. Assign the newly created
|
||||||
// ClassLoaderData into the java/lang/ClassLoader object as a hidden field
|
// ClassLoaderData into the java/lang/ClassLoader object as a hidden field
|
||||||
ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous) {
|
ClassLoaderData* ClassLoaderDataGraph::add_to_graph(Handle loader, bool is_anonymous) {
|
||||||
NoSafepointVerifier no_safepoints; // we mustn't GC until we've installed the
|
NoSafepointVerifier no_safepoints; // we mustn't GC until we've installed the
|
||||||
// ClassLoaderData in the graph since the CLD
|
// ClassLoaderData in the graph since the CLD
|
||||||
// contains unhandled oops
|
// contains oops in _handles that must be walked.
|
||||||
|
|
||||||
ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous);
|
ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous);
|
||||||
|
|
||||||
@ -1002,6 +1034,16 @@ ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous) {
|
|||||||
} while (true);
|
} while (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClassLoaderData* ClassLoaderDataGraph::add(Handle loader, bool is_anonymous) {
|
||||||
|
ClassLoaderData* loader_data = add_to_graph(loader, is_anonymous);
|
||||||
|
// Initialize name and class after the loader data is added to the CLDG
|
||||||
|
// because adding the Symbol for the name might safepoint.
|
||||||
|
if (loader.not_null()) {
|
||||||
|
loader_data->initialize_name_and_klass(loader);
|
||||||
|
}
|
||||||
|
return loader_data;
|
||||||
|
}
|
||||||
|
|
||||||
void ClassLoaderDataGraph::oops_do(OopClosure* f, bool must_claim) {
|
void ClassLoaderDataGraph::oops_do(OopClosure* f, bool must_claim) {
|
||||||
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
||||||
cld->oops_do(f, must_claim);
|
cld->oops_do(f, must_claim);
|
||||||
@ -1237,8 +1279,7 @@ bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) {
|
|||||||
|
|
||||||
// Move class loader data from main list to the unloaded list for unloading
|
// Move class loader data from main list to the unloaded list for unloading
|
||||||
// and deallocation later.
|
// and deallocation later.
|
||||||
bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure,
|
bool ClassLoaderDataGraph::do_unloading(bool clean_previous_versions) {
|
||||||
bool clean_previous_versions) {
|
|
||||||
|
|
||||||
ClassLoaderData* data = _head;
|
ClassLoaderData* data = _head;
|
||||||
ClassLoaderData* prev = NULL;
|
ClassLoaderData* prev = NULL;
|
||||||
@ -1296,7 +1337,7 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure,
|
|||||||
// Remove entries in the dictionary of live class loader that have
|
// Remove entries in the dictionary of live class loader that have
|
||||||
// initiated loading classes in a dead class loader.
|
// initiated loading classes in a dead class loader.
|
||||||
if (data->dictionary() != NULL) {
|
if (data->dictionary() != NULL) {
|
||||||
data->dictionary()->do_unloading(is_alive_closure);
|
data->dictionary()->do_unloading();
|
||||||
}
|
}
|
||||||
// Walk a ModuleEntry's reads, and a PackageEntry's exports
|
// Walk a ModuleEntry's reads, and a PackageEntry's exports
|
||||||
// lists to determine if there are modules on those lists that are now
|
// lists to determine if there are modules on those lists that are now
|
||||||
|
@ -28,7 +28,6 @@
|
|||||||
#include "memory/allocation.hpp"
|
#include "memory/allocation.hpp"
|
||||||
#include "memory/memRegion.hpp"
|
#include "memory/memRegion.hpp"
|
||||||
#include "memory/metaspace.hpp"
|
#include "memory/metaspace.hpp"
|
||||||
#include "memory/metaspaceCounters.hpp"
|
|
||||||
#include "oops/oopHandle.hpp"
|
#include "oops/oopHandle.hpp"
|
||||||
#include "oops/weakHandle.hpp"
|
#include "oops/weakHandle.hpp"
|
||||||
#include "runtime/mutex.hpp"
|
#include "runtime/mutex.hpp"
|
||||||
@ -84,6 +83,7 @@ class ClassLoaderDataGraph : public AllStatic {
|
|||||||
static volatile size_t _num_instance_classes;
|
static volatile size_t _num_instance_classes;
|
||||||
static volatile size_t _num_array_classes;
|
static volatile size_t _num_array_classes;
|
||||||
|
|
||||||
|
static ClassLoaderData* add_to_graph(Handle class_loader, bool anonymous);
|
||||||
static ClassLoaderData* add(Handle class_loader, bool anonymous);
|
static ClassLoaderData* add(Handle class_loader, bool anonymous);
|
||||||
static void post_class_unload_events();
|
static void post_class_unload_events();
|
||||||
public:
|
public:
|
||||||
@ -114,7 +114,7 @@ class ClassLoaderDataGraph : public AllStatic {
|
|||||||
static void packages_unloading_do(void f(PackageEntry*));
|
static void packages_unloading_do(void f(PackageEntry*));
|
||||||
static void loaded_classes_do(KlassClosure* klass_closure);
|
static void loaded_classes_do(KlassClosure* klass_closure);
|
||||||
static void classes_unloading_do(void f(Klass* const));
|
static void classes_unloading_do(void f(Klass* const));
|
||||||
static bool do_unloading(BoolObjectClosure* is_alive_closure, bool clean_previous_versions);
|
static bool do_unloading(bool clean_previous_versions);
|
||||||
|
|
||||||
// dictionary do
|
// dictionary do
|
||||||
// Iterate over all klasses in dictionary, but
|
// Iterate over all klasses in dictionary, but
|
||||||
@ -221,7 +221,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
|||||||
static ClassLoaderData * _the_null_class_loader_data;
|
static ClassLoaderData * _the_null_class_loader_data;
|
||||||
|
|
||||||
WeakHandle<vm_class_loader_data> _holder; // The oop that determines lifetime of this class loader
|
WeakHandle<vm_class_loader_data> _holder; // The oop that determines lifetime of this class loader
|
||||||
oop _class_loader; // The instance of java/lang/ClassLoader associated with
|
OopHandle _class_loader; // The instance of java/lang/ClassLoader associated with
|
||||||
// this ClassLoaderData
|
// this ClassLoaderData
|
||||||
|
|
||||||
ClassLoaderMetaspace * volatile _metaspace; // Meta-space where meta-data defined by the
|
ClassLoaderMetaspace * volatile _metaspace; // Meta-space where meta-data defined by the
|
||||||
@ -234,7 +234,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
|||||||
bool _modified_oops; // Card Table Equivalent (YC/CMS support)
|
bool _modified_oops; // Card Table Equivalent (YC/CMS support)
|
||||||
bool _accumulated_modified_oops; // Mod Union Equivalent (CMS support)
|
bool _accumulated_modified_oops; // Mod Union Equivalent (CMS support)
|
||||||
|
|
||||||
s2 _keep_alive; // if this CLD is kept alive without a keep_alive_object().
|
s2 _keep_alive; // if this CLD is kept alive.
|
||||||
// Used for anonymous classes and the boot class
|
// Used for anonymous classes and the boot class
|
||||||
// loader. _keep_alive does not need to be volatile or
|
// loader. _keep_alive does not need to be volatile or
|
||||||
// atomic since there is one unique CLD per anonymous class.
|
// atomic since there is one unique CLD per anonymous class.
|
||||||
@ -265,6 +265,9 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
|||||||
// Support for walking class loader data objects
|
// Support for walking class loader data objects
|
||||||
ClassLoaderData* _next; /// Next loader_datas created
|
ClassLoaderData* _next; /// Next loader_datas created
|
||||||
|
|
||||||
|
// JFR support
|
||||||
|
Klass* _class_loader_klass;
|
||||||
|
Symbol* _class_loader_name;
|
||||||
TRACE_DEFINE_TRACE_ID_FIELD;
|
TRACE_DEFINE_TRACE_ID_FIELD;
|
||||||
|
|
||||||
void set_next(ClassLoaderData* next) { _next = next; }
|
void set_next(ClassLoaderData* next) { _next = next; }
|
||||||
@ -305,6 +308,8 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
|||||||
MetaWord* allocate(size_t size);
|
MetaWord* allocate(size_t size);
|
||||||
|
|
||||||
Dictionary* create_dictionary();
|
Dictionary* create_dictionary();
|
||||||
|
|
||||||
|
void initialize_name_and_klass(Handle class_loader);
|
||||||
public:
|
public:
|
||||||
// GC interface.
|
// GC interface.
|
||||||
void clear_claimed() { _claimed = 0; }
|
void clear_claimed() { _claimed = 0; }
|
||||||
@ -340,9 +345,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
|||||||
|
|
||||||
// Returns true if this class loader data is for the boot class loader.
|
// Returns true if this class loader data is for the boot class loader.
|
||||||
// (Note that the class loader data may be anonymous.)
|
// (Note that the class loader data may be anonymous.)
|
||||||
bool is_boot_class_loader_data() const {
|
inline bool is_boot_class_loader_data() const;
|
||||||
return class_loader() == NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_builtin_class_loader_data() const;
|
bool is_builtin_class_loader_data() const;
|
||||||
bool is_permanent_class_loader_data() const;
|
bool is_permanent_class_loader_data() const;
|
||||||
@ -351,10 +354,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
|||||||
// method will allocate a Metaspace if needed.
|
// method will allocate a Metaspace if needed.
|
||||||
ClassLoaderMetaspace* metaspace_non_null();
|
ClassLoaderMetaspace* metaspace_non_null();
|
||||||
|
|
||||||
oop class_loader() const { return _class_loader; }
|
inline oop class_loader() const;
|
||||||
|
|
||||||
// The object the GC is using to keep this ClassLoaderData alive.
|
|
||||||
oop keep_alive_object() const;
|
|
||||||
|
|
||||||
// Returns true if this class loader data is for a loader going away.
|
// Returns true if this class loader data is for a loader going away.
|
||||||
bool is_unloading() const {
|
bool is_unloading() const {
|
||||||
@ -363,7 +363,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Used to refcount an anonymous class's CLD in order to
|
// Used to refcount an anonymous class's CLD in order to
|
||||||
// indicate their aliveness without a keep_alive_object().
|
// indicate their aliveness.
|
||||||
void inc_keep_alive();
|
void inc_keep_alive();
|
||||||
void dec_keep_alive();
|
void dec_keep_alive();
|
||||||
|
|
||||||
@ -407,6 +407,9 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
|||||||
static ClassLoaderData* class_loader_data_or_null(oop loader);
|
static ClassLoaderData* class_loader_data_or_null(oop loader);
|
||||||
static ClassLoaderData* anonymous_class_loader_data(Handle loader);
|
static ClassLoaderData* anonymous_class_loader_data(Handle loader);
|
||||||
|
|
||||||
|
|
||||||
|
Klass* class_loader_klass() const { return _class_loader_klass; }
|
||||||
|
Symbol* class_loader_name() const { return _class_loader_name; }
|
||||||
TRACE_DEFINE_TRACE_ID_METHODS;
|
TRACE_DEFINE_TRACE_ID_METHODS;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -28,6 +28,18 @@
|
|||||||
#include "classfile/classLoaderData.hpp"
|
#include "classfile/classLoaderData.hpp"
|
||||||
#include "classfile/javaClasses.hpp"
|
#include "classfile/javaClasses.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
|
#include "oops/oopHandle.inline.hpp"
|
||||||
|
#include "oops/weakHandle.inline.hpp"
|
||||||
|
|
||||||
|
inline oop ClassLoaderData::class_loader() const {
|
||||||
|
assert(!_unloading, "This oop is not available to unloading class loader data");
|
||||||
|
assert(_holder.is_null() || _holder.peek() != NULL , "This class loader data holder must be alive");
|
||||||
|
return _class_loader.resolve();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool ClassLoaderData::is_boot_class_loader_data() const {
|
||||||
|
return class_loader() == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
inline ClassLoaderData* ClassLoaderData::class_loader_data_or_null(oop loader) {
|
inline ClassLoaderData* ClassLoaderData::class_loader_data_or_null(oop loader) {
|
||||||
if (loader == NULL) {
|
if (loader == NULL) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2014, 2018, 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
|
||||||
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
#include "classfile/classLoaderStats.hpp"
|
#include "classfile/classLoaderStats.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "utilities/globalDefinitions.hpp"
|
#include "utilities/globalDefinitions.hpp"
|
||||||
|
@ -214,13 +214,13 @@ void DictionaryEntry::add_protection_domain(Dictionary* dict, Handle protection_
|
|||||||
|
|
||||||
// During class loading we may have cached a protection domain that has
|
// During class loading we may have cached a protection domain that has
|
||||||
// since been unreferenced, so this entry should be cleared.
|
// since been unreferenced, so this entry should be cleared.
|
||||||
void Dictionary::clean_cached_protection_domains(BoolObjectClosure* is_alive, DictionaryEntry* probe) {
|
void Dictionary::clean_cached_protection_domains(DictionaryEntry* probe) {
|
||||||
assert_locked_or_safepoint(SystemDictionary_lock);
|
assert_locked_or_safepoint(SystemDictionary_lock);
|
||||||
|
|
||||||
ProtectionDomainEntry* current = probe->pd_set();
|
ProtectionDomainEntry* current = probe->pd_set();
|
||||||
ProtectionDomainEntry* prev = NULL;
|
ProtectionDomainEntry* prev = NULL;
|
||||||
while (current != NULL) {
|
while (current != NULL) {
|
||||||
if (!is_alive->do_object_b(current->object_no_keepalive())) {
|
if (current->object_no_keepalive() == NULL) {
|
||||||
LogTarget(Debug, protectiondomain) lt;
|
LogTarget(Debug, protectiondomain) lt;
|
||||||
if (lt.is_enabled()) {
|
if (lt.is_enabled()) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
@ -228,7 +228,6 @@ void Dictionary::clean_cached_protection_domains(BoolObjectClosure* is_alive, Di
|
|||||||
LogStream ls(lt);
|
LogStream ls(lt);
|
||||||
ls.print_cr("PD in set is not alive:");
|
ls.print_cr("PD in set is not alive:");
|
||||||
ls.print("class loader: "); loader_data()->class_loader()->print_value_on(&ls);
|
ls.print("class loader: "); loader_data()->class_loader()->print_value_on(&ls);
|
||||||
ls.print(" protection domain: "); current->object_no_keepalive()->print_value_on(&ls);
|
|
||||||
ls.print(" loading: "); probe->instance_klass()->print_value_on(&ls);
|
ls.print(" loading: "); probe->instance_klass()->print_value_on(&ls);
|
||||||
ls.cr();
|
ls.cr();
|
||||||
}
|
}
|
||||||
@ -249,7 +248,7 @@ void Dictionary::clean_cached_protection_domains(BoolObjectClosure* is_alive, Di
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Dictionary::do_unloading(BoolObjectClosure* is_alive) {
|
void Dictionary::do_unloading() {
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
||||||
|
|
||||||
// The NULL class loader doesn't initiate loading classes from other class loaders
|
// The NULL class loader doesn't initiate loading classes from other class loaders
|
||||||
@ -276,7 +275,7 @@ void Dictionary::do_unloading(BoolObjectClosure* is_alive) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Clean pd_set
|
// Clean pd_set
|
||||||
clean_cached_protection_domains(is_alive, probe);
|
clean_cached_protection_domains(probe);
|
||||||
p = probe->next_addr();
|
p = probe->next_addr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ class Dictionary : public Hashtable<InstanceKlass*, mtClass> {
|
|||||||
|
|
||||||
DictionaryEntry* get_entry(int index, unsigned int hash, Symbol* name);
|
DictionaryEntry* get_entry(int index, unsigned int hash, Symbol* name);
|
||||||
|
|
||||||
void clean_cached_protection_domains(BoolObjectClosure* is_alive, DictionaryEntry* probe);
|
void clean_cached_protection_domains(DictionaryEntry* probe);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static size_t entry_size();
|
static size_t entry_size();
|
||||||
@ -72,20 +72,16 @@ public:
|
|||||||
|
|
||||||
InstanceKlass* find_shared_class(int index, unsigned int hash, Symbol* name);
|
InstanceKlass* find_shared_class(int index, unsigned int hash, Symbol* name);
|
||||||
|
|
||||||
// GC support
|
|
||||||
void oops_do(OopClosure* f);
|
|
||||||
void roots_oops_do(OopClosure* strong, OopClosure* weak);
|
|
||||||
|
|
||||||
void classes_do(void f(InstanceKlass*));
|
void classes_do(void f(InstanceKlass*));
|
||||||
void classes_do(void f(InstanceKlass*, TRAPS), TRAPS);
|
void classes_do(void f(InstanceKlass*, TRAPS), TRAPS);
|
||||||
void all_entries_do(void f(InstanceKlass*, ClassLoaderData*));
|
void all_entries_do(void f(InstanceKlass*, ClassLoaderData*));
|
||||||
void classes_do(MetaspaceClosure* it);
|
void classes_do(MetaspaceClosure* it);
|
||||||
|
|
||||||
void unlink(BoolObjectClosure* is_alive);
|
void unlink();
|
||||||
void remove_classes_in_error_state();
|
void remove_classes_in_error_state();
|
||||||
|
|
||||||
// Unload classes whose defining loaders are unloaded
|
// Unload classes whose defining loaders are unloaded
|
||||||
void do_unloading(BoolObjectClosure* is_alive);
|
void do_unloading();
|
||||||
|
|
||||||
// Protection domains
|
// Protection domains
|
||||||
InstanceKlass* find(unsigned int hash, Symbol* name, Handle protection_domain);
|
InstanceKlass* find(unsigned int hash, Symbol* name, Handle protection_domain);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -99,7 +99,7 @@ void LoaderConstraintTable::purge_loader_constraints() {
|
|||||||
InstanceKlass* klass = probe->klass();
|
InstanceKlass* klass = probe->klass();
|
||||||
// Remove klass that is no longer alive
|
// Remove klass that is no longer alive
|
||||||
if (klass != NULL &&
|
if (klass != NULL &&
|
||||||
klass->class_loader_data()->is_unloading()) {
|
!klass->is_loader_alive()) {
|
||||||
probe->set_klass(NULL);
|
probe->set_klass(NULL);
|
||||||
if (lt.is_enabled()) {
|
if (lt.is_enabled()) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
@ -116,31 +116,31 @@ void LoaderConstraintTable::purge_loader_constraints() {
|
|||||||
int n = 0;
|
int n = 0;
|
||||||
while (n < probe->num_loaders()) {
|
while (n < probe->num_loaders()) {
|
||||||
if (probe->loader_data(n)->is_unloading()) {
|
if (probe->loader_data(n)->is_unloading()) {
|
||||||
if (lt.is_enabled()) {
|
if (lt.is_enabled()) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
lt.print("purging loader %s from constraint for name %s",
|
lt.print("purging loader %s from constraint for name %s",
|
||||||
probe->loader_data(n)->loader_name(),
|
probe->loader_data(n)->loader_name(),
|
||||||
probe->name()->as_C_string()
|
probe->name()->as_C_string()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compact array
|
// Compact array
|
||||||
int num = probe->num_loaders() - 1;
|
int num = probe->num_loaders() - 1;
|
||||||
probe->set_num_loaders(num);
|
probe->set_num_loaders(num);
|
||||||
probe->set_loader_data(n, probe->loader_data(num));
|
probe->set_loader_data(n, probe->loader_data(num));
|
||||||
probe->set_loader_data(num, NULL);
|
probe->set_loader_data(num, NULL);
|
||||||
|
|
||||||
if (lt.is_enabled()) {
|
if (lt.is_enabled()) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
lt.print("new loader list:");
|
lt.print("new loader list:");
|
||||||
for (int i = 0; i < probe->num_loaders(); i++) {
|
for (int i = 0; i < probe->num_loaders(); i++) {
|
||||||
lt.print(" [%d]: %s", i,
|
lt.print(" [%d]: %s", i,
|
||||||
probe->loader_data(i)->loader_name());
|
probe->loader_data(i)->loader_name());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
continue; // current element replaced, so restart without
|
continue; // current element replaced, so restart without
|
||||||
// incrementing n
|
// incrementing n
|
||||||
}
|
}
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
@ -159,9 +159,7 @@ void LoaderConstraintTable::purge_loader_constraints() {
|
|||||||
} else {
|
} else {
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
if (probe->klass() != NULL) {
|
if (probe->klass() != NULL) {
|
||||||
ClassLoaderData* loader_data =
|
assert(probe->klass()->is_loader_alive(), "klass should be live");
|
||||||
probe->klass()->class_loader_data();
|
|
||||||
assert(!loader_data->is_unloading(), "klass should be live");
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
// Go to next entry
|
// Go to next entry
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "jni.h"
|
#include "jni.h"
|
||||||
#include "classfile/classLoaderData.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
#include "classfile/javaClasses.hpp"
|
#include "classfile/javaClasses.hpp"
|
||||||
#include "classfile/moduleEntry.hpp"
|
#include "classfile/moduleEntry.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2018, 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
|
||||||
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
#include "classfile/placeholders.hpp"
|
#include "classfile/placeholders.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "memory/iterator.hpp"
|
#include "memory/iterator.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
|
#include "oops/weakHandle.inline.hpp"
|
||||||
#include "utilities/hashtable.inline.hpp"
|
#include "utilities/hashtable.inline.hpp"
|
||||||
|
|
||||||
unsigned int ProtectionDomainCacheTable::compute_hash(Handle protection_domain) {
|
unsigned int ProtectionDomainCacheTable::compute_hash(Handle protection_domain) {
|
||||||
@ -42,26 +43,26 @@ int ProtectionDomainCacheTable::index_for(Handle protection_domain) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ProtectionDomainCacheTable::ProtectionDomainCacheTable(int table_size)
|
ProtectionDomainCacheTable::ProtectionDomainCacheTable(int table_size)
|
||||||
: Hashtable<oop, mtClass>(table_size, sizeof(ProtectionDomainCacheEntry))
|
: Hashtable<ClassLoaderWeakHandle, mtClass>(table_size, sizeof(ProtectionDomainCacheEntry))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtectionDomainCacheTable::unlink(BoolObjectClosure* is_alive) {
|
void ProtectionDomainCacheTable::unlink() {
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must be");
|
assert(SafepointSynchronize::is_at_safepoint(), "must be");
|
||||||
for (int i = 0; i < table_size(); ++i) {
|
for (int i = 0; i < table_size(); ++i) {
|
||||||
ProtectionDomainCacheEntry** p = bucket_addr(i);
|
ProtectionDomainCacheEntry** p = bucket_addr(i);
|
||||||
ProtectionDomainCacheEntry* entry = bucket(i);
|
ProtectionDomainCacheEntry* entry = bucket(i);
|
||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
if (is_alive->do_object_b(entry->object_no_keepalive())) {
|
oop pd = entry->object_no_keepalive();
|
||||||
|
if (pd != NULL) {
|
||||||
p = entry->next_addr();
|
p = entry->next_addr();
|
||||||
} else {
|
} else {
|
||||||
LogTarget(Debug, protectiondomain) lt;
|
LogTarget(Debug, protectiondomain) lt;
|
||||||
if (lt.is_enabled()) {
|
if (lt.is_enabled()) {
|
||||||
LogStream ls(lt);
|
LogStream ls(lt);
|
||||||
ls.print("protection domain unlinked: ");
|
ls.print_cr("protection domain unlinked at %d", i);
|
||||||
entry->object_no_keepalive()->print_value_on(&ls);
|
|
||||||
ls.cr();
|
|
||||||
}
|
}
|
||||||
|
entry->literal().release();
|
||||||
*p = entry->next();
|
*p = entry->next();
|
||||||
free_entry(entry);
|
free_entry(entry);
|
||||||
}
|
}
|
||||||
@ -70,16 +71,6 @@ void ProtectionDomainCacheTable::unlink(BoolObjectClosure* is_alive) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtectionDomainCacheTable::oops_do(OopClosure* f) {
|
|
||||||
for (int index = 0; index < table_size(); index++) {
|
|
||||||
for (ProtectionDomainCacheEntry* probe = bucket(index);
|
|
||||||
probe != NULL;
|
|
||||||
probe = probe->next()) {
|
|
||||||
probe->oops_do(f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProtectionDomainCacheTable::print_on(outputStream* st) const {
|
void ProtectionDomainCacheTable::print_on(outputStream* st) const {
|
||||||
st->print_cr("Protection domain cache table (table_size=%d, classes=%d)",
|
st->print_cr("Protection domain cache table (table_size=%d, classes=%d)",
|
||||||
table_size(), number_of_entries());
|
table_size(), number_of_entries());
|
||||||
@ -97,7 +88,7 @@ void ProtectionDomainCacheTable::verify() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
oop ProtectionDomainCacheEntry::object() {
|
oop ProtectionDomainCacheEntry::object() {
|
||||||
return RootAccess<ON_PHANTOM_OOP_REF>::oop_load(literal_addr());
|
return literal().resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
oop ProtectionDomainEntry::object() {
|
oop ProtectionDomainEntry::object() {
|
||||||
@ -108,7 +99,7 @@ oop ProtectionDomainEntry::object() {
|
|||||||
// keeping it alive. This is okay to do in the VM thread state if it is not
|
// keeping it alive. This is okay to do in the VM thread state if it is not
|
||||||
// leaked out to become strongly reachable.
|
// leaked out to become strongly reachable.
|
||||||
oop ProtectionDomainCacheEntry::object_no_keepalive() {
|
oop ProtectionDomainCacheEntry::object_no_keepalive() {
|
||||||
return RootAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(literal_addr());
|
return literal().peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
oop ProtectionDomainEntry::object_no_keepalive() {
|
oop ProtectionDomainEntry::object_no_keepalive() {
|
||||||
@ -116,7 +107,7 @@ oop ProtectionDomainEntry::object_no_keepalive() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ProtectionDomainCacheEntry::verify() {
|
void ProtectionDomainCacheEntry::verify() {
|
||||||
guarantee(oopDesc::is_oop(object_no_keepalive()), "must be an oop");
|
guarantee(object_no_keepalive() == NULL || oopDesc::is_oop(object_no_keepalive()), "must be an oop");
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtectionDomainCacheEntry* ProtectionDomainCacheTable::get(Handle protection_domain) {
|
ProtectionDomainCacheEntry* ProtectionDomainCacheTable::get(Handle protection_domain) {
|
||||||
@ -127,6 +118,8 @@ ProtectionDomainCacheEntry* ProtectionDomainCacheTable::get(Handle protection_do
|
|||||||
if (entry == NULL) {
|
if (entry == NULL) {
|
||||||
entry = add_entry(index, hash, protection_domain);
|
entry = add_entry(index, hash, protection_domain);
|
||||||
}
|
}
|
||||||
|
// keep entry alive
|
||||||
|
(void)entry->object();
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +138,8 @@ ProtectionDomainCacheEntry* ProtectionDomainCacheTable::add_entry(int index, uns
|
|||||||
assert(index == index_for(protection_domain), "incorrect index?");
|
assert(index == index_for(protection_domain), "incorrect index?");
|
||||||
assert(find_entry(index, protection_domain) == NULL, "no double entry");
|
assert(find_entry(index, protection_domain) == NULL, "no double entry");
|
||||||
|
|
||||||
ProtectionDomainCacheEntry* p = new_entry(hash, protection_domain);
|
ClassLoaderWeakHandle w = ClassLoaderWeakHandle::create(protection_domain);
|
||||||
Hashtable<oop, mtClass>::add_entry(index, p);
|
ProtectionDomainCacheEntry* p = new_entry(hash, w);
|
||||||
|
Hashtable<ClassLoaderWeakHandle, mtClass>::add_entry(index, p);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#define SHARE_VM_CLASSFILE_PROTECTIONDOMAINCACHE_HPP
|
#define SHARE_VM_CLASSFILE_PROTECTIONDOMAINCACHE_HPP
|
||||||
|
|
||||||
#include "oops/oop.hpp"
|
#include "oops/oop.hpp"
|
||||||
|
#include "oops/weakHandle.hpp"
|
||||||
#include "memory/iterator.hpp"
|
#include "memory/iterator.hpp"
|
||||||
#include "utilities/hashtable.hpp"
|
#include "utilities/hashtable.hpp"
|
||||||
|
|
||||||
@ -34,22 +35,18 @@
|
|||||||
// to dictionary.hpp pd_set for more information about how protection domain entries
|
// to dictionary.hpp pd_set for more information about how protection domain entries
|
||||||
// are used.
|
// are used.
|
||||||
// This table is walked during GC, rather than the class loader data graph dictionaries.
|
// This table is walked during GC, rather than the class loader data graph dictionaries.
|
||||||
class ProtectionDomainCacheEntry : public HashtableEntry<oop, mtClass> {
|
class ProtectionDomainCacheEntry : public HashtableEntry<ClassLoaderWeakHandle, mtClass> {
|
||||||
friend class VMStructs;
|
friend class VMStructs;
|
||||||
public:
|
public:
|
||||||
oop object();
|
oop object();
|
||||||
oop object_no_keepalive();
|
oop object_no_keepalive();
|
||||||
|
|
||||||
ProtectionDomainCacheEntry* next() {
|
ProtectionDomainCacheEntry* next() {
|
||||||
return (ProtectionDomainCacheEntry*)HashtableEntry<oop, mtClass>::next();
|
return (ProtectionDomainCacheEntry*)HashtableEntry<ClassLoaderWeakHandle, mtClass>::next();
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtectionDomainCacheEntry** next_addr() {
|
ProtectionDomainCacheEntry** next_addr() {
|
||||||
return (ProtectionDomainCacheEntry**)HashtableEntry<oop, mtClass>::next_addr();
|
return (ProtectionDomainCacheEntry**)HashtableEntry<ClassLoaderWeakHandle, mtClass>::next_addr();
|
||||||
}
|
|
||||||
|
|
||||||
void oops_do(OopClosure* f) {
|
|
||||||
f->do_oop(literal_addr());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void verify();
|
void verify();
|
||||||
@ -64,20 +61,21 @@ class ProtectionDomainCacheEntry : public HashtableEntry<oop, mtClass> {
|
|||||||
// we only need to iterate over this set.
|
// we only need to iterate over this set.
|
||||||
// The amount of different protection domains used is typically magnitudes smaller
|
// The amount of different protection domains used is typically magnitudes smaller
|
||||||
// than the number of system dictionary entries (loaded classes).
|
// than the number of system dictionary entries (loaded classes).
|
||||||
class ProtectionDomainCacheTable : public Hashtable<oop, mtClass> {
|
class ProtectionDomainCacheTable : public Hashtable<ClassLoaderWeakHandle, mtClass> {
|
||||||
friend class VMStructs;
|
friend class VMStructs;
|
||||||
private:
|
private:
|
||||||
ProtectionDomainCacheEntry* bucket(int i) const {
|
ProtectionDomainCacheEntry* bucket(int i) const {
|
||||||
return (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::bucket(i);
|
return (ProtectionDomainCacheEntry*) Hashtable<ClassLoaderWeakHandle, mtClass>::bucket(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
ProtectionDomainCacheEntry** bucket_addr(int i) {
|
ProtectionDomainCacheEntry** bucket_addr(int i) {
|
||||||
return (ProtectionDomainCacheEntry**) Hashtable<oop, mtClass>::bucket_addr(i);
|
return (ProtectionDomainCacheEntry**) Hashtable<ClassLoaderWeakHandle, mtClass>::bucket_addr(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProtectionDomainCacheEntry* new_entry(unsigned int hash, Handle protection_domain) {
|
ProtectionDomainCacheEntry* new_entry(unsigned int hash, ClassLoaderWeakHandle protection_domain) {
|
||||||
ProtectionDomainCacheEntry* entry = (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::new_entry(hash, protection_domain());
|
ProtectionDomainCacheEntry* entry = (ProtectionDomainCacheEntry*)
|
||||||
|
Hashtable<ClassLoaderWeakHandle, mtClass>::new_entry(hash, protection_domain);
|
||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,10 +89,7 @@ public:
|
|||||||
ProtectionDomainCacheTable(int table_size);
|
ProtectionDomainCacheTable(int table_size);
|
||||||
ProtectionDomainCacheEntry* get(Handle protection_domain);
|
ProtectionDomainCacheEntry* get(Handle protection_domain);
|
||||||
|
|
||||||
void unlink(BoolObjectClosure* cl);
|
void unlink();
|
||||||
|
|
||||||
// GC support
|
|
||||||
void oops_do(OopClosure* f);
|
|
||||||
|
|
||||||
void print_on(outputStream* st) const;
|
void print_on(outputStream* st) const;
|
||||||
void verify();
|
void verify();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2005, 2018, 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,9 +125,8 @@ void ResolutionErrorTable::purge_resolution_errors() {
|
|||||||
assert(entry->pool() != (ConstantPool*)NULL, "resolution error table is corrupt");
|
assert(entry->pool() != (ConstantPool*)NULL, "resolution error table is corrupt");
|
||||||
ConstantPool* pool = entry->pool();
|
ConstantPool* pool = entry->pool();
|
||||||
assert(pool->pool_holder() != NULL, "Constant pool without a class?");
|
assert(pool->pool_holder() != NULL, "Constant pool without a class?");
|
||||||
ClassLoaderData* loader_data =
|
|
||||||
pool->pool_holder()->class_loader_data();
|
if (pool->pool_holder()->is_loader_alive()) {
|
||||||
if (!loader_data->is_unloading()) {
|
|
||||||
p = entry->next_addr();
|
p = entry->next_addr();
|
||||||
} else {
|
} else {
|
||||||
*p = entry->next();
|
*p = entry->next();
|
||||||
|
@ -1831,24 +1831,6 @@ void SystemDictionary::always_strong_oops_do(OopClosure* blk) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef ASSERT
|
|
||||||
class VerifySDReachableAndLiveClosure : public OopClosure {
|
|
||||||
private:
|
|
||||||
BoolObjectClosure* _is_alive;
|
|
||||||
|
|
||||||
template <class T> void do_oop_work(T* p) {
|
|
||||||
oop obj = RawAccess<>::oop_load(p);
|
|
||||||
guarantee(_is_alive->do_object_b(obj), "Oop in protection domain cache table must be live");
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
VerifySDReachableAndLiveClosure(BoolObjectClosure* is_alive) : OopClosure(), _is_alive(is_alive) { }
|
|
||||||
|
|
||||||
virtual void do_oop(oop* p) { do_oop_work(p); }
|
|
||||||
virtual void do_oop(narrowOop* p) { do_oop_work(p); }
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Assumes classes in the SystemDictionary are only unloaded at a safepoint
|
// Assumes classes in the SystemDictionary are only unloaded at a safepoint
|
||||||
// Note: anonymous classes are not in the SD.
|
// Note: anonymous classes are not in the SD.
|
||||||
bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive,
|
bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive,
|
||||||
@ -1865,8 +1847,7 @@ bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive,
|
|||||||
GCTraceTime(Debug, gc, phases) t("ClassLoaderData", gc_timer);
|
GCTraceTime(Debug, gc, phases) t("ClassLoaderData", gc_timer);
|
||||||
|
|
||||||
// First, mark for unload all ClassLoaderData referencing a dead class loader.
|
// First, mark for unload all ClassLoaderData referencing a dead class loader.
|
||||||
unloading_occurred = ClassLoaderDataGraph::do_unloading(is_alive,
|
unloading_occurred = ClassLoaderDataGraph::do_unloading(do_cleaning);
|
||||||
do_cleaning);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (unloading_occurred) {
|
if (unloading_occurred) {
|
||||||
@ -1880,17 +1861,12 @@ bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive,
|
|||||||
// Oops referenced by the protection domain cache table may get unreachable independently
|
// Oops referenced by the protection domain cache table may get unreachable independently
|
||||||
// of the class loader (eg. cached protection domain oops). So we need to
|
// of the class loader (eg. cached protection domain oops). So we need to
|
||||||
// explicitly unlink them here.
|
// explicitly unlink them here.
|
||||||
_pd_cache_table->unlink(is_alive);
|
_pd_cache_table->unlink();
|
||||||
|
|
||||||
#ifdef ASSERT
|
|
||||||
VerifySDReachableAndLiveClosure cl(is_alive);
|
|
||||||
_pd_cache_table->oops_do(&cl);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_cleaning) {
|
if (do_cleaning) {
|
||||||
GCTraceTime(Debug, gc, phases) t("ResolvedMethodTable", gc_timer);
|
GCTraceTime(Debug, gc, phases) t("ResolvedMethodTable", gc_timer);
|
||||||
ResolvedMethodTable::unlink(is_alive);
|
ResolvedMethodTable::unlink();
|
||||||
}
|
}
|
||||||
|
|
||||||
return unloading_occurred;
|
return unloading_occurred;
|
||||||
@ -1906,21 +1882,15 @@ void SystemDictionary::roots_oops_do(OopClosure* strong, OopClosure* weak) {
|
|||||||
if (strong == weak || !ClassUnloading) {
|
if (strong == weak || !ClassUnloading) {
|
||||||
// Only the protection domain oops contain references into the heap. Iterate
|
// Only the protection domain oops contain references into the heap. Iterate
|
||||||
// over all of them.
|
// over all of them.
|
||||||
_pd_cache_table->oops_do(strong);
|
|
||||||
vm_weak_oop_storage()->oops_do(strong);
|
vm_weak_oop_storage()->oops_do(strong);
|
||||||
} else {
|
} else {
|
||||||
if (weak != NULL) {
|
if (weak != NULL) {
|
||||||
_pd_cache_table->oops_do(weak);
|
|
||||||
vm_weak_oop_storage()->oops_do(weak);
|
vm_weak_oop_storage()->oops_do(weak);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visit extra methods
|
// Visit extra methods
|
||||||
invoke_method_table()->oops_do(strong);
|
invoke_method_table()->oops_do(strong);
|
||||||
|
|
||||||
if (weak != NULL) {
|
|
||||||
ResolvedMethodTable::oops_do(weak);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SystemDictionary::oops_do(OopClosure* f) {
|
void SystemDictionary::oops_do(OopClosure* f) {
|
||||||
@ -1929,15 +1899,9 @@ void SystemDictionary::oops_do(OopClosure* f) {
|
|||||||
f->do_oop(&_system_loader_lock_obj);
|
f->do_oop(&_system_loader_lock_obj);
|
||||||
CDS_ONLY(SystemDictionaryShared::oops_do(f);)
|
CDS_ONLY(SystemDictionaryShared::oops_do(f);)
|
||||||
|
|
||||||
// Only the protection domain oops contain references into the heap. Iterate
|
|
||||||
// over all of them.
|
|
||||||
_pd_cache_table->oops_do(f);
|
|
||||||
|
|
||||||
// Visit extra methods
|
// Visit extra methods
|
||||||
invoke_method_table()->oops_do(f);
|
invoke_method_table()->oops_do(f);
|
||||||
|
|
||||||
ResolvedMethodTable::oops_do(f);
|
|
||||||
|
|
||||||
vm_weak_oop_storage()->oops_do(f);
|
vm_weak_oop_storage()->oops_do(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,6 +357,14 @@ Handle SystemDictionaryShared::init_security_info(Handle class_loader, InstanceK
|
|||||||
return pd;
|
return pd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SystemDictionaryShared::is_sharing_possible(ClassLoaderData* loader_data) {
|
||||||
|
oop class_loader = loader_data->class_loader();
|
||||||
|
return (class_loader == NULL ||
|
||||||
|
(UseAppCDS && (SystemDictionary::is_system_class_loader(class_loader) ||
|
||||||
|
SystemDictionary::is_platform_class_loader(class_loader)))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Currently AppCDS only archives classes from the run-time image, the
|
// Currently AppCDS only archives classes from the run-time image, the
|
||||||
// -Xbootclasspath/a path, the class path, and the module path.
|
// -Xbootclasspath/a path, the class path, and the module path.
|
||||||
//
|
//
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2014, 2018, 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
|
||||||
@ -300,13 +300,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if sharing is supported for the class loader.
|
// Check if sharing is supported for the class loader.
|
||||||
static bool is_sharing_possible(ClassLoaderData* loader_data) {
|
static bool is_sharing_possible(ClassLoaderData* loader_data);
|
||||||
oop class_loader = loader_data->class_loader();
|
|
||||||
return (class_loader == NULL ||
|
|
||||||
(UseAppCDS && (SystemDictionary::is_system_class_loader(class_loader) ||
|
|
||||||
SystemDictionary::is_platform_class_loader(class_loader)))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
static bool is_shared_class_visible_for_classloader(InstanceKlass* ik,
|
static bool is_shared_class_visible_for_classloader(InstanceKlass* ik,
|
||||||
Handle class_loader,
|
Handle class_loader,
|
||||||
const char* pkg_string,
|
const char* pkg_string,
|
||||||
|
@ -613,16 +613,22 @@ void CodeHeapState::aggregate(outputStream* out, CodeHeap* heap, const char* gra
|
|||||||
//---< some sanity checks >---
|
//---< some sanity checks >---
|
||||||
// Do not assert here, just check, print error message and return.
|
// Do not assert here, just check, print error message and return.
|
||||||
// This is a diagnostic function. It is not supposed to tear down the VM.
|
// This is a diagnostic function. It is not supposed to tear down the VM.
|
||||||
if ((char*)h < low_bound ) {
|
if ((char*)h < low_bound) {
|
||||||
insane = true; ast->print_cr("Sanity check: HeapBlock @%p below low bound (%p)", (char*)h, low_bound);
|
insane = true; ast->print_cr("Sanity check: HeapBlock @%p below low bound (%p)", (char*)h, low_bound);
|
||||||
}
|
}
|
||||||
if (ix_end >= granules ) {
|
if ((char*)h > (low_bound + res_size)) {
|
||||||
|
insane = true; ast->print_cr("Sanity check: HeapBlock @%p outside reserved range (%p)", (char*)h, low_bound + res_size);
|
||||||
|
}
|
||||||
|
if ((char*)h > (low_bound + size)) {
|
||||||
|
insane = true; ast->print_cr("Sanity check: HeapBlock @%p outside used range (%p)", (char*)h, low_bound + size);
|
||||||
|
}
|
||||||
|
if (ix_end >= granules) {
|
||||||
insane = true; ast->print_cr("Sanity check: end index (%d) out of bounds (" SIZE_FORMAT ")", ix_end, granules);
|
insane = true; ast->print_cr("Sanity check: end index (%d) out of bounds (" SIZE_FORMAT ")", ix_end, granules);
|
||||||
}
|
}
|
||||||
if (size != heap->capacity()) {
|
if (size != heap->capacity()) {
|
||||||
insane = true; ast->print_cr("Sanity check: code heap capacity has changed (" SIZE_FORMAT "K to " SIZE_FORMAT "K)", size/(size_t)K, heap->capacity()/(size_t)K);
|
insane = true; ast->print_cr("Sanity check: code heap capacity has changed (" SIZE_FORMAT "K to " SIZE_FORMAT "K)", size/(size_t)K, heap->capacity()/(size_t)K);
|
||||||
}
|
}
|
||||||
if (ix_beg > ix_end ) {
|
if (ix_beg > ix_end) {
|
||||||
insane = true; ast->print_cr("Sanity check: end index (%d) lower than begin index (%d)", ix_end, ix_beg);
|
insane = true; ast->print_cr("Sanity check: end index (%d) lower than begin index (%d)", ix_end, ix_beg);
|
||||||
}
|
}
|
||||||
if (insane) {
|
if (insane) {
|
||||||
@ -988,6 +994,11 @@ void CodeHeapState::aggregate(outputStream* out, CodeHeap* heap, const char* gra
|
|||||||
ast->print_cr(" deadSpace = " SIZE_FORMAT_W(8) "k, nBlocks_dead = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", deadSpace/(size_t)K, nBlocks_dead, (100.0*deadSpace)/size, (100.0*deadSpace)/res_size);
|
ast->print_cr(" deadSpace = " SIZE_FORMAT_W(8) "k, nBlocks_dead = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", deadSpace/(size_t)K, nBlocks_dead, (100.0*deadSpace)/size, (100.0*deadSpace)/res_size);
|
||||||
ast->print_cr(" stubSpace = " SIZE_FORMAT_W(8) "k, nBlocks_stub = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", stubSpace/(size_t)K, nBlocks_stub, (100.0*stubSpace)/size, (100.0*stubSpace)/res_size);
|
ast->print_cr(" stubSpace = " SIZE_FORMAT_W(8) "k, nBlocks_stub = %6d, %10.3f%% of capacity, %10.3f%% of max_capacity", stubSpace/(size_t)K, nBlocks_stub, (100.0*stubSpace)/size, (100.0*stubSpace)/res_size);
|
||||||
ast->print_cr("ZombieBlocks = %8d. These are HeapBlocks which could not be identified as CodeBlobs.", nBlocks_zomb);
|
ast->print_cr("ZombieBlocks = %8d. These are HeapBlocks which could not be identified as CodeBlobs.", nBlocks_zomb);
|
||||||
|
ast->cr();
|
||||||
|
ast->print_cr("Segment start = " INTPTR_FORMAT ", used space = " SIZE_FORMAT_W(8)"k", p2i(low_bound), size/K);
|
||||||
|
ast->print_cr("Segment end (used) = " INTPTR_FORMAT ", remaining space = " SIZE_FORMAT_W(8)"k", p2i(low_bound) + size, (res_size - size)/K);
|
||||||
|
ast->print_cr("Segment end (reserved) = " INTPTR_FORMAT ", reserved space = " SIZE_FORMAT_W(8)"k", p2i(low_bound) + res_size, res_size/K);
|
||||||
|
ast->cr();
|
||||||
ast->print_cr("latest allocated compilation id = %d", latest_compilation_id);
|
ast->print_cr("latest allocated compilation id = %d", latest_compilation_id);
|
||||||
ast->print_cr("highest observed compilation id = %d", highest_compilation_id);
|
ast->print_cr("highest observed compilation id = %d", highest_compilation_id);
|
||||||
ast->print_cr("Building TopSizeList iterations = %ld", total_iterations);
|
ast->print_cr("Building TopSizeList iterations = %ld", total_iterations);
|
||||||
@ -1218,14 +1229,14 @@ void CodeHeapState::print_usedSpace(outputStream* out, CodeHeap* heap) {
|
|||||||
blob_name = this_blob->name();
|
blob_name = this_blob->name();
|
||||||
nm = this_blob->as_nmethod_or_null();
|
nm = this_blob->as_nmethod_or_null();
|
||||||
//---< blob address >---
|
//---< blob address >---
|
||||||
ast->print("%p", this_blob);
|
ast->print(INTPTR_FORMAT, p2i(this_blob));
|
||||||
ast->fill_to(19);
|
ast->fill_to(19);
|
||||||
//---< blob offset from CodeHeap begin >---
|
//---< blob offset from CodeHeap begin >---
|
||||||
ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)this_blob-low_bound));
|
ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)this_blob-low_bound));
|
||||||
ast->fill_to(33);
|
ast->fill_to(33);
|
||||||
} else {
|
} else {
|
||||||
//---< block address >---
|
//---< block address >---
|
||||||
ast->print("%p", TopSizeArray[i].start);
|
ast->print(INTPTR_FORMAT, p2i(TopSizeArray[i].start));
|
||||||
ast->fill_to(19);
|
ast->fill_to(19);
|
||||||
//---< block offset from CodeHeap begin >---
|
//---< block offset from CodeHeap begin >---
|
||||||
ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)TopSizeArray[i].start-low_bound));
|
ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)TopSizeArray[i].start-low_bound));
|
||||||
@ -1404,7 +1415,7 @@ void CodeHeapState::print_freeSpace(outputStream* out, CodeHeap* heap) {
|
|||||||
|
|
||||||
unsigned int ix = 0;
|
unsigned int ix = 0;
|
||||||
for (ix = 0; ix < alloc_freeBlocks-1; ix++) {
|
for (ix = 0; ix < alloc_freeBlocks-1; ix++) {
|
||||||
ast->print("%p: Len[%4d] = " HEX32_FORMAT ",", FreeArray[ix].start, ix, FreeArray[ix].len);
|
ast->print(INTPTR_FORMAT ": Len[%4d] = " HEX32_FORMAT ",", p2i(FreeArray[ix].start), ix, FreeArray[ix].len);
|
||||||
ast->fill_to(38);
|
ast->fill_to(38);
|
||||||
ast->print("Gap[%4d..%4d]: " HEX32_FORMAT " bytes,", ix, ix+1, FreeArray[ix].gap);
|
ast->print("Gap[%4d..%4d]: " HEX32_FORMAT " bytes,", ix, ix+1, FreeArray[ix].gap);
|
||||||
ast->fill_to(71);
|
ast->fill_to(71);
|
||||||
@ -1414,7 +1425,7 @@ void CodeHeapState::print_freeSpace(outputStream* out, CodeHeap* heap) {
|
|||||||
}
|
}
|
||||||
STRINGSTREAM_FLUSH_LOCKED("\n")
|
STRINGSTREAM_FLUSH_LOCKED("\n")
|
||||||
}
|
}
|
||||||
ast->print_cr("%p: Len[%4d] = " HEX32_FORMAT, FreeArray[ix].start, ix, FreeArray[ix].len);
|
ast->print_cr(INTPTR_FORMAT ": Len[%4d] = " HEX32_FORMAT, p2i(FreeArray[ix].start), ix, FreeArray[ix].len);
|
||||||
STRINGSTREAM_FLUSH_LOCKED("\n\n")
|
STRINGSTREAM_FLUSH_LOCKED("\n\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2039,10 +2050,16 @@ void CodeHeapState::print_age(outputStream* out, CodeHeap* heap) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define JDK8200450_REMEDY
|
||||||
|
#define JDK8200450_TRACE
|
||||||
void CodeHeapState::print_names(outputStream* out, CodeHeap* heap) {
|
void CodeHeapState::print_names(outputStream* out, CodeHeap* heap) {
|
||||||
if (!initialization_complete) {
|
if (!initialization_complete) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#ifdef JDK8200450_TRACE
|
||||||
|
out->print_cr("print_names() entered for heap @ " INTPTR_FORMAT, p2i(heap));
|
||||||
|
out->flush();
|
||||||
|
#endif
|
||||||
|
|
||||||
const char* heapName = get_heapName(heap);
|
const char* heapName = get_heapName(heap);
|
||||||
get_HeapStatGlobals(out, heapName);
|
get_HeapStatGlobals(out, heapName);
|
||||||
@ -2057,7 +2074,7 @@ void CodeHeapState::print_names(outputStream* out, CodeHeap* heap) {
|
|||||||
CodeBlob* last_blob = NULL;
|
CodeBlob* last_blob = NULL;
|
||||||
bool name_in_addr_range = true;
|
bool name_in_addr_range = true;
|
||||||
|
|
||||||
//---< print at least 128K per block >---
|
//---< print at least 128K per block (i.e. between headers) >---
|
||||||
if (granules_per_line*granule_size < 128*K) {
|
if (granules_per_line*granule_size < 128*K) {
|
||||||
granules_per_line = (unsigned int)((128*K)/granule_size);
|
granules_per_line = (unsigned int)((128*K)/granule_size);
|
||||||
}
|
}
|
||||||
@ -2067,7 +2084,7 @@ void CodeHeapState::print_names(outputStream* out, CodeHeap* heap) {
|
|||||||
" Due to the living nature of the code heap and because the CodeCache_lock\n"
|
" Due to the living nature of the code heap and because the CodeCache_lock\n"
|
||||||
" is not continuously held, the displayed name might be wrong or no name\n"
|
" is not continuously held, the displayed name might be wrong or no name\n"
|
||||||
" might be found at all. The likelihood for that to happen increases\n"
|
" might be found at all. The likelihood for that to happen increases\n"
|
||||||
" over time passed between analysis and print step.\n");
|
" over time passed between aggregtion and print steps.\n");
|
||||||
STRINGSTREAM_FLUSH_LOCKED("")
|
STRINGSTREAM_FLUSH_LOCKED("")
|
||||||
|
|
||||||
for (unsigned int ix = 0; ix < alloc_granules; ix++) {
|
for (unsigned int ix = 0; ix < alloc_granules; ix++) {
|
||||||
@ -2078,23 +2095,69 @@ void CodeHeapState::print_names(outputStream* out, CodeHeap* heap) {
|
|||||||
}
|
}
|
||||||
name_in_addr_range = false;
|
name_in_addr_range = false;
|
||||||
|
|
||||||
|
size_t end_ix = (ix+granules_per_line <= alloc_granules) ? ix+granules_per_line : alloc_granules;
|
||||||
ast->cr();
|
ast->cr();
|
||||||
ast->print_cr("--------------------------------------------------------------------");
|
ast->print_cr("--------------------------------------------------------------------");
|
||||||
ast->print_cr("Address range [%p,%p), " SIZE_FORMAT "k", low_bound+ix*granule_size, low_bound+(ix+granules_per_line)*granule_size, granules_per_line*granule_size/(size_t)K);
|
ast->print_cr("Address range [" INTPTR_FORMAT "," INTPTR_FORMAT "), " SIZE_FORMAT "k", p2i(low_bound+ix*granule_size), p2i(low_bound + end_ix*granule_size), (end_ix - ix)*granule_size/(size_t)K);
|
||||||
ast->print_cr("--------------------------------------------------------------------");
|
ast->print_cr("--------------------------------------------------------------------");
|
||||||
STRINGSTREAM_FLUSH_LOCKED("")
|
STRINGSTREAM_FLUSH_LOCKED("")
|
||||||
}
|
}
|
||||||
// Only check granule if it contains at least one blob.
|
// Only check granule if it contains at least one blob.
|
||||||
unsigned int nBlobs = StatArray[ix].t1_count + StatArray[ix].t2_count + StatArray[ix].tx_count +
|
unsigned int nBlobs = StatArray[ix].t1_count + StatArray[ix].t2_count + StatArray[ix].tx_count +
|
||||||
StatArray[ix].stub_count + StatArray[ix].dead_count;
|
StatArray[ix].stub_count + StatArray[ix].dead_count;
|
||||||
if (nBlobs > 0 ) {
|
#ifdef JDK8200450_REMEDY
|
||||||
|
if (nBlobs > 0 )
|
||||||
|
#endif
|
||||||
|
{
|
||||||
for (unsigned int is = 0; is < granule_size; is+=(unsigned int)seg_size) {
|
for (unsigned int is = 0; is < granule_size; is+=(unsigned int)seg_size) {
|
||||||
// heap->find_start() is safe. Only working with _segmap. Returns NULL or void*. Returned CodeBlob may be uninitialized.
|
// heap->find_start() is safe. Only working with _segmap. Returns NULL or void*. Returned CodeBlob may be uninitialized.
|
||||||
CodeBlob* this_blob = (CodeBlob *)(heap->find_start(low_bound+ix*granule_size+is));
|
CodeBlob* this_blob = (CodeBlob *)(heap->find_start(low_bound+ix*granule_size+is));
|
||||||
bool blob_initialized = (this_blob != NULL) &&
|
#ifndef JDK8200450_REMEDY
|
||||||
((char*)this_blob + this_blob->header_size() == (char*)(this_blob->relocation_begin())) &&
|
bool blob_initialized = (this_blob != NULL)
|
||||||
((char*)this_blob + CodeBlob::align_code_offset(this_blob->header_size() + this_blob->relocation_size()) == (char*)(this_blob->content_begin()));
|
#else
|
||||||
|
#ifndef JDK8200450_TRACE
|
||||||
|
bool blob_initialized = (this_blob != NULL) && (this_blob->header_size() >= 0) && (this_blob->relocation_size() >= 0) &&
|
||||||
|
((address)this_blob + this_blob->header_size() == (address)(this_blob->relocation_begin())) &&
|
||||||
|
((address)this_blob + CodeBlob::align_code_offset(this_blob->header_size() + this_blob->relocation_size()) == (address)(this_blob->content_begin()) &&
|
||||||
|
is_readable_pointer((address)(this_blob->relocation_begin()) &&
|
||||||
|
is_readable_pointer(this_blob->content_begin());
|
||||||
|
#else
|
||||||
|
int hdr_size = 0;
|
||||||
|
int reloc_size = 0;
|
||||||
|
address reloc_begin = NULL;
|
||||||
|
address cntnt_begin = NULL;
|
||||||
|
if (this_blob != NULL) {
|
||||||
|
hdr_size = this_blob->header_size();
|
||||||
|
reloc_size = this_blob->relocation_size();
|
||||||
|
reloc_begin = (address)(this_blob->relocation_begin());
|
||||||
|
cntnt_begin = this_blob->content_begin();
|
||||||
|
}
|
||||||
|
bool blob_initialized = (this_blob != NULL) && (hdr_size >= 0) && (reloc_size >= 0) &&
|
||||||
|
((address)this_blob + hdr_size == reloc_begin) &&
|
||||||
|
((address)this_blob + CodeBlob::align_code_offset(hdr_size + reloc_size) == cntnt_begin) &&
|
||||||
|
is_readable_pointer(reloc_begin) &&
|
||||||
|
is_readable_pointer(cntnt_begin);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
if (blob_initialized && (this_blob != last_blob)) {
|
if (blob_initialized && (this_blob != last_blob)) {
|
||||||
|
last_blob = this_blob;
|
||||||
|
|
||||||
|
//---< get type and name >---
|
||||||
|
blobType cbType = noType;
|
||||||
|
if (segment_granules) {
|
||||||
|
cbType = (blobType)StatArray[ix].type;
|
||||||
|
} else {
|
||||||
|
cbType = get_cbType(this_blob); // Is this here safe?
|
||||||
|
}
|
||||||
|
// this_blob->name() could return NULL if no name is given to CTOR. Inlined, maybe invisible on stack
|
||||||
|
const char* blob_name = this_blob->name();
|
||||||
|
#ifdef JDK8200450_REMEDY
|
||||||
|
if (blob_name == NULL) {
|
||||||
|
blob_name = "<unavailable>";
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//---< print table header for new print range >---
|
||||||
if (!name_in_addr_range) {
|
if (!name_in_addr_range) {
|
||||||
name_in_addr_range = true;
|
name_in_addr_range = true;
|
||||||
ast->fill_to(51);
|
ast->fill_to(51);
|
||||||
@ -2102,32 +2165,34 @@ void CodeHeapState::print_names(outputStream* out, CodeHeap* heap) {
|
|||||||
ast->fill_to(61);
|
ast->fill_to(61);
|
||||||
ast->print_cr("%6s", "method");
|
ast->print_cr("%6s", "method");
|
||||||
ast->print_cr("%18s %13s %17s %9s %5s %18s %s", "Addr(module) ", "offset", "size", " type lvl", " temp", "blobType ", "Name");
|
ast->print_cr("%18s %13s %17s %9s %5s %18s %s", "Addr(module) ", "offset", "size", " type lvl", " temp", "blobType ", "Name");
|
||||||
|
STRINGSTREAM_FLUSH_LOCKED("")
|
||||||
}
|
}
|
||||||
|
|
||||||
//---< Print blobTypeName as recorded during analysis >---
|
//---< print line prefix (address and offset from CodeHeap start) >---
|
||||||
ast->print("%p", this_blob);
|
ast->print(INTPTR_FORMAT, p2i(this_blob));
|
||||||
ast->fill_to(19);
|
ast->fill_to(19);
|
||||||
ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)this_blob-low_bound));
|
ast->print("(+" PTR32_FORMAT ")", (unsigned int)((char*)this_blob-low_bound));
|
||||||
ast->fill_to(33);
|
ast->fill_to(33);
|
||||||
|
|
||||||
//---< print size, name, and signature (for nMethods) >---
|
#ifdef JDK8200450_TRACE
|
||||||
// this_blob->name() could return NULL if no name is given to CTOR. Inlined, maybe not visible on stack
|
STRINGSTREAM_FLUSH_LOCKED("") // Remove before push!!!
|
||||||
const char* blob_name = this_blob->name();
|
#endif
|
||||||
if (blob_name == 0) {
|
|
||||||
blob_name = "<unavailable>";
|
// this_blob->as_nmethod_or_null() is safe. Inlined, maybe invisible on stack.
|
||||||
}
|
nmethod* nm = this_blob->as_nmethod_or_null();
|
||||||
// this_blob->as_nmethod_or_null() is safe. Inlined, maybe not visible on stack.
|
Method* method = (nm == NULL) ? NULL : nm->method(); // may be uninitialized, i.e. != NULL, but invalid
|
||||||
nmethod* nm = this_blob->as_nmethod_or_null();
|
#ifdef JDK8200450_REMEDY
|
||||||
blobType cbType = noType;
|
if ((nm != NULL) && (method != NULL) && is_readable_pointer(method) && is_readable_pointer(method->constants())) {
|
||||||
if (segment_granules) {
|
#else
|
||||||
cbType = (blobType)StatArray[ix].type;
|
if ((nm != NULL) && (method != NULL)) {
|
||||||
} else {
|
#endif
|
||||||
cbType = get_cbType(this_blob);
|
|
||||||
}
|
|
||||||
if ((nm != NULL) && (nm->method() != NULL)) {
|
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
//---< nMethod size in hex >---
|
//---< collect all data to locals as quickly as possible >---
|
||||||
unsigned int total_size = nm->total_size();
|
unsigned int total_size = nm->total_size();
|
||||||
|
int hotness = nm->hotness_counter();
|
||||||
|
bool nm_zombie = nm->is_zombie();
|
||||||
|
bool get_name = nm->is_in_use() || nm->is_not_entrant();
|
||||||
|
//---< nMethod size in hex >---
|
||||||
ast->print(PTR32_FORMAT, total_size);
|
ast->print(PTR32_FORMAT, total_size);
|
||||||
ast->print("(" SIZE_FORMAT_W(4) "K)", total_size/K);
|
ast->print("(" SIZE_FORMAT_W(4) "K)", total_size/K);
|
||||||
//---< compiler information >---
|
//---< compiler information >---
|
||||||
@ -2135,21 +2200,36 @@ void CodeHeapState::print_names(outputStream* out, CodeHeap* heap) {
|
|||||||
ast->print("%5s %3d", compTypeName[StatArray[ix].compiler], StatArray[ix].level);
|
ast->print("%5s %3d", compTypeName[StatArray[ix].compiler], StatArray[ix].level);
|
||||||
//---< method temperature >---
|
//---< method temperature >---
|
||||||
ast->fill_to(62);
|
ast->fill_to(62);
|
||||||
ast->print("%5d", nm->hotness_counter());
|
ast->print("%5d", hotness);
|
||||||
//---< name and signature >---
|
//---< name and signature >---
|
||||||
ast->fill_to(62+6);
|
ast->fill_to(62+6);
|
||||||
ast->print("%s", blobTypeName[cbType]);
|
ast->print("%s", blobTypeName[cbType]);
|
||||||
ast->fill_to(82+6);
|
ast->fill_to(82+6);
|
||||||
if (nm->is_in_use()) {
|
if (nm_zombie) {
|
||||||
blob_name = nm->method()->name_and_sig_as_C_string();
|
|
||||||
}
|
|
||||||
if (nm->is_not_entrant()) {
|
|
||||||
blob_name = nm->method()->name_and_sig_as_C_string();
|
|
||||||
}
|
|
||||||
if (nm->is_zombie()) {
|
|
||||||
ast->print("%14s", " zombie method");
|
ast->print("%14s", " zombie method");
|
||||||
}
|
}
|
||||||
ast->print("%s", blob_name);
|
|
||||||
|
#ifdef JDK8200450_TRACE
|
||||||
|
STRINGSTREAM_FLUSH_LOCKED("") // Remove before push!!!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (get_name) {
|
||||||
|
#ifdef JDK8200450_REMEDY
|
||||||
|
Symbol* methName = method->name();
|
||||||
|
const char* methNameS = (methName == NULL) ? NULL : methName->as_C_string();
|
||||||
|
methNameS = (methNameS == NULL) ? "<method name unavailable>" : methNameS;
|
||||||
|
Symbol* methSig = method->signature();
|
||||||
|
const char* methSigS = (methSig == NULL) ? NULL : methSig->as_C_string();
|
||||||
|
methSigS = (methSigS == NULL) ? "<method signature unavailable>" : methSigS;
|
||||||
|
ast->print("%s", methNameS);
|
||||||
|
ast->print("%s", methSigS);
|
||||||
|
#else
|
||||||
|
blob_name = method->name_and_sig_as_C_string();
|
||||||
|
ast->print("%s", blob_name);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
ast->print("%s", blob_name);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ast->fill_to(62+6);
|
ast->fill_to(62+6);
|
||||||
ast->print("%s", blobTypeName[cbType]);
|
ast->print("%s", blobTypeName[cbType]);
|
||||||
@ -2157,12 +2237,48 @@ void CodeHeapState::print_names(outputStream* out, CodeHeap* heap) {
|
|||||||
ast->print("%s", blob_name);
|
ast->print("%s", blob_name);
|
||||||
}
|
}
|
||||||
STRINGSTREAM_FLUSH_LOCKED("\n")
|
STRINGSTREAM_FLUSH_LOCKED("\n")
|
||||||
|
#ifdef JDK8200450_TRACE
|
||||||
|
if ((nm != NULL) && (method != NULL) && !(is_readable_pointer(method) && is_readable_pointer(method->constants()))) {
|
||||||
|
ast->print("Potential CodeHeap State Analytics issue found.\n");
|
||||||
|
if (is_readable_pointer(method)) {
|
||||||
|
ast->print(" Issue would have been detected by is_readable_pointer(" INTPTR_FORMAT "(method->constants())) check.\n", p2i(method->constants()));
|
||||||
|
} else {
|
||||||
|
ast->print(" Issue would have been detected by is_readable_pointer(" INTPTR_FORMAT "(method)) check.\n", p2i(method));
|
||||||
|
}
|
||||||
|
STRINGSTREAM_FLUSH_LOCKED("\n")
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else if (!blob_initialized && (this_blob != last_blob) && (this_blob != NULL)) {
|
||||||
last_blob = this_blob;
|
last_blob = this_blob;
|
||||||
} else if (!blob_initialized && (this_blob != NULL)) {
|
#ifdef JDK8200450_TRACE
|
||||||
last_blob = this_blob;
|
ast->print("Potential CodeHeap State Analytics issue found.\n");
|
||||||
|
if (nBlobs == 0) {
|
||||||
|
ast->print(" Issue would have been detected by (nBlobs > 0) check.\n");
|
||||||
|
} else {
|
||||||
|
if (!((address)this_blob + hdr_size == reloc_begin)) {
|
||||||
|
ast->print(" Issue would have been detected by (this(" INTPTR_FORMAT ") + header(%d) == relocation_begin(" INTPTR_FORMAT ")) check.\n", p2i(this_blob), hdr_size, p2i(reloc_begin));
|
||||||
|
}
|
||||||
|
if (!((address)this_blob + CodeBlob::align_code_offset(hdr_size + reloc_size) == cntnt_begin)) {
|
||||||
|
ast->print(" Issue would have been detected by (this(" INTPTR_FORMAT ") + header(%d) + relocation(%d) == content_begin(" INTPTR_FORMAT ")) check.\n", p2i(this_blob), hdr_size, reloc_size, p2i(cntnt_begin));
|
||||||
|
}
|
||||||
|
if (hdr_size != this_blob->header_size()) {
|
||||||
|
ast->print(" header_size meanwhile changed from %d to %d\n", hdr_size, this_blob->header_size());
|
||||||
|
}
|
||||||
|
if (reloc_size != this_blob->relocation_size()) {
|
||||||
|
ast->print(" relocation_size meanwhile changed from %d to %d\n", reloc_size, this_blob->relocation_size());
|
||||||
|
}
|
||||||
|
if (reloc_begin != (address)(this_blob->relocation_begin())) {
|
||||||
|
ast->print(" relocation_begin meanwhile changed from " INTPTR_FORMAT " to " INTPTR_FORMAT "\n", p2i(reloc_begin), p2i(this_blob->relocation_begin()));
|
||||||
|
}
|
||||||
|
if (cntnt_begin != this_blob->content_begin()) {
|
||||||
|
ast->print(" relocation_begin meanwhile changed from " INTPTR_FORMAT " to " INTPTR_FORMAT "\n", p2i(cntnt_begin), p2i(this_blob->content_begin()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
STRINGSTREAM_FLUSH_LOCKED("\n")
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} // nBlobs > 0
|
||||||
}
|
}
|
||||||
STRINGSTREAM_FLUSH_LOCKED("\n\n")
|
STRINGSTREAM_FLUSH_LOCKED("\n\n")
|
||||||
}
|
}
|
||||||
@ -2287,7 +2403,7 @@ void CodeHeapState::print_line_delim(outputStream* out, outputStream* ast, char*
|
|||||||
ast->cr();
|
ast->cr();
|
||||||
assert(out == ast, "must use the same stream!");
|
assert(out == ast, "must use the same stream!");
|
||||||
|
|
||||||
ast->print("%p", low_bound + ix*granule_size);
|
ast->print(INTPTR_FORMAT, p2i(low_bound + ix*granule_size));
|
||||||
ast->fill_to(19);
|
ast->fill_to(19);
|
||||||
ast->print("(+" PTR32_FORMAT "): |", (unsigned int)(ix*granule_size));
|
ast->print("(+" PTR32_FORMAT "): |", (unsigned int)(ix*granule_size));
|
||||||
}
|
}
|
||||||
@ -2307,7 +2423,7 @@ void CodeHeapState::print_line_delim(outputStream* out, bufferedStream* ast, cha
|
|||||||
ast->reset();
|
ast->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
ast->print("%p", low_bound + ix*granule_size);
|
ast->print(INTPTR_FORMAT, p2i(low_bound + ix*granule_size));
|
||||||
ast->fill_to(19);
|
ast->fill_to(19);
|
||||||
ast->print("(+" PTR32_FORMAT "): |", (unsigned int)(ix*granule_size));
|
ast->print("(+" PTR32_FORMAT "): |", (unsigned int)(ix*granule_size));
|
||||||
}
|
}
|
||||||
@ -2336,3 +2452,17 @@ CodeHeapState::blobType CodeHeapState::get_cbType(CodeBlob* cb) {
|
|||||||
}
|
}
|
||||||
return noType;
|
return noType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if pointer can be read from (4-byte read access).
|
||||||
|
// Helps to prove validity of a not-NULL pointer.
|
||||||
|
// Returns true in very early stages of VM life when stub is not yet generated.
|
||||||
|
#define SAFEFETCH_DEFAULT true
|
||||||
|
bool CodeHeapState::is_readable_pointer(const void* p) {
|
||||||
|
if (!CanUseSafeFetch32()) {
|
||||||
|
return SAFEFETCH_DEFAULT;
|
||||||
|
}
|
||||||
|
int* const aligned = (int*) align_down((intptr_t)p, 4);
|
||||||
|
int cafebabe = 0xcafebabe; // tester value 1
|
||||||
|
int deadbeef = 0xdeadbeef; // tester value 2
|
||||||
|
return (SafeFetch32(aligned, cafebabe) != cafebabe) || (SafeFetch32(aligned, deadbeef) != deadbeef);
|
||||||
|
}
|
||||||
|
@ -93,6 +93,7 @@ class CodeHeapState : public CHeapObj<mtCode> {
|
|||||||
static void print_line_delim(outputStream* out, bufferedStream *sst, char* low_bound, unsigned int ix, unsigned int gpl);
|
static void print_line_delim(outputStream* out, bufferedStream *sst, char* low_bound, unsigned int ix, unsigned int gpl);
|
||||||
static void print_line_delim(outputStream* out, outputStream *sst, char* low_bound, unsigned int ix, unsigned int gpl);
|
static void print_line_delim(outputStream* out, outputStream *sst, char* low_bound, unsigned int ix, unsigned int gpl);
|
||||||
static blobType get_cbType(CodeBlob* cb);
|
static blobType get_cbType(CodeBlob* cb);
|
||||||
|
static bool is_readable_pointer(const void* p);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void discard(outputStream* out, CodeHeap* heap);
|
static void discard(outputStream* out, CodeHeap* heap);
|
||||||
|
@ -99,7 +99,7 @@ void CompiledMethod::add_exception_cache_entry(ExceptionCache* new_entry) {
|
|||||||
release_set_exception_cache(new_entry);
|
release_set_exception_cache(new_entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompiledMethod::clean_exception_cache(BoolObjectClosure* is_alive) {
|
void CompiledMethod::clean_exception_cache() {
|
||||||
ExceptionCache* prev = NULL;
|
ExceptionCache* prev = NULL;
|
||||||
ExceptionCache* curr = exception_cache();
|
ExceptionCache* curr = exception_cache();
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ void CompiledMethod::clean_exception_cache(BoolObjectClosure* is_alive) {
|
|||||||
ExceptionCache* next = curr->next();
|
ExceptionCache* next = curr->next();
|
||||||
|
|
||||||
Klass* ex_klass = curr->exception_type();
|
Klass* ex_klass = curr->exception_type();
|
||||||
if (ex_klass != NULL && !ex_klass->is_loader_alive(is_alive)) {
|
if (ex_klass != NULL && !ex_klass->is_loader_alive()) {
|
||||||
if (prev == NULL) {
|
if (prev == NULL) {
|
||||||
set_exception_cache(next);
|
set_exception_cache(next);
|
||||||
} else {
|
} else {
|
||||||
@ -369,56 +369,42 @@ void CompiledMethod::clear_ic_stubs() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
|
// Check class_loader is alive for this bit of metadata.
|
||||||
class CheckClass : AllStatic {
|
static void check_class(Metadata* md) {
|
||||||
static BoolObjectClosure* _is_alive;
|
Klass* klass = NULL;
|
||||||
|
if (md->is_klass()) {
|
||||||
// Check class_loader is alive for this bit of metadata.
|
klass = ((Klass*)md);
|
||||||
static void check_class(Metadata* md) {
|
} else if (md->is_method()) {
|
||||||
Klass* klass = NULL;
|
klass = ((Method*)md)->method_holder();
|
||||||
if (md->is_klass()) {
|
} else if (md->is_methodData()) {
|
||||||
klass = ((Klass*)md);
|
klass = ((MethodData*)md)->method()->method_holder();
|
||||||
} else if (md->is_method()) {
|
} else {
|
||||||
klass = ((Method*)md)->method_holder();
|
md->print();
|
||||||
} else if (md->is_methodData()) {
|
ShouldNotReachHere();
|
||||||
klass = ((MethodData*)md)->method()->method_holder();
|
}
|
||||||
} else {
|
assert(klass->is_loader_alive(), "must be alive");
|
||||||
md->print();
|
}
|
||||||
ShouldNotReachHere();
|
|
||||||
}
|
|
||||||
assert(klass->is_loader_alive(_is_alive), "must be alive");
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
static void do_check_class(BoolObjectClosure* is_alive, CompiledMethod* nm) {
|
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "this is only ok at safepoint");
|
|
||||||
_is_alive = is_alive;
|
|
||||||
nm->metadata_do(check_class);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is called during a safepoint so can use static data
|
|
||||||
BoolObjectClosure* CheckClass::_is_alive = NULL;
|
|
||||||
#endif // ASSERT
|
#endif // ASSERT
|
||||||
|
|
||||||
|
|
||||||
void CompiledMethod::clean_ic_if_metadata_is_dead(CompiledIC *ic, BoolObjectClosure *is_alive) {
|
void CompiledMethod::clean_ic_if_metadata_is_dead(CompiledIC *ic) {
|
||||||
if (ic->is_icholder_call()) {
|
if (ic->is_icholder_call()) {
|
||||||
// The only exception is compiledICHolder oops which may
|
// The only exception is compiledICHolder oops which may
|
||||||
// yet be marked below. (We check this further below).
|
// yet be marked below. (We check this further below).
|
||||||
CompiledICHolder* cichk_oop = ic->cached_icholder();
|
CompiledICHolder* cichk_oop = ic->cached_icholder();
|
||||||
|
|
||||||
if (cichk_oop->is_loader_alive(is_alive)) {
|
if (cichk_oop->is_loader_alive()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Metadata* ic_oop = ic->cached_metadata();
|
Metadata* ic_oop = ic->cached_metadata();
|
||||||
if (ic_oop != NULL) {
|
if (ic_oop != NULL) {
|
||||||
if (ic_oop->is_klass()) {
|
if (ic_oop->is_klass()) {
|
||||||
if (((Klass*)ic_oop)->is_loader_alive(is_alive)) {
|
if (((Klass*)ic_oop)->is_loader_alive()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (ic_oop->is_method()) {
|
} else if (ic_oop->is_method()) {
|
||||||
if (((Method*)ic_oop)->method_holder()->is_loader_alive(is_alive)) {
|
if (((Method*)ic_oop)->method_holder()->is_loader_alive()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -453,7 +439,7 @@ unsigned char CompiledMethod::unloading_clock() {
|
|||||||
// all strong references alive. Any weak references should have been
|
// all strong references alive. Any weak references should have been
|
||||||
// cleared as well. Visit all the metadata and ensure that it's
|
// cleared as well. Visit all the metadata and ensure that it's
|
||||||
// really alive.
|
// really alive.
|
||||||
void CompiledMethod::verify_metadata_loaders(address low_boundary, BoolObjectClosure* is_alive) {
|
void CompiledMethod::verify_metadata_loaders(address low_boundary) {
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
RelocIterator iter(this, low_boundary);
|
RelocIterator iter(this, low_boundary);
|
||||||
while (iter.next()) {
|
while (iter.next()) {
|
||||||
@ -483,7 +469,7 @@ void CompiledMethod::verify_metadata_loaders(address low_boundary, BoolObjectClo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check that the metadata embedded in the nmethod is alive
|
// Check that the metadata embedded in the nmethod is alive
|
||||||
CheckClass::do_check_class(is_alive, this);
|
metadata_do(check_class);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -518,7 +504,7 @@ void CompiledMethod::do_unloading(BoolObjectClosure* is_alive, bool unloading_oc
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Exception cache
|
// Exception cache
|
||||||
clean_exception_cache(is_alive);
|
clean_exception_cache();
|
||||||
|
|
||||||
// If class unloading occurred we first iterate over all inline caches and
|
// If class unloading occurred we first iterate over all inline caches and
|
||||||
// clear ICs where the cached oop is referring to an unloaded klass or method.
|
// clear ICs where the cached oop is referring to an unloaded klass or method.
|
||||||
@ -529,7 +515,7 @@ void CompiledMethod::do_unloading(BoolObjectClosure* is_alive, bool unloading_oc
|
|||||||
while(iter.next()) {
|
while(iter.next()) {
|
||||||
if (iter.type() == relocInfo::virtual_call_type) {
|
if (iter.type() == relocInfo::virtual_call_type) {
|
||||||
CompiledIC *ic = CompiledIC_at(&iter);
|
CompiledIC *ic = CompiledIC_at(&iter);
|
||||||
clean_ic_if_metadata_is_dead(ic, is_alive);
|
clean_ic_if_metadata_is_dead(ic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -545,7 +531,7 @@ void CompiledMethod::do_unloading(BoolObjectClosure* is_alive, bool unloading_oc
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Ensure that all metadata is still alive
|
// Ensure that all metadata is still alive
|
||||||
verify_metadata_loaders(low_boundary, is_alive);
|
verify_metadata_loaders(low_boundary);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class CompiledICorStaticCall>
|
template <class CompiledICorStaticCall>
|
||||||
@ -606,7 +592,7 @@ bool CompiledMethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unl
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Exception cache
|
// Exception cache
|
||||||
clean_exception_cache(is_alive);
|
clean_exception_cache();
|
||||||
|
|
||||||
bool postponed = false;
|
bool postponed = false;
|
||||||
|
|
||||||
@ -619,7 +605,7 @@ bool CompiledMethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unl
|
|||||||
if (unloading_occurred) {
|
if (unloading_occurred) {
|
||||||
// If class unloading occurred we first iterate over all inline caches and
|
// If class unloading occurred we first iterate over all inline caches and
|
||||||
// clear ICs where the cached oop is referring to an unloaded klass or method.
|
// clear ICs where the cached oop is referring to an unloaded klass or method.
|
||||||
clean_ic_if_metadata_is_dead(CompiledIC_at(&iter), is_alive);
|
clean_ic_if_metadata_is_dead(CompiledIC_at(&iter));
|
||||||
}
|
}
|
||||||
|
|
||||||
postponed |= clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), is_alive, this);
|
postponed |= clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), is_alive, this);
|
||||||
@ -656,7 +642,7 @@ bool CompiledMethod::do_unloading_parallel(BoolObjectClosure* is_alive, bool unl
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Ensure that all metadata is still alive
|
// Ensure that all metadata is still alive
|
||||||
verify_metadata_loaders(low_boundary, is_alive);
|
verify_metadata_loaders(low_boundary);
|
||||||
|
|
||||||
return postponed;
|
return postponed;
|
||||||
}
|
}
|
||||||
|
@ -295,7 +295,7 @@ public:
|
|||||||
void release_set_exception_cache(ExceptionCache *ec);
|
void release_set_exception_cache(ExceptionCache *ec);
|
||||||
address handler_for_exception_and_pc(Handle exception, address pc);
|
address handler_for_exception_and_pc(Handle exception, address pc);
|
||||||
void add_handler_for_exception_and_pc(Handle exception, address pc, address handler);
|
void add_handler_for_exception_and_pc(Handle exception, address pc, address handler);
|
||||||
void clean_exception_cache(BoolObjectClosure* is_alive);
|
void clean_exception_cache();
|
||||||
|
|
||||||
void add_exception_cache_entry(ExceptionCache* new_entry);
|
void add_exception_cache_entry(ExceptionCache* new_entry);
|
||||||
ExceptionCache* exception_cache_entry_for_exception(Handle exception);
|
ExceptionCache* exception_cache_entry_for_exception(Handle exception);
|
||||||
@ -364,10 +364,10 @@ public:
|
|||||||
void set_unloading_next(CompiledMethod* next) { _unloading_next = next; }
|
void set_unloading_next(CompiledMethod* next) { _unloading_next = next; }
|
||||||
CompiledMethod* unloading_next() { return _unloading_next; }
|
CompiledMethod* unloading_next() { return _unloading_next; }
|
||||||
|
|
||||||
void static clean_ic_if_metadata_is_dead(CompiledIC *ic, BoolObjectClosure *is_alive);
|
void static clean_ic_if_metadata_is_dead(CompiledIC *ic);
|
||||||
|
|
||||||
// Check that all metadata is still alive
|
// Check that all metadata is still alive
|
||||||
void verify_metadata_loaders(address low_boundary, BoolObjectClosure* is_alive);
|
void verify_metadata_loaders(address low_boundary);
|
||||||
|
|
||||||
virtual void do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred);
|
virtual void do_unloading(BoolObjectClosure* is_alive, bool unloading_occurred);
|
||||||
// The parallel versions are used by G1.
|
// The parallel versions are used by G1.
|
||||||
|
@ -1365,7 +1365,7 @@ void nmethod::flush_dependencies(BoolObjectClosure* is_alive) {
|
|||||||
}
|
}
|
||||||
// During GC the is_alive closure is non-NULL, and is used to
|
// During GC the is_alive closure is non-NULL, and is used to
|
||||||
// determine liveness of dependees that need to be updated.
|
// determine liveness of dependees that need to be updated.
|
||||||
if (is_alive == NULL || klass->is_loader_alive(is_alive)) {
|
if (is_alive == NULL || klass->is_loader_alive()) {
|
||||||
// The GC defers deletion of this entry, since there might be multiple threads
|
// The GC defers deletion of this entry, since there might be multiple threads
|
||||||
// iterating over the _dependencies graph. Other call paths are single-threaded
|
// iterating over the _dependencies graph. Other call paths are single-threaded
|
||||||
// and may delete it immediately.
|
// and may delete it immediately.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -113,7 +113,7 @@ class PushAndMarkClosure: public MetadataAwareOopClosure {
|
|||||||
public:
|
public:
|
||||||
PushAndMarkClosure(CMSCollector* collector,
|
PushAndMarkClosure(CMSCollector* collector,
|
||||||
MemRegion span,
|
MemRegion span,
|
||||||
ReferenceProcessor* rp,
|
ReferenceDiscoverer* rd,
|
||||||
CMSBitMap* bit_map,
|
CMSBitMap* bit_map,
|
||||||
CMSBitMap* mod_union_table,
|
CMSBitMap* mod_union_table,
|
||||||
CMSMarkStack* mark_stack,
|
CMSMarkStack* mark_stack,
|
||||||
@ -141,7 +141,7 @@ class ParPushAndMarkClosure: public MetadataAwareOopClosure {
|
|||||||
public:
|
public:
|
||||||
ParPushAndMarkClosure(CMSCollector* collector,
|
ParPushAndMarkClosure(CMSCollector* collector,
|
||||||
MemRegion span,
|
MemRegion span,
|
||||||
ReferenceProcessor* rp,
|
ReferenceDiscoverer* rd,
|
||||||
CMSBitMap* bit_map,
|
CMSBitMap* bit_map,
|
||||||
OopTaskQueue* work_queue);
|
OopTaskQueue* work_queue);
|
||||||
virtual void do_oop(oop* p);
|
virtual void do_oop(oop* p);
|
||||||
@ -166,7 +166,7 @@ class MarkRefsIntoAndScanClosure: public MetadataAwareOopsInGenClosure {
|
|||||||
DO_OOP_WORK_DEFN
|
DO_OOP_WORK_DEFN
|
||||||
public:
|
public:
|
||||||
MarkRefsIntoAndScanClosure(MemRegion span,
|
MarkRefsIntoAndScanClosure(MemRegion span,
|
||||||
ReferenceProcessor* rp,
|
ReferenceDiscoverer* rd,
|
||||||
CMSBitMap* bit_map,
|
CMSBitMap* bit_map,
|
||||||
CMSBitMap* mod_union_table,
|
CMSBitMap* mod_union_table,
|
||||||
CMSMarkStack* mark_stack,
|
CMSMarkStack* mark_stack,
|
||||||
@ -204,7 +204,7 @@ class ParMarkRefsIntoAndScanClosure: public MetadataAwareOopsInGenClosure {
|
|||||||
public:
|
public:
|
||||||
ParMarkRefsIntoAndScanClosure(CMSCollector* collector,
|
ParMarkRefsIntoAndScanClosure(CMSCollector* collector,
|
||||||
MemRegion span,
|
MemRegion span,
|
||||||
ReferenceProcessor* rp,
|
ReferenceDiscoverer* rd,
|
||||||
CMSBitMap* bit_map,
|
CMSBitMap* bit_map,
|
||||||
OopTaskQueue* work_queue);
|
OopTaskQueue* work_queue);
|
||||||
virtual void do_oop(oop* p);
|
virtual void do_oop(oop* p);
|
||||||
|
@ -5244,7 +5244,7 @@ void CMSCollector::refProcessingWork() {
|
|||||||
CodeCache::do_unloading(&_is_alive_closure, purged_class);
|
CodeCache::do_unloading(&_is_alive_closure, purged_class);
|
||||||
|
|
||||||
// Prune dead klasses from subklass/sibling/implementor lists.
|
// Prune dead klasses from subklass/sibling/implementor lists.
|
||||||
Klass::clean_weak_klass_links(&_is_alive_closure);
|
Klass::clean_weak_klass_links();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -5825,7 +5825,7 @@ MarkRefsIntoClosure::MarkRefsIntoClosure(
|
|||||||
_span(span),
|
_span(span),
|
||||||
_bitMap(bitMap)
|
_bitMap(bitMap)
|
||||||
{
|
{
|
||||||
assert(ref_processor() == NULL, "deliberately left NULL");
|
assert(ref_discoverer() == NULL, "deliberately left NULL");
|
||||||
assert(_bitMap->covers(_span), "_bitMap/_span mismatch");
|
assert(_bitMap->covers(_span), "_bitMap/_span mismatch");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5847,7 +5847,7 @@ ParMarkRefsIntoClosure::ParMarkRefsIntoClosure(
|
|||||||
_span(span),
|
_span(span),
|
||||||
_bitMap(bitMap)
|
_bitMap(bitMap)
|
||||||
{
|
{
|
||||||
assert(ref_processor() == NULL, "deliberately left NULL");
|
assert(ref_discoverer() == NULL, "deliberately left NULL");
|
||||||
assert(_bitMap->covers(_span), "_bitMap/_span mismatch");
|
assert(_bitMap->covers(_span), "_bitMap/_span mismatch");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5871,7 +5871,7 @@ MarkRefsIntoVerifyClosure::MarkRefsIntoVerifyClosure(
|
|||||||
_verification_bm(verification_bm),
|
_verification_bm(verification_bm),
|
||||||
_cms_bm(cms_bm)
|
_cms_bm(cms_bm)
|
||||||
{
|
{
|
||||||
assert(ref_processor() == NULL, "deliberately left NULL");
|
assert(ref_discoverer() == NULL, "deliberately left NULL");
|
||||||
assert(_verification_bm->covers(_span), "_verification_bm/_span mismatch");
|
assert(_verification_bm->covers(_span), "_verification_bm/_span mismatch");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -5900,7 +5900,7 @@ void MarkRefsIntoVerifyClosure::do_oop(narrowOop* p) { MarkRefsIntoVerifyClosure
|
|||||||
//////////////////////////////////////////////////
|
//////////////////////////////////////////////////
|
||||||
|
|
||||||
MarkRefsIntoAndScanClosure::MarkRefsIntoAndScanClosure(MemRegion span,
|
MarkRefsIntoAndScanClosure::MarkRefsIntoAndScanClosure(MemRegion span,
|
||||||
ReferenceProcessor* rp,
|
ReferenceDiscoverer* rd,
|
||||||
CMSBitMap* bit_map,
|
CMSBitMap* bit_map,
|
||||||
CMSBitMap* mod_union_table,
|
CMSBitMap* mod_union_table,
|
||||||
CMSMarkStack* mark_stack,
|
CMSMarkStack* mark_stack,
|
||||||
@ -5911,15 +5911,15 @@ MarkRefsIntoAndScanClosure::MarkRefsIntoAndScanClosure(MemRegion span,
|
|||||||
_span(span),
|
_span(span),
|
||||||
_bit_map(bit_map),
|
_bit_map(bit_map),
|
||||||
_mark_stack(mark_stack),
|
_mark_stack(mark_stack),
|
||||||
_pushAndMarkClosure(collector, span, rp, bit_map, mod_union_table,
|
_pushAndMarkClosure(collector, span, rd, bit_map, mod_union_table,
|
||||||
mark_stack, concurrent_precleaning),
|
mark_stack, concurrent_precleaning),
|
||||||
_yield(should_yield),
|
_yield(should_yield),
|
||||||
_concurrent_precleaning(concurrent_precleaning),
|
_concurrent_precleaning(concurrent_precleaning),
|
||||||
_freelistLock(NULL)
|
_freelistLock(NULL)
|
||||||
{
|
{
|
||||||
// FIXME: Should initialize in base class constructor.
|
// FIXME: Should initialize in base class constructor.
|
||||||
assert(rp != NULL, "ref_processor shouldn't be NULL");
|
assert(rd != NULL, "ref_discoverer shouldn't be NULL");
|
||||||
set_ref_processor_internal(rp);
|
set_ref_discoverer_internal(rd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This closure is used to mark refs into the CMS generation at the
|
// This closure is used to mark refs into the CMS generation at the
|
||||||
@ -6004,18 +6004,18 @@ void MarkRefsIntoAndScanClosure::do_yield_work() {
|
|||||||
// MarkRefsIntoAndScanClosure
|
// MarkRefsIntoAndScanClosure
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
ParMarkRefsIntoAndScanClosure::ParMarkRefsIntoAndScanClosure(
|
ParMarkRefsIntoAndScanClosure::ParMarkRefsIntoAndScanClosure(
|
||||||
CMSCollector* collector, MemRegion span, ReferenceProcessor* rp,
|
CMSCollector* collector, MemRegion span, ReferenceDiscoverer* rd,
|
||||||
CMSBitMap* bit_map, OopTaskQueue* work_queue):
|
CMSBitMap* bit_map, OopTaskQueue* work_queue):
|
||||||
_span(span),
|
_span(span),
|
||||||
_bit_map(bit_map),
|
_bit_map(bit_map),
|
||||||
_work_queue(work_queue),
|
_work_queue(work_queue),
|
||||||
_low_water_mark(MIN2((work_queue->max_elems()/4),
|
_low_water_mark(MIN2((work_queue->max_elems()/4),
|
||||||
((uint)CMSWorkQueueDrainThreshold * ParallelGCThreads))),
|
((uint)CMSWorkQueueDrainThreshold * ParallelGCThreads))),
|
||||||
_parPushAndMarkClosure(collector, span, rp, bit_map, work_queue)
|
_parPushAndMarkClosure(collector, span, rd, bit_map, work_queue)
|
||||||
{
|
{
|
||||||
// FIXME: Should initialize in base class constructor.
|
// FIXME: Should initialize in base class constructor.
|
||||||
assert(rp != NULL, "ref_processor shouldn't be NULL");
|
assert(rd != NULL, "ref_discoverer shouldn't be NULL");
|
||||||
set_ref_processor_internal(rp);
|
set_ref_discoverer_internal(rd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This closure is used to mark refs into the CMS generation at the
|
// This closure is used to mark refs into the CMS generation at the
|
||||||
@ -6842,12 +6842,12 @@ void ParPushOrMarkClosure::do_oop(narrowOop* p) { ParPushOrMarkClosure::do_oop_w
|
|||||||
|
|
||||||
PushAndMarkClosure::PushAndMarkClosure(CMSCollector* collector,
|
PushAndMarkClosure::PushAndMarkClosure(CMSCollector* collector,
|
||||||
MemRegion span,
|
MemRegion span,
|
||||||
ReferenceProcessor* rp,
|
ReferenceDiscoverer* rd,
|
||||||
CMSBitMap* bit_map,
|
CMSBitMap* bit_map,
|
||||||
CMSBitMap* mod_union_table,
|
CMSBitMap* mod_union_table,
|
||||||
CMSMarkStack* mark_stack,
|
CMSMarkStack* mark_stack,
|
||||||
bool concurrent_precleaning):
|
bool concurrent_precleaning):
|
||||||
MetadataAwareOopClosure(rp),
|
MetadataAwareOopClosure(rd),
|
||||||
_collector(collector),
|
_collector(collector),
|
||||||
_span(span),
|
_span(span),
|
||||||
_bit_map(bit_map),
|
_bit_map(bit_map),
|
||||||
@ -6855,7 +6855,7 @@ PushAndMarkClosure::PushAndMarkClosure(CMSCollector* collector,
|
|||||||
_mark_stack(mark_stack),
|
_mark_stack(mark_stack),
|
||||||
_concurrent_precleaning(concurrent_precleaning)
|
_concurrent_precleaning(concurrent_precleaning)
|
||||||
{
|
{
|
||||||
assert(ref_processor() != NULL, "ref_processor shouldn't be NULL");
|
assert(ref_discoverer() != NULL, "ref_discoverer shouldn't be NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grey object rescan during pre-cleaning and second checkpoint phases --
|
// Grey object rescan during pre-cleaning and second checkpoint phases --
|
||||||
@ -6916,16 +6916,16 @@ void PushAndMarkClosure::do_oop(oop obj) {
|
|||||||
|
|
||||||
ParPushAndMarkClosure::ParPushAndMarkClosure(CMSCollector* collector,
|
ParPushAndMarkClosure::ParPushAndMarkClosure(CMSCollector* collector,
|
||||||
MemRegion span,
|
MemRegion span,
|
||||||
ReferenceProcessor* rp,
|
ReferenceDiscoverer* rd,
|
||||||
CMSBitMap* bit_map,
|
CMSBitMap* bit_map,
|
||||||
OopTaskQueue* work_queue):
|
OopTaskQueue* work_queue):
|
||||||
MetadataAwareOopClosure(rp),
|
MetadataAwareOopClosure(rd),
|
||||||
_collector(collector),
|
_collector(collector),
|
||||||
_span(span),
|
_span(span),
|
||||||
_bit_map(bit_map),
|
_bit_map(bit_map),
|
||||||
_work_queue(work_queue)
|
_work_queue(work_queue)
|
||||||
{
|
{
|
||||||
assert(ref_processor() != NULL, "ref_processor shouldn't be NULL");
|
assert(ref_discoverer() != NULL, "ref_discoverer shouldn't be NULL");
|
||||||
}
|
}
|
||||||
|
|
||||||
void PushAndMarkClosure::do_oop(oop* p) { PushAndMarkClosure::do_oop_work(p); }
|
void PushAndMarkClosure::do_oop(oop* p) { PushAndMarkClosure::do_oop_work(p); }
|
||||||
|
@ -3125,7 +3125,7 @@ public:
|
|||||||
ReferenceProcessor* rp = _g1h->ref_processor_stw();
|
ReferenceProcessor* rp = _g1h->ref_processor_stw();
|
||||||
|
|
||||||
G1ParScanThreadState* pss = _pss->state_for_worker(worker_id);
|
G1ParScanThreadState* pss = _pss->state_for_worker(worker_id);
|
||||||
pss->set_ref_processor(rp);
|
pss->set_ref_discoverer(rp);
|
||||||
|
|
||||||
double start_strong_roots_sec = os::elapsedTime();
|
double start_strong_roots_sec = os::elapsedTime();
|
||||||
|
|
||||||
@ -3457,13 +3457,11 @@ private:
|
|||||||
Monitor* G1CodeCacheUnloadingTask::_lock = new Monitor(Mutex::leaf, "Code Cache Unload lock", false, Monitor::_safepoint_check_never);
|
Monitor* G1CodeCacheUnloadingTask::_lock = new Monitor(Mutex::leaf, "Code Cache Unload lock", false, Monitor::_safepoint_check_never);
|
||||||
|
|
||||||
class G1KlassCleaningTask : public StackObj {
|
class G1KlassCleaningTask : public StackObj {
|
||||||
BoolObjectClosure* _is_alive;
|
|
||||||
volatile int _clean_klass_tree_claimed;
|
volatile int _clean_klass_tree_claimed;
|
||||||
ClassLoaderDataGraphKlassIteratorAtomic _klass_iterator;
|
ClassLoaderDataGraphKlassIteratorAtomic _klass_iterator;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
G1KlassCleaningTask(BoolObjectClosure* is_alive) :
|
G1KlassCleaningTask() :
|
||||||
_is_alive(is_alive),
|
|
||||||
_clean_klass_tree_claimed(0),
|
_clean_klass_tree_claimed(0),
|
||||||
_klass_iterator() {
|
_klass_iterator() {
|
||||||
}
|
}
|
||||||
@ -3490,7 +3488,7 @@ class G1KlassCleaningTask : public StackObj {
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
void clean_klass(InstanceKlass* ik) {
|
void clean_klass(InstanceKlass* ik) {
|
||||||
ik->clean_weak_instanceklass_links(_is_alive);
|
ik->clean_weak_instanceklass_links();
|
||||||
}
|
}
|
||||||
|
|
||||||
void work() {
|
void work() {
|
||||||
@ -3498,7 +3496,7 @@ public:
|
|||||||
|
|
||||||
// One worker will clean the subklass/sibling klass tree.
|
// One worker will clean the subklass/sibling klass tree.
|
||||||
if (claim_clean_klass_tree_task()) {
|
if (claim_clean_klass_tree_task()) {
|
||||||
Klass::clean_subklass_tree(_is_alive);
|
Klass::clean_subklass_tree();
|
||||||
}
|
}
|
||||||
|
|
||||||
// All workers will help cleaning the classes,
|
// All workers will help cleaning the classes,
|
||||||
@ -3510,11 +3508,10 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class G1ResolvedMethodCleaningTask : public StackObj {
|
class G1ResolvedMethodCleaningTask : public StackObj {
|
||||||
BoolObjectClosure* _is_alive;
|
|
||||||
volatile int _resolved_method_task_claimed;
|
volatile int _resolved_method_task_claimed;
|
||||||
public:
|
public:
|
||||||
G1ResolvedMethodCleaningTask(BoolObjectClosure* is_alive) :
|
G1ResolvedMethodCleaningTask() :
|
||||||
_is_alive(is_alive), _resolved_method_task_claimed(0) {}
|
_resolved_method_task_claimed(0) {}
|
||||||
|
|
||||||
bool claim_resolved_method_task() {
|
bool claim_resolved_method_task() {
|
||||||
if (_resolved_method_task_claimed) {
|
if (_resolved_method_task_claimed) {
|
||||||
@ -3526,7 +3523,7 @@ public:
|
|||||||
// These aren't big, one thread can do it all.
|
// These aren't big, one thread can do it all.
|
||||||
void work() {
|
void work() {
|
||||||
if (claim_resolved_method_task()) {
|
if (claim_resolved_method_task()) {
|
||||||
ResolvedMethodTable::unlink(_is_alive);
|
ResolvedMethodTable::unlink();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -3546,8 +3543,8 @@ public:
|
|||||||
AbstractGangTask("Parallel Cleaning"),
|
AbstractGangTask("Parallel Cleaning"),
|
||||||
_string_symbol_task(is_alive, true, true, G1StringDedup::is_enabled()),
|
_string_symbol_task(is_alive, true, true, G1StringDedup::is_enabled()),
|
||||||
_code_cache_task(num_workers, is_alive, unloading_occurred),
|
_code_cache_task(num_workers, is_alive, unloading_occurred),
|
||||||
_klass_cleaning_task(is_alive),
|
_klass_cleaning_task(),
|
||||||
_resolved_method_cleaning_task(is_alive) {
|
_resolved_method_cleaning_task() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The parallel work done by all worker threads.
|
// The parallel work done by all worker threads.
|
||||||
@ -3823,7 +3820,7 @@ public:
|
|||||||
G1STWIsAliveClosure is_alive(_g1h);
|
G1STWIsAliveClosure is_alive(_g1h);
|
||||||
|
|
||||||
G1ParScanThreadState* pss = _pss->state_for_worker(worker_id);
|
G1ParScanThreadState* pss = _pss->state_for_worker(worker_id);
|
||||||
pss->set_ref_processor(NULL);
|
pss->set_ref_discoverer(NULL);
|
||||||
|
|
||||||
// Keep alive closure.
|
// Keep alive closure.
|
||||||
G1CopyingKeepAliveClosure keep_alive(_g1h, pss->closures()->raw_strong_oops(), pss);
|
G1CopyingKeepAliveClosure keep_alive(_g1h, pss->closures()->raw_strong_oops(), pss);
|
||||||
@ -3915,7 +3912,7 @@ public:
|
|||||||
HandleMark hm;
|
HandleMark hm;
|
||||||
|
|
||||||
G1ParScanThreadState* pss = _pss->state_for_worker(worker_id);
|
G1ParScanThreadState* pss = _pss->state_for_worker(worker_id);
|
||||||
pss->set_ref_processor(NULL);
|
pss->set_ref_discoverer(NULL);
|
||||||
assert(pss->queue_is_empty(), "both queue and overflow should be empty");
|
assert(pss->queue_is_empty(), "both queue and overflow should be empty");
|
||||||
|
|
||||||
// Is alive closure
|
// Is alive closure
|
||||||
@ -4021,7 +4018,7 @@ void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per
|
|||||||
|
|
||||||
// Use only a single queue for this PSS.
|
// Use only a single queue for this PSS.
|
||||||
G1ParScanThreadState* pss = per_thread_states->state_for_worker(0);
|
G1ParScanThreadState* pss = per_thread_states->state_for_worker(0);
|
||||||
pss->set_ref_processor(NULL);
|
pss->set_ref_discoverer(NULL);
|
||||||
assert(pss->queue_is_empty(), "pre-condition");
|
assert(pss->queue_is_empty(), "pre-condition");
|
||||||
|
|
||||||
// Keep alive closure.
|
// Keep alive closure.
|
||||||
|
@ -1413,14 +1413,13 @@ bool G1CMIsAliveClosure::do_object_b(oop obj) {
|
|||||||
class G1CMKeepAliveAndDrainClosure : public OopClosure {
|
class G1CMKeepAliveAndDrainClosure : public OopClosure {
|
||||||
G1ConcurrentMark* _cm;
|
G1ConcurrentMark* _cm;
|
||||||
G1CMTask* _task;
|
G1CMTask* _task;
|
||||||
int _ref_counter_limit;
|
uint _ref_counter_limit;
|
||||||
int _ref_counter;
|
uint _ref_counter;
|
||||||
bool _is_serial;
|
bool _is_serial;
|
||||||
public:
|
public:
|
||||||
G1CMKeepAliveAndDrainClosure(G1ConcurrentMark* cm, G1CMTask* task, bool is_serial) :
|
G1CMKeepAliveAndDrainClosure(G1ConcurrentMark* cm, G1CMTask* task, bool is_serial) :
|
||||||
_cm(cm), _task(task), _is_serial(is_serial),
|
_cm(cm), _task(task), _is_serial(is_serial),
|
||||||
_ref_counter_limit(G1RefProcDrainInterval) {
|
_ref_counter_limit(G1RefProcDrainInterval) {
|
||||||
assert(_ref_counter_limit > 0, "sanity");
|
|
||||||
assert(!_is_serial || _task->worker_id() == 0, "only task 0 for serial code");
|
assert(!_is_serial || _task->worker_id() == 0, "only task 0 for serial code");
|
||||||
_ref_counter = _ref_counter_limit;
|
_ref_counter = _ref_counter_limit;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -37,6 +37,7 @@
|
|||||||
#include "gc/g1/g1OopClosures.hpp"
|
#include "gc/g1/g1OopClosures.hpp"
|
||||||
#include "gc/g1/g1Policy.hpp"
|
#include "gc/g1/g1Policy.hpp"
|
||||||
#include "gc/g1/g1StringDedup.hpp"
|
#include "gc/g1/g1StringDedup.hpp"
|
||||||
|
#include "gc/shared/adaptiveSizePolicy.hpp"
|
||||||
#include "gc/shared/gcTraceTime.inline.hpp"
|
#include "gc/shared/gcTraceTime.inline.hpp"
|
||||||
#include "gc/shared/preservedMarks.hpp"
|
#include "gc/shared/preservedMarks.hpp"
|
||||||
#include "gc/shared/referenceProcessor.hpp"
|
#include "gc/shared/referenceProcessor.hpp"
|
||||||
@ -72,10 +73,40 @@ ReferenceProcessor* G1FullCollector::reference_processor() {
|
|||||||
return _heap->ref_processor_stw();
|
return _heap->ref_processor_stw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint G1FullCollector::calc_active_workers() {
|
||||||
|
G1CollectedHeap* heap = G1CollectedHeap::heap();
|
||||||
|
uint max_worker_count = heap->workers()->total_workers();
|
||||||
|
// Only calculate number of workers if UseDynamicNumberOfGCThreads
|
||||||
|
// is enabled, otherwise use max.
|
||||||
|
if (!UseDynamicNumberOfGCThreads) {
|
||||||
|
return max_worker_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consider G1HeapWastePercent to decide max number of workers. Each worker
|
||||||
|
// will in average cause half a region waste.
|
||||||
|
uint max_wasted_regions_allowed = ((heap->num_regions() * G1HeapWastePercent) / 100);
|
||||||
|
uint waste_worker_count = MAX2((max_wasted_regions_allowed * 2) , 1u);
|
||||||
|
uint heap_waste_worker_limit = MIN2(waste_worker_count, max_worker_count);
|
||||||
|
|
||||||
|
// Also consider HeapSizePerGCThread by calling AdaptiveSizePolicy to calculate
|
||||||
|
// the number of workers.
|
||||||
|
uint current_active_workers = heap->workers()->active_workers();
|
||||||
|
uint adaptive_worker_limit = AdaptiveSizePolicy::calc_active_workers(max_worker_count, current_active_workers, 0);
|
||||||
|
|
||||||
|
// Update active workers to the lower of the limits.
|
||||||
|
uint worker_count = MIN2(heap_waste_worker_limit, adaptive_worker_limit);
|
||||||
|
log_debug(gc, task)("Requesting %u active workers for full compaction (waste limited workers: %u, adaptive workers: %u)",
|
||||||
|
worker_count, heap_waste_worker_limit, adaptive_worker_limit);
|
||||||
|
worker_count = heap->workers()->update_active_workers(worker_count);
|
||||||
|
log_info(gc, task)("Using %u workers of %u for full compaction", worker_count, max_worker_count);
|
||||||
|
|
||||||
|
return worker_count;
|
||||||
|
}
|
||||||
|
|
||||||
G1FullCollector::G1FullCollector(G1CollectedHeap* heap, GCMemoryManager* memory_manager, bool explicit_gc, bool clear_soft_refs) :
|
G1FullCollector::G1FullCollector(G1CollectedHeap* heap, GCMemoryManager* memory_manager, bool explicit_gc, bool clear_soft_refs) :
|
||||||
_heap(heap),
|
_heap(heap),
|
||||||
_scope(memory_manager, explicit_gc, clear_soft_refs),
|
_scope(memory_manager, explicit_gc, clear_soft_refs),
|
||||||
_num_workers(heap->workers()->active_workers()),
|
_num_workers(calc_active_workers()),
|
||||||
_oop_queue_set(_num_workers),
|
_oop_queue_set(_num_workers),
|
||||||
_array_queue_set(_num_workers),
|
_array_queue_set(_num_workers),
|
||||||
_preserved_marks_set(true),
|
_preserved_marks_set(true),
|
||||||
|
@ -56,6 +56,8 @@ class G1FullCollector : StackObj {
|
|||||||
G1IsAliveClosure _is_alive;
|
G1IsAliveClosure _is_alive;
|
||||||
ReferenceProcessorIsAliveMutator _is_alive_mutator;
|
ReferenceProcessorIsAliveMutator _is_alive_mutator;
|
||||||
|
|
||||||
|
static uint calc_active_workers();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
G1FullCollector(G1CollectedHeap* heap, GCMemoryManager* memory_manager, bool explicit_gc, bool clear_soft_refs);
|
G1FullCollector(G1CollectedHeap* heap, GCMemoryManager* memory_manager, bool explicit_gc, bool clear_soft_refs);
|
||||||
~G1FullCollector();
|
~G1FullCollector();
|
||||||
|
@ -60,7 +60,7 @@ class G1MarkAndPushClosure : public ExtendedOopClosure {
|
|||||||
uint _worker_id;
|
uint _worker_id;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
G1MarkAndPushClosure(uint worker, G1FullGCMarker* marker, ReferenceProcessor* ref) :
|
G1MarkAndPushClosure(uint worker, G1FullGCMarker* marker, ReferenceDiscoverer* ref) :
|
||||||
_marker(marker),
|
_marker(marker),
|
||||||
_worker_id(worker),
|
_worker_id(worker),
|
||||||
ExtendedOopClosure(ref) { }
|
ExtendedOopClosure(ref) { }
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "gc/g1/g1MonitoringSupport.hpp"
|
#include "gc/g1/g1MonitoringSupport.hpp"
|
||||||
#include "gc/g1/g1Policy.hpp"
|
#include "gc/g1/g1Policy.hpp"
|
||||||
#include "gc/shared/hSpaceCounters.hpp"
|
#include "gc/shared/hSpaceCounters.hpp"
|
||||||
|
#include "memory/metaspaceCounters.hpp"
|
||||||
|
|
||||||
G1GenerationCounters::G1GenerationCounters(G1MonitoringSupport* g1mm,
|
G1GenerationCounters::G1GenerationCounters(G1MonitoringSupport* g1mm,
|
||||||
const char* name,
|
const char* name,
|
||||||
|
@ -96,8 +96,8 @@ public:
|
|||||||
virtual void do_oop(oop* p) { do_oop_nv(p); }
|
virtual void do_oop(oop* p) { do_oop_nv(p); }
|
||||||
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
|
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
|
||||||
|
|
||||||
void set_ref_processor(ReferenceProcessor* rp) {
|
void set_ref_discoverer(ReferenceDiscoverer* rd) {
|
||||||
set_ref_processor_internal(rp);
|
set_ref_discoverer_internal(rd);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ class G1ParScanThreadState : public CHeapObj<mtGC> {
|
|||||||
G1ParScanThreadState(G1CollectedHeap* g1h, uint worker_id, size_t young_cset_length);
|
G1ParScanThreadState(G1CollectedHeap* g1h, uint worker_id, size_t young_cset_length);
|
||||||
virtual ~G1ParScanThreadState();
|
virtual ~G1ParScanThreadState();
|
||||||
|
|
||||||
void set_ref_processor(ReferenceProcessor* rp) { _scanner.set_ref_processor(rp); }
|
void set_ref_discoverer(ReferenceDiscoverer* rd) { _scanner.set_ref_discoverer(rd); }
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
bool queue_is_empty() const { return _refs->is_empty(); }
|
bool queue_is_empty() const { return _refs->is_empty(); }
|
||||||
|
@ -74,7 +74,7 @@
|
|||||||
"in milliseconds.") \
|
"in milliseconds.") \
|
||||||
range(1.0, DBL_MAX) \
|
range(1.0, DBL_MAX) \
|
||||||
\
|
\
|
||||||
product(int, G1RefProcDrainInterval, 10, \
|
product(uint, G1RefProcDrainInterval, 1000, \
|
||||||
"The number of discovered reference objects to process before " \
|
"The number of discovered reference objects to process before " \
|
||||||
"draining concurrent marking work queues.") \
|
"draining concurrent marking work queues.") \
|
||||||
range(1, INT_MAX) \
|
range(1, INT_MAX) \
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#include "gc/shared/gcLocker.hpp"
|
#include "gc/shared/gcLocker.hpp"
|
||||||
#include "gc/shared/gcWhen.hpp"
|
#include "gc/shared/gcWhen.hpp"
|
||||||
#include "logging/log.hpp"
|
#include "logging/log.hpp"
|
||||||
|
#include "memory/metaspaceCounters.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "runtime/handles.inline.hpp"
|
#include "runtime/handles.inline.hpp"
|
||||||
#include "runtime/java.hpp"
|
#include "runtime/java.hpp"
|
||||||
|
@ -562,7 +562,7 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
|
|||||||
CodeCache::do_unloading(is_alive_closure(), purged_class);
|
CodeCache::do_unloading(is_alive_closure(), purged_class);
|
||||||
|
|
||||||
// Prune dead klasses from subklass/sibling/implementor lists.
|
// Prune dead klasses from subklass/sibling/implementor lists.
|
||||||
Klass::clean_weak_klass_links(is_alive_closure());
|
Klass::clean_weak_klass_links();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -2139,7 +2139,7 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm,
|
|||||||
CodeCache::do_unloading(is_alive_closure(), purged_class);
|
CodeCache::do_unloading(is_alive_closure(), purged_class);
|
||||||
|
|
||||||
// Prune dead klasses from subklass/sibling/implementor lists.
|
// Prune dead klasses from subklass/sibling/implementor lists.
|
||||||
Klass::clean_weak_klass_links(is_alive_closure());
|
Klass::clean_weak_klass_links();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2018, 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
|
||||||
@ -234,7 +234,7 @@ void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
|
|||||||
CodeCache::do_unloading(&is_alive, purged_class);
|
CodeCache::do_unloading(&is_alive, purged_class);
|
||||||
|
|
||||||
// Prune dead klasses from subklass/sibling/implementor lists.
|
// Prune dead klasses from subklass/sibling/implementor lists.
|
||||||
Klass::clean_weak_klass_links(&is_alive);
|
Klass::clean_weak_klass_links();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -211,7 +211,7 @@ void MarkSweep::preserve_mark(oop obj, markOop mark) {
|
|||||||
|
|
||||||
void MarkSweep::set_ref_processor(ReferenceProcessor* rp) {
|
void MarkSweep::set_ref_processor(ReferenceProcessor* rp) {
|
||||||
_ref_processor = rp;
|
_ref_processor = rp;
|
||||||
mark_and_push_closure.set_ref_processor(_ref_processor);
|
mark_and_push_closure.set_ref_discoverer(_ref_processor);
|
||||||
}
|
}
|
||||||
|
|
||||||
AdjustPointerClosure MarkSweep::adjust_pointer_closure;
|
AdjustPointerClosure MarkSweep::adjust_pointer_closure;
|
||||||
|
@ -184,8 +184,8 @@ public:
|
|||||||
virtual void do_cld(ClassLoaderData* cld);
|
virtual void do_cld(ClassLoaderData* cld);
|
||||||
void do_cld_nv(ClassLoaderData* cld);
|
void do_cld_nv(ClassLoaderData* cld);
|
||||||
|
|
||||||
void set_ref_processor(ReferenceProcessor* rp) {
|
void set_ref_discoverer(ReferenceDiscoverer* rd) {
|
||||||
set_ref_processor_internal(rp);
|
set_ref_discoverer_internal(rd);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2004, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2004, 2018, 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
|
||||||
@ -355,6 +355,7 @@ class AdaptiveSizePolicy : public CHeapObj<mtGC> {
|
|||||||
// For ParNew collections
|
// For ParNew collections
|
||||||
// For PS scavenge and ParOld collections
|
// For PS scavenge and ParOld collections
|
||||||
// For G1 evacuation pauses (subject to update)
|
// For G1 evacuation pauses (subject to update)
|
||||||
|
// For G1 Full GCs (subject to update)
|
||||||
// Other collection phases inherit the number of
|
// Other collection phases inherit the number of
|
||||||
// GC workers from the calls above. For example,
|
// GC workers from the calls above. For example,
|
||||||
// a CMS parallel remark uses the same number of GC
|
// a CMS parallel remark uses the same number of GC
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
#include "gc/shared/weakProcessor.hpp"
|
#include "gc/shared/weakProcessor.hpp"
|
||||||
#include "gc/shared/workgroup.hpp"
|
#include "gc/shared/workgroup.hpp"
|
||||||
#include "memory/filemap.hpp"
|
#include "memory/filemap.hpp"
|
||||||
|
#include "memory/metaspaceCounters.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "runtime/biasedLocking.hpp"
|
#include "runtime/biasedLocking.hpp"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2018, 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
|
||||||
@ -151,7 +151,7 @@ class FilteringClosure: public ExtendedOopClosure {
|
|||||||
template <class T> inline void do_oop_work(T* p);
|
template <class T> inline void do_oop_work(T* p);
|
||||||
public:
|
public:
|
||||||
FilteringClosure(HeapWord* boundary, ExtendedOopClosure* cl) :
|
FilteringClosure(HeapWord* boundary, ExtendedOopClosure* cl) :
|
||||||
ExtendedOopClosure(cl->ref_processor()), _boundary(boundary),
|
ExtendedOopClosure(cl->ref_discoverer()), _boundary(boundary),
|
||||||
_cl(cl) {}
|
_cl(cl) {}
|
||||||
virtual void do_oop(oop* p);
|
virtual void do_oop(oop* p);
|
||||||
virtual void do_oop(narrowOop* p);
|
virtual void do_oop(narrowOop* p);
|
||||||
|
37
src/hotspot/share/gc/shared/referenceDiscoverer.hpp
Normal file
37
src/hotspot/share/gc/shared/referenceDiscoverer.hpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHARE_GC_SHARED_REFERENCEDISCOVERER_HPP
|
||||||
|
#define SHARE_GC_SHARED_REFERENCEDISCOVERER_HPP
|
||||||
|
|
||||||
|
#include "memory/allocation.hpp"
|
||||||
|
#include "memory/referenceType.hpp"
|
||||||
|
#include "oops/oopsHierarchy.hpp"
|
||||||
|
|
||||||
|
class ReferenceDiscoverer : public CHeapObj<mtGC> {
|
||||||
|
public:
|
||||||
|
virtual bool discover_reference(oop obj, ReferenceType type) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SHARE_GC_SHARED_REFERENCEDISCOVERER_HPP
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -25,6 +25,7 @@
|
|||||||
#ifndef SHARE_VM_GC_SHARED_REFERENCEPROCESSOR_HPP
|
#ifndef SHARE_VM_GC_SHARED_REFERENCEPROCESSOR_HPP
|
||||||
#define SHARE_VM_GC_SHARED_REFERENCEPROCESSOR_HPP
|
#define SHARE_VM_GC_SHARED_REFERENCEPROCESSOR_HPP
|
||||||
|
|
||||||
|
#include "gc/shared/referenceDiscoverer.hpp"
|
||||||
#include "gc/shared/referencePolicy.hpp"
|
#include "gc/shared/referencePolicy.hpp"
|
||||||
#include "gc/shared/referenceProcessorPhaseTimes.hpp"
|
#include "gc/shared/referenceProcessorPhaseTimes.hpp"
|
||||||
#include "gc/shared/referenceProcessorStats.hpp"
|
#include "gc/shared/referenceProcessorStats.hpp"
|
||||||
@ -166,7 +167,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ReferenceProcessor : public CHeapObj<mtGC> {
|
class ReferenceProcessor : public ReferenceDiscoverer {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
size_t total_count(DiscoveredList lists[]) const;
|
size_t total_count(DiscoveredList lists[]) const;
|
||||||
@ -405,7 +406,7 @@ class ReferenceProcessor : public CHeapObj<mtGC> {
|
|||||||
void verify_list(DiscoveredList& ref_list);
|
void verify_list(DiscoveredList& ref_list);
|
||||||
|
|
||||||
// Discover a Reference object, using appropriate discovery criteria
|
// Discover a Reference object, using appropriate discovery criteria
|
||||||
bool discover_reference(oop obj, ReferenceType rt);
|
virtual bool discover_reference(oop obj, ReferenceType rt);
|
||||||
|
|
||||||
// Has discovered references that need handling
|
// Has discovered references that need handling
|
||||||
bool has_discovered_references();
|
bool has_discovered_references();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1999, 2018, 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
|
||||||
@ -164,6 +164,13 @@ public:
|
|||||||
|
|
||||||
static size_t refill_waste_limit_increment() { return TLABWasteIncrement; }
|
static size_t refill_waste_limit_increment() { return TLABWasteIncrement; }
|
||||||
|
|
||||||
|
template <typename T> void addresses_do(T f) {
|
||||||
|
f(&_start);
|
||||||
|
f(&_top);
|
||||||
|
f(&_pf_top);
|
||||||
|
f(&_end);
|
||||||
|
}
|
||||||
|
|
||||||
// Code generation support
|
// Code generation support
|
||||||
static ByteSize start_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _start); }
|
static ByteSize start_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _start); }
|
||||||
static ByteSize end_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _end ); }
|
static ByteSize end_offset() { return byte_offset_of(ThreadLocalAllocBuffer, _end ); }
|
||||||
|
@ -415,6 +415,34 @@ JRT_LEAF(void, JVMCIRuntime::monitorexit(JavaThread* thread, oopDesc* obj, Basic
|
|||||||
}
|
}
|
||||||
JRT_END
|
JRT_END
|
||||||
|
|
||||||
|
// Object.notify() fast path, caller does slow path
|
||||||
|
JRT_LEAF(jboolean, JVMCIRuntime::object_notify(JavaThread *thread, oopDesc* obj))
|
||||||
|
|
||||||
|
// Very few notify/notifyAll operations find any threads on the waitset, so
|
||||||
|
// the dominant fast-path is to simply return.
|
||||||
|
// Relatedly, it's critical that notify/notifyAll be fast in order to
|
||||||
|
// reduce lock hold times.
|
||||||
|
if (!SafepointSynchronize::is_synchronizing()) {
|
||||||
|
if (ObjectSynchronizer::quick_notify(obj, thread, false)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false; // caller must perform slow path
|
||||||
|
|
||||||
|
JRT_END
|
||||||
|
|
||||||
|
// Object.notifyAll() fast path, caller does slow path
|
||||||
|
JRT_LEAF(jboolean, JVMCIRuntime::object_notifyAll(JavaThread *thread, oopDesc* obj))
|
||||||
|
|
||||||
|
if (!SafepointSynchronize::is_synchronizing() ) {
|
||||||
|
if (ObjectSynchronizer::quick_notify(obj, thread, true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false; // caller must perform slow path
|
||||||
|
|
||||||
|
JRT_END
|
||||||
|
|
||||||
JRT_ENTRY(void, JVMCIRuntime::throw_and_post_jvmti_exception(JavaThread* thread, const char* exception, const char* message))
|
JRT_ENTRY(void, JVMCIRuntime::throw_and_post_jvmti_exception(JavaThread* thread, const char* exception, const char* message))
|
||||||
TempNewSymbol symbol = SymbolTable::new_symbol(exception, CHECK);
|
TempNewSymbol symbol = SymbolTable::new_symbol(exception, CHECK);
|
||||||
SharedRuntime::throw_and_post_jvmti_exception(thread, symbol, message);
|
SharedRuntime::throw_and_post_jvmti_exception(thread, symbol, message);
|
||||||
|
@ -139,6 +139,8 @@ class JVMCIRuntime: public AllStatic {
|
|||||||
static address exception_handler_for_pc(JavaThread* thread);
|
static address exception_handler_for_pc(JavaThread* thread);
|
||||||
static void monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock);
|
static void monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock);
|
||||||
static void monitorexit (JavaThread* thread, oopDesc* obj, BasicLock* lock);
|
static void monitorexit (JavaThread* thread, oopDesc* obj, BasicLock* lock);
|
||||||
|
static jboolean object_notify(JavaThread* thread, oopDesc* obj);
|
||||||
|
static jboolean object_notifyAll(JavaThread* thread, oopDesc* obj);
|
||||||
static void vm_error(JavaThread* thread, jlong where, jlong format, jlong value);
|
static void vm_error(JavaThread* thread, jlong where, jlong format, jlong value);
|
||||||
static oopDesc* load_and_clear_exception(JavaThread* thread);
|
static oopDesc* load_and_clear_exception(JavaThread* thread);
|
||||||
static void log_printf(JavaThread* thread, oopDesc* format, jlong v1, jlong v2, jlong v3);
|
static void log_printf(JavaThread* thread, oopDesc* format, jlong v1, jlong v2, jlong v3);
|
||||||
|
@ -625,6 +625,8 @@
|
|||||||
declare_function(JVMCIRuntime::exception_handler_for_pc) \
|
declare_function(JVMCIRuntime::exception_handler_for_pc) \
|
||||||
declare_function(JVMCIRuntime::monitorenter) \
|
declare_function(JVMCIRuntime::monitorenter) \
|
||||||
declare_function(JVMCIRuntime::monitorexit) \
|
declare_function(JVMCIRuntime::monitorexit) \
|
||||||
|
declare_function(JVMCIRuntime::object_notify) \
|
||||||
|
declare_function(JVMCIRuntime::object_notifyAll) \
|
||||||
declare_function(JVMCIRuntime::throw_and_post_jvmti_exception) \
|
declare_function(JVMCIRuntime::throw_and_post_jvmti_exception) \
|
||||||
declare_function(JVMCIRuntime::throw_klass_external_name_exception) \
|
declare_function(JVMCIRuntime::throw_klass_external_name_exception) \
|
||||||
declare_function(JVMCIRuntime::throw_class_cast_exception) \
|
declare_function(JVMCIRuntime::throw_class_cast_exception) \
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2002, 2018, 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
|
||||||
@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "classfile/classLoaderData.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
#include "classfile/moduleEntry.hpp"
|
#include "classfile/moduleEntry.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "gc/shared/collectedHeap.hpp"
|
#include "gc/shared/collectedHeap.hpp"
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
class CodeBlob;
|
class CodeBlob;
|
||||||
class nmethod;
|
class nmethod;
|
||||||
class ReferenceProcessor;
|
class ReferenceDiscoverer;
|
||||||
class DataLayout;
|
class DataLayout;
|
||||||
class KlassClosure;
|
class KlassClosure;
|
||||||
class ClassLoaderData;
|
class ClassLoaderData;
|
||||||
@ -60,17 +60,17 @@ extern DoNothingClosure do_nothing_cl;
|
|||||||
// pollute the OopClosure interface.
|
// pollute the OopClosure interface.
|
||||||
class ExtendedOopClosure : public OopClosure {
|
class ExtendedOopClosure : public OopClosure {
|
||||||
private:
|
private:
|
||||||
ReferenceProcessor* _ref_processor;
|
ReferenceDiscoverer* _ref_discoverer;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ExtendedOopClosure(ReferenceProcessor* rp) : _ref_processor(rp) { }
|
ExtendedOopClosure(ReferenceDiscoverer* rd) : _ref_discoverer(rd) { }
|
||||||
ExtendedOopClosure() : _ref_processor(NULL) { }
|
ExtendedOopClosure() : _ref_discoverer(NULL) { }
|
||||||
~ExtendedOopClosure() { }
|
~ExtendedOopClosure() { }
|
||||||
|
|
||||||
void set_ref_processor_internal(ReferenceProcessor* rp) { _ref_processor = rp; }
|
void set_ref_discoverer_internal(ReferenceDiscoverer* rd) { _ref_discoverer = rd; }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ReferenceProcessor* ref_processor() const { return _ref_processor; }
|
ReferenceDiscoverer* ref_discoverer() const { return _ref_discoverer; }
|
||||||
|
|
||||||
// Iteration of InstanceRefKlasses differ depending on the closure,
|
// Iteration of InstanceRefKlasses differ depending on the closure,
|
||||||
// the below enum describes the different alternatives.
|
// the below enum describes the different alternatives.
|
||||||
@ -165,7 +165,7 @@ class MetadataAwareOopClosure: public ExtendedOopClosure {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
MetadataAwareOopClosure() : ExtendedOopClosure() { }
|
MetadataAwareOopClosure() : ExtendedOopClosure() { }
|
||||||
MetadataAwareOopClosure(ReferenceProcessor* rp) : ExtendedOopClosure(rp) { }
|
MetadataAwareOopClosure(ReferenceDiscoverer* rd) : ExtendedOopClosure(rd) { }
|
||||||
|
|
||||||
bool do_metadata_nv() { return true; }
|
bool do_metadata_nv() { return true; }
|
||||||
virtual bool do_metadata() { return do_metadata_nv(); }
|
virtual bool do_metadata() { return do_metadata_nv(); }
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include "memory/filemap.hpp"
|
#include "memory/filemap.hpp"
|
||||||
#include "memory/metadataFactory.hpp"
|
#include "memory/metadataFactory.hpp"
|
||||||
#include "memory/metaspaceClosure.hpp"
|
#include "memory/metaspaceClosure.hpp"
|
||||||
|
#include "memory/metaspaceCounters.hpp"
|
||||||
#include "memory/metaspaceShared.hpp"
|
#include "memory/metaspaceShared.hpp"
|
||||||
#include "memory/oopFactory.hpp"
|
#include "memory/oopFactory.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
|
@ -74,12 +74,12 @@ class CompiledICHolder : public CHeapObj<mtCompiler> {
|
|||||||
CompiledICHolder* next() { return _next; }
|
CompiledICHolder* next() { return _next; }
|
||||||
void set_next(CompiledICHolder* n) { _next = n; }
|
void set_next(CompiledICHolder* n) { _next = n; }
|
||||||
|
|
||||||
inline bool is_loader_alive(BoolObjectClosure* is_alive) {
|
inline bool is_loader_alive() {
|
||||||
Klass* k = _is_metadata_method ? ((Method*)_holder_metadata)->method_holder() : (Klass*)_holder_metadata;
|
Klass* k = _is_metadata_method ? ((Method*)_holder_metadata)->method_holder() : (Klass*)_holder_metadata;
|
||||||
if (!k->is_loader_alive(is_alive)) {
|
if (!k->is_loader_alive()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!_holder_klass->is_loader_alive(is_alive)) {
|
if (!_holder_klass->is_loader_alive()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "classfile/classFileParser.hpp"
|
#include "classfile/classFileParser.hpp"
|
||||||
#include "classfile/classFileStream.hpp"
|
#include "classfile/classFileStream.hpp"
|
||||||
#include "classfile/classLoader.hpp"
|
#include "classfile/classLoader.hpp"
|
||||||
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
#include "classfile/javaClasses.hpp"
|
#include "classfile/javaClasses.hpp"
|
||||||
#include "classfile/moduleEntry.hpp"
|
#include "classfile/moduleEntry.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
@ -1891,22 +1892,22 @@ bool InstanceKlass::is_dependent_nmethod(nmethod* nm) {
|
|||||||
}
|
}
|
||||||
#endif //PRODUCT
|
#endif //PRODUCT
|
||||||
|
|
||||||
void InstanceKlass::clean_weak_instanceklass_links(BoolObjectClosure* is_alive) {
|
void InstanceKlass::clean_weak_instanceklass_links() {
|
||||||
clean_implementors_list(is_alive);
|
clean_implementors_list();
|
||||||
clean_method_data(is_alive);
|
clean_method_data();
|
||||||
|
|
||||||
// Since GC iterates InstanceKlasses sequentially, it is safe to remove stale entries here.
|
// Since GC iterates InstanceKlasses sequentially, it is safe to remove stale entries here.
|
||||||
DependencyContext dep_context(&_dep_context);
|
DependencyContext dep_context(&_dep_context);
|
||||||
dep_context.expunge_stale_entries();
|
dep_context.expunge_stale_entries();
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) {
|
void InstanceKlass::clean_implementors_list() {
|
||||||
assert(class_loader_data()->is_alive(), "this klass should be live");
|
assert(is_loader_alive(), "this klass should be live");
|
||||||
if (is_interface()) {
|
if (is_interface()) {
|
||||||
if (ClassUnloading) {
|
if (ClassUnloading) {
|
||||||
Klass* impl = implementor();
|
Klass* impl = implementor();
|
||||||
if (impl != NULL) {
|
if (impl != NULL) {
|
||||||
if (!impl->is_loader_alive(is_alive)) {
|
if (!impl->is_loader_alive()) {
|
||||||
// remove this guy
|
// remove this guy
|
||||||
Klass** klass = adr_implementor();
|
Klass** klass = adr_implementor();
|
||||||
assert(klass != NULL, "null klass");
|
assert(klass != NULL, "null klass");
|
||||||
@ -1919,11 +1920,11 @@ void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceKlass::clean_method_data(BoolObjectClosure* is_alive) {
|
void InstanceKlass::clean_method_data() {
|
||||||
for (int m = 0; m < methods()->length(); m++) {
|
for (int m = 0; m < methods()->length(); m++) {
|
||||||
MethodData* mdo = methods()->at(m)->method_data();
|
MethodData* mdo = methods()->at(m)->method_data();
|
||||||
if (mdo != NULL) {
|
if (mdo != NULL) {
|
||||||
mdo->clean_method_data(is_alive);
|
mdo->clean_method_data(/*always_clean*/false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1148,9 +1148,9 @@ public:
|
|||||||
void adjust_default_methods(InstanceKlass* holder, bool* trace_name_printed);
|
void adjust_default_methods(InstanceKlass* holder, bool* trace_name_printed);
|
||||||
#endif // INCLUDE_JVMTI
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
||||||
void clean_weak_instanceklass_links(BoolObjectClosure* is_alive);
|
void clean_weak_instanceklass_links();
|
||||||
void clean_implementors_list(BoolObjectClosure* is_alive);
|
void clean_implementors_list();
|
||||||
void clean_method_data(BoolObjectClosure* is_alive);
|
void clean_method_data();
|
||||||
|
|
||||||
// Explicit metaspace deallocation of fields
|
// Explicit metaspace deallocation of fields
|
||||||
// For RedefineClasses and class file parsing errors, we need to deallocate
|
// For RedefineClasses and class file parsing errors, we need to deallocate
|
||||||
|
@ -63,14 +63,14 @@ void InstanceRefKlass::do_discovered(oop obj, OopClosureType* closure, Contains&
|
|||||||
|
|
||||||
template <typename T, class OopClosureType>
|
template <typename T, class OopClosureType>
|
||||||
bool InstanceRefKlass::try_discover(oop obj, ReferenceType type, OopClosureType* closure) {
|
bool InstanceRefKlass::try_discover(oop obj, ReferenceType type, OopClosureType* closure) {
|
||||||
ReferenceProcessor* rp = closure->ref_processor();
|
ReferenceDiscoverer* rd = closure->ref_discoverer();
|
||||||
if (rp != NULL) {
|
if (rd != NULL) {
|
||||||
T referent_oop = RawAccess<>::oop_load((T*)java_lang_ref_Reference::referent_addr_raw(obj));
|
T referent_oop = RawAccess<>::oop_load((T*)java_lang_ref_Reference::referent_addr_raw(obj));
|
||||||
if (!CompressedOops::is_null(referent_oop)) {
|
if (!CompressedOops::is_null(referent_oop)) {
|
||||||
oop referent = CompressedOops::decode_not_null(referent_oop);
|
oop referent = CompressedOops::decode_not_null(referent_oop);
|
||||||
if (!referent->is_gc_marked()) {
|
if (!referent->is_gc_marked()) {
|
||||||
// Only try to discover if not yet marked.
|
// Only try to discover if not yet marked.
|
||||||
return rp->discover_reference(obj, type);
|
return rd->discover_reference(obj, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
#include "classfile/dictionary.hpp"
|
#include "classfile/dictionary.hpp"
|
||||||
#include "classfile/javaClasses.hpp"
|
#include "classfile/javaClasses.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
@ -381,22 +382,7 @@ void Klass::append_to_sibling_list() {
|
|||||||
debug_only(verify();)
|
debug_only(verify();)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Klass::is_loader_alive(BoolObjectClosure* is_alive) {
|
void Klass::clean_weak_klass_links(bool clean_alive_klasses) {
|
||||||
#ifdef ASSERT
|
|
||||||
// The class is alive iff the class loader is alive.
|
|
||||||
oop loader = class_loader();
|
|
||||||
bool loader_alive = (loader == NULL) || is_alive->do_object_b(loader);
|
|
||||||
#endif // ASSERT
|
|
||||||
|
|
||||||
// The class is alive if it's mirror is alive (which should be marked if the
|
|
||||||
// loader is alive) unless it's an anoymous class.
|
|
||||||
bool mirror_alive = is_alive->do_object_b(java_mirror());
|
|
||||||
assert(!mirror_alive || loader_alive, "loader must be alive if the mirror is"
|
|
||||||
" but not the other way around with anonymous classes");
|
|
||||||
return mirror_alive;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive, bool clean_alive_klasses) {
|
|
||||||
if (!ClassUnloading) {
|
if (!ClassUnloading) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -408,11 +394,11 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive, bool clean_alive
|
|||||||
while (!stack.is_empty()) {
|
while (!stack.is_empty()) {
|
||||||
Klass* current = stack.pop();
|
Klass* current = stack.pop();
|
||||||
|
|
||||||
assert(current->is_loader_alive(is_alive), "just checking, this should be live");
|
assert(current->is_loader_alive(), "just checking, this should be live");
|
||||||
|
|
||||||
// Find and set the first alive subklass
|
// Find and set the first alive subklass
|
||||||
Klass* sub = current->subklass();
|
Klass* sub = current->subklass();
|
||||||
while (sub != NULL && !sub->is_loader_alive(is_alive)) {
|
while (sub != NULL && !sub->is_loader_alive()) {
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (log_is_enabled(Trace, class, unload)) {
|
if (log_is_enabled(Trace, class, unload)) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
@ -428,7 +414,7 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive, bool clean_alive
|
|||||||
|
|
||||||
// Find and set the first alive sibling
|
// Find and set the first alive sibling
|
||||||
Klass* sibling = current->next_sibling();
|
Klass* sibling = current->next_sibling();
|
||||||
while (sibling != NULL && !sibling->is_loader_alive(is_alive)) {
|
while (sibling != NULL && !sibling->is_loader_alive()) {
|
||||||
if (log_is_enabled(Trace, class, unload)) {
|
if (log_is_enabled(Trace, class, unload)) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
log_trace(class, unload)("[Unlinking class (sibling) %s]", sibling->external_name());
|
log_trace(class, unload)("[Unlinking class (sibling) %s]", sibling->external_name());
|
||||||
@ -443,12 +429,12 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive, bool clean_alive
|
|||||||
// Clean the implementors list and method data.
|
// Clean the implementors list and method data.
|
||||||
if (clean_alive_klasses && current->is_instance_klass()) {
|
if (clean_alive_klasses && current->is_instance_klass()) {
|
||||||
InstanceKlass* ik = InstanceKlass::cast(current);
|
InstanceKlass* ik = InstanceKlass::cast(current);
|
||||||
ik->clean_weak_instanceklass_links(is_alive);
|
ik->clean_weak_instanceklass_links();
|
||||||
|
|
||||||
// JVMTI RedefineClasses creates previous versions that are not in
|
// JVMTI RedefineClasses creates previous versions that are not in
|
||||||
// the class hierarchy, so process them here.
|
// the class hierarchy, so process them here.
|
||||||
while ((ik = ik->previous_versions()) != NULL) {
|
while ((ik = ik->previous_versions()) != NULL) {
|
||||||
ik->clean_weak_instanceklass_links(is_alive);
|
ik->clean_weak_instanceklass_links();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#ifndef SHARE_VM_OOPS_KLASS_HPP
|
#ifndef SHARE_VM_OOPS_KLASS_HPP
|
||||||
#define SHARE_VM_OOPS_KLASS_HPP
|
#define SHARE_VM_OOPS_KLASS_HPP
|
||||||
|
|
||||||
|
#include "classfile/classLoaderData.hpp"
|
||||||
#include "gc/shared/specialized_oop_closures.hpp"
|
#include "gc/shared/specialized_oop_closures.hpp"
|
||||||
#include "memory/iterator.hpp"
|
#include "memory/iterator.hpp"
|
||||||
#include "memory/memRegion.hpp"
|
#include "memory/memRegion.hpp"
|
||||||
@ -52,7 +53,6 @@
|
|||||||
// Forward declarations.
|
// Forward declarations.
|
||||||
template <class T> class Array;
|
template <class T> class Array;
|
||||||
template <class T> class GrowableArray;
|
template <class T> class GrowableArray;
|
||||||
class ClassLoaderData;
|
|
||||||
class fieldDescriptor;
|
class fieldDescriptor;
|
||||||
class KlassSizeStats;
|
class KlassSizeStats;
|
||||||
class klassVtable;
|
class klassVtable;
|
||||||
@ -634,13 +634,12 @@ protected:
|
|||||||
virtual MetaspaceObj::Type type() const { return ClassType; }
|
virtual MetaspaceObj::Type type() const { return ClassType; }
|
||||||
|
|
||||||
// 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. Has already been marked as unloading.
|
||||||
// The is_alive closure passed in depends on the Garbage Collector used.
|
bool is_loader_alive() const { return !class_loader_data()->is_unloading(); }
|
||||||
bool is_loader_alive(BoolObjectClosure* is_alive);
|
|
||||||
|
|
||||||
static void clean_weak_klass_links(BoolObjectClosure* is_alive, bool clean_alive_klasses = true);
|
static void clean_weak_klass_links(bool clean_alive_klasses = true);
|
||||||
static void clean_subklass_tree(BoolObjectClosure* is_alive) {
|
static void clean_subklass_tree() {
|
||||||
clean_weak_klass_links(is_alive, false /* clean_alive_klasses */);
|
clean_weak_klass_links(false /* clean_alive_klasses */);
|
||||||
}
|
}
|
||||||
|
|
||||||
// GC specific object visitors
|
// GC specific object visitors
|
||||||
|
@ -71,9 +71,9 @@ void DataLayout::initialize(u1 tag, u2 bci, int cell_count) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DataLayout::clean_weak_klass_links(BoolObjectClosure* cl) {
|
void DataLayout::clean_weak_klass_links(bool always_clean) {
|
||||||
ResourceMark m;
|
ResourceMark m;
|
||||||
data_in()->clean_weak_klass_links(cl);
|
data_in()->clean_weak_klass_links(always_clean);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -315,23 +315,20 @@ void VirtualCallTypeData::post_initialize(BytecodeStream* stream, MethodData* md
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TypeEntries::is_loader_alive(BoolObjectClosure* is_alive_cl, intptr_t p) {
|
void TypeStackSlotEntries::clean_weak_klass_links(bool always_clean) {
|
||||||
Klass* k = (Klass*)klass_part(p);
|
|
||||||
return k != NULL && k->is_loader_alive(is_alive_cl);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TypeStackSlotEntries::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) {
|
|
||||||
for (int i = 0; i < _number_of_entries; i++) {
|
for (int i = 0; i < _number_of_entries; i++) {
|
||||||
intptr_t p = type(i);
|
intptr_t p = type(i);
|
||||||
if (!is_loader_alive(is_alive_cl, p)) {
|
Klass* k = (Klass*)klass_part(p);
|
||||||
|
if (k != NULL && (always_clean || !k->is_loader_alive())) {
|
||||||
set_type(i, with_status((Klass*)NULL, p));
|
set_type(i, with_status((Klass*)NULL, p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReturnTypeEntry::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) {
|
void ReturnTypeEntry::clean_weak_klass_links(bool always_clean) {
|
||||||
intptr_t p = type();
|
intptr_t p = type();
|
||||||
if (!is_loader_alive(is_alive_cl, p)) {
|
Klass* k = (Klass*)klass_part(p);
|
||||||
|
if (k != NULL && (always_clean || !k->is_loader_alive())) {
|
||||||
set_type(with_status((Klass*)NULL, p));
|
set_type(with_status((Klass*)NULL, p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -408,21 +405,21 @@ void VirtualCallTypeData::print_data_on(outputStream* st, const char* extra) con
|
|||||||
// that the check is reached, and a series of (Klass*, count) pairs
|
// that the check is reached, and a series of (Klass*, count) pairs
|
||||||
// which are used to store a type profile for the receiver of the check.
|
// which are used to store a type profile for the receiver of the check.
|
||||||
|
|
||||||
void ReceiverTypeData::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) {
|
void ReceiverTypeData::clean_weak_klass_links(bool always_clean) {
|
||||||
for (uint row = 0; row < row_limit(); row++) {
|
for (uint row = 0; row < row_limit(); row++) {
|
||||||
Klass* p = receiver(row);
|
Klass* p = receiver(row);
|
||||||
if (p != NULL && !p->is_loader_alive(is_alive_cl)) {
|
if (p != NULL && (always_clean || !p->is_loader_alive())) {
|
||||||
clear_row(row);
|
clear_row(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if INCLUDE_JVMCI
|
#if INCLUDE_JVMCI
|
||||||
void VirtualCallData::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) {
|
void VirtualCallData::clean_weak_klass_links(bool always_clean) {
|
||||||
ReceiverTypeData::clean_weak_klass_links(is_alive_cl);
|
ReceiverTypeData::clean_weak_klass_links(always_clean);
|
||||||
for (uint row = 0; row < method_row_limit(); row++) {
|
for (uint row = 0; row < method_row_limit(); row++) {
|
||||||
Method* p = method(row);
|
Method* p = method(row);
|
||||||
if (p != NULL && !p->method_holder()->is_loader_alive(is_alive_cl)) {
|
if (p != NULL && (always_clean || !p->method_holder()->is_loader_alive())) {
|
||||||
clear_method_row(row);
|
clear_method_row(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1669,12 +1666,11 @@ public:
|
|||||||
|
|
||||||
// Check for entries that reference an unloaded method
|
// Check for entries that reference an unloaded method
|
||||||
class CleanExtraDataKlassClosure : public CleanExtraDataClosure {
|
class CleanExtraDataKlassClosure : public CleanExtraDataClosure {
|
||||||
private:
|
bool _always_clean;
|
||||||
BoolObjectClosure* _is_alive;
|
|
||||||
public:
|
public:
|
||||||
CleanExtraDataKlassClosure(BoolObjectClosure* is_alive) : _is_alive(is_alive) {}
|
CleanExtraDataKlassClosure(bool always_clean) : _always_clean(always_clean) {}
|
||||||
bool is_live(Method* m) {
|
bool is_live(Method* m) {
|
||||||
return m->method_holder()->is_loader_alive(_is_alive);
|
return !(_always_clean) && m->method_holder()->is_loader_alive();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1757,19 +1753,19 @@ void MethodData::verify_extra_data_clean(CleanExtraDataClosure* cl) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void MethodData::clean_method_data(BoolObjectClosure* is_alive) {
|
void MethodData::clean_method_data(bool always_clean) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
for (ProfileData* data = first_data();
|
for (ProfileData* data = first_data();
|
||||||
is_valid(data);
|
is_valid(data);
|
||||||
data = next_data(data)) {
|
data = next_data(data)) {
|
||||||
data->clean_weak_klass_links(is_alive);
|
data->clean_weak_klass_links(always_clean);
|
||||||
}
|
}
|
||||||
ParametersTypeData* parameters = parameters_type_data();
|
ParametersTypeData* parameters = parameters_type_data();
|
||||||
if (parameters != NULL) {
|
if (parameters != NULL) {
|
||||||
parameters->clean_weak_klass_links(is_alive);
|
parameters->clean_weak_klass_links(always_clean);
|
||||||
}
|
}
|
||||||
|
|
||||||
CleanExtraDataKlassClosure cl(is_alive);
|
CleanExtraDataKlassClosure cl(always_clean);
|
||||||
clean_extra_data(&cl);
|
clean_extra_data(&cl);
|
||||||
verify_extra_data_clean(&cl);
|
verify_extra_data_clean(&cl);
|
||||||
}
|
}
|
||||||
|
@ -254,7 +254,7 @@ public:
|
|||||||
ProfileData* data_in();
|
ProfileData* data_in();
|
||||||
|
|
||||||
// GC support
|
// GC support
|
||||||
void clean_weak_klass_links(BoolObjectClosure* cl);
|
void clean_weak_klass_links(bool always_clean);
|
||||||
|
|
||||||
// Redefinition support
|
// Redefinition support
|
||||||
void clean_weak_method_links();
|
void clean_weak_method_links();
|
||||||
@ -505,7 +505,7 @@ public:
|
|||||||
virtual void post_initialize(BytecodeStream* stream, MethodData* mdo) {}
|
virtual void post_initialize(BytecodeStream* stream, MethodData* mdo) {}
|
||||||
|
|
||||||
// GC support
|
// GC support
|
||||||
virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {}
|
virtual void clean_weak_klass_links(bool always_clean) {}
|
||||||
|
|
||||||
// Redefinition support
|
// Redefinition support
|
||||||
virtual void clean_weak_method_links() {}
|
virtual void clean_weak_method_links() {}
|
||||||
@ -820,9 +820,6 @@ public:
|
|||||||
|
|
||||||
static void print_klass(outputStream* st, intptr_t k);
|
static void print_klass(outputStream* st, intptr_t k);
|
||||||
|
|
||||||
// GC support
|
|
||||||
static bool is_loader_alive(BoolObjectClosure* is_alive_cl, intptr_t p);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// ProfileData object these entries are part of
|
// ProfileData object these entries are part of
|
||||||
ProfileData* _pd;
|
ProfileData* _pd;
|
||||||
@ -930,7 +927,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GC support
|
// GC support
|
||||||
void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
|
void clean_weak_klass_links(bool always_clean);
|
||||||
|
|
||||||
void print_data_on(outputStream* st) const;
|
void print_data_on(outputStream* st) const;
|
||||||
};
|
};
|
||||||
@ -973,7 +970,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GC support
|
// GC support
|
||||||
void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
|
void clean_weak_klass_links(bool always_clean);
|
||||||
|
|
||||||
void print_data_on(outputStream* st) const;
|
void print_data_on(outputStream* st) const;
|
||||||
};
|
};
|
||||||
@ -1157,12 +1154,12 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GC support
|
// GC support
|
||||||
virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {
|
virtual void clean_weak_klass_links(bool always_clean) {
|
||||||
if (has_arguments()) {
|
if (has_arguments()) {
|
||||||
_args.clean_weak_klass_links(is_alive_closure);
|
_args.clean_weak_klass_links(always_clean);
|
||||||
}
|
}
|
||||||
if (has_return()) {
|
if (has_return()) {
|
||||||
_ret.clean_weak_klass_links(is_alive_closure);
|
_ret.clean_weak_klass_links(always_clean);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1303,7 +1300,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GC support
|
// GC support
|
||||||
virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
|
virtual void clean_weak_klass_links(bool always_clean);
|
||||||
|
|
||||||
#ifdef CC_INTERP
|
#ifdef CC_INTERP
|
||||||
static int receiver_type_data_size_in_bytes() {
|
static int receiver_type_data_size_in_bytes() {
|
||||||
@ -1433,7 +1430,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GC support
|
// GC support
|
||||||
virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
|
virtual void clean_weak_klass_links(bool always_clean);
|
||||||
|
|
||||||
// Redefinition support
|
// Redefinition support
|
||||||
virtual void clean_weak_method_links();
|
virtual void clean_weak_method_links();
|
||||||
@ -1562,13 +1559,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GC support
|
// GC support
|
||||||
virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {
|
virtual void clean_weak_klass_links(bool always_clean) {
|
||||||
ReceiverTypeData::clean_weak_klass_links(is_alive_closure);
|
ReceiverTypeData::clean_weak_klass_links(always_clean);
|
||||||
if (has_arguments()) {
|
if (has_arguments()) {
|
||||||
_args.clean_weak_klass_links(is_alive_closure);
|
_args.clean_weak_klass_links(always_clean);
|
||||||
}
|
}
|
||||||
if (has_return()) {
|
if (has_return()) {
|
||||||
_ret.clean_weak_klass_links(is_alive_closure);
|
_ret.clean_weak_klass_links(always_clean);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2021,8 +2018,8 @@ public:
|
|||||||
_parameters.set_type(i, TypeEntries::with_status((intptr_t)k, current));
|
_parameters.set_type(i, TypeEntries::with_status((intptr_t)k, current));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {
|
virtual void clean_weak_klass_links(bool always_clean) {
|
||||||
_parameters.clean_weak_klass_links(is_alive_closure);
|
_parameters.clean_weak_klass_links(always_clean);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
|
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
|
||||||
@ -2610,7 +2607,7 @@ public:
|
|||||||
static bool profile_parameters();
|
static bool profile_parameters();
|
||||||
static bool profile_return_jsr292_only();
|
static bool profile_return_jsr292_only();
|
||||||
|
|
||||||
void clean_method_data(BoolObjectClosure* is_alive);
|
void clean_method_data(bool always_clean);
|
||||||
void clean_weak_method_links();
|
void clean_weak_method_links();
|
||||||
DEBUG_ONLY(void verify_clean_weak_method_links();)
|
DEBUG_ONLY(void verify_clean_weak_method_links();)
|
||||||
Mutex* extra_data_lock() { return &_extra_data_lock; }
|
Mutex* extra_data_lock() { return &_extra_data_lock; }
|
||||||
|
@ -46,7 +46,7 @@ public:
|
|||||||
inline oop resolve() const;
|
inline oop resolve() const;
|
||||||
|
|
||||||
// Used only for removing handle.
|
// Used only for removing handle.
|
||||||
oop* ptr_raw() { return _obj; }
|
oop* ptr_raw() const { return _obj; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // SHARE_VM_OOPS_OOPHANDLE_HPP
|
#endif // SHARE_VM_OOPS_OOPHANDLE_HPP
|
||||||
|
@ -51,8 +51,8 @@ template <WeakHandleType T>
|
|||||||
void WeakHandle<T>::release() const {
|
void WeakHandle<T>::release() const {
|
||||||
// Only release if the pointer to the object has been created.
|
// Only release if the pointer to the object has been created.
|
||||||
if (_obj != NULL) {
|
if (_obj != NULL) {
|
||||||
// Clear the WeakHandle. For class loader data race, the handle may not have
|
// Clear the WeakHandle. For race in creating ClassLoaderData, we can release this
|
||||||
// been previously cleared by GC.
|
// WeakHandle before it is cleared by GC.
|
||||||
RootAccess<ON_PHANTOM_OOP_REF>::oop_store(_obj, (oop)NULL);
|
RootAccess<ON_PHANTOM_OOP_REF>::oop_store(_obj, (oop)NULL);
|
||||||
get_storage()->release(_obj);
|
get_storage()->release(_obj);
|
||||||
}
|
}
|
||||||
|
@ -63,4 +63,6 @@ class WeakHandle {
|
|||||||
void print_on(outputStream* st) const;
|
void print_on(outputStream* st) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef WeakHandle<vm_class_loader_data> ClassLoaderWeakHandle;
|
||||||
|
|
||||||
#endif // SHARE_VM_OOPS_WEAKHANDLE_HPP
|
#endif // SHARE_VM_OOPS_WEAKHANDLE_HPP
|
||||||
|
@ -2768,15 +2768,14 @@ JNIEXPORT int jio_printf(const char *fmt, ...) {
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// HotSpot specific jio method
|
// HotSpot specific jio method
|
||||||
void jio_print(const char* s) {
|
void jio_print(const char* s, size_t len) {
|
||||||
// Try to make this function as atomic as possible.
|
// Try to make this function as atomic as possible.
|
||||||
if (Arguments::vfprintf_hook() != NULL) {
|
if (Arguments::vfprintf_hook() != NULL) {
|
||||||
jio_fprintf(defaultStream::output_stream(), "%s", s);
|
jio_fprintf(defaultStream::output_stream(), "%.*s", (int)len, s);
|
||||||
} else {
|
} else {
|
||||||
// Make an unused local variable to avoid warning from gcc 4.x compiler.
|
// Make an unused local variable to avoid warning from gcc 4.x compiler.
|
||||||
size_t count = ::write(defaultStream::output_fd(), s, (int)strlen(s));
|
size_t count = ::write(defaultStream::output_fd(), s, (int)len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
#include "classfile/systemDictionary.hpp"
|
#include "classfile/systemDictionary.hpp"
|
||||||
#include "gc/shared/collectedHeap.hpp"
|
#include "gc/shared/collectedHeap.hpp"
|
||||||
#include "memory/universe.hpp"
|
#include "memory/universe.hpp"
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
#include "oops/method.hpp"
|
#include "oops/method.hpp"
|
||||||
#include "oops/symbol.hpp"
|
#include "oops/symbol.hpp"
|
||||||
|
#include "oops/weakHandle.inline.hpp"
|
||||||
#include "prims/resolvedMethodTable.hpp"
|
#include "prims/resolvedMethodTable.hpp"
|
||||||
#include "runtime/handles.inline.hpp"
|
#include "runtime/handles.inline.hpp"
|
||||||
#include "runtime/mutexLocker.hpp"
|
#include "runtime/mutexLocker.hpp"
|
||||||
@ -39,7 +40,7 @@
|
|||||||
|
|
||||||
|
|
||||||
oop ResolvedMethodEntry::object() {
|
oop ResolvedMethodEntry::object() {
|
||||||
return RootAccess<ON_PHANTOM_OOP_REF>::oop_load(literal_addr());
|
return literal().resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
oop ResolvedMethodEntry::object_no_keepalive() {
|
oop ResolvedMethodEntry::object_no_keepalive() {
|
||||||
@ -48,11 +49,11 @@ oop ResolvedMethodEntry::object_no_keepalive() {
|
|||||||
// not leak out past a thread transition where a safepoint can happen.
|
// not leak out past a thread transition where a safepoint can happen.
|
||||||
// A subsequent oop_load without AS_NO_KEEPALIVE (the object() accessor)
|
// A subsequent oop_load without AS_NO_KEEPALIVE (the object() accessor)
|
||||||
// keeps the oop alive before doing so.
|
// keeps the oop alive before doing so.
|
||||||
return RootAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(literal_addr());
|
return literal().peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedMethodTable::ResolvedMethodTable()
|
ResolvedMethodTable::ResolvedMethodTable()
|
||||||
: Hashtable<oop, mtClass>(_table_size, sizeof(ResolvedMethodEntry)) { }
|
: Hashtable<ClassLoaderWeakHandle, mtClass>(_table_size, sizeof(ResolvedMethodEntry)) { }
|
||||||
|
|
||||||
oop ResolvedMethodTable::lookup(int index, unsigned int hash, Method* method) {
|
oop ResolvedMethodTable::lookup(int index, unsigned int hash, Method* method) {
|
||||||
for (ResolvedMethodEntry* p = bucket(index); p != NULL; p = p->next()) {
|
for (ResolvedMethodEntry* p = bucket(index); p != NULL; p = p->next()) {
|
||||||
@ -62,7 +63,7 @@ oop ResolvedMethodTable::lookup(int index, unsigned int hash, Method* method) {
|
|||||||
oop target = p->object_no_keepalive();
|
oop target = p->object_no_keepalive();
|
||||||
|
|
||||||
// The method is in the table as a target already
|
// The method is in the table as a target already
|
||||||
if (java_lang_invoke_ResolvedMethodName::vmtarget(target) == method) {
|
if (target != NULL && java_lang_invoke_ResolvedMethodName::vmtarget(target) == method) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
log_debug(membername, table) ("ResolvedMethod entry found for %s index %d",
|
log_debug(membername, table) ("ResolvedMethod entry found for %s index %d",
|
||||||
method->name_and_sig_as_C_string(), index);
|
method->name_and_sig_as_C_string(), index);
|
||||||
@ -88,7 +89,7 @@ oop ResolvedMethodTable::lookup(Method* method) {
|
|||||||
return lookup(index, hash, method);
|
return lookup(index, hash, method);
|
||||||
}
|
}
|
||||||
|
|
||||||
oop ResolvedMethodTable::basic_add(Method* method, oop rmethod_name) {
|
oop ResolvedMethodTable::basic_add(Method* method, Handle rmethod_name) {
|
||||||
assert_locked_or_safepoint(ResolvedMethodTable_lock);
|
assert_locked_or_safepoint(ResolvedMethodTable_lock);
|
||||||
|
|
||||||
unsigned int hash = compute_hash(method);
|
unsigned int hash = compute_hash(method);
|
||||||
@ -100,12 +101,13 @@ oop ResolvedMethodTable::basic_add(Method* method, oop rmethod_name) {
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedMethodEntry* p = (ResolvedMethodEntry*) Hashtable<oop, mtClass>::new_entry(hash, rmethod_name);
|
ClassLoaderWeakHandle w = ClassLoaderWeakHandle::create(rmethod_name);
|
||||||
Hashtable<oop, mtClass>::add_entry(index, p);
|
ResolvedMethodEntry* p = (ResolvedMethodEntry*) Hashtable<ClassLoaderWeakHandle, mtClass>::new_entry(hash, w);
|
||||||
|
Hashtable<ClassLoaderWeakHandle, mtClass>::add_entry(index, p);
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
log_debug(membername, table) ("ResolvedMethod entry added for %s index %d",
|
log_debug(membername, table) ("ResolvedMethod entry added for %s index %d",
|
||||||
method->name_and_sig_as_C_string(), index);
|
method->name_and_sig_as_C_string(), index);
|
||||||
return rmethod_name;
|
return rmethod_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedMethodTable* ResolvedMethodTable::_the_table = NULL;
|
ResolvedMethodTable* ResolvedMethodTable::_the_table = NULL;
|
||||||
@ -134,7 +136,7 @@ oop ResolvedMethodTable::add_method(Handle resolved_method_name) {
|
|||||||
// have any membernames in the table.
|
// have any membernames in the table.
|
||||||
method->method_holder()->set_has_resolved_methods();
|
method->method_holder()->set_has_resolved_methods();
|
||||||
|
|
||||||
return _the_table->basic_add(method, resolved_method_name());
|
return _the_table->basic_add(method, resolved_method_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removing entries
|
// Removing entries
|
||||||
@ -143,7 +145,7 @@ int ResolvedMethodTable::_oops_counted = 0;
|
|||||||
|
|
||||||
// Serially invoke removed unused oops from the table.
|
// Serially invoke removed unused oops from the table.
|
||||||
// This is done late during GC.
|
// This is done late during GC.
|
||||||
void ResolvedMethodTable::unlink(BoolObjectClosure* is_alive) {
|
void ResolvedMethodTable::unlink() {
|
||||||
_oops_removed = 0;
|
_oops_removed = 0;
|
||||||
_oops_counted = 0;
|
_oops_counted = 0;
|
||||||
for (int i = 0; i < _the_table->table_size(); ++i) {
|
for (int i = 0; i < _the_table->table_size(); ++i) {
|
||||||
@ -151,38 +153,27 @@ void ResolvedMethodTable::unlink(BoolObjectClosure* is_alive) {
|
|||||||
ResolvedMethodEntry* entry = _the_table->bucket(i);
|
ResolvedMethodEntry* entry = _the_table->bucket(i);
|
||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
_oops_counted++;
|
_oops_counted++;
|
||||||
if (is_alive->do_object_b(entry->object_no_keepalive())) {
|
oop l = entry->object_no_keepalive();
|
||||||
|
if (l != NULL) {
|
||||||
p = entry->next_addr();
|
p = entry->next_addr();
|
||||||
} else {
|
} else {
|
||||||
|
// Entry has been removed.
|
||||||
_oops_removed++;
|
_oops_removed++;
|
||||||
if (log_is_enabled(Debug, membername, table)) {
|
if (log_is_enabled(Debug, membername, table)) {
|
||||||
Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(entry->object_no_keepalive());
|
log_debug(membername, table) ("ResolvedMethod entry removed for index %d", i);
|
||||||
ResourceMark rm;
|
|
||||||
log_debug(membername, table) ("ResolvedMethod entry removed for %s index %d",
|
|
||||||
m->name_and_sig_as_C_string(), i);
|
|
||||||
}
|
}
|
||||||
|
entry->literal().release();
|
||||||
*p = entry->next();
|
*p = entry->next();
|
||||||
_the_table->free_entry(entry);
|
_the_table->free_entry(entry);
|
||||||
}
|
}
|
||||||
// get next entry
|
// get next entry
|
||||||
entry = (ResolvedMethodEntry*)HashtableEntry<oop, mtClass>::make_ptr(*p);
|
entry = (ResolvedMethodEntry*)HashtableEntry<ClassLoaderWeakHandle, mtClass>::make_ptr(*p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
log_debug(membername, table) ("ResolvedMethod entries counted %d removed %d",
|
log_debug(membername, table) ("ResolvedMethod entries counted %d removed %d",
|
||||||
_oops_counted, _oops_removed);
|
_oops_counted, _oops_removed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serially invoke "f->do_oop" on the locations of all oops in the table.
|
|
||||||
void ResolvedMethodTable::oops_do(OopClosure* f) {
|
|
||||||
for (int i = 0; i < _the_table->table_size(); ++i) {
|
|
||||||
ResolvedMethodEntry* entry = _the_table->bucket(i);
|
|
||||||
while (entry != NULL) {
|
|
||||||
f->do_oop(entry->literal_addr());
|
|
||||||
entry = entry->next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void ResolvedMethodTable::print() {
|
void ResolvedMethodTable::print() {
|
||||||
for (int i = 0; i < table_size(); ++i) {
|
for (int i = 0; i < table_size(); ++i) {
|
||||||
@ -190,9 +181,11 @@ void ResolvedMethodTable::print() {
|
|||||||
while (entry != NULL) {
|
while (entry != NULL) {
|
||||||
tty->print("%d : ", i);
|
tty->print("%d : ", i);
|
||||||
oop rmethod_name = entry->object_no_keepalive();
|
oop rmethod_name = entry->object_no_keepalive();
|
||||||
rmethod_name->print();
|
if (rmethod_name != NULL) {
|
||||||
Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(rmethod_name);
|
rmethod_name->print();
|
||||||
m->print();
|
Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(rmethod_name);
|
||||||
|
m->print();
|
||||||
|
}
|
||||||
entry = entry->next();
|
entry = entry->next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -205,9 +198,15 @@ void ResolvedMethodTable::adjust_method_entries(bool * trace_name_printed) {
|
|||||||
assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
|
assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
|
||||||
// For each entry in RMT, change to new method
|
// For each entry in RMT, change to new method
|
||||||
for (int i = 0; i < _the_table->table_size(); ++i) {
|
for (int i = 0; i < _the_table->table_size(); ++i) {
|
||||||
ResolvedMethodEntry* entry = _the_table->bucket(i);
|
for (ResolvedMethodEntry* entry = _the_table->bucket(i);
|
||||||
while (entry != NULL) {
|
entry != NULL;
|
||||||
|
entry = entry->next()) {
|
||||||
|
|
||||||
oop mem_name = entry->object_no_keepalive();
|
oop mem_name = entry->object_no_keepalive();
|
||||||
|
// except ones removed
|
||||||
|
if (mem_name == NULL) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Method* old_method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name);
|
Method* old_method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name);
|
||||||
|
|
||||||
if (old_method->is_old()) {
|
if (old_method->is_old()) {
|
||||||
@ -235,7 +234,6 @@ void ResolvedMethodTable::adjust_method_entries(bool * trace_name_printed) {
|
|||||||
("ResolvedMethod method update: %s(%s)",
|
("ResolvedMethod method update: %s(%s)",
|
||||||
new_method->name()->as_C_string(), new_method->signature()->as_C_string());
|
new_method->name()->as_C_string(), new_method->signature()->as_C_string());
|
||||||
}
|
}
|
||||||
entry = entry->next();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2017, 2018, 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
|
||||||
@ -26,22 +26,23 @@
|
|||||||
#define SHARE_VM_PRIMS_RESOLVEDMETHOD_HPP
|
#define SHARE_VM_PRIMS_RESOLVEDMETHOD_HPP
|
||||||
|
|
||||||
#include "oops/symbol.hpp"
|
#include "oops/symbol.hpp"
|
||||||
|
#include "oops/weakHandle.hpp"
|
||||||
#include "utilities/hashtable.hpp"
|
#include "utilities/hashtable.hpp"
|
||||||
|
|
||||||
// Hashtable to record Method* used in ResolvedMethods, via. ResolvedMethod oops.
|
// Hashtable to record Method* used in ResolvedMethods, via. ResolvedMethod oops.
|
||||||
// This is needed for redefinition to replace Method* with redefined versions.
|
// This is needed for redefinition to replace Method* with redefined versions.
|
||||||
|
|
||||||
// Entry in a ResolvedMethodTable, mapping a single oop of java_lang_invoke_ResolvedMethodName which
|
// Entry in a ResolvedMethodTable, mapping a ClassLoaderWeakHandle for a single oop of
|
||||||
// holds JVM Method* in vmtarget.
|
// java_lang_invoke_ResolvedMethodName which holds JVM Method* in vmtarget.
|
||||||
|
|
||||||
class ResolvedMethodEntry : public HashtableEntry<oop, mtClass> {
|
class ResolvedMethodEntry : public HashtableEntry<ClassLoaderWeakHandle, mtClass> {
|
||||||
public:
|
public:
|
||||||
ResolvedMethodEntry* next() const {
|
ResolvedMethodEntry* next() const {
|
||||||
return (ResolvedMethodEntry*)HashtableEntry<oop, mtClass>::next();
|
return (ResolvedMethodEntry*)HashtableEntry<ClassLoaderWeakHandle, mtClass>::next();
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedMethodEntry** next_addr() {
|
ResolvedMethodEntry** next_addr() {
|
||||||
return (ResolvedMethodEntry**)HashtableEntry<oop, mtClass>::next_addr();
|
return (ResolvedMethodEntry**)HashtableEntry<ClassLoaderWeakHandle, mtClass>::next_addr();
|
||||||
}
|
}
|
||||||
|
|
||||||
oop object();
|
oop object();
|
||||||
@ -50,7 +51,7 @@ class ResolvedMethodEntry : public HashtableEntry<oop, mtClass> {
|
|||||||
void print_on(outputStream* st) const;
|
void print_on(outputStream* st) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ResolvedMethodTable : public Hashtable<oop, mtClass> {
|
class ResolvedMethodTable : public Hashtable<ClassLoaderWeakHandle, mtClass> {
|
||||||
enum Constants {
|
enum Constants {
|
||||||
_table_size = 1007
|
_table_size = 1007
|
||||||
};
|
};
|
||||||
@ -61,11 +62,11 @@ class ResolvedMethodTable : public Hashtable<oop, mtClass> {
|
|||||||
static ResolvedMethodTable* _the_table;
|
static ResolvedMethodTable* _the_table;
|
||||||
private:
|
private:
|
||||||
ResolvedMethodEntry* bucket(int i) {
|
ResolvedMethodEntry* bucket(int i) {
|
||||||
return (ResolvedMethodEntry*) Hashtable<oop, mtClass>::bucket(i);
|
return (ResolvedMethodEntry*) Hashtable<ClassLoaderWeakHandle, mtClass>::bucket(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResolvedMethodEntry** bucket_addr(int i) {
|
ResolvedMethodEntry** bucket_addr(int i) {
|
||||||
return (ResolvedMethodEntry**) Hashtable<oop, mtClass>::bucket_addr(i);
|
return (ResolvedMethodEntry**) Hashtable<ClassLoaderWeakHandle, mtClass>::bucket_addr(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int compute_hash(Method* method);
|
unsigned int compute_hash(Method* method);
|
||||||
@ -75,7 +76,7 @@ private:
|
|||||||
oop lookup(Method* method);
|
oop lookup(Method* method);
|
||||||
|
|
||||||
// must be done under ResolvedMethodTable_lock
|
// must be done under ResolvedMethodTable_lock
|
||||||
oop basic_add(Method* method, oop rmethod_name);
|
oop basic_add(Method* method, Handle rmethod_name);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ResolvedMethodTable();
|
ResolvedMethodTable();
|
||||||
@ -95,8 +96,7 @@ public:
|
|||||||
#endif // INCLUDE_JVMTI
|
#endif // INCLUDE_JVMTI
|
||||||
|
|
||||||
// Cleanup cleared entries
|
// Cleanup cleared entries
|
||||||
static void unlink(BoolObjectClosure* is_alive);
|
static void unlink();
|
||||||
static void oops_do(OopClosure* f);
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void print();
|
void print();
|
||||||
|
@ -933,8 +933,6 @@ WB_ENTRY(jint, WB_MatchesMethod(JNIEnv* env, jobject o, jobject method, jstring
|
|||||||
return result;
|
return result;
|
||||||
WB_END
|
WB_END
|
||||||
|
|
||||||
static AlwaysFalseClosure always_false;
|
|
||||||
|
|
||||||
WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
|
WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
|
||||||
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
|
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
|
||||||
CHECK_JNI_EXCEPTION(env);
|
CHECK_JNI_EXCEPTION(env);
|
||||||
@ -951,7 +949,7 @@ WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
|
|||||||
mdo->set_arg_modified(i, 0);
|
mdo->set_arg_modified(i, 0);
|
||||||
}
|
}
|
||||||
MutexLockerEx mu(mdo->extra_data_lock());
|
MutexLockerEx mu(mdo->extra_data_lock());
|
||||||
mdo->clean_method_data(&always_false);
|
mdo->clean_method_data(/*always_clean*/true);
|
||||||
}
|
}
|
||||||
|
|
||||||
mh->clear_not_c1_compilable();
|
mh->clear_not_c1_compilable();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1998, 2018, 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
|
||||||
@ -106,7 +106,8 @@ class Monitor : public CHeapObj<mtInternal> {
|
|||||||
access = event + 1,
|
access = event + 1,
|
||||||
special = access + 2,
|
special = access + 2,
|
||||||
suspend_resume = special + 1,
|
suspend_resume = special + 1,
|
||||||
leaf = suspend_resume + 2,
|
vmweak = suspend_resume + 2,
|
||||||
|
leaf = vmweak + 2,
|
||||||
safepoint = leaf + 10,
|
safepoint = leaf + 10,
|
||||||
barrier = safepoint + 1,
|
barrier = safepoint + 1,
|
||||||
nonleaf = barrier + 1,
|
nonleaf = barrier + 1,
|
||||||
|
@ -182,6 +182,9 @@ void mutex_init() {
|
|||||||
def(CGC_lock , PaddedMonitor, special, true, Monitor::_safepoint_check_never); // coordinate between fore- and background GC
|
def(CGC_lock , PaddedMonitor, special, true, Monitor::_safepoint_check_never); // coordinate between fore- and background GC
|
||||||
def(STS_lock , PaddedMonitor, leaf, true, Monitor::_safepoint_check_never);
|
def(STS_lock , PaddedMonitor, leaf, true, Monitor::_safepoint_check_never);
|
||||||
|
|
||||||
|
def(VMWeakAlloc_lock , PaddedMutex , vmweak, true, Monitor::_safepoint_check_never);
|
||||||
|
def(VMWeakActive_lock , PaddedMutex , vmweak-1, true, Monitor::_safepoint_check_never);
|
||||||
|
|
||||||
if (UseConcMarkSweepGC || UseG1GC) {
|
if (UseConcMarkSweepGC || UseG1GC) {
|
||||||
def(FullGCCount_lock , PaddedMonitor, leaf, true, Monitor::_safepoint_check_never); // in support of ExplicitGCInvokesConcurrent
|
def(FullGCCount_lock , PaddedMonitor, leaf, true, Monitor::_safepoint_check_never); // in support of ExplicitGCInvokesConcurrent
|
||||||
}
|
}
|
||||||
@ -262,8 +265,6 @@ void mutex_init() {
|
|||||||
def(JNIGlobalActive_lock , PaddedMutex , nonleaf-1, true, Monitor::_safepoint_check_never);
|
def(JNIGlobalActive_lock , PaddedMutex , nonleaf-1, true, Monitor::_safepoint_check_never);
|
||||||
def(JNIWeakAlloc_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never);
|
def(JNIWeakAlloc_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never);
|
||||||
def(JNIWeakActive_lock , PaddedMutex , nonleaf-1, true, Monitor::_safepoint_check_never);
|
def(JNIWeakActive_lock , PaddedMutex , nonleaf-1, true, Monitor::_safepoint_check_never);
|
||||||
def(VMWeakAlloc_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never);
|
|
||||||
def(VMWeakActive_lock , PaddedMutex , nonleaf-1, true, Monitor::_safepoint_check_never);
|
|
||||||
def(JNICritical_lock , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_always); // used for JNI critical regions
|
def(JNICritical_lock , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_always); // used for JNI critical regions
|
||||||
def(AdapterHandlerLibrary_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_always);
|
def(AdapterHandlerLibrary_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_always);
|
||||||
|
|
||||||
|
@ -1495,7 +1495,6 @@ void WatcherThread::print_on(outputStream* st) const {
|
|||||||
jlong* JavaThread::_jvmci_old_thread_counters;
|
jlong* JavaThread::_jvmci_old_thread_counters;
|
||||||
|
|
||||||
bool jvmci_counters_include(JavaThread* thread) {
|
bool jvmci_counters_include(JavaThread* thread) {
|
||||||
oop threadObj = thread->threadObj();
|
|
||||||
return !JVMCICountersExcludeCompiler || !thread->is_Compiler_thread();
|
return !JVMCICountersExcludeCompiler || !thread->is_Compiler_thread();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,7 +543,7 @@ typedef PaddedEnd<ObjectMonitor> PaddedObjectMonitor;
|
|||||||
/*******************/ \
|
/*******************/ \
|
||||||
/* ClassLoaderData */ \
|
/* ClassLoaderData */ \
|
||||||
/*******************/ \
|
/*******************/ \
|
||||||
nonstatic_field(ClassLoaderData, _class_loader, oop) \
|
nonstatic_field(ClassLoaderData, _class_loader, OopHandle) \
|
||||||
nonstatic_field(ClassLoaderData, _next, ClassLoaderData*) \
|
nonstatic_field(ClassLoaderData, _next, ClassLoaderData*) \
|
||||||
volatile_nonstatic_field(ClassLoaderData, _klasses, Klass*) \
|
volatile_nonstatic_field(ClassLoaderData, _klasses, Klass*) \
|
||||||
nonstatic_field(ClassLoaderData, _is_anonymous, bool) \
|
nonstatic_field(ClassLoaderData, _is_anonymous, bool) \
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2018, 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,7 +53,7 @@
|
|||||||
len = name->utf8_length(); \
|
len = name->utf8_length(); \
|
||||||
} \
|
} \
|
||||||
HOTSPOT_CLASS_##type( /* type = unloaded, loaded */ \
|
HOTSPOT_CLASS_##type( /* type = unloaded, loaded */ \
|
||||||
data, len, (void*)(clss)->class_loader(), (shared)); \
|
data, len, (void*)(clss)->class_loader_data(), (shared)); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // ndef DTRACE_ENABLED
|
#else // ndef DTRACE_ENABLED
|
||||||
|
@ -931,7 +931,7 @@ void CodeCacheDCmd::execute(DCmdSource source, TRAPS) {
|
|||||||
//---< BEGIN >--- CodeHeap State Analytics.
|
//---< BEGIN >--- CodeHeap State Analytics.
|
||||||
CodeHeapAnalyticsDCmd::CodeHeapAnalyticsDCmd(outputStream* output, bool heap) :
|
CodeHeapAnalyticsDCmd::CodeHeapAnalyticsDCmd(outputStream* output, bool heap) :
|
||||||
DCmdWithParser(output, heap),
|
DCmdWithParser(output, heap),
|
||||||
_function("function", "Function to be performed (aggregate, UsedSpace, FreeSpace, MethodCount, MethodSpace, MethodAge, discard", "STRING", false, "all"),
|
_function("function", "Function to be performed (aggregate, UsedSpace, FreeSpace, MethodCount, MethodSpace, MethodAge, MethodNames, discard", "STRING", false, "all"),
|
||||||
_granularity("granularity", "Detail level - smaller value -> more detail", "STRING", false, "4096") {
|
_granularity("granularity", "Detail level - smaller value -> more detail", "STRING", false, "4096") {
|
||||||
_dcmdparser.add_dcmd_argument(&_function);
|
_dcmdparser.add_dcmd_argument(&_function);
|
||||||
_dcmdparser.add_dcmd_argument(&_granularity);
|
_dcmdparser.add_dcmd_argument(&_granularity);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -25,7 +25,7 @@
|
|||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "trace/traceStream.hpp"
|
#include "trace/traceStream.hpp"
|
||||||
#if INCLUDE_TRACE
|
#if INCLUDE_TRACE
|
||||||
#include "classfile/classLoaderData.hpp"
|
#include "classfile/classLoaderData.inline.hpp"
|
||||||
#include "classfile/javaClasses.inline.hpp"
|
#include "classfile/javaClasses.inline.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
#include "oops/klass.hpp"
|
#include "oops/klass.hpp"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2018, 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
|
||||||
@ -72,7 +72,7 @@ class ArenaBitMapAllocator : StackObj {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <class Allocator>
|
template <class Allocator>
|
||||||
BitMap::bm_word_t* BitMap::reallocate(const Allocator& allocator, bm_word_t* old_map, idx_t old_size_in_bits, idx_t new_size_in_bits) {
|
BitMap::bm_word_t* BitMap::reallocate(const Allocator& allocator, bm_word_t* old_map, idx_t old_size_in_bits, idx_t new_size_in_bits, bool clear) {
|
||||||
size_t old_size_in_words = calc_size_in_words(old_size_in_bits);
|
size_t old_size_in_words = calc_size_in_words(old_size_in_bits);
|
||||||
size_t new_size_in_words = calc_size_in_words(new_size_in_bits);
|
size_t new_size_in_words = calc_size_in_words(new_size_in_bits);
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ BitMap::bm_word_t* BitMap::reallocate(const Allocator& allocator, bm_word_t* old
|
|||||||
MIN2(old_size_in_words, new_size_in_words));
|
MIN2(old_size_in_words, new_size_in_words));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (new_size_in_words > old_size_in_words) {
|
if (clear && new_size_in_words > old_size_in_words) {
|
||||||
clear_range_of_words(map, old_size_in_words, new_size_in_words);
|
clear_range_of_words(map, old_size_in_words, new_size_in_words);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,9 +99,9 @@ BitMap::bm_word_t* BitMap::reallocate(const Allocator& allocator, bm_word_t* old
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class Allocator>
|
template <class Allocator>
|
||||||
bm_word_t* BitMap::allocate(const Allocator& allocator, idx_t size_in_bits) {
|
bm_word_t* BitMap::allocate(const Allocator& allocator, idx_t size_in_bits, bool clear) {
|
||||||
// Reuse reallocate to ensure that the new memory is cleared.
|
// Reuse reallocate to ensure that the new memory is cleared.
|
||||||
return reallocate(allocator, NULL, 0, size_in_bits);
|
return reallocate(allocator, NULL, 0, size_in_bits, clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Allocator>
|
template <class Allocator>
|
||||||
@ -153,8 +153,8 @@ ArenaBitMap::ArenaBitMap(Arena* arena, idx_t size_in_bits)
|
|||||||
: BitMap(allocate(ArenaBitMapAllocator(arena), size_in_bits), size_in_bits) {
|
: BitMap(allocate(ArenaBitMapAllocator(arena), size_in_bits), size_in_bits) {
|
||||||
}
|
}
|
||||||
|
|
||||||
CHeapBitMap::CHeapBitMap(idx_t size_in_bits, MEMFLAGS flags)
|
CHeapBitMap::CHeapBitMap(idx_t size_in_bits, MEMFLAGS flags, bool clear)
|
||||||
: BitMap(allocate(CHeapBitMapAllocator(flags), size_in_bits), size_in_bits), _flags(flags) {
|
: BitMap(allocate(CHeapBitMapAllocator(flags), size_in_bits, clear), size_in_bits), _flags(flags) {
|
||||||
}
|
}
|
||||||
|
|
||||||
CHeapBitMap::~CHeapBitMap() {
|
CHeapBitMap::~CHeapBitMap() {
|
||||||
|
@ -123,11 +123,11 @@ class BitMap {
|
|||||||
|
|
||||||
// Allocates and clears the bitmap memory.
|
// Allocates and clears the bitmap memory.
|
||||||
template <class Allocator>
|
template <class Allocator>
|
||||||
static bm_word_t* allocate(const Allocator&, idx_t size_in_bits);
|
static bm_word_t* allocate(const Allocator&, idx_t size_in_bits, bool clear = true);
|
||||||
|
|
||||||
// Reallocates and clears the new bitmap memory.
|
// Reallocates and clears the new bitmap memory.
|
||||||
template <class Allocator>
|
template <class Allocator>
|
||||||
static bm_word_t* reallocate(const Allocator&, bm_word_t* map, idx_t old_size_in_bits, idx_t new_size_in_bits);
|
static bm_word_t* reallocate(const Allocator&, bm_word_t* map, idx_t old_size_in_bits, idx_t new_size_in_bits, bool clear = true);
|
||||||
|
|
||||||
// Free the bitmap memory.
|
// Free the bitmap memory.
|
||||||
template <class Allocator>
|
template <class Allocator>
|
||||||
@ -359,7 +359,7 @@ class CHeapBitMap : public BitMap {
|
|||||||
public:
|
public:
|
||||||
CHeapBitMap(MEMFLAGS flags = mtInternal) : BitMap(NULL, 0), _flags(flags) {}
|
CHeapBitMap(MEMFLAGS flags = mtInternal) : BitMap(NULL, 0), _flags(flags) {}
|
||||||
// Clears the bitmap memory.
|
// Clears the bitmap memory.
|
||||||
CHeapBitMap(idx_t size_in_bits, MEMFLAGS flags = mtInternal);
|
CHeapBitMap(idx_t size_in_bits, MEMFLAGS flags = mtInternal, bool clear = true);
|
||||||
~CHeapBitMap();
|
~CHeapBitMap();
|
||||||
|
|
||||||
// Resize the backing bitmap memory.
|
// Resize the backing bitmap memory.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -35,6 +35,7 @@
|
|||||||
#include "memory/metaspaceShared.hpp"
|
#include "memory/metaspaceShared.hpp"
|
||||||
#include "memory/resourceArea.hpp"
|
#include "memory/resourceArea.hpp"
|
||||||
#include "oops/oop.inline.hpp"
|
#include "oops/oop.inline.hpp"
|
||||||
|
#include "oops/weakHandle.inline.hpp"
|
||||||
#include "runtime/safepoint.hpp"
|
#include "runtime/safepoint.hpp"
|
||||||
#include "utilities/dtrace.hpp"
|
#include "utilities/dtrace.hpp"
|
||||||
#include "utilities/hashtable.hpp"
|
#include "utilities/hashtable.hpp"
|
||||||
@ -148,7 +149,6 @@ template <class T, MEMFLAGS F> void RehashableHashtable<T, F>::move_to(Rehashabl
|
|||||||
}
|
}
|
||||||
// give the new table the free list as well
|
// give the new table the free list as well
|
||||||
new_table->copy_freelist(this);
|
new_table->copy_freelist(this);
|
||||||
assert(new_table->number_of_entries() == saved_entry_count, "lost entry on dictionary copy?");
|
|
||||||
|
|
||||||
// Destroy memory used by the buckets in the hashtable. The memory
|
// Destroy memory used by the buckets in the hashtable. The memory
|
||||||
// for the elements has been used in a new table and is not
|
// for the elements has been used in a new table and is not
|
||||||
@ -263,6 +263,10 @@ static int literal_size(oop obj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int literal_size(ClassLoaderWeakHandle v) {
|
||||||
|
return literal_size(v.peek());
|
||||||
|
}
|
||||||
|
|
||||||
template <MEMFLAGS F> bool BasicHashtable<F>::resize(int new_size) {
|
template <MEMFLAGS F> bool BasicHashtable<F>::resize(int new_size) {
|
||||||
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
|
||||||
|
|
||||||
@ -382,6 +386,13 @@ template <MEMFLAGS F> void BasicHashtable<F>::copy_buckets(char* top, char* end)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
|
template <class T> void print_literal(T l) {
|
||||||
|
l->print();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_literal(ClassLoaderWeakHandle l) {
|
||||||
|
l.print();
|
||||||
|
}
|
||||||
|
|
||||||
template <class T, MEMFLAGS F> void Hashtable<T, F>::print() {
|
template <class T, MEMFLAGS F> void Hashtable<T, F>::print() {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
@ -390,7 +401,7 @@ template <class T, MEMFLAGS F> void Hashtable<T, F>::print() {
|
|||||||
HashtableEntry<T, F>* entry = bucket(i);
|
HashtableEntry<T, F>* entry = bucket(i);
|
||||||
while(entry != NULL) {
|
while(entry != NULL) {
|
||||||
tty->print("%d : ", i);
|
tty->print("%d : ", i);
|
||||||
entry->literal()->print();
|
print_literal(entry->literal());
|
||||||
tty->cr();
|
tty->cr();
|
||||||
entry = entry->next();
|
entry = entry->next();
|
||||||
}
|
}
|
||||||
@ -443,21 +454,19 @@ template class BasicHashtable<mtGC>;
|
|||||||
#endif
|
#endif
|
||||||
template class Hashtable<ConstantPool*, mtClass>;
|
template class Hashtable<ConstantPool*, mtClass>;
|
||||||
template class RehashableHashtable<Symbol*, mtSymbol>;
|
template class RehashableHashtable<Symbol*, mtSymbol>;
|
||||||
template class RehashableHashtable<oopDesc*, mtSymbol>;
|
template class RehashableHashtable<oop, mtSymbol>;
|
||||||
template class Hashtable<Symbol*, mtSymbol>;
|
template class Hashtable<Symbol*, mtSymbol>;
|
||||||
template class Hashtable<Klass*, mtClass>;
|
template class Hashtable<Klass*, mtClass>;
|
||||||
template class Hashtable<InstanceKlass*, mtClass>;
|
template class Hashtable<InstanceKlass*, mtClass>;
|
||||||
template class Hashtable<oop, mtClass>;
|
template class Hashtable<ClassLoaderWeakHandle, mtClass>;
|
||||||
template class Hashtable<Symbol*, mtModule>;
|
template class Hashtable<Symbol*, mtModule>;
|
||||||
#if defined(SOLARIS) || defined(CHECK_UNHANDLED_OOPS)
|
|
||||||
template class Hashtable<oop, mtSymbol>;
|
template class Hashtable<oop, mtSymbol>;
|
||||||
template class RehashableHashtable<oop, mtSymbol>;
|
template class Hashtable<ClassLoaderWeakHandle, mtSymbol>;
|
||||||
#endif // SOLARIS || CHECK_UNHANDLED_OOPS
|
|
||||||
template class Hashtable<oopDesc*, mtSymbol>;
|
|
||||||
template class Hashtable<Symbol*, mtClass>;
|
template class Hashtable<Symbol*, mtClass>;
|
||||||
template class HashtableEntry<Symbol*, mtSymbol>;
|
template class HashtableEntry<Symbol*, mtSymbol>;
|
||||||
template class HashtableEntry<Symbol*, mtClass>;
|
template class HashtableEntry<Symbol*, mtClass>;
|
||||||
template class HashtableEntry<oop, mtSymbol>;
|
template class HashtableEntry<oop, mtSymbol>;
|
||||||
|
template class HashtableEntry<ClassLoaderWeakHandle, mtSymbol>;
|
||||||
template class HashtableBucket<mtClass>;
|
template class HashtableBucket<mtClass>;
|
||||||
template class BasicHashtableEntry<mtSymbol>;
|
template class BasicHashtableEntry<mtSymbol>;
|
||||||
template class BasicHashtableEntry<mtCode>;
|
template class BasicHashtableEntry<mtCode>;
|
||||||
|
@ -36,7 +36,9 @@
|
|||||||
#include "utilities/vmError.hpp"
|
#include "utilities/vmError.hpp"
|
||||||
#include "utilities/xmlstream.hpp"
|
#include "utilities/xmlstream.hpp"
|
||||||
|
|
||||||
extern "C" void jio_print(const char* s); // Declarationtion of jvm method
|
// Declarations of jvm methods
|
||||||
|
extern "C" void jio_print(const char* s, size_t len);
|
||||||
|
extern "C" int jio_printf(const char *fmt, ...);
|
||||||
|
|
||||||
outputStream::outputStream(int width) {
|
outputStream::outputStream(int width) {
|
||||||
_width = width;
|
_width = width;
|
||||||
@ -612,19 +614,15 @@ fileStream* defaultStream::open_file(const char* log_name) {
|
|||||||
|
|
||||||
// Try again to open the file in the temp directory.
|
// Try again to open the file in the temp directory.
|
||||||
delete file;
|
delete file;
|
||||||
char warnbuf[O_BUFLEN*2];
|
// Note: This feature is for maintainer use only. No need for L10N.
|
||||||
jio_snprintf(warnbuf, sizeof(warnbuf), "Warning: Cannot open log file: %s\n", log_name);
|
jio_printf("Warning: Cannot open log file: %s\n", log_name);
|
||||||
// Note: This feature is for maintainer use only. No need for L10N.
|
|
||||||
jio_print(warnbuf);
|
|
||||||
try_name = make_log_name(log_name, os::get_temp_directory());
|
try_name = make_log_name(log_name, os::get_temp_directory());
|
||||||
if (try_name == NULL) {
|
if (try_name == NULL) {
|
||||||
warning("Cannot open file %s: file name is too long for directory %s.\n", log_name, os::get_temp_directory());
|
warning("Cannot open file %s: file name is too long for directory %s.\n", log_name, os::get_temp_directory());
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
jio_snprintf(warnbuf, sizeof(warnbuf),
|
jio_printf("Warning: Forcing option -XX:LogFile=%s\n", try_name);
|
||||||
"Warning: Forcing option -XX:LogFile=%s\n", try_name);
|
|
||||||
jio_print(warnbuf);
|
|
||||||
|
|
||||||
file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name);
|
file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name);
|
||||||
FREE_C_HEAP_ARRAY(char, try_name);
|
FREE_C_HEAP_ARRAY(char, try_name);
|
||||||
@ -824,20 +822,6 @@ void defaultStream::release(intx holder) {
|
|||||||
tty_lock->unlock();
|
tty_lock->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Yuck: jio_print does not accept char*/len.
|
|
||||||
static void call_jio_print(const char* s, size_t len) {
|
|
||||||
char buffer[O_BUFLEN+100];
|
|
||||||
if (len > sizeof(buffer)-1) {
|
|
||||||
warning("increase O_BUFLEN in ostream.cpp -- output truncated");
|
|
||||||
len = sizeof(buffer)-1;
|
|
||||||
}
|
|
||||||
strncpy(buffer, s, len);
|
|
||||||
buffer[len] = '\0';
|
|
||||||
jio_print(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void defaultStream::write(const char* s, size_t len) {
|
void defaultStream::write(const char* s, size_t len) {
|
||||||
intx thread_id = os::current_thread_id();
|
intx thread_id = os::current_thread_id();
|
||||||
intx holder = hold(thread_id);
|
intx holder = hold(thread_id);
|
||||||
@ -845,11 +829,7 @@ void defaultStream::write(const char* s, size_t len) {
|
|||||||
if (DisplayVMOutput &&
|
if (DisplayVMOutput &&
|
||||||
(_outer_xmlStream == NULL || !_outer_xmlStream->inside_attrs())) {
|
(_outer_xmlStream == NULL || !_outer_xmlStream->inside_attrs())) {
|
||||||
// print to output stream. It can be redirected by a vfprintf hook
|
// print to output stream. It can be redirected by a vfprintf hook
|
||||||
if (s[len] == '\0') {
|
jio_print(s, len);
|
||||||
jio_print(s);
|
|
||||||
} else {
|
|
||||||
call_jio_print(s, len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// print to log file
|
// print to log file
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2012, 2018, 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
|
||||||
@ -159,6 +159,17 @@ public final class Optional<T> {
|
|||||||
return value != null;
|
return value != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a value is not present, returns {@code true}, otherwise
|
||||||
|
* {@code false}.
|
||||||
|
*
|
||||||
|
* @return {@code true} if a value is not present, otherwise {@code false}
|
||||||
|
* @since 11
|
||||||
|
*/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return value == null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a value is present, performs the given action with the value,
|
* If a value is present, performs the given action with the value,
|
||||||
* otherwise does nothing.
|
* otherwise does nothing.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -139,6 +139,17 @@ public final class OptionalDouble {
|
|||||||
return isPresent;
|
return isPresent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a value is not present, returns {@code true}, otherwise
|
||||||
|
* {@code false}.
|
||||||
|
*
|
||||||
|
* @return {@code true} if a value is not present, otherwise {@code false}
|
||||||
|
* @since 11
|
||||||
|
*/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return !isPresent;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a value is present, performs the given action with the value,
|
* If a value is present, performs the given action with the value,
|
||||||
* otherwise does nothing.
|
* otherwise does nothing.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -139,6 +139,17 @@ public final class OptionalInt {
|
|||||||
return isPresent;
|
return isPresent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a value is not present, returns {@code true}, otherwise
|
||||||
|
* {@code false}.
|
||||||
|
*
|
||||||
|
* @return {@code true} if a value is not present, otherwise {@code false}
|
||||||
|
* @since 11
|
||||||
|
*/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return !isPresent;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a value is present, performs the given action with the value,
|
* If a value is present, performs the given action with the value,
|
||||||
* otherwise does nothing.
|
* otherwise does nothing.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -139,6 +139,17 @@ public final class OptionalLong {
|
|||||||
return isPresent;
|
return isPresent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a value is not present, returns {@code true}, otherwise
|
||||||
|
* {@code false}.
|
||||||
|
*
|
||||||
|
* @return {@code true} if a value is not present, otherwise {@code false}
|
||||||
|
* @since 11
|
||||||
|
*/
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return !isPresent;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If a value is present, performs the given action with the value,
|
* If a value is present, performs the given action with the value,
|
||||||
* otherwise does nothing.
|
* otherwise does nothing.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1996, 2018, 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
|
||||||
@ -26,7 +26,13 @@
|
|||||||
package java.util.zip;
|
package java.util.zip;
|
||||||
|
|
||||||
import java.lang.ref.Cleaner.Cleanable;
|
import java.lang.ref.Cleaner.Cleanable;
|
||||||
|
import java.lang.ref.Reference;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ReadOnlyBufferException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import jdk.internal.ref.CleanerFactory;
|
import jdk.internal.ref.CleanerFactory;
|
||||||
|
import sun.nio.ch.DirectBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides support for general purpose compression using the
|
* This class provides support for general purpose compression using the
|
||||||
@ -35,8 +41,14 @@ import jdk.internal.ref.CleanerFactory;
|
|||||||
* protected by patents. It is fully described in the specifications at
|
* protected by patents. It is fully described in the specifications at
|
||||||
* the <a href="package-summary.html#package.description">java.util.zip
|
* the <a href="package-summary.html#package.description">java.util.zip
|
||||||
* package description</a>.
|
* package description</a>.
|
||||||
*
|
* <p>
|
||||||
* <p>The following code fragment demonstrates a trivial compression
|
* This class deflates sequences of bytes into ZLIB compressed data format.
|
||||||
|
* The input byte sequence is provided in either byte array or byte buffer,
|
||||||
|
* via one of the {@code setInput()} methods. The output byte sequence is
|
||||||
|
* written to the output byte array or byte buffer passed to the
|
||||||
|
* {@code deflate()} methods.
|
||||||
|
* <p>
|
||||||
|
* The following code fragment demonstrates a trivial compression
|
||||||
* and decompression of a string using {@code Deflater} and
|
* and decompression of a string using {@code Deflater} and
|
||||||
* {@code Inflater}.
|
* {@code Inflater}.
|
||||||
*
|
*
|
||||||
@ -92,8 +104,9 @@ import jdk.internal.ref.CleanerFactory;
|
|||||||
public class Deflater {
|
public class Deflater {
|
||||||
|
|
||||||
private final DeflaterZStreamRef zsRef;
|
private final DeflaterZStreamRef zsRef;
|
||||||
private byte[] buf = new byte[0];
|
private ByteBuffer input = ZipUtils.defaultBuf;
|
||||||
private int off, len;
|
private byte[] inputArray;
|
||||||
|
private int inputPos, inputLim;
|
||||||
private int level, strategy;
|
private int level, strategy;
|
||||||
private boolean setParams;
|
private boolean setParams;
|
||||||
private boolean finish, finished;
|
private boolean finish, finished;
|
||||||
@ -170,9 +183,14 @@ public class Deflater {
|
|||||||
*/
|
*/
|
||||||
public static final int FULL_FLUSH = 3;
|
public static final int FULL_FLUSH = 3;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flush mode to use at the end of output. Can only be provided by the
|
||||||
|
* user by way of {@link #finish()}.
|
||||||
|
*/
|
||||||
|
private static final int FINISH = 4;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ZipUtils.loadLibrary();
|
ZipUtils.loadLibrary();
|
||||||
initIDs();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -208,35 +226,71 @@ public class Deflater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets input data for compression. This should be called whenever
|
* Sets input data for compression.
|
||||||
* needsInput() returns true indicating that more input data is required.
|
* <p>
|
||||||
* @param b the input data bytes
|
* One of the {@code setInput()} methods should be called whenever
|
||||||
|
* {@code needsInput()} returns true indicating that more input data
|
||||||
|
* is required.
|
||||||
|
* <p>
|
||||||
|
* @param input the input data bytes
|
||||||
* @param off the start offset of the data
|
* @param off the start offset of the data
|
||||||
* @param len the length of the data
|
* @param len the length of the data
|
||||||
* @see Deflater#needsInput
|
* @see Deflater#needsInput
|
||||||
*/
|
*/
|
||||||
public void setInput(byte[] b, int off, int len) {
|
public void setInput(byte[] input, int off, int len) {
|
||||||
if (b== null) {
|
if (off < 0 || len < 0 || off > input.length - len) {
|
||||||
throw new NullPointerException();
|
|
||||||
}
|
|
||||||
if (off < 0 || len < 0 || off > b.length - len) {
|
|
||||||
throw new ArrayIndexOutOfBoundsException();
|
throw new ArrayIndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
synchronized (zsRef) {
|
synchronized (zsRef) {
|
||||||
this.buf = b;
|
this.input = null;
|
||||||
this.off = off;
|
this.inputArray = input;
|
||||||
this.len = len;
|
this.inputPos = off;
|
||||||
|
this.inputLim = off + len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets input data for compression. This should be called whenever
|
* Sets input data for compression.
|
||||||
* needsInput() returns true indicating that more input data is required.
|
* <p>
|
||||||
* @param b the input data bytes
|
* One of the {@code setInput()} methods should be called whenever
|
||||||
|
* {@code needsInput()} returns true indicating that more input data
|
||||||
|
* is required.
|
||||||
|
* <p>
|
||||||
|
* @param input the input data bytes
|
||||||
* @see Deflater#needsInput
|
* @see Deflater#needsInput
|
||||||
*/
|
*/
|
||||||
public void setInput(byte[] b) {
|
public void setInput(byte[] input) {
|
||||||
setInput(b, 0, b.length);
|
setInput(input, 0, input.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets input data for compression.
|
||||||
|
* <p>
|
||||||
|
* One of the {@code setInput()} methods should be called whenever
|
||||||
|
* {@code needsInput()} returns true indicating that more input data
|
||||||
|
* is required.
|
||||||
|
* <p>
|
||||||
|
* The given buffer's position will be advanced as deflate
|
||||||
|
* operations are performed, up to the buffer's limit.
|
||||||
|
* The input buffer may be modified (refilled) between deflate
|
||||||
|
* operations; doing so is equivalent to creating a new buffer
|
||||||
|
* and setting it with this method.
|
||||||
|
* <p>
|
||||||
|
* Modifying the input buffer's contents, position, or limit
|
||||||
|
* concurrently with an deflate operation will result in
|
||||||
|
* undefined behavior, which may include incorrect operation
|
||||||
|
* results or operation failure.
|
||||||
|
*
|
||||||
|
* @param input the input data bytes
|
||||||
|
* @see Deflater#needsInput
|
||||||
|
* @since 11
|
||||||
|
*/
|
||||||
|
public void setInput(ByteBuffer input) {
|
||||||
|
Objects.requireNonNull(input);
|
||||||
|
synchronized (zsRef) {
|
||||||
|
this.input = input;
|
||||||
|
this.inputArray = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -245,22 +299,19 @@ public class Deflater {
|
|||||||
* uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
|
* uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
|
||||||
* in order to get the Adler-32 value of the dictionary required for
|
* in order to get the Adler-32 value of the dictionary required for
|
||||||
* decompression.
|
* decompression.
|
||||||
* @param b the dictionary data bytes
|
* @param dictionary the dictionary data bytes
|
||||||
* @param off the start offset of the data
|
* @param off the start offset of the data
|
||||||
* @param len the length of the data
|
* @param len the length of the data
|
||||||
* @see Inflater#inflate
|
* @see Inflater#inflate
|
||||||
* @see Inflater#getAdler
|
* @see Inflater#getAdler
|
||||||
*/
|
*/
|
||||||
public void setDictionary(byte[] b, int off, int len) {
|
public void setDictionary(byte[] dictionary, int off, int len) {
|
||||||
if (b == null) {
|
if (off < 0 || len < 0 || off > dictionary.length - len) {
|
||||||
throw new NullPointerException();
|
|
||||||
}
|
|
||||||
if (off < 0 || len < 0 || off > b.length - len) {
|
|
||||||
throw new ArrayIndexOutOfBoundsException();
|
throw new ArrayIndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
synchronized (zsRef) {
|
synchronized (zsRef) {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
setDictionary(zsRef.address(), b, off, len);
|
setDictionary(zsRef.address(), dictionary, off, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,12 +321,47 @@ public class Deflater {
|
|||||||
* uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
|
* uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
|
||||||
* in order to get the Adler-32 value of the dictionary required for
|
* in order to get the Adler-32 value of the dictionary required for
|
||||||
* decompression.
|
* decompression.
|
||||||
* @param b the dictionary data bytes
|
* @param dictionary the dictionary data bytes
|
||||||
* @see Inflater#inflate
|
* @see Inflater#inflate
|
||||||
* @see Inflater#getAdler
|
* @see Inflater#getAdler
|
||||||
*/
|
*/
|
||||||
public void setDictionary(byte[] b) {
|
public void setDictionary(byte[] dictionary) {
|
||||||
setDictionary(b, 0, b.length);
|
setDictionary(dictionary, 0, dictionary.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets preset dictionary for compression. A preset dictionary is used
|
||||||
|
* when the history buffer can be predetermined. When the data is later
|
||||||
|
* uncompressed with Inflater.inflate(), Inflater.getAdler() can be called
|
||||||
|
* in order to get the Adler-32 value of the dictionary required for
|
||||||
|
* decompression.
|
||||||
|
* <p>
|
||||||
|
* The bytes in given byte buffer will be fully consumed by this method. On
|
||||||
|
* return, its position will equal its limit.
|
||||||
|
*
|
||||||
|
* @param dictionary the dictionary data bytes
|
||||||
|
* @see Inflater#inflate
|
||||||
|
* @see Inflater#getAdler
|
||||||
|
*/
|
||||||
|
public void setDictionary(ByteBuffer dictionary) {
|
||||||
|
synchronized (zsRef) {
|
||||||
|
int position = dictionary.position();
|
||||||
|
int remaining = Math.max(dictionary.limit() - position, 0);
|
||||||
|
ensureOpen();
|
||||||
|
if (dictionary.isDirect()) {
|
||||||
|
long address = ((DirectBuffer) dictionary).address();
|
||||||
|
try {
|
||||||
|
setDictionaryBuffer(zsRef.address(), address + position, remaining);
|
||||||
|
} finally {
|
||||||
|
Reference.reachabilityFence(dictionary);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
byte[] array = ZipUtils.getBufferArray(dictionary);
|
||||||
|
int offset = ZipUtils.getBufferOffset(dictionary);
|
||||||
|
setDictionary(zsRef.address(), array, offset + position, remaining);
|
||||||
|
}
|
||||||
|
dictionary.position(position + remaining);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -331,14 +417,17 @@ public class Deflater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the input data buffer is empty and setInput()
|
* Returns true if no data remains in the input buffer. This can
|
||||||
* should be called in order to provide more input.
|
* be used to determine if one of the {@code setInput()} methods should be
|
||||||
|
* called in order to provide more input.
|
||||||
|
*
|
||||||
* @return true if the input data buffer is empty and setInput()
|
* @return true if the input data buffer is empty and setInput()
|
||||||
* should be called in order to provide more input
|
* should be called in order to provide more input
|
||||||
*/
|
*/
|
||||||
public boolean needsInput() {
|
public boolean needsInput() {
|
||||||
synchronized (zsRef) {
|
synchronized (zsRef) {
|
||||||
return len <= 0;
|
ByteBuffer input = this.input;
|
||||||
|
return input == null ? inputLim == inputPos : ! input.hasRemaining();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -375,14 +464,14 @@ public class Deflater {
|
|||||||
* yields the same result as the invocation of
|
* yields the same result as the invocation of
|
||||||
* {@code deflater.deflate(b, off, len, Deflater.NO_FLUSH)}.
|
* {@code deflater.deflate(b, off, len, Deflater.NO_FLUSH)}.
|
||||||
*
|
*
|
||||||
* @param b the buffer for the compressed data
|
* @param output the buffer for the compressed data
|
||||||
* @param off the start offset of the data
|
* @param off the start offset of the data
|
||||||
* @param len the maximum number of bytes of compressed data
|
* @param len the maximum number of bytes of compressed data
|
||||||
* @return the actual number of bytes of compressed data written to the
|
* @return the actual number of bytes of compressed data written to the
|
||||||
* output buffer
|
* output buffer
|
||||||
*/
|
*/
|
||||||
public int deflate(byte[] b, int off, int len) {
|
public int deflate(byte[] output, int off, int len) {
|
||||||
return deflate(b, off, len, NO_FLUSH);
|
return deflate(output, off, len, NO_FLUSH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -396,12 +485,32 @@ public class Deflater {
|
|||||||
* yields the same result as the invocation of
|
* yields the same result as the invocation of
|
||||||
* {@code deflater.deflate(b, 0, b.length, Deflater.NO_FLUSH)}.
|
* {@code deflater.deflate(b, 0, b.length, Deflater.NO_FLUSH)}.
|
||||||
*
|
*
|
||||||
* @param b the buffer for the compressed data
|
* @param output the buffer for the compressed data
|
||||||
* @return the actual number of bytes of compressed data written to the
|
* @return the actual number of bytes of compressed data written to the
|
||||||
* output buffer
|
* output buffer
|
||||||
*/
|
*/
|
||||||
public int deflate(byte[] b) {
|
public int deflate(byte[] output) {
|
||||||
return deflate(b, 0, b.length, NO_FLUSH);
|
return deflate(output, 0, output.length, NO_FLUSH);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compresses the input data and fills specified buffer with compressed
|
||||||
|
* data. Returns actual number of bytes of compressed data. A return value
|
||||||
|
* of 0 indicates that {@link #needsInput() needsInput} should be called
|
||||||
|
* in order to determine if more input data is required.
|
||||||
|
*
|
||||||
|
* <p>This method uses {@link #NO_FLUSH} as its compression flush mode.
|
||||||
|
* An invocation of this method of the form {@code deflater.deflate(output)}
|
||||||
|
* yields the same result as the invocation of
|
||||||
|
* {@code deflater.deflate(output, Deflater.NO_FLUSH)}.
|
||||||
|
*
|
||||||
|
* @param output the buffer for the compressed data
|
||||||
|
* @return the actual number of bytes of compressed data written to the
|
||||||
|
* output buffer
|
||||||
|
* @since 11
|
||||||
|
*/
|
||||||
|
public int deflate(ByteBuffer output) {
|
||||||
|
return deflate(output, NO_FLUSH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -441,7 +550,11 @@ public class Deflater {
|
|||||||
* repeatedly output to the output buffer every time this method is
|
* repeatedly output to the output buffer every time this method is
|
||||||
* invoked.
|
* invoked.
|
||||||
*
|
*
|
||||||
* @param b the buffer for the compressed data
|
* <p>If the {@link #setInput(ByteBuffer)} method was called to provide a buffer
|
||||||
|
* for input, the input buffer's position will be advanced by the number of bytes
|
||||||
|
* consumed by this operation.
|
||||||
|
*
|
||||||
|
* @param output the buffer for the compressed data
|
||||||
* @param off the start offset of the data
|
* @param off the start offset of the data
|
||||||
* @param len the maximum number of bytes of compressed data
|
* @param len the maximum number of bytes of compressed data
|
||||||
* @param flush the compression flush mode
|
* @param flush the compression flush mode
|
||||||
@ -451,25 +564,248 @@ public class Deflater {
|
|||||||
* @throws IllegalArgumentException if the flush mode is invalid
|
* @throws IllegalArgumentException if the flush mode is invalid
|
||||||
* @since 1.7
|
* @since 1.7
|
||||||
*/
|
*/
|
||||||
public int deflate(byte[] b, int off, int len, int flush) {
|
public int deflate(byte[] output, int off, int len, int flush) {
|
||||||
if (b == null) {
|
if (off < 0 || len < 0 || off > output.length - len) {
|
||||||
throw new NullPointerException();
|
|
||||||
}
|
|
||||||
if (off < 0 || len < 0 || off > b.length - len) {
|
|
||||||
throw new ArrayIndexOutOfBoundsException();
|
throw new ArrayIndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
|
if (flush != NO_FLUSH && flush != SYNC_FLUSH && flush != FULL_FLUSH) {
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
synchronized (zsRef) {
|
synchronized (zsRef) {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
if (flush == NO_FLUSH || flush == SYNC_FLUSH ||
|
|
||||||
flush == FULL_FLUSH) {
|
ByteBuffer input = this.input;
|
||||||
int thisLen = this.len;
|
if (finish) {
|
||||||
int n = deflateBytes(zsRef.address(), b, off, len, flush);
|
// disregard given flush mode in this case
|
||||||
bytesWritten += n;
|
flush = FINISH;
|
||||||
bytesRead += (thisLen - this.len);
|
|
||||||
return n;
|
|
||||||
}
|
}
|
||||||
|
int params;
|
||||||
|
if (setParams) {
|
||||||
|
// bit 0: true to set params
|
||||||
|
// bit 1-2: strategy (0, 1, or 2)
|
||||||
|
// bit 3-31: level (0..9 or -1)
|
||||||
|
params = 1 | strategy << 1 | level << 3;
|
||||||
|
} else {
|
||||||
|
params = 0;
|
||||||
|
}
|
||||||
|
int inputPos;
|
||||||
|
long result;
|
||||||
|
if (input == null) {
|
||||||
|
inputPos = this.inputPos;
|
||||||
|
result = deflateBytesBytes(zsRef.address(),
|
||||||
|
inputArray, inputPos, inputLim - inputPos,
|
||||||
|
output, off, len,
|
||||||
|
flush, params);
|
||||||
|
} else {
|
||||||
|
inputPos = input.position();
|
||||||
|
int inputRem = Math.max(input.limit() - inputPos, 0);
|
||||||
|
if (input.isDirect()) {
|
||||||
|
try {
|
||||||
|
long inputAddress = ((DirectBuffer) input).address();
|
||||||
|
result = deflateBufferBytes(zsRef.address(),
|
||||||
|
inputAddress + inputPos, inputRem,
|
||||||
|
output, off, len,
|
||||||
|
flush, params);
|
||||||
|
} finally {
|
||||||
|
Reference.reachabilityFence(input);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
byte[] inputArray = ZipUtils.getBufferArray(input);
|
||||||
|
int inputOffset = ZipUtils.getBufferOffset(input);
|
||||||
|
result = deflateBytesBytes(zsRef.address(),
|
||||||
|
inputArray, inputOffset + inputPos, inputRem,
|
||||||
|
output, off, len,
|
||||||
|
flush, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int read = (int) (result & 0x7fff_ffffL);
|
||||||
|
int written = (int) (result >>> 31 & 0x7fff_ffffL);
|
||||||
|
if ((result >>> 62 & 1) != 0) {
|
||||||
|
finished = true;
|
||||||
|
}
|
||||||
|
if (params != 0 && (result >>> 63 & 1) == 0) {
|
||||||
|
setParams = false;
|
||||||
|
}
|
||||||
|
if (input != null) {
|
||||||
|
input.position(inputPos + read);
|
||||||
|
} else {
|
||||||
|
this.inputPos = inputPos + read;
|
||||||
|
}
|
||||||
|
bytesWritten += written;
|
||||||
|
bytesRead += read;
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compresses the input data and fills the specified buffer with compressed
|
||||||
|
* data. Returns actual number of bytes of data compressed.
|
||||||
|
*
|
||||||
|
* <p>Compression flush mode is one of the following three modes:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link #NO_FLUSH}: allows the deflater to decide how much data
|
||||||
|
* to accumulate, before producing output, in order to achieve the best
|
||||||
|
* compression (should be used in normal use scenario). A return value
|
||||||
|
* of 0 in this flush mode indicates that {@link #needsInput()} should
|
||||||
|
* be called in order to determine if more input data is required.
|
||||||
|
*
|
||||||
|
* <li>{@link #SYNC_FLUSH}: all pending output in the deflater is flushed,
|
||||||
|
* to the specified output buffer, so that an inflater that works on
|
||||||
|
* compressed data can get all input data available so far (In particular
|
||||||
|
* the {@link #needsInput()} returns {@code true} after this invocation
|
||||||
|
* if enough output space is provided). Flushing with {@link #SYNC_FLUSH}
|
||||||
|
* may degrade compression for some compression algorithms and so it
|
||||||
|
* should be used only when necessary.
|
||||||
|
*
|
||||||
|
* <li>{@link #FULL_FLUSH}: all pending output is flushed out as with
|
||||||
|
* {@link #SYNC_FLUSH}. The compression state is reset so that the inflater
|
||||||
|
* that works on the compressed output data can restart from this point
|
||||||
|
* if previous compressed data has been damaged or if random access is
|
||||||
|
* desired. Using {@link #FULL_FLUSH} too often can seriously degrade
|
||||||
|
* compression.
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>In the case of {@link #FULL_FLUSH} or {@link #SYNC_FLUSH}, if
|
||||||
|
* the return value is equal to the {@linkplain ByteBuffer#remaining() remaining space}
|
||||||
|
* of the buffer, this method should be invoked again with the same
|
||||||
|
* {@code flush} parameter and more output space. Make sure that
|
||||||
|
* the buffer has at least 6 bytes of remaining space to avoid the
|
||||||
|
* flush marker (5 bytes) being repeatedly output to the output buffer
|
||||||
|
* every time this method is invoked.
|
||||||
|
*
|
||||||
|
* <p>On success, the position of the given {@code output} byte buffer will be
|
||||||
|
* advanced by as many bytes as were produced by the operation, which is equal
|
||||||
|
* to the number returned by this method.
|
||||||
|
*
|
||||||
|
* <p>If the {@link #setInput(ByteBuffer)} method was called to provide a buffer
|
||||||
|
* for input, the input buffer's position will be advanced by the number of bytes
|
||||||
|
* consumed by this operation.
|
||||||
|
*
|
||||||
|
* @param output the buffer for the compressed data
|
||||||
|
* @param flush the compression flush mode
|
||||||
|
* @return the actual number of bytes of compressed data written to
|
||||||
|
* the output buffer
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if the flush mode is invalid
|
||||||
|
* @since 11
|
||||||
|
*/
|
||||||
|
public int deflate(ByteBuffer output, int flush) {
|
||||||
|
if (output.isReadOnly()) {
|
||||||
|
throw new ReadOnlyBufferException();
|
||||||
|
}
|
||||||
|
if (flush != NO_FLUSH && flush != SYNC_FLUSH && flush != FULL_FLUSH) {
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
synchronized (zsRef) {
|
||||||
|
ensureOpen();
|
||||||
|
|
||||||
|
ByteBuffer input = this.input;
|
||||||
|
if (finish) {
|
||||||
|
// disregard given flush mode in this case
|
||||||
|
flush = FINISH;
|
||||||
|
}
|
||||||
|
int params;
|
||||||
|
if (setParams) {
|
||||||
|
// bit 0: true to set params
|
||||||
|
// bit 1-2: strategy (0, 1, or 2)
|
||||||
|
// bit 3-31: level (0..9 or -1)
|
||||||
|
params = 1 | strategy << 1 | level << 3;
|
||||||
|
} else {
|
||||||
|
params = 0;
|
||||||
|
}
|
||||||
|
int outputPos = output.position();
|
||||||
|
int outputRem = Math.max(output.limit() - outputPos, 0);
|
||||||
|
int inputPos;
|
||||||
|
long result;
|
||||||
|
if (input == null) {
|
||||||
|
inputPos = this.inputPos;
|
||||||
|
if (output.isDirect()) {
|
||||||
|
long outputAddress = ((DirectBuffer) output).address();
|
||||||
|
try {
|
||||||
|
result = deflateBytesBuffer(zsRef.address(),
|
||||||
|
inputArray, inputPos, inputLim - inputPos,
|
||||||
|
outputAddress + outputPos, outputRem,
|
||||||
|
flush, params);
|
||||||
|
} finally {
|
||||||
|
Reference.reachabilityFence(output);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
byte[] outputArray = ZipUtils.getBufferArray(output);
|
||||||
|
int outputOffset = ZipUtils.getBufferOffset(output);
|
||||||
|
result = deflateBytesBytes(zsRef.address(),
|
||||||
|
inputArray, inputPos, inputLim - inputPos,
|
||||||
|
outputArray, outputOffset + outputPos, outputRem,
|
||||||
|
flush, params);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputPos = input.position();
|
||||||
|
int inputRem = Math.max(input.limit() - inputPos, 0);
|
||||||
|
if (input.isDirect()) {
|
||||||
|
long inputAddress = ((DirectBuffer) input).address();
|
||||||
|
try {
|
||||||
|
if (output.isDirect()) {
|
||||||
|
long outputAddress = outputPos + ((DirectBuffer) output).address();
|
||||||
|
try {
|
||||||
|
result = deflateBufferBuffer(zsRef.address(),
|
||||||
|
inputAddress + inputPos, inputRem,
|
||||||
|
outputAddress, outputRem,
|
||||||
|
flush, params);
|
||||||
|
} finally {
|
||||||
|
Reference.reachabilityFence(output);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
byte[] outputArray = ZipUtils.getBufferArray(output);
|
||||||
|
int outputOffset = ZipUtils.getBufferOffset(output);
|
||||||
|
result = deflateBufferBytes(zsRef.address(),
|
||||||
|
inputAddress + inputPos, inputRem,
|
||||||
|
outputArray, outputOffset + outputPos, outputRem,
|
||||||
|
flush, params);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Reference.reachabilityFence(input);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
byte[] inputArray = ZipUtils.getBufferArray(input);
|
||||||
|
int inputOffset = ZipUtils.getBufferOffset(input);
|
||||||
|
if (output.isDirect()) {
|
||||||
|
long outputAddress = ((DirectBuffer) output).address();
|
||||||
|
try {
|
||||||
|
result = deflateBytesBuffer(zsRef.address(),
|
||||||
|
inputArray, inputOffset + inputPos, inputRem,
|
||||||
|
outputAddress + outputPos, outputRem,
|
||||||
|
flush, params);
|
||||||
|
} finally {
|
||||||
|
Reference.reachabilityFence(output);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
byte[] outputArray = ZipUtils.getBufferArray(output);
|
||||||
|
int outputOffset = ZipUtils.getBufferOffset(output);
|
||||||
|
result = deflateBytesBytes(zsRef.address(),
|
||||||
|
inputArray, inputOffset + inputPos, inputRem,
|
||||||
|
outputArray, outputOffset + outputPos, outputRem,
|
||||||
|
flush, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int read = (int) (result & 0x7fff_ffffL);
|
||||||
|
int written = (int) (result >>> 31 & 0x7fff_ffffL);
|
||||||
|
if ((result >>> 62 & 1) != 0) {
|
||||||
|
finished = true;
|
||||||
|
}
|
||||||
|
if (params != 0 && (result >>> 63 & 1) == 0) {
|
||||||
|
setParams = false;
|
||||||
|
}
|
||||||
|
if (input != null) {
|
||||||
|
input.position(inputPos + read);
|
||||||
|
} else {
|
||||||
|
this.inputPos = inputPos + read;
|
||||||
|
}
|
||||||
|
output.position(outputPos + written);
|
||||||
|
bytesWritten += written;
|
||||||
|
bytesRead += read;
|
||||||
|
return written;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -545,7 +881,8 @@ public class Deflater {
|
|||||||
reset(zsRef.address());
|
reset(zsRef.address());
|
||||||
finish = false;
|
finish = false;
|
||||||
finished = false;
|
finished = false;
|
||||||
off = len = 0;
|
input = ZipUtils.defaultBuf;
|
||||||
|
inputArray = null;
|
||||||
bytesRead = bytesWritten = 0;
|
bytesRead = bytesWritten = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -560,7 +897,7 @@ public class Deflater {
|
|||||||
public void end() {
|
public void end() {
|
||||||
synchronized (zsRef) {
|
synchronized (zsRef) {
|
||||||
zsRef.clean();
|
zsRef.clean();
|
||||||
buf = null;
|
input = ZipUtils.defaultBuf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,11 +922,26 @@ public class Deflater {
|
|||||||
throw new NullPointerException("Deflater has been closed");
|
throw new NullPointerException("Deflater has been closed");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static native void initIDs();
|
|
||||||
private static native long init(int level, int strategy, boolean nowrap);
|
private static native long init(int level, int strategy, boolean nowrap);
|
||||||
private static native void setDictionary(long addr, byte[] b, int off, int len);
|
private static native void setDictionary(long addr, byte[] b, int off,
|
||||||
private native int deflateBytes(long addr, byte[] b, int off, int len,
|
int len);
|
||||||
int flush);
|
private static native void setDictionaryBuffer(long addr, long bufAddress, int len);
|
||||||
|
private native long deflateBytesBytes(long addr,
|
||||||
|
byte[] inputArray, int inputOff, int inputLen,
|
||||||
|
byte[] outputArray, int outputOff, int outputLen,
|
||||||
|
int flush, int params);
|
||||||
|
private native long deflateBytesBuffer(long addr,
|
||||||
|
byte[] inputArray, int inputOff, int inputLen,
|
||||||
|
long outputAddress, int outputLen,
|
||||||
|
int flush, int params);
|
||||||
|
private native long deflateBufferBytes(long addr,
|
||||||
|
long inputAddress, int inputLen,
|
||||||
|
byte[] outputArray, int outputOff, int outputLen,
|
||||||
|
int flush, int params);
|
||||||
|
private native long deflateBufferBuffer(long addr,
|
||||||
|
long inputAddress, int inputLen,
|
||||||
|
long outputAddress, int outputLen,
|
||||||
|
int flush, int params);
|
||||||
private static native int getAdler(long addr);
|
private static native int getAdler(long addr);
|
||||||
private static native void reset(long addr);
|
private static native void reset(long addr);
|
||||||
private static native void end(long addr);
|
private static native void end(long addr);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1996, 2018, 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
|
||||||
@ -26,7 +26,13 @@
|
|||||||
package java.util.zip;
|
package java.util.zip;
|
||||||
|
|
||||||
import java.lang.ref.Cleaner.Cleanable;
|
import java.lang.ref.Cleaner.Cleanable;
|
||||||
|
import java.lang.ref.Reference;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ReadOnlyBufferException;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import jdk.internal.ref.CleanerFactory;
|
import jdk.internal.ref.CleanerFactory;
|
||||||
|
import sun.nio.ch.DirectBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides support for general purpose decompression using the
|
* This class provides support for general purpose decompression using the
|
||||||
@ -35,8 +41,13 @@ import jdk.internal.ref.CleanerFactory;
|
|||||||
* protected by patents. It is fully described in the specifications at
|
* protected by patents. It is fully described in the specifications at
|
||||||
* the <a href="package-summary.html#package.description">java.util.zip
|
* the <a href="package-summary.html#package.description">java.util.zip
|
||||||
* package description</a>.
|
* package description</a>.
|
||||||
*
|
* <p>
|
||||||
* <p>The following code fragment demonstrates a trivial compression
|
* This class inflates sequences of ZLIB compressed bytes. The input byte
|
||||||
|
* sequence is provided in either byte array or byte buffer, via one of the
|
||||||
|
* {@code setInput()} methods. The output byte sequence is written to the
|
||||||
|
* output byte array or byte buffer passed to the {@code deflate()} methods.
|
||||||
|
* <p>
|
||||||
|
* The following code fragment demonstrates a trivial compression
|
||||||
* and decompression of a string using {@code Deflater} and
|
* and decompression of a string using {@code Deflater} and
|
||||||
* {@code Inflater}.
|
* {@code Inflater}.
|
||||||
*
|
*
|
||||||
@ -92,14 +103,20 @@ import jdk.internal.ref.CleanerFactory;
|
|||||||
public class Inflater {
|
public class Inflater {
|
||||||
|
|
||||||
private final InflaterZStreamRef zsRef;
|
private final InflaterZStreamRef zsRef;
|
||||||
private byte[] buf = defaultBuf;
|
private ByteBuffer input = ZipUtils.defaultBuf;
|
||||||
private int off, len;
|
private byte[] inputArray;
|
||||||
|
private int inputPos, inputLim;
|
||||||
private boolean finished;
|
private boolean finished;
|
||||||
private boolean needDict;
|
private boolean needDict;
|
||||||
private long bytesRead;
|
private long bytesRead;
|
||||||
private long bytesWritten;
|
private long bytesWritten;
|
||||||
|
|
||||||
private static final byte[] defaultBuf = new byte[0];
|
/*
|
||||||
|
* These fields are used as an "out" parameter from JNI when a
|
||||||
|
* DataFormatException is thrown during the inflate operation.
|
||||||
|
*/
|
||||||
|
private int inputConsumed;
|
||||||
|
private int outputConsumed;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ZipUtils.loadLibrary();
|
ZipUtils.loadLibrary();
|
||||||
@ -129,37 +146,71 @@ public class Inflater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets input data for decompression. Should be called whenever
|
* Sets input data for decompression.
|
||||||
* needsInput() returns true indicating that more input data is
|
* <p>
|
||||||
* required.
|
* One of the {@code setInput()} methods should be called whenever
|
||||||
* @param b the input data bytes
|
* {@code needsInput()} returns true indicating that more input data
|
||||||
|
* is required.
|
||||||
|
*
|
||||||
|
* @param input the input data bytes
|
||||||
* @param off the start offset of the input data
|
* @param off the start offset of the input data
|
||||||
* @param len the length of the input data
|
* @param len the length of the input data
|
||||||
* @see Inflater#needsInput
|
* @see Inflater#needsInput
|
||||||
*/
|
*/
|
||||||
public void setInput(byte[] b, int off, int len) {
|
public void setInput(byte[] input, int off, int len) {
|
||||||
if (b == null) {
|
if (off < 0 || len < 0 || off > input.length - len) {
|
||||||
throw new NullPointerException();
|
|
||||||
}
|
|
||||||
if (off < 0 || len < 0 || off > b.length - len) {
|
|
||||||
throw new ArrayIndexOutOfBoundsException();
|
throw new ArrayIndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
synchronized (zsRef) {
|
synchronized (zsRef) {
|
||||||
this.buf = b;
|
this.input = null;
|
||||||
this.off = off;
|
this.inputArray = input;
|
||||||
this.len = len;
|
this.inputPos = off;
|
||||||
|
this.inputLim = off + len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets input data for decompression. Should be called whenever
|
* Sets input data for decompression.
|
||||||
* needsInput() returns true indicating that more input data is
|
* <p>
|
||||||
* required.
|
* One of the {@code setInput()} methods should be called whenever
|
||||||
* @param b the input data bytes
|
* {@code needsInput()} returns true indicating that more input data
|
||||||
|
* is required.
|
||||||
|
*
|
||||||
|
* @param input the input data bytes
|
||||||
* @see Inflater#needsInput
|
* @see Inflater#needsInput
|
||||||
*/
|
*/
|
||||||
public void setInput(byte[] b) {
|
public void setInput(byte[] input) {
|
||||||
setInput(b, 0, b.length);
|
setInput(input, 0, input.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets input data for decompression.
|
||||||
|
* <p>
|
||||||
|
* One of the {@code setInput()} methods should be called whenever
|
||||||
|
* {@code needsInput()} returns true indicating that more input data
|
||||||
|
* is required.
|
||||||
|
* <p>
|
||||||
|
* The given buffer's position will be advanced as inflate
|
||||||
|
* operations are performed, up to the buffer's limit.
|
||||||
|
* The input buffer may be modified (refilled) between inflate
|
||||||
|
* operations; doing so is equivalent to creating a new buffer
|
||||||
|
* and setting it with this method.
|
||||||
|
* <p>
|
||||||
|
* Modifying the input buffer's contents, position, or limit
|
||||||
|
* concurrently with an inflate operation will result in
|
||||||
|
* undefined behavior, which may include incorrect operation
|
||||||
|
* results or operation failure.
|
||||||
|
*
|
||||||
|
* @param input the input data bytes
|
||||||
|
* @see Inflater#needsInput
|
||||||
|
* @since 11
|
||||||
|
*/
|
||||||
|
public void setInput(ByteBuffer input) {
|
||||||
|
Objects.requireNonNull(input);
|
||||||
|
synchronized (zsRef) {
|
||||||
|
this.input = input;
|
||||||
|
this.inputArray = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -167,22 +218,19 @@ public class Inflater {
|
|||||||
* called when inflate() returns 0 and needsDictionary() returns true
|
* called when inflate() returns 0 and needsDictionary() returns true
|
||||||
* indicating that a preset dictionary is required. The method getAdler()
|
* indicating that a preset dictionary is required. The method getAdler()
|
||||||
* can be used to get the Adler-32 value of the dictionary needed.
|
* can be used to get the Adler-32 value of the dictionary needed.
|
||||||
* @param b the dictionary data bytes
|
* @param dictionary the dictionary data bytes
|
||||||
* @param off the start offset of the data
|
* @param off the start offset of the data
|
||||||
* @param len the length of the data
|
* @param len the length of the data
|
||||||
* @see Inflater#needsDictionary
|
* @see Inflater#needsDictionary
|
||||||
* @see Inflater#getAdler
|
* @see Inflater#getAdler
|
||||||
*/
|
*/
|
||||||
public void setDictionary(byte[] b, int off, int len) {
|
public void setDictionary(byte[] dictionary, int off, int len) {
|
||||||
if (b == null) {
|
if (off < 0 || len < 0 || off > dictionary.length - len) {
|
||||||
throw new NullPointerException();
|
|
||||||
}
|
|
||||||
if (off < 0 || len < 0 || off > b.length - len) {
|
|
||||||
throw new ArrayIndexOutOfBoundsException();
|
throw new ArrayIndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
synchronized (zsRef) {
|
synchronized (zsRef) {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
setDictionary(zsRef.address(), b, off, len);
|
setDictionary(zsRef.address(), dictionary, off, len);
|
||||||
needDict = false;
|
needDict = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,12 +240,48 @@ public class Inflater {
|
|||||||
* called when inflate() returns 0 and needsDictionary() returns true
|
* called when inflate() returns 0 and needsDictionary() returns true
|
||||||
* indicating that a preset dictionary is required. The method getAdler()
|
* indicating that a preset dictionary is required. The method getAdler()
|
||||||
* can be used to get the Adler-32 value of the dictionary needed.
|
* can be used to get the Adler-32 value of the dictionary needed.
|
||||||
* @param b the dictionary data bytes
|
* @param dictionary the dictionary data bytes
|
||||||
* @see Inflater#needsDictionary
|
* @see Inflater#needsDictionary
|
||||||
* @see Inflater#getAdler
|
* @see Inflater#getAdler
|
||||||
*/
|
*/
|
||||||
public void setDictionary(byte[] b) {
|
public void setDictionary(byte[] dictionary) {
|
||||||
setDictionary(b, 0, b.length);
|
setDictionary(dictionary, 0, dictionary.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the preset dictionary to the bytes in the given buffer. Should be
|
||||||
|
* called when inflate() returns 0 and needsDictionary() returns true
|
||||||
|
* indicating that a preset dictionary is required. The method getAdler()
|
||||||
|
* can be used to get the Adler-32 value of the dictionary needed.
|
||||||
|
* <p>
|
||||||
|
* The bytes in given byte buffer will be fully consumed by this method. On
|
||||||
|
* return, its position will equal its limit.
|
||||||
|
*
|
||||||
|
* @param dictionary the dictionary data bytes
|
||||||
|
* @see Inflater#needsDictionary
|
||||||
|
* @see Inflater#getAdler
|
||||||
|
* @since 11
|
||||||
|
*/
|
||||||
|
public void setDictionary(ByteBuffer dictionary) {
|
||||||
|
synchronized (zsRef) {
|
||||||
|
int position = dictionary.position();
|
||||||
|
int remaining = Math.max(dictionary.limit() - position, 0);
|
||||||
|
ensureOpen();
|
||||||
|
if (dictionary.isDirect()) {
|
||||||
|
long address = ((DirectBuffer) dictionary).address();
|
||||||
|
try {
|
||||||
|
setDictionaryBuffer(zsRef.address(), address + position, remaining);
|
||||||
|
} finally {
|
||||||
|
Reference.reachabilityFence(dictionary);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
byte[] array = ZipUtils.getBufferArray(dictionary);
|
||||||
|
int offset = ZipUtils.getBufferOffset(dictionary);
|
||||||
|
setDictionary(zsRef.address(), array, offset + position, remaining);
|
||||||
|
}
|
||||||
|
dictionary.position(position + remaining);
|
||||||
|
needDict = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -208,19 +292,22 @@ public class Inflater {
|
|||||||
*/
|
*/
|
||||||
public int getRemaining() {
|
public int getRemaining() {
|
||||||
synchronized (zsRef) {
|
synchronized (zsRef) {
|
||||||
return len;
|
ByteBuffer input = this.input;
|
||||||
|
return input == null ? inputLim - inputPos : input.remaining();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if no data remains in the input buffer. This can
|
* Returns true if no data remains in the input buffer. This can
|
||||||
* be used to determine if #setInput should be called in order
|
* be used to determine if one of the {@code setInput()} methods should be
|
||||||
* to provide more input.
|
* called in order to provide more input.
|
||||||
|
*
|
||||||
* @return true if no data remains in the input buffer
|
* @return true if no data remains in the input buffer
|
||||||
*/
|
*/
|
||||||
public boolean needsInput() {
|
public boolean needsInput() {
|
||||||
synchronized (zsRef) {
|
synchronized (zsRef) {
|
||||||
return len <= 0;
|
ByteBuffer input = this.input;
|
||||||
|
return input == null ? inputLim == inputPos : ! input.hasRemaining();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,30 +341,103 @@ public class Inflater {
|
|||||||
* determine if more input data or a preset dictionary is required.
|
* determine if more input data or a preset dictionary is required.
|
||||||
* In the latter case, getAdler() can be used to get the Adler-32
|
* In the latter case, getAdler() can be used to get the Adler-32
|
||||||
* value of the dictionary required.
|
* value of the dictionary required.
|
||||||
* @param b the buffer for the uncompressed data
|
* <p>
|
||||||
|
* If the {@link #setInput(ByteBuffer)} method was called to provide a buffer
|
||||||
|
* for input, the input buffer's position will be advanced by the number of bytes
|
||||||
|
* consumed by this operation, even in the event that a {@link DataFormatException}
|
||||||
|
* is thrown.
|
||||||
|
* <p>
|
||||||
|
* The {@linkplain #getRemaining() remaining byte count} will be reduced by
|
||||||
|
* the number of consumed input bytes. If the {@link #setInput(ByteBuffer)}
|
||||||
|
* method was called to provide a buffer for input, the input buffer's position
|
||||||
|
* will be advanced the number of consumed bytes.
|
||||||
|
* <p>
|
||||||
|
* These byte totals, as well as
|
||||||
|
* the {@linkplain #getBytesRead() total bytes read}
|
||||||
|
* and the {@linkplain #getBytesWritten() total bytes written}
|
||||||
|
* values, will be updated even in the event that a {@link DataFormatException}
|
||||||
|
* is thrown to reflect the amount of data consumed and produced before the
|
||||||
|
* exception occurred.
|
||||||
|
*
|
||||||
|
* @param output the buffer for the uncompressed data
|
||||||
* @param off the start offset of the data
|
* @param off the start offset of the data
|
||||||
* @param len the maximum number of uncompressed bytes
|
* @param len the maximum number of uncompressed bytes
|
||||||
* @return the actual number of uncompressed bytes
|
* @return the actual number of uncompressed bytes
|
||||||
* @exception DataFormatException if the compressed data format is invalid
|
* @throws DataFormatException if the compressed data format is invalid
|
||||||
* @see Inflater#needsInput
|
* @see Inflater#needsInput
|
||||||
* @see Inflater#needsDictionary
|
* @see Inflater#needsDictionary
|
||||||
*/
|
*/
|
||||||
public int inflate(byte[] b, int off, int len)
|
public int inflate(byte[] output, int off, int len)
|
||||||
throws DataFormatException
|
throws DataFormatException
|
||||||
{
|
{
|
||||||
if (b == null) {
|
if (off < 0 || len < 0 || off > output.length - len) {
|
||||||
throw new NullPointerException();
|
|
||||||
}
|
|
||||||
if (off < 0 || len < 0 || off > b.length - len) {
|
|
||||||
throw new ArrayIndexOutOfBoundsException();
|
throw new ArrayIndexOutOfBoundsException();
|
||||||
}
|
}
|
||||||
synchronized (zsRef) {
|
synchronized (zsRef) {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
int thisLen = this.len;
|
ByteBuffer input = this.input;
|
||||||
int n = inflateBytes(zsRef.address(), b, off, len);
|
long result;
|
||||||
bytesWritten += n;
|
int inputPos;
|
||||||
bytesRead += (thisLen - this.len);
|
try {
|
||||||
return n;
|
if (input == null) {
|
||||||
|
inputPos = this.inputPos;
|
||||||
|
try {
|
||||||
|
result = inflateBytesBytes(zsRef.address(),
|
||||||
|
inputArray, inputPos, inputLim - inputPos,
|
||||||
|
output, off, len);
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
this.inputPos = inputPos + inputConsumed;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputPos = input.position();
|
||||||
|
try {
|
||||||
|
int inputRem = Math.max(input.limit() - inputPos, 0);
|
||||||
|
if (input.isDirect()) {
|
||||||
|
try {
|
||||||
|
long inputAddress = ((DirectBuffer) input).address();
|
||||||
|
result = inflateBufferBytes(zsRef.address(),
|
||||||
|
inputAddress + inputPos, inputRem,
|
||||||
|
output, off, len);
|
||||||
|
} finally {
|
||||||
|
Reference.reachabilityFence(input);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
byte[] inputArray = ZipUtils.getBufferArray(input);
|
||||||
|
int inputOffset = ZipUtils.getBufferOffset(input);
|
||||||
|
result = inflateBytesBytes(zsRef.address(),
|
||||||
|
inputArray, inputOffset + inputPos, inputRem,
|
||||||
|
output, off, len);
|
||||||
|
}
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
input.position(inputPos + inputConsumed);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
bytesRead += inputConsumed;
|
||||||
|
inputConsumed = 0;
|
||||||
|
int written = outputConsumed;
|
||||||
|
bytesWritten += written;
|
||||||
|
outputConsumed = 0;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
int read = (int) (result & 0x7fff_ffffL);
|
||||||
|
int written = (int) (result >>> 31 & 0x7fff_ffffL);
|
||||||
|
if ((result >>> 62 & 1) != 0) {
|
||||||
|
finished = true;
|
||||||
|
}
|
||||||
|
if ((result >>> 63 & 1) != 0) {
|
||||||
|
needDict = true;
|
||||||
|
}
|
||||||
|
if (input != null) {
|
||||||
|
input.position(inputPos + read);
|
||||||
|
} else {
|
||||||
|
this.inputPos = inputPos + read;
|
||||||
|
}
|
||||||
|
bytesWritten += written;
|
||||||
|
bytesRead += read;
|
||||||
|
return written;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,14 +448,177 @@ public class Inflater {
|
|||||||
* determine if more input data or a preset dictionary is required.
|
* determine if more input data or a preset dictionary is required.
|
||||||
* In the latter case, getAdler() can be used to get the Adler-32
|
* In the latter case, getAdler() can be used to get the Adler-32
|
||||||
* value of the dictionary required.
|
* value of the dictionary required.
|
||||||
* @param b the buffer for the uncompressed data
|
* <p>
|
||||||
|
* The {@linkplain #getRemaining() remaining byte count} will be reduced by
|
||||||
|
* the number of consumed input bytes. If the {@link #setInput(ByteBuffer)}
|
||||||
|
* method was called to provide a buffer for input, the input buffer's position
|
||||||
|
* will be advanced the number of consumed bytes.
|
||||||
|
* <p>
|
||||||
|
* These byte totals, as well as
|
||||||
|
* the {@linkplain #getBytesRead() total bytes read}
|
||||||
|
* and the {@linkplain #getBytesWritten() total bytes written}
|
||||||
|
* values, will be updated even in the event that a {@link DataFormatException}
|
||||||
|
* is thrown to reflect the amount of data consumed and produced before the
|
||||||
|
* exception occurred.
|
||||||
|
*
|
||||||
|
* @param output the buffer for the uncompressed data
|
||||||
* @return the actual number of uncompressed bytes
|
* @return the actual number of uncompressed bytes
|
||||||
* @exception DataFormatException if the compressed data format is invalid
|
* @throws DataFormatException if the compressed data format is invalid
|
||||||
* @see Inflater#needsInput
|
* @see Inflater#needsInput
|
||||||
* @see Inflater#needsDictionary
|
* @see Inflater#needsDictionary
|
||||||
*/
|
*/
|
||||||
public int inflate(byte[] b) throws DataFormatException {
|
public int inflate(byte[] output) throws DataFormatException {
|
||||||
return inflate(b, 0, b.length);
|
return inflate(output, 0, output.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uncompresses bytes into specified buffer. Returns actual number
|
||||||
|
* of bytes uncompressed. A return value of 0 indicates that
|
||||||
|
* needsInput() or needsDictionary() should be called in order to
|
||||||
|
* determine if more input data or a preset dictionary is required.
|
||||||
|
* In the latter case, getAdler() can be used to get the Adler-32
|
||||||
|
* value of the dictionary required.
|
||||||
|
* <p>
|
||||||
|
* On success, the position of the given {@code output} byte buffer will be
|
||||||
|
* advanced by as many bytes as were produced by the operation, which is equal
|
||||||
|
* to the number returned by this method. Note that the position of the
|
||||||
|
* {@code output} buffer will be advanced even in the event that a
|
||||||
|
* {@link DataFormatException} is thrown.
|
||||||
|
* <p>
|
||||||
|
* The {@linkplain #getRemaining() remaining byte count} will be reduced by
|
||||||
|
* the number of consumed input bytes. If the {@link #setInput(ByteBuffer)}
|
||||||
|
* method was called to provide a buffer for input, the input buffer's position
|
||||||
|
* will be advanced the number of consumed bytes.
|
||||||
|
* <p>
|
||||||
|
* These byte totals, as well as
|
||||||
|
* the {@linkplain #getBytesRead() total bytes read}
|
||||||
|
* and the {@linkplain #getBytesWritten() total bytes written}
|
||||||
|
* values, will be updated even in the event that a {@link DataFormatException}
|
||||||
|
* is thrown to reflect the amount of data consumed and produced before the
|
||||||
|
* exception occurred.
|
||||||
|
*
|
||||||
|
* @param output the buffer for the uncompressed data
|
||||||
|
* @return the actual number of uncompressed bytes
|
||||||
|
* @throws DataFormatException if the compressed data format is invalid
|
||||||
|
* @throws ReadOnlyBufferException if the given output buffer is read-only
|
||||||
|
* @see Inflater#needsInput
|
||||||
|
* @see Inflater#needsDictionary
|
||||||
|
* @since 11
|
||||||
|
*/
|
||||||
|
public int inflate(ByteBuffer output) throws DataFormatException {
|
||||||
|
if (output.isReadOnly()) {
|
||||||
|
throw new ReadOnlyBufferException();
|
||||||
|
}
|
||||||
|
synchronized (zsRef) {
|
||||||
|
ensureOpen();
|
||||||
|
ByteBuffer input = this.input;
|
||||||
|
long result;
|
||||||
|
int inputPos;
|
||||||
|
int outputPos = output.position();
|
||||||
|
int outputRem = Math.max(output.limit() - outputPos, 0);
|
||||||
|
try {
|
||||||
|
if (input == null) {
|
||||||
|
inputPos = this.inputPos;
|
||||||
|
try {
|
||||||
|
if (output.isDirect()) {
|
||||||
|
long outputAddress = ((DirectBuffer) output).address();
|
||||||
|
try {
|
||||||
|
result = inflateBytesBuffer(zsRef.address(),
|
||||||
|
inputArray, inputPos, inputLim - inputPos,
|
||||||
|
outputAddress + outputPos, outputRem);
|
||||||
|
} finally {
|
||||||
|
Reference.reachabilityFence(output);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
byte[] outputArray = ZipUtils.getBufferArray(output);
|
||||||
|
int outputOffset = ZipUtils.getBufferOffset(output);
|
||||||
|
result = inflateBytesBytes(zsRef.address(),
|
||||||
|
inputArray, inputPos, inputLim - inputPos,
|
||||||
|
outputArray, outputOffset + outputPos, outputRem);
|
||||||
|
}
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
this.inputPos = inputPos + inputConsumed;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
inputPos = input.position();
|
||||||
|
int inputRem = Math.max(input.limit() - inputPos, 0);
|
||||||
|
try {
|
||||||
|
if (input.isDirect()) {
|
||||||
|
long inputAddress = ((DirectBuffer) input).address();
|
||||||
|
try {
|
||||||
|
if (output.isDirect()) {
|
||||||
|
long outputAddress = ((DirectBuffer) output).address();
|
||||||
|
try {
|
||||||
|
result = inflateBufferBuffer(zsRef.address(),
|
||||||
|
inputAddress + inputPos, inputRem,
|
||||||
|
outputAddress + outputPos, outputRem);
|
||||||
|
} finally {
|
||||||
|
Reference.reachabilityFence(output);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
byte[] outputArray = ZipUtils.getBufferArray(output);
|
||||||
|
int outputOffset = ZipUtils.getBufferOffset(output);
|
||||||
|
result = inflateBufferBytes(zsRef.address(),
|
||||||
|
inputAddress + inputPos, inputRem,
|
||||||
|
outputArray, outputOffset + outputPos, outputRem);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
Reference.reachabilityFence(input);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
byte[] inputArray = ZipUtils.getBufferArray(input);
|
||||||
|
int inputOffset = ZipUtils.getBufferOffset(input);
|
||||||
|
if (output.isDirect()) {
|
||||||
|
long outputAddress = ((DirectBuffer) output).address();
|
||||||
|
try {
|
||||||
|
result = inflateBytesBuffer(zsRef.address(),
|
||||||
|
inputArray, inputOffset + inputPos, inputRem,
|
||||||
|
outputAddress + outputPos, outputRem);
|
||||||
|
} finally {
|
||||||
|
Reference.reachabilityFence(output);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
byte[] outputArray = ZipUtils.getBufferArray(output);
|
||||||
|
int outputOffset = ZipUtils.getBufferOffset(output);
|
||||||
|
result = inflateBytesBytes(zsRef.address(),
|
||||||
|
inputArray, inputOffset + inputPos, inputRem,
|
||||||
|
outputArray, outputOffset + outputPos, outputRem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
input.position(inputPos + inputConsumed);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (DataFormatException e) {
|
||||||
|
bytesRead += inputConsumed;
|
||||||
|
inputConsumed = 0;
|
||||||
|
int written = outputConsumed;
|
||||||
|
output.position(outputPos + written);
|
||||||
|
bytesWritten += written;
|
||||||
|
outputConsumed = 0;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
int read = (int) (result & 0x7fff_ffffL);
|
||||||
|
int written = (int) (result >>> 31 & 0x7fff_ffffL);
|
||||||
|
if ((result >>> 62 & 1) != 0) {
|
||||||
|
finished = true;
|
||||||
|
}
|
||||||
|
if ((result >>> 63 & 1) != 0) {
|
||||||
|
needDict = true;
|
||||||
|
}
|
||||||
|
if (input != null) {
|
||||||
|
input.position(inputPos + read);
|
||||||
|
} else {
|
||||||
|
this.inputPos = inputPos + read;
|
||||||
|
}
|
||||||
|
// Note: this method call also serves to keep the byteBuffer ref alive
|
||||||
|
output.position(outputPos + written);
|
||||||
|
bytesWritten += written;
|
||||||
|
bytesRead += read;
|
||||||
|
return written;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -368,10 +691,10 @@ public class Inflater {
|
|||||||
synchronized (zsRef) {
|
synchronized (zsRef) {
|
||||||
ensureOpen();
|
ensureOpen();
|
||||||
reset(zsRef.address());
|
reset(zsRef.address());
|
||||||
buf = defaultBuf;
|
input = ZipUtils.defaultBuf;
|
||||||
|
inputArray = null;
|
||||||
finished = false;
|
finished = false;
|
||||||
needDict = false;
|
needDict = false;
|
||||||
off = len = 0;
|
|
||||||
bytesRead = bytesWritten = 0;
|
bytesRead = bytesWritten = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -386,7 +709,8 @@ public class Inflater {
|
|||||||
public void end() {
|
public void end() {
|
||||||
synchronized (zsRef) {
|
synchronized (zsRef) {
|
||||||
zsRef.clean();
|
zsRef.clean();
|
||||||
buf = null;
|
input = ZipUtils.defaultBuf;
|
||||||
|
inputArray = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,18 +740,23 @@ public class Inflater {
|
|||||||
throw new NullPointerException("Inflater has been closed");
|
throw new NullPointerException("Inflater has been closed");
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean ended() {
|
|
||||||
synchronized (zsRef) {
|
|
||||||
return zsRef.address() == 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static native void initIDs();
|
private static native void initIDs();
|
||||||
private static native long init(boolean nowrap);
|
private static native long init(boolean nowrap);
|
||||||
private static native void setDictionary(long addr, byte[] b, int off,
|
private static native void setDictionary(long addr, byte[] b, int off,
|
||||||
int len);
|
int len);
|
||||||
private native int inflateBytes(long addr, byte[] b, int off, int len)
|
private static native void setDictionaryBuffer(long addr, long bufAddress, int len);
|
||||||
throws DataFormatException;
|
private native long inflateBytesBytes(long addr,
|
||||||
|
byte[] inputArray, int inputOff, int inputLen,
|
||||||
|
byte[] outputArray, int outputOff, int outputLen) throws DataFormatException;
|
||||||
|
private native long inflateBytesBuffer(long addr,
|
||||||
|
byte[] inputArray, int inputOff, int inputLen,
|
||||||
|
long outputAddress, int outputLen) throws DataFormatException;
|
||||||
|
private native long inflateBufferBytes(long addr,
|
||||||
|
long inputAddress, int inputLen,
|
||||||
|
byte[] outputArray, int outputOff, int outputLen) throws DataFormatException;
|
||||||
|
private native long inflateBufferBuffer(long addr,
|
||||||
|
long inputAddress, int inputLen,
|
||||||
|
long outputAddress, int outputLen) throws DataFormatException;
|
||||||
private static native int getAdler(long addr);
|
private static native int getAdler(long addr);
|
||||||
private static native void reset(long addr);
|
private static native void reset(long addr);
|
||||||
private static native void end(long addr);
|
private static native void end(long addr);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -25,6 +25,8 @@
|
|||||||
|
|
||||||
package java.util.zip;
|
package java.util.zip;
|
||||||
|
|
||||||
|
import java.nio.Buffer;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.file.attribute.FileTime;
|
import java.nio.file.attribute.FileTime;
|
||||||
import java.security.AccessController;
|
import java.security.AccessController;
|
||||||
import java.security.PrivilegedAction;
|
import java.security.PrivilegedAction;
|
||||||
@ -37,6 +39,9 @@ import java.util.concurrent.TimeUnit;
|
|||||||
|
|
||||||
import static java.util.zip.ZipConstants.ENDHDR;
|
import static java.util.zip.ZipConstants.ENDHDR;
|
||||||
|
|
||||||
|
import jdk.internal.misc.Unsafe;
|
||||||
|
import sun.nio.ch.DirectBuffer;
|
||||||
|
|
||||||
class ZipUtils {
|
class ZipUtils {
|
||||||
|
|
||||||
// used to adjust values between Windows and java epoch
|
// used to adjust values between Windows and java epoch
|
||||||
@ -45,6 +50,9 @@ class ZipUtils {
|
|||||||
// used to indicate the corresponding windows time is not available
|
// used to indicate the corresponding windows time is not available
|
||||||
public static final long WINDOWS_TIME_NOT_AVAILABLE = Long.MIN_VALUE;
|
public static final long WINDOWS_TIME_NOT_AVAILABLE = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
// static final ByteBuffer defaultBuf = ByteBuffer.allocateDirect(0);
|
||||||
|
static final ByteBuffer defaultBuf = ByteBuffer.allocate(0);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts Windows time (in microseconds, UTC/GMT) time to FileTime.
|
* Converts Windows time (in microseconds, UTC/GMT) time to FileTime.
|
||||||
*/
|
*/
|
||||||
@ -281,4 +289,17 @@ class ZipUtils {
|
|||||||
AccessController.doPrivileged(pa);
|
AccessController.doPrivileged(pa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final Unsafe unsafe = Unsafe.getUnsafe();
|
||||||
|
|
||||||
|
private static final long byteBufferArrayOffset = unsafe.objectFieldOffset(ByteBuffer.class, "hb");
|
||||||
|
private static final long byteBufferOffsetOffset = unsafe.objectFieldOffset(ByteBuffer.class, "offset");
|
||||||
|
|
||||||
|
static byte[] getBufferArray(ByteBuffer byteBuffer) {
|
||||||
|
return (byte[]) unsafe.getObject(byteBuffer, byteBufferArrayOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getBufferOffset(ByteBuffer byteBuffer) {
|
||||||
|
return unsafe.getInt(byteBuffer, byteBufferOffsetOffset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,7 +93,7 @@ WinMain(HINSTANCE inst, HINSTANCE previnst, LPSTR cmdline, int cmdshow)
|
|||||||
__initenv = _environ;
|
__initenv = _environ;
|
||||||
|
|
||||||
#else /* JAVAW */
|
#else /* JAVAW */
|
||||||
JNIEXPORT int JNICALL
|
JNIEXPORT int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int margc;
|
int margc;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user