Merge
This commit is contained in:
commit
0b14ff7e05
@ -315,3 +315,4 @@ f546760134eb861fcfecd4ce611b0040b0d25a6a jdk9-b67
|
||||
eed77fcd77711fcdba05f18fc22f37d86efb243c jdk9-b70
|
||||
c706ef5ea5da00078dc5e4334660315f7d99c15b jdk9-b71
|
||||
8582c35016fb6211b373810b6b172feccf9c483b jdk9-b72
|
||||
4c2cbaae528bce970dabbb5676005d379357f4b6 jdk9-b73
|
||||
|
@ -475,3 +475,4 @@ ff0929a59ced0e144201aa05819ae2e47d6f2c61 jdk9-b69
|
||||
8672e9264db30c21504063932dbc374eabc287a1 jdk9-b70
|
||||
07c6b035d68b0c41b1dcd442157b50b41a2551e9 jdk9-b71
|
||||
c1b2825ef47e75cb34dd18450d1c4280b7c5853c jdk9-b72
|
||||
e37d432868be0aa7cb5e0f3d7caff1e825d8ead3 jdk9-b73
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -48,8 +48,13 @@ public class CodeCache {
|
||||
Type type = db.lookupType("CodeCache");
|
||||
|
||||
// Get array of CodeHeaps
|
||||
// Note: CodeHeap may be subclassed with optional private heap mechanisms.
|
||||
Type codeHeapType = db.lookupType("CodeHeap");
|
||||
VirtualBaseConstructor heapConstructor =
|
||||
new VirtualBaseConstructor(db, codeHeapType, "sun.jvm.hotspot.memory", CodeHeap.class);
|
||||
|
||||
AddressField heapsField = type.getAddressField("_heaps");
|
||||
heapArray = GrowableArray.create(heapsField.getValue(), new StaticBaseConstructor<CodeHeap>(CodeHeap.class));
|
||||
heapArray = GrowableArray.create(heapsField.getValue(), heapConstructor);
|
||||
|
||||
scavengeRootNMethodsField = type.getAddressField("_scavenge_root_nmethods");
|
||||
|
||||
@ -180,31 +185,9 @@ public class CodeCache {
|
||||
|
||||
public void iterate(CodeCacheVisitor visitor) {
|
||||
visitor.prologue(lowBound(), highBound());
|
||||
CodeBlob lastBlob = null;
|
||||
|
||||
for (int i = 0; i < heapArray.length(); ++i) {
|
||||
CodeHeap current_heap = heapArray.at(i);
|
||||
Address ptr = current_heap.begin();
|
||||
while (ptr != null && ptr.lessThan(current_heap.end())) {
|
||||
try {
|
||||
// Use findStart to get a pointer inside blob other findBlob asserts
|
||||
CodeBlob blob = findBlobUnsafe(current_heap.findStart(ptr));
|
||||
if (blob != null) {
|
||||
visitor.visit(blob);
|
||||
if (blob == lastBlob) {
|
||||
throw new InternalError("saw same blob twice");
|
||||
}
|
||||
lastBlob = blob;
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Address next = current_heap.nextBlock(ptr);
|
||||
if (next != null && next.lessThan(ptr)) {
|
||||
throw new InternalError("pointer moved backwards");
|
||||
}
|
||||
ptr = next;
|
||||
}
|
||||
current_heap.iterate(visitor, this);
|
||||
}
|
||||
visitor.epilogue();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,7 @@
|
||||
package sun.jvm.hotspot.memory;
|
||||
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.code.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
@ -90,7 +91,7 @@ public class CodeHeap extends VMObject {
|
||||
return h.getAllocatedSpace();
|
||||
}
|
||||
|
||||
public Address nextBlock(Address ptr) {
|
||||
private Address nextBlock(Address ptr) {
|
||||
Address base = blockBase(ptr);
|
||||
if (base == null) {
|
||||
return null;
|
||||
@ -99,6 +100,31 @@ public class CodeHeap extends VMObject {
|
||||
return base.addOffsetTo(block.getLength() * (1 << getLog2SegmentSize()));
|
||||
}
|
||||
|
||||
public void iterate(CodeCacheVisitor visitor, CodeCache cache) {
|
||||
CodeBlob lastBlob = null;
|
||||
Address ptr = begin();
|
||||
while (ptr != null && ptr.lessThan(end())) {
|
||||
try {
|
||||
// Use findStart to get a pointer inside blob other findBlob asserts
|
||||
CodeBlob blob = cache.createCodeBlobWrapper(findStart(ptr));
|
||||
if (blob != null) {
|
||||
visitor.visit(blob);
|
||||
if (blob == lastBlob) {
|
||||
throw new InternalError("saw same blob twice");
|
||||
}
|
||||
lastBlob = blob;
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
Address next = nextBlock(ptr);
|
||||
if (next != null && next.lessThan(ptr)) {
|
||||
throw new InternalError("pointer moved backwards");
|
||||
}
|
||||
ptr = next;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// Internals only below this point
|
||||
//
|
||||
|
@ -141,6 +141,18 @@ SUNWprivate_1.1 {
|
||||
JVM_Halt;
|
||||
JVM_HoldsLock;
|
||||
JVM_IHashCode;
|
||||
JVM_ImageAttributeOffsets;
|
||||
JVM_ImageAttributeOffsetsLength;
|
||||
JVM_ImageClose;
|
||||
JVM_ImageFindAttributes;
|
||||
JVM_ImageGetAttributes;
|
||||
JVM_ImageGetAttributesCount;
|
||||
JVM_ImageGetDataAddress;
|
||||
JVM_ImageGetIndexAddress;
|
||||
JVM_ImageGetStringBytes;
|
||||
JVM_ImageOpen;
|
||||
JVM_ImageRead;
|
||||
JVM_ImageReadCompressed;
|
||||
JVM_InitAgentProperties;
|
||||
JVM_InitProperties;
|
||||
JVM_InternString;
|
||||
|
@ -139,6 +139,18 @@ SUNWprivate_1.1 {
|
||||
JVM_Halt;
|
||||
JVM_HoldsLock;
|
||||
JVM_IHashCode;
|
||||
JVM_ImageAttributeOffsets;
|
||||
JVM_ImageAttributeOffsetsLength;
|
||||
JVM_ImageClose;
|
||||
JVM_ImageFindAttributes;
|
||||
JVM_ImageGetAttributes;
|
||||
JVM_ImageGetAttributesCount;
|
||||
JVM_ImageGetDataAddress;
|
||||
JVM_ImageGetIndexAddress;
|
||||
JVM_ImageGetStringBytes;
|
||||
JVM_ImageOpen;
|
||||
JVM_ImageRead;
|
||||
JVM_ImageReadCompressed;
|
||||
JVM_InitAgentProperties;
|
||||
JVM_InitProperties;
|
||||
JVM_InternString;
|
||||
|
@ -139,6 +139,18 @@
|
||||
_JVM_Halt
|
||||
_JVM_HoldsLock
|
||||
_JVM_IHashCode
|
||||
_JVM_ImageAttributeOffsets
|
||||
_JVM_ImageAttributeOffsetsLength
|
||||
_JVM_ImageClose
|
||||
_JVM_ImageFindAttributes
|
||||
_JVM_ImageGetAttributes
|
||||
_JVM_ImageGetAttributesCount
|
||||
_JVM_ImageGetDataAddress
|
||||
_JVM_ImageGetIndexAddress
|
||||
_JVM_ImageGetStringBytes
|
||||
_JVM_ImageOpen
|
||||
_JVM_ImageRead
|
||||
_JVM_ImageReadCompressed
|
||||
_JVM_InitAgentProperties
|
||||
_JVM_InitProperties
|
||||
_JVM_InternString
|
||||
@ -188,7 +200,7 @@
|
||||
_JVM_Yield
|
||||
_JVM_handle_bsd_signal
|
||||
|
||||
# miscellaneous functions
|
||||
# miscellaneous functions
|
||||
_jio_fprintf
|
||||
_jio_printf
|
||||
_jio_snprintf
|
||||
|
@ -139,6 +139,18 @@
|
||||
_JVM_Halt
|
||||
_JVM_HoldsLock
|
||||
_JVM_IHashCode
|
||||
_JVM_ImageAttributeOffsets
|
||||
_JVM_ImageAttributeOffsetsLength
|
||||
_JVM_ImageClose
|
||||
_JVM_ImageFindAttributes
|
||||
_JVM_ImageGetAttributes
|
||||
_JVM_ImageGetAttributesCount
|
||||
_JVM_ImageGetDataAddress
|
||||
_JVM_ImageGetIndexAddress
|
||||
_JVM_ImageGetStringBytes
|
||||
_JVM_ImageOpen
|
||||
_JVM_ImageRead
|
||||
_JVM_ImageReadCompressed
|
||||
_JVM_InitAgentProperties
|
||||
_JVM_InitProperties
|
||||
_JVM_InternString
|
||||
|
@ -141,6 +141,18 @@ SUNWprivate_1.1 {
|
||||
JVM_Halt;
|
||||
JVM_HoldsLock;
|
||||
JVM_IHashCode;
|
||||
JVM_ImageAttributeOffsets;
|
||||
JVM_ImageAttributeOffsetsLength;
|
||||
JVM_ImageClose;
|
||||
JVM_ImageFindAttributes;
|
||||
JVM_ImageGetAttributes;
|
||||
JVM_ImageGetAttributesCount;
|
||||
JVM_ImageGetDataAddress;
|
||||
JVM_ImageGetIndexAddress;
|
||||
JVM_ImageGetStringBytes;
|
||||
JVM_ImageOpen;
|
||||
JVM_ImageRead;
|
||||
JVM_ImageReadCompressed;
|
||||
JVM_InitAgentProperties;
|
||||
JVM_InitProperties;
|
||||
JVM_InternString;
|
||||
|
@ -141,6 +141,18 @@ SUNWprivate_1.1 {
|
||||
JVM_Halt;
|
||||
JVM_HoldsLock;
|
||||
JVM_IHashCode;
|
||||
JVM_ImageAttributeOffsets;
|
||||
JVM_ImageAttributeOffsetsLength;
|
||||
JVM_ImageClose;
|
||||
JVM_ImageFindAttributes;
|
||||
JVM_ImageGetAttributes;
|
||||
JVM_ImageGetAttributesCount;
|
||||
JVM_ImageGetDataAddress;
|
||||
JVM_ImageGetIndexAddress;
|
||||
JVM_ImageGetStringBytes;
|
||||
JVM_ImageOpen;
|
||||
JVM_ImageRead;
|
||||
JVM_ImageReadCompressed;
|
||||
JVM_InitAgentProperties;
|
||||
JVM_InitProperties;
|
||||
JVM_InternString;
|
||||
|
@ -118,7 +118,8 @@ SIMPLE_DIRS = \
|
||||
$(PLATFORM_DIR)/generated/dependencies \
|
||||
$(PLATFORM_DIR)/generated/adfiles \
|
||||
$(PLATFORM_DIR)/generated/jvmtifiles \
|
||||
$(PLATFORM_DIR)/generated/tracefiles
|
||||
$(PLATFORM_DIR)/generated/tracefiles \
|
||||
$(PLATFORM_DIR)/generated/extensions
|
||||
|
||||
TARGETS = debug fastdebug optimized product
|
||||
SUBMAKE_DIRS = $(addprefix $(PLATFORM_DIR)/,$(TARGETS))
|
||||
|
@ -141,6 +141,18 @@ SUNWprivate_1.1 {
|
||||
JVM_Halt;
|
||||
JVM_HoldsLock;
|
||||
JVM_IHashCode;
|
||||
JVM_ImageAttributeOffsets;
|
||||
JVM_ImageAttributeOffsetsLength;
|
||||
JVM_ImageClose;
|
||||
JVM_ImageFindAttributes;
|
||||
JVM_ImageGetAttributes;
|
||||
JVM_ImageGetAttributesCount;
|
||||
JVM_ImageGetDataAddress;
|
||||
JVM_ImageGetIndexAddress;
|
||||
JVM_ImageGetStringBytes;
|
||||
JVM_ImageOpen;
|
||||
JVM_ImageRead;
|
||||
JVM_ImageReadCompressed;
|
||||
JVM_InitAgentProperties;
|
||||
JVM_InitProperties;
|
||||
JVM_InternString;
|
||||
|
@ -141,6 +141,18 @@ SUNWprivate_1.1 {
|
||||
JVM_Halt;
|
||||
JVM_HoldsLock;
|
||||
JVM_IHashCode;
|
||||
JVM_ImageAttributeOffsets;
|
||||
JVM_ImageAttributeOffsetsLength;
|
||||
JVM_ImageClose;
|
||||
JVM_ImageFindAttributes;
|
||||
JVM_ImageGetAttributes;
|
||||
JVM_ImageGetAttributesCount;
|
||||
JVM_ImageGetDataAddress;
|
||||
JVM_ImageGetIndexAddress;
|
||||
JVM_ImageGetStringBytes;
|
||||
JVM_ImageOpen;
|
||||
JVM_ImageRead;
|
||||
JVM_ImageReadCompressed;
|
||||
JVM_InitAgentProperties;
|
||||
JVM_InitProperties;
|
||||
JVM_InternString;
|
||||
|
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -34,7 +34,7 @@ DEMANGLE = $(DEMANGLER) < $@ > .$@ && $(MV) -f .$@ $@
|
||||
CC_COMPILE = $(CC) $(CXXFLAGS) $(CFLAGS)
|
||||
CXX_COMPILE = $(CXX) $(CXXFLAGS) $(CFLAGS)
|
||||
|
||||
AS.S = $(AS) $(ASFLAGS)
|
||||
AS.S = $(AS) $(ASFLAGS)
|
||||
|
||||
COMPILE.CC = $(CC_COMPILE) -c
|
||||
GENASM.CC = $(CC_COMPILE) -S
|
||||
@ -170,6 +170,12 @@ endif
|
||||
$(QUIETLY) $(REMOVE_TARGET)
|
||||
$(QUIETLY) $(AS.S) $(DEPFLAGS) -o $@ $< $(COMPILE_DONE)
|
||||
|
||||
# gcc applies preprocessing if the file extension is .S instead of .s
|
||||
%.o: %.S
|
||||
@echo $(LOG_INFO) Preprocessing and assembling $<
|
||||
$(QUIETLY) $(REMOVE_TARGET)
|
||||
$(QUIETLY) $(AS.S) $(DEPFLAGS) -o $@ $< $(COMPILE_DONE)
|
||||
|
||||
%.s: %.cpp
|
||||
@echo $(LOG_INFO) Generating assembly for $<
|
||||
$(QUIETLY) $(GENASM.CXX) -o $@ $<
|
||||
|
@ -54,7 +54,7 @@ endif
|
||||
# Src_Dirs_V is everything in src/share/vm/*, plus the right os/*/vm and cpu/*/vm
|
||||
# The adfiles directory contains ad_<arch>.[ch]pp.
|
||||
# The jvmtifiles directory contains jvmti*.[ch]pp
|
||||
Src_Dirs_V += $(GENERATED)/adfiles $(GENERATED)/jvmtifiles $(GENERATED)/tracefiles
|
||||
Src_Dirs_V += $(GENERATED)/adfiles $(GENERATED)/jvmtifiles $(GENERATED)/tracefiles $(GENERATED)/extensions
|
||||
VPATH += $(Src_Dirs_V:%=%:)
|
||||
|
||||
# set INCLUDES for C preprocessor.
|
||||
@ -161,6 +161,8 @@ CORE_PATHS+=$(shell if [ -d $(HS_ALT_SRC)/share/vm/jfr ]; then \
|
||||
fi)
|
||||
endif
|
||||
|
||||
CORE_PATHS+=$(GENERATED)/extensions
|
||||
|
||||
COMPILER1_PATHS := $(call altsrc,$(HS_COMMON_SRC)/share/vm/c1)
|
||||
COMPILER1_PATHS += $(HS_COMMON_SRC)/share/vm/c1
|
||||
|
||||
@ -207,6 +209,8 @@ ifeq ($(Platform_arch_model), x86_64)
|
||||
Src_Files_EXCLUDE += \*x86_32\*
|
||||
endif
|
||||
|
||||
Src_Files_BASE += \*.c \*.cpp \*.s
|
||||
|
||||
# Alternate vm.make
|
||||
# This has to be included here to allow changes to the source
|
||||
# directories and excluded files before they are expanded
|
||||
@ -216,13 +220,13 @@ endif
|
||||
# Locate all source files in the given directory, excluding files in Src_Files_EXCLUDE.
|
||||
define findsrc
|
||||
$(notdir $(shell find $(1)/. ! -name . -prune \
|
||||
-a \( -name \*.c -o -name \*.cpp -o -name \*.s \) \
|
||||
-a \( -name DUMMY $(addprefix -o -name ,$(Src_Files_BASE)) \) \
|
||||
-a ! \( -name DUMMY $(addprefix -o -name ,$(Src_Files_EXCLUDE)) \)))
|
||||
endef
|
||||
|
||||
Src_Files := $(foreach e,$(Src_Dirs),$(call findsrc,$(e)))
|
||||
|
||||
Obj_Files = $(sort $(addsuffix .o,$(basename $(Src_Files))))
|
||||
Obj_Files = $(sort $(addsuffix .o,$(basename $(Src_Files))) $(EXTENDED_JVM_OBJ_FILES))
|
||||
|
||||
JVM_OBJ_FILES = $(Obj_Files)
|
||||
|
||||
@ -244,10 +248,16 @@ VMDEF_PAT = ^_ZTV
|
||||
VMDEF_PAT := ^gHotSpotVM|$(VMDEF_PAT)
|
||||
VMDEF_PAT := ^UseSharedSpaces$$|$(VMDEF_PAT)
|
||||
VMDEF_PAT := ^_ZN9Arguments17SharedArchivePathE$$|$(VMDEF_PAT)
|
||||
ifneq ($(VMDEF_PAT_EXT),)
|
||||
VMDEF_PAT := $(VMDEF_PAT_EXT)|$(VMDEF_PAT)
|
||||
endif
|
||||
|
||||
vm.def: $(Res_Files) $(Obj_Files)
|
||||
vm.def: $(Res_Files) $(Obj_Files) $(VM_DEF_EXT)
|
||||
$(QUIETLY) $(NM) --defined-only $(Obj_Files) | sort -k3 -u | \
|
||||
awk '$$3 ~ /$(VMDEF_PAT)/ { print "\t" $$3 ";" }' > $@
|
||||
ifneq ($(VM_DEF_EXT),)
|
||||
cat $(VM_DEF_EXT) >> $@
|
||||
endif
|
||||
|
||||
mapfile_ext:
|
||||
rm -f $@
|
||||
|
@ -141,6 +141,18 @@ SUNWprivate_1.1 {
|
||||
JVM_Halt;
|
||||
JVM_HoldsLock;
|
||||
JVM_IHashCode;
|
||||
JVM_ImageAttributeOffsets;
|
||||
JVM_ImageAttributeOffsetsLength;
|
||||
JVM_ImageClose;
|
||||
JVM_ImageFindAttributes;
|
||||
JVM_ImageGetAttributes;
|
||||
JVM_ImageGetAttributesCount;
|
||||
JVM_ImageGetDataAddress;
|
||||
JVM_ImageGetIndexAddress;
|
||||
JVM_ImageGetStringBytes;
|
||||
JVM_ImageOpen;
|
||||
JVM_ImageRead;
|
||||
JVM_ImageReadCompressed;
|
||||
JVM_InitAgentProperties;
|
||||
JVM_InitProperties;
|
||||
JVM_InternString;
|
||||
|
@ -143,7 +143,7 @@ else
|
||||
LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc -ldemangle
|
||||
endif # sparcWorks
|
||||
|
||||
LIBS += -lkstat
|
||||
LIBS += -lkstat -lrt
|
||||
|
||||
# By default, link the *.o into the library, not the executable.
|
||||
LINK_INTO$(LINK_INTO) = LIBJVM
|
||||
|
@ -2270,17 +2270,21 @@ public:
|
||||
}
|
||||
|
||||
// CRC32 instructions
|
||||
#define INSN(NAME, sf, sz) \
|
||||
#define INSN(NAME, c, sf, sz) \
|
||||
void NAME(Register Rd, Register Rn, Register Rm) { \
|
||||
starti; \
|
||||
f(sf, 31), f(0b0011010110, 30, 21), f(0b0100, 15, 12), f(sz, 11, 10); \
|
||||
rf(Rm, 16), rf(Rn, 5), rf(Rd, 0); \
|
||||
f(sf, 31), f(0b0011010110, 30, 21), f(0b010, 15, 13), f(c, 12); \
|
||||
f(sz, 11, 10), rf(Rm, 16), rf(Rn, 5), rf(Rd, 0); \
|
||||
}
|
||||
|
||||
INSN(crc32b, 0, 0b00);
|
||||
INSN(crc32h, 0, 0b01);
|
||||
INSN(crc32w, 0, 0b10);
|
||||
INSN(crc32x, 1, 0b11);
|
||||
INSN(crc32b, 0, 0, 0b00);
|
||||
INSN(crc32h, 0, 0, 0b01);
|
||||
INSN(crc32w, 0, 0, 0b10);
|
||||
INSN(crc32x, 0, 1, 0b11);
|
||||
INSN(crc32cb, 1, 0, 0b00);
|
||||
INSN(crc32ch, 1, 0, 0b01);
|
||||
INSN(crc32cw, 1, 0, 0b10);
|
||||
INSN(crc32cx, 1, 1, 0b11);
|
||||
|
||||
#undef INSN
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, Red Hat Inc. All rights reserved.
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2015, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -28,12 +28,6 @@
|
||||
|
||||
const int StackAlignmentInBytes = 16;
|
||||
|
||||
// Indicates whether the C calling conventions require that
|
||||
// 32-bit integer argument values are properly extended to 64 bits.
|
||||
// If set, SharedRuntime::c_calling_convention() must adapt
|
||||
// signatures accordingly.
|
||||
const bool CCallingConventionRequiresIntsAsLongs = true;
|
||||
|
||||
#define SUPPORTS_NATIVE_CX8
|
||||
|
||||
// The maximum B/BL offset range on AArch64 is 128MB.
|
||||
|
@ -2914,6 +2914,65 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len,
|
||||
ornw(crc, zr, crc);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param crc register containing existing CRC (32-bit)
|
||||
* @param buf register pointing to input byte buffer (byte*)
|
||||
* @param len register containing number of bytes
|
||||
* @param table register that will contain address of CRC table
|
||||
* @param tmp scratch register
|
||||
*/
|
||||
void MacroAssembler::kernel_crc32c(Register crc, Register buf, Register len,
|
||||
Register table0, Register table1, Register table2, Register table3,
|
||||
Register tmp, Register tmp2, Register tmp3) {
|
||||
Label L_exit;
|
||||
Label CRC_by64_loop, CRC_by4_loop, CRC_by1_loop;
|
||||
|
||||
subs(len, len, 64);
|
||||
br(Assembler::GE, CRC_by64_loop);
|
||||
adds(len, len, 64-4);
|
||||
br(Assembler::GE, CRC_by4_loop);
|
||||
adds(len, len, 4);
|
||||
br(Assembler::GT, CRC_by1_loop);
|
||||
b(L_exit);
|
||||
|
||||
BIND(CRC_by4_loop);
|
||||
ldrw(tmp, Address(post(buf, 4)));
|
||||
subs(len, len, 4);
|
||||
crc32cw(crc, crc, tmp);
|
||||
br(Assembler::GE, CRC_by4_loop);
|
||||
adds(len, len, 4);
|
||||
br(Assembler::LE, L_exit);
|
||||
BIND(CRC_by1_loop);
|
||||
ldrb(tmp, Address(post(buf, 1)));
|
||||
subs(len, len, 1);
|
||||
crc32cb(crc, crc, tmp);
|
||||
br(Assembler::GT, CRC_by1_loop);
|
||||
b(L_exit);
|
||||
|
||||
align(CodeEntryAlignment);
|
||||
BIND(CRC_by64_loop);
|
||||
subs(len, len, 64);
|
||||
ldp(tmp, tmp3, Address(post(buf, 16)));
|
||||
crc32cx(crc, crc, tmp);
|
||||
crc32cx(crc, crc, tmp3);
|
||||
ldp(tmp, tmp3, Address(post(buf, 16)));
|
||||
crc32cx(crc, crc, tmp);
|
||||
crc32cx(crc, crc, tmp3);
|
||||
ldp(tmp, tmp3, Address(post(buf, 16)));
|
||||
crc32cx(crc, crc, tmp);
|
||||
crc32cx(crc, crc, tmp3);
|
||||
ldp(tmp, tmp3, Address(post(buf, 16)));
|
||||
crc32cx(crc, crc, tmp);
|
||||
crc32cx(crc, crc, tmp3);
|
||||
br(Assembler::GE, CRC_by64_loop);
|
||||
adds(len, len, 64-4);
|
||||
br(Assembler::GE, CRC_by4_loop);
|
||||
adds(len, len, 4);
|
||||
br(Assembler::GT, CRC_by1_loop);
|
||||
BIND(L_exit);
|
||||
return;
|
||||
}
|
||||
|
||||
SkipIfEqual::SkipIfEqual(
|
||||
MacroAssembler* masm, const bool* flag_addr, bool value) {
|
||||
_masm = masm;
|
||||
|
@ -967,6 +967,10 @@ public:
|
||||
void kernel_crc32(Register crc, Register buf, Register len,
|
||||
Register table0, Register table1, Register table2, Register table3,
|
||||
Register tmp, Register tmp2, Register tmp3);
|
||||
// CRC32 code for java.util.zip.CRC32C::updateBytes() instrinsic.
|
||||
void kernel_crc32c(Register crc, Register buf, Register len,
|
||||
Register table0, Register table1, Register table2, Register table3,
|
||||
Register tmp, Register tmp2, Register tmp3);
|
||||
|
||||
#undef VIRTUAL
|
||||
|
||||
|
@ -2356,6 +2356,47 @@ class StubGenerator: public StubCodeGenerator {
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Arguments:
|
||||
*
|
||||
* Inputs:
|
||||
* c_rarg0 - int crc
|
||||
* c_rarg1 - byte* buf
|
||||
* c_rarg2 - int length
|
||||
* c_rarg3 - int* table
|
||||
*
|
||||
* Ouput:
|
||||
* rax - int crc result
|
||||
*/
|
||||
address generate_updateBytesCRC32C() {
|
||||
assert(UseCRC32CIntrinsics, "what are we doing here?");
|
||||
|
||||
__ align(CodeEntryAlignment);
|
||||
StubCodeMark mark(this, "StubRoutines", "updateBytesCRC32C");
|
||||
|
||||
address start = __ pc();
|
||||
|
||||
const Register crc = c_rarg0; // crc
|
||||
const Register buf = c_rarg1; // source java byte array address
|
||||
const Register len = c_rarg2; // length
|
||||
const Register table0 = c_rarg3; // crc_table address
|
||||
const Register table1 = c_rarg4;
|
||||
const Register table2 = c_rarg5;
|
||||
const Register table3 = c_rarg6;
|
||||
const Register tmp3 = c_rarg7;
|
||||
|
||||
BLOCK_COMMENT("Entry:");
|
||||
__ enter(); // required for proper stackwalking of RuntimeStub frame
|
||||
|
||||
__ kernel_crc32c(crc, buf, len,
|
||||
table0, table1, table2, table3, rscratch1, rscratch2, tmp3);
|
||||
|
||||
__ leave(); // required for proper stackwalking of RuntimeStub frame
|
||||
__ ret(lr);
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* Arguments:
|
||||
*
|
||||
@ -2579,6 +2620,10 @@ class StubGenerator: public StubCodeGenerator {
|
||||
StubRoutines::_sha256_implCompressMB = generate_sha256_implCompress(true, "sha256_implCompressMB");
|
||||
}
|
||||
|
||||
if (UseCRC32CIntrinsics) {
|
||||
StubRoutines::_updateBytesCRC32C = generate_updateBytesCRC32C();
|
||||
}
|
||||
|
||||
// Safefetch stubs.
|
||||
generate_safefetch("SafeFetch32", sizeof(int), &StubRoutines::_safefetch32_entry,
|
||||
&StubRoutines::_safefetch32_fault_pc,
|
||||
|
@ -199,9 +199,12 @@ void VM_Version::get_processor_features() {
|
||||
UseCRC32Intrinsics = true;
|
||||
}
|
||||
|
||||
if (UseCRC32CIntrinsics) {
|
||||
if (!FLAG_IS_DEFAULT(UseCRC32CIntrinsics))
|
||||
warning("CRC32C intrinsics are not available on this CPU");
|
||||
if (auxv & HWCAP_CRC32) {
|
||||
if (FLAG_IS_DEFAULT(UseCRC32CIntrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseCRC32CIntrinsics, true);
|
||||
}
|
||||
} else if (UseCRC32CIntrinsics) {
|
||||
warning("CRC32C is not available on the CPU");
|
||||
FLAG_SET_DEFAULT(UseCRC32CIntrinsics, false);
|
||||
}
|
||||
|
||||
@ -214,34 +217,31 @@ void VM_Version::get_processor_features() {
|
||||
FLAG_SET_DEFAULT(UseSHA, false);
|
||||
}
|
||||
|
||||
if (!UseSHA) {
|
||||
if (UseSHA && (auxv & HWCAP_SHA1)) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA1Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA1Intrinsics, true);
|
||||
}
|
||||
} else if (UseSHA1Intrinsics) {
|
||||
warning("Intrinsics for SHA-1 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
|
||||
}
|
||||
|
||||
if (UseSHA && (auxv & HWCAP_SHA2)) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, true);
|
||||
}
|
||||
} else if (UseSHA256Intrinsics) {
|
||||
warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
|
||||
}
|
||||
|
||||
if (UseSHA512Intrinsics) {
|
||||
warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
|
||||
} else {
|
||||
if (auxv & HWCAP_SHA1) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA1Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA1Intrinsics, true);
|
||||
}
|
||||
} else if (UseSHA1Intrinsics) {
|
||||
warning("SHA1 instruction is not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
|
||||
}
|
||||
if (auxv & HWCAP_SHA2) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, true);
|
||||
}
|
||||
} else if (UseSHA256Intrinsics) {
|
||||
warning("SHA256 instruction (for SHA-224 and SHA-256) is not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
|
||||
}
|
||||
if (UseSHA512Intrinsics) {
|
||||
warning("SHA512 instruction (for SHA-384 and SHA-512) is not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
|
||||
}
|
||||
if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA, false);
|
||||
}
|
||||
|
||||
// This machine allows unaligned memory accesses
|
||||
|
@ -105,7 +105,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||
__ flush();
|
||||
|
||||
if (PrintMiscellaneous && (WizardMode || Verbose)) {
|
||||
tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d",
|
||||
tty->print_cr("vtable #%d at " PTR_FORMAT "[%d] left over: %d",
|
||||
vtable_index, p2i(s->entry_point()),
|
||||
(int)(s->code_end() - s->entry_point()),
|
||||
(int)(s->code_end() - __ pc()));
|
||||
@ -184,7 +184,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
__ flush();
|
||||
|
||||
if (PrintMiscellaneous && (WizardMode || Verbose)) {
|
||||
tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d",
|
||||
tty->print_cr("itable #%d at " PTR_FORMAT "[%d] left over: %d",
|
||||
itable_index, p2i(s->entry_point()),
|
||||
(int)(s->code_end() - s->entry_point()),
|
||||
(int)(s->code_end() - __ pc()));
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2012, 2013 SAP AG. All rights reserved.
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2012, 2015 SAP AG. 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
|
||||
@ -31,12 +31,6 @@ const int BytesPerInstWord = 4;
|
||||
|
||||
const int StackAlignmentInBytes = 16;
|
||||
|
||||
// Indicates whether the C calling conventions require that
|
||||
// 32-bit integer argument values are properly extended to 64 bits.
|
||||
// If set, SharedRuntime::c_calling_convention() must adapt
|
||||
// signatures accordingly.
|
||||
const bool CCallingConventionRequiresIntsAsLongs = true;
|
||||
|
||||
#define SUPPORTS_NATIVE_CX8
|
||||
|
||||
// The PPC CPUs are NOT multiple-copy-atomic.
|
||||
|
@ -465,7 +465,7 @@ void trace_method_handle_stub(const char* adaptername,
|
||||
bool has_mh = (strstr(adaptername, "/static") == NULL &&
|
||||
strstr(adaptername, "linkTo") == NULL); // static linkers don't have MH
|
||||
const char* mh_reg_name = has_mh ? "R23_method_handle" : "G23";
|
||||
tty->print_cr("MH %s %s="INTPTR_FORMAT " sp=" INTPTR_FORMAT,
|
||||
tty->print_cr("MH %s %s=" INTPTR_FORMAT " sp=" INTPTR_FORMAT,
|
||||
adaptername, mh_reg_name, p2i(mh), p2i(entry_sp));
|
||||
|
||||
if (Verbose) {
|
||||
|
@ -731,23 +731,8 @@ int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
|
||||
case T_SHORT:
|
||||
case T_INT:
|
||||
// We must cast ints to longs and use full 64 bit stack slots
|
||||
// here. We do the cast in GraphKit::gen_stub() and just guard
|
||||
// here against loosing that change.
|
||||
assert(CCallingConventionRequiresIntsAsLongs,
|
||||
"argument of type int should be promoted to type long");
|
||||
guarantee(i > 0 && sig_bt[i-1] == T_LONG,
|
||||
"argument of type (bt) should have been promoted to type (T_LONG,bt) for bt in "
|
||||
"{T_BOOLEAN, T_CHAR, T_BYTE, T_SHORT, T_INT}");
|
||||
// Do not count halves.
|
||||
regs[i].set_bad();
|
||||
--arg;
|
||||
break;
|
||||
// here. Thus fall through, handle as long.
|
||||
case T_LONG:
|
||||
guarantee(sig_bt[i+1] == T_VOID ||
|
||||
sig_bt[i+1] == T_BOOLEAN || sig_bt[i+1] == T_CHAR ||
|
||||
sig_bt[i+1] == T_BYTE || sig_bt[i+1] == T_SHORT ||
|
||||
sig_bt[i+1] == T_INT,
|
||||
"expecting type (T_LONG,half) or type (T_LONG,bt) with bt in {T_BOOLEAN, T_CHAR, T_BYTE, T_SHORT, T_INT}");
|
||||
case T_OBJECT:
|
||||
case T_ARRAY:
|
||||
case T_ADDRESS:
|
||||
@ -1273,7 +1258,7 @@ static void object_move(MacroAssembler* masm,
|
||||
static void int_move(MacroAssembler*masm,
|
||||
VMRegPair src, VMRegPair dst,
|
||||
Register r_caller_sp, Register r_temp) {
|
||||
assert(src.first()->is_valid() && src.second() == src.first()->next(), "incoming must be long-int");
|
||||
assert(src.first()->is_valid(), "incoming must be int");
|
||||
assert(dst.first()->is_valid() && dst.second() == dst.first()->next(), "outgoing must be long");
|
||||
|
||||
if (src.first()->is_stack()) {
|
||||
@ -1762,13 +1747,6 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||
// the jni function will expect them. To figure out where they go
|
||||
// we convert the java signature to a C signature by inserting
|
||||
// the hidden arguments as arg[0] and possibly arg[1] (static method)
|
||||
//
|
||||
// Additionally, on ppc64 we must convert integers to longs in the C
|
||||
// signature. We do this in advance in order to have no trouble with
|
||||
// indexes into the bt-arrays.
|
||||
// So convert the signature and registers now, and adjust the total number
|
||||
// of in-arguments accordingly.
|
||||
int i2l_argcnt = convert_ints_to_longints_argcnt(total_in_args, in_sig_bt); // PPC64: pass ints as longs.
|
||||
|
||||
// Calculate the total number of C arguments and create arrays for the
|
||||
// signature and the outgoing registers.
|
||||
@ -1776,7 +1754,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||
// some floating-point arguments must be passed in registers _and_
|
||||
// in stack locations.
|
||||
bool method_is_static = method->is_static();
|
||||
int total_c_args = i2l_argcnt;
|
||||
int total_c_args = total_in_args;
|
||||
|
||||
if (!is_critical_native) {
|
||||
int n_hidden_args = method_is_static ? 2 : 1;
|
||||
@ -1785,7 +1763,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||
// No JNIEnv*, no this*, but unpacked arrays (base+length).
|
||||
for (int i = 0; i < total_in_args; i++) {
|
||||
if (in_sig_bt[i] == T_ARRAY) {
|
||||
total_c_args += 2; // PPC64: T_LONG, T_INT, T_ADDRESS (see convert_ints_to_longints and c_calling_convention)
|
||||
total_c_args++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1803,8 +1781,6 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||
|
||||
int argc = 0;
|
||||
if (!is_critical_native) {
|
||||
convert_ints_to_longints(i2l_argcnt, total_in_args, in_sig_bt, in_regs); // PPC64: pass ints as longs.
|
||||
|
||||
out_sig_bt[argc++] = T_ADDRESS;
|
||||
if (method->is_static()) {
|
||||
out_sig_bt[argc++] = T_OBJECT;
|
||||
@ -1815,7 +1791,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||
}
|
||||
} else {
|
||||
Thread* THREAD = Thread::current();
|
||||
in_elem_bt = NEW_RESOURCE_ARRAY(BasicType, i2l_argcnt);
|
||||
in_elem_bt = NEW_RESOURCE_ARRAY(BasicType, total_c_args);
|
||||
SignatureStream ss(method->signature());
|
||||
int o = 0;
|
||||
for (int i = 0; i < total_in_args ; i++, o++) {
|
||||
@ -1839,28 +1815,16 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||
}
|
||||
} else {
|
||||
in_elem_bt[o] = T_VOID;
|
||||
switch(in_sig_bt[i]) { // PPC64: pass ints as longs.
|
||||
case T_BOOLEAN:
|
||||
case T_CHAR:
|
||||
case T_BYTE:
|
||||
case T_SHORT:
|
||||
case T_INT: in_elem_bt[++o] = T_VOID; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
if (in_sig_bt[i] != T_VOID) {
|
||||
assert(in_sig_bt[i] == ss.type(), "must match");
|
||||
ss.next();
|
||||
}
|
||||
}
|
||||
assert(i2l_argcnt==o, "must match");
|
||||
|
||||
convert_ints_to_longints(i2l_argcnt, total_in_args, in_sig_bt, in_regs); // PPC64: pass ints as longs.
|
||||
|
||||
for (int i = 0; i < total_in_args ; i++ ) {
|
||||
if (in_sig_bt[i] == T_ARRAY) {
|
||||
// Arrays are passed as int, elem* pair.
|
||||
out_sig_bt[argc++] = T_LONG; // PPC64: pass ints as longs.
|
||||
out_sig_bt[argc++] = T_INT;
|
||||
out_sig_bt[argc++] = T_ADDRESS;
|
||||
} else {
|
||||
@ -1921,7 +1885,8 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||
case T_BYTE:
|
||||
case T_SHORT:
|
||||
case T_CHAR:
|
||||
case T_INT: /*single_slots++;*/ break; // PPC64: pass ints as longs.
|
||||
case T_INT:
|
||||
// Fall through.
|
||||
case T_ARRAY:
|
||||
case T_LONG: double_slots++; break;
|
||||
default: ShouldNotReachHere();
|
||||
@ -2019,7 +1984,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||
|
||||
__ save_LR_CR(r_temp_1);
|
||||
__ generate_stack_overflow_check(frame_size_in_bytes); // Check before creating frame.
|
||||
__ mr(r_callers_sp, R1_SP); // Remember frame pointer.
|
||||
__ mr(r_callers_sp, R1_SP); // Remember frame pointer.
|
||||
__ push_frame(frame_size_in_bytes, r_temp_1); // Push the c2n adapter's frame.
|
||||
frame_done_pc = (intptr_t)__ pc();
|
||||
|
||||
@ -2098,24 +2063,16 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||
case T_BYTE:
|
||||
case T_SHORT:
|
||||
case T_INT:
|
||||
guarantee(in > 0 && in_sig_bt[in-1] == T_LONG,
|
||||
"expecting type (T_LONG,bt) for bt in {T_BOOLEAN, T_CHAR, T_BYTE, T_SHORT, T_INT}");
|
||||
// Move int and do sign extension.
|
||||
int_move(masm, in_regs[in], out_regs[out], r_callers_sp, r_temp_1);
|
||||
break;
|
||||
case T_LONG:
|
||||
if (in_sig_bt[in+1] == T_VOID) {
|
||||
long_move(masm, in_regs[in], out_regs[out], r_callers_sp, r_temp_1);
|
||||
} else {
|
||||
guarantee(in_sig_bt[in+1] == T_BOOLEAN || in_sig_bt[in+1] == T_CHAR ||
|
||||
in_sig_bt[in+1] == T_BYTE || in_sig_bt[in+1] == T_SHORT ||
|
||||
in_sig_bt[in+1] == T_INT,
|
||||
"expecting type (T_LONG,bt) for bt in {T_BOOLEAN, T_CHAR, T_BYTE, T_SHORT, T_INT}");
|
||||
int_move(masm, in_regs[in], out_regs[out], r_callers_sp, r_temp_1);
|
||||
}
|
||||
long_move(masm, in_regs[in], out_regs[out], r_callers_sp, r_temp_1);
|
||||
break;
|
||||
case T_ARRAY:
|
||||
if (is_critical_native) {
|
||||
int body_arg = out;
|
||||
out -= 2; // Point to length arg. PPC64: pass ints as longs.
|
||||
out -= 1; // Point to length arg.
|
||||
unpack_array_argument(masm, in_regs[in], in_elem_bt[in], out_regs[body_arg], out_regs[out],
|
||||
r_callers_sp, r_temp_1, r_temp_2);
|
||||
break;
|
||||
@ -2187,7 +2144,6 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm,
|
||||
// Make sure that thread is non-volatile; it crosses a bunch of VM calls below.
|
||||
assert(R16_thread->is_nonvolatile(), "thread must be in non-volatile register");
|
||||
|
||||
|
||||
# if 0
|
||||
// DTrace method entry
|
||||
# endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,12 +30,6 @@ const int BytesPerInstWord = 4;
|
||||
|
||||
const int StackAlignmentInBytes = (2*wordSize);
|
||||
|
||||
// Indicates whether the C calling conventions require that
|
||||
// 32-bit integer argument values are properly extended to 64 bits.
|
||||
// If set, SharedRuntime::c_calling_convention() must adapt
|
||||
// signatures accordingly.
|
||||
const bool CCallingConventionRequiresIntsAsLongs = false;
|
||||
|
||||
#define SUPPORTS_NATIVE_CX8
|
||||
|
||||
// The expected size in bytes of a cache line, used to pad data structures.
|
||||
|
@ -483,7 +483,7 @@ void trace_method_handle_stub(const char* adaptername,
|
||||
bool has_mh = (strstr(adaptername, "/static") == NULL &&
|
||||
strstr(adaptername, "linkTo") == NULL); // static linkers don't have MH
|
||||
const char* mh_reg_name = has_mh ? "G3_mh" : "G3";
|
||||
tty->print_cr("MH %s %s="INTPTR_FORMAT " saved_sp=" INTPTR_FORMAT " args=" INTPTR_FORMAT,
|
||||
tty->print_cr("MH %s %s=" INTPTR_FORMAT " saved_sp=" INTPTR_FORMAT " args=" INTPTR_FORMAT,
|
||||
adaptername, mh_reg_name,
|
||||
p2i(mh), p2i(saved_sp), p2i(args));
|
||||
|
||||
|
@ -329,39 +329,35 @@ void VM_Version::initialize() {
|
||||
FLAG_SET_DEFAULT(UseSHA, false);
|
||||
}
|
||||
|
||||
if (!UseSHA) {
|
||||
if (UseSHA && has_sha1()) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA1Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA1Intrinsics, true);
|
||||
}
|
||||
} else if (UseSHA1Intrinsics) {
|
||||
warning("Intrinsics for SHA-1 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
|
||||
} else {
|
||||
if (has_sha1()) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA1Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA1Intrinsics, true);
|
||||
}
|
||||
} else if (UseSHA1Intrinsics) {
|
||||
warning("SHA1 instruction is not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
|
||||
}
|
||||
if (has_sha256()) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, true);
|
||||
}
|
||||
} else if (UseSHA256Intrinsics) {
|
||||
warning("SHA256 instruction (for SHA-224 and SHA-256) is not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (has_sha512()) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, true);
|
||||
}
|
||||
} else if (UseSHA512Intrinsics) {
|
||||
warning("SHA512 instruction (for SHA-384 and SHA-512) is not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
|
||||
if (UseSHA && has_sha256()) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA256Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, true);
|
||||
}
|
||||
if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA, false);
|
||||
} else if (UseSHA256Intrinsics) {
|
||||
warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
|
||||
}
|
||||
|
||||
if (UseSHA && has_sha512()) {
|
||||
if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, true);
|
||||
}
|
||||
} else if (UseSHA512Intrinsics) {
|
||||
warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
|
||||
}
|
||||
|
||||
if (!(UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics)) {
|
||||
FLAG_SET_DEFAULT(UseSHA, false);
|
||||
}
|
||||
|
||||
// SPARC T4 and above should have support for CRC32C instruction
|
||||
|
@ -110,7 +110,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||
masm->flush();
|
||||
|
||||
if (PrintMiscellaneous && (WizardMode || Verbose)) {
|
||||
tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d",
|
||||
tty->print_cr("vtable #%d at " PTR_FORMAT "[%d] left over: %d",
|
||||
vtable_index, p2i(s->entry_point()),
|
||||
(int)(s->code_end() - s->entry_point()),
|
||||
(int)(s->code_end() - __ pc()));
|
||||
@ -205,7 +205,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
masm->flush();
|
||||
|
||||
if (PrintMiscellaneous && (WizardMode || Verbose)) {
|
||||
tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d",
|
||||
tty->print_cr("itable #%d at " PTR_FORMAT "[%d] left over: %d",
|
||||
itable_index, p2i(s->entry_point()),
|
||||
(int)(s->code_end() - s->entry_point()),
|
||||
(int)(s->code_end() - __ pc()));
|
||||
|
@ -27,12 +27,6 @@
|
||||
|
||||
const int StackAlignmentInBytes = 16;
|
||||
|
||||
// Indicates whether the C calling conventions require that
|
||||
// 32-bit integer argument values are properly extended to 64 bits.
|
||||
// If set, SharedRuntime::c_calling_convention() must adapt
|
||||
// signatures accordingly.
|
||||
const bool CCallingConventionRequiresIntsAsLongs = false;
|
||||
|
||||
#define SUPPORTS_NATIVE_CX8
|
||||
|
||||
// The expected size in bytes of a cache line, used to pad data structures.
|
||||
|
@ -5152,7 +5152,7 @@ RegisterOrConstant MacroAssembler::delayed_value_impl(intptr_t* delayed_value_ad
|
||||
{
|
||||
ResourceMark rm;
|
||||
stringStream ss;
|
||||
ss.print("DelayedValue="INTPTR_FORMAT, delayed_value_addr[1]);
|
||||
ss.print("DelayedValue=" INTPTR_FORMAT, delayed_value_addr[1]);
|
||||
buf = code_string(ss.as_string());
|
||||
}
|
||||
jcc(Assembler::notZero, L);
|
||||
|
@ -484,7 +484,7 @@ void trace_method_handle_stub(const char* adaptername,
|
||||
bool has_mh = (strstr(adaptername, "/static") == NULL &&
|
||||
strstr(adaptername, "linkTo") == NULL); // static linkers don't have MH
|
||||
const char* mh_reg_name = has_mh ? "rcx_mh" : "rcx";
|
||||
tty->print_cr("MH %s %s="PTR_FORMAT" sp="PTR_FORMAT,
|
||||
tty->print_cr("MH %s %s=" PTR_FORMAT " sp=" PTR_FORMAT,
|
||||
adaptername, mh_reg_name,
|
||||
(void *)mh, entry_sp);
|
||||
|
||||
|
@ -23,6 +23,9 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#ifndef _WINDOWS
|
||||
#include "alloca.h"
|
||||
#endif
|
||||
#include "asm/macroAssembler.hpp"
|
||||
#include "asm/macroAssembler.inline.hpp"
|
||||
#include "code/debugInfoRec.hpp"
|
||||
@ -3511,6 +3514,250 @@ RuntimeStub* SharedRuntime::generate_resolve_blob(address destination, const cha
|
||||
}
|
||||
|
||||
|
||||
//------------------------------Montgomery multiplication------------------------
|
||||
//
|
||||
|
||||
#ifndef _WINDOWS
|
||||
|
||||
#define ASM_SUBTRACT
|
||||
|
||||
#ifdef ASM_SUBTRACT
|
||||
// Subtract 0:b from carry:a. Return carry.
|
||||
static unsigned long
|
||||
sub(unsigned long a[], unsigned long b[], unsigned long carry, long len) {
|
||||
long i = 0, cnt = len;
|
||||
unsigned long tmp;
|
||||
asm volatile("clc; "
|
||||
"0: ; "
|
||||
"mov (%[b], %[i], 8), %[tmp]; "
|
||||
"sbb %[tmp], (%[a], %[i], 8); "
|
||||
"inc %[i]; dec %[cnt]; "
|
||||
"jne 0b; "
|
||||
"mov %[carry], %[tmp]; sbb $0, %[tmp]; "
|
||||
: [i]"+r"(i), [cnt]"+r"(cnt), [tmp]"=&r"(tmp)
|
||||
: [a]"r"(a), [b]"r"(b), [carry]"r"(carry)
|
||||
: "memory");
|
||||
return tmp;
|
||||
}
|
||||
#else // ASM_SUBTRACT
|
||||
typedef int __attribute__((mode(TI))) int128;
|
||||
|
||||
// Subtract 0:b from carry:a. Return carry.
|
||||
static unsigned long
|
||||
sub(unsigned long a[], unsigned long b[], unsigned long carry, int len) {
|
||||
int128 tmp = 0;
|
||||
int i;
|
||||
for (i = 0; i < len; i++) {
|
||||
tmp += a[i];
|
||||
tmp -= b[i];
|
||||
a[i] = tmp;
|
||||
tmp >>= 64;
|
||||
assert(-1 <= tmp && tmp <= 0, "invariant");
|
||||
}
|
||||
return tmp + carry;
|
||||
}
|
||||
#endif // ! ASM_SUBTRACT
|
||||
|
||||
// Multiply (unsigned) Long A by Long B, accumulating the double-
|
||||
// length result into the accumulator formed of T0, T1, and T2.
|
||||
#define MACC(A, B, T0, T1, T2) \
|
||||
do { \
|
||||
unsigned long hi, lo; \
|
||||
__asm__ ("mul %5; add %%rax, %2; adc %%rdx, %3; adc $0, %4" \
|
||||
: "=&d"(hi), "=a"(lo), "+r"(T0), "+r"(T1), "+g"(T2) \
|
||||
: "r"(A), "a"(B) : "cc"); \
|
||||
} while(0)
|
||||
|
||||
// As above, but add twice the double-length result into the
|
||||
// accumulator.
|
||||
#define MACC2(A, B, T0, T1, T2) \
|
||||
do { \
|
||||
unsigned long hi, lo; \
|
||||
__asm__ ("mul %5; add %%rax, %2; adc %%rdx, %3; adc $0, %4; " \
|
||||
"add %%rax, %2; adc %%rdx, %3; adc $0, %4" \
|
||||
: "=&d"(hi), "=a"(lo), "+r"(T0), "+r"(T1), "+g"(T2) \
|
||||
: "r"(A), "a"(B) : "cc"); \
|
||||
} while(0)
|
||||
|
||||
// Fast Montgomery multiplication. The derivation of the algorithm is
|
||||
// in A Cryptographic Library for the Motorola DSP56000,
|
||||
// Dusse and Kaliski, Proc. EUROCRYPT 90, pp. 230-237.
|
||||
|
||||
static void __attribute__((noinline))
|
||||
montgomery_multiply(unsigned long a[], unsigned long b[], unsigned long n[],
|
||||
unsigned long m[], unsigned long inv, int len) {
|
||||
unsigned long t0 = 0, t1 = 0, t2 = 0; // Triple-precision accumulator
|
||||
int i;
|
||||
|
||||
assert(inv * n[0] == -1UL, "broken inverse in Montgomery multiply");
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int j;
|
||||
for (j = 0; j < i; j++) {
|
||||
MACC(a[j], b[i-j], t0, t1, t2);
|
||||
MACC(m[j], n[i-j], t0, t1, t2);
|
||||
}
|
||||
MACC(a[i], b[0], t0, t1, t2);
|
||||
m[i] = t0 * inv;
|
||||
MACC(m[i], n[0], t0, t1, t2);
|
||||
|
||||
assert(t0 == 0, "broken Montgomery multiply");
|
||||
|
||||
t0 = t1; t1 = t2; t2 = 0;
|
||||
}
|
||||
|
||||
for (i = len; i < 2*len; i++) {
|
||||
int j;
|
||||
for (j = i-len+1; j < len; j++) {
|
||||
MACC(a[j], b[i-j], t0, t1, t2);
|
||||
MACC(m[j], n[i-j], t0, t1, t2);
|
||||
}
|
||||
m[i-len] = t0;
|
||||
t0 = t1; t1 = t2; t2 = 0;
|
||||
}
|
||||
|
||||
while (t0)
|
||||
t0 = sub(m, n, t0, len);
|
||||
}
|
||||
|
||||
// Fast Montgomery squaring. This uses asymptotically 25% fewer
|
||||
// multiplies so it should be up to 25% faster than Montgomery
|
||||
// multiplication. However, its loop control is more complex and it
|
||||
// may actually run slower on some machines.
|
||||
|
||||
static void __attribute__((noinline))
|
||||
montgomery_square(unsigned long a[], unsigned long n[],
|
||||
unsigned long m[], unsigned long inv, int len) {
|
||||
unsigned long t0 = 0, t1 = 0, t2 = 0; // Triple-precision accumulator
|
||||
int i;
|
||||
|
||||
assert(inv * n[0] == -1UL, "broken inverse in Montgomery multiply");
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int j;
|
||||
int end = (i+1)/2;
|
||||
for (j = 0; j < end; j++) {
|
||||
MACC2(a[j], a[i-j], t0, t1, t2);
|
||||
MACC(m[j], n[i-j], t0, t1, t2);
|
||||
}
|
||||
if ((i & 1) == 0) {
|
||||
MACC(a[j], a[j], t0, t1, t2);
|
||||
}
|
||||
for (; j < i; j++) {
|
||||
MACC(m[j], n[i-j], t0, t1, t2);
|
||||
}
|
||||
m[i] = t0 * inv;
|
||||
MACC(m[i], n[0], t0, t1, t2);
|
||||
|
||||
assert(t0 == 0, "broken Montgomery square");
|
||||
|
||||
t0 = t1; t1 = t2; t2 = 0;
|
||||
}
|
||||
|
||||
for (i = len; i < 2*len; i++) {
|
||||
int start = i-len+1;
|
||||
int end = start + (len - start)/2;
|
||||
int j;
|
||||
for (j = start; j < end; j++) {
|
||||
MACC2(a[j], a[i-j], t0, t1, t2);
|
||||
MACC(m[j], n[i-j], t0, t1, t2);
|
||||
}
|
||||
if ((i & 1) == 0) {
|
||||
MACC(a[j], a[j], t0, t1, t2);
|
||||
}
|
||||
for (; j < len; j++) {
|
||||
MACC(m[j], n[i-j], t0, t1, t2);
|
||||
}
|
||||
m[i-len] = t0;
|
||||
t0 = t1; t1 = t2; t2 = 0;
|
||||
}
|
||||
|
||||
while (t0)
|
||||
t0 = sub(m, n, t0, len);
|
||||
}
|
||||
|
||||
// Swap words in a longword.
|
||||
static unsigned long swap(unsigned long x) {
|
||||
return (x << 32) | (x >> 32);
|
||||
}
|
||||
|
||||
// Copy len longwords from s to d, word-swapping as we go. The
|
||||
// destination array is reversed.
|
||||
static void reverse_words(unsigned long *s, unsigned long *d, int len) {
|
||||
d += len;
|
||||
while(len-- > 0) {
|
||||
d--;
|
||||
*d = swap(*s);
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
// The threshold at which squaring is advantageous was determined
|
||||
// experimentally on an i7-3930K (Ivy Bridge) CPU @ 3.5GHz.
|
||||
#define MONTGOMERY_SQUARING_THRESHOLD 64
|
||||
|
||||
void SharedRuntime::montgomery_multiply(jint *a_ints, jint *b_ints, jint *n_ints,
|
||||
jint len, jlong inv,
|
||||
jint *m_ints) {
|
||||
assert(len % 2 == 0, "array length in montgomery_multiply must be even");
|
||||
int longwords = len/2;
|
||||
|
||||
// Make very sure we don't use so much space that the stack might
|
||||
// overflow. 512 jints corresponds to an 16384-bit integer and
|
||||
// will use here a total of 8k bytes of stack space.
|
||||
int total_allocation = longwords * sizeof (unsigned long) * 4;
|
||||
guarantee(total_allocation <= 8192, "must be");
|
||||
unsigned long *scratch = (unsigned long *)alloca(total_allocation);
|
||||
|
||||
// Local scratch arrays
|
||||
unsigned long
|
||||
*a = scratch + 0 * longwords,
|
||||
*b = scratch + 1 * longwords,
|
||||
*n = scratch + 2 * longwords,
|
||||
*m = scratch + 3 * longwords;
|
||||
|
||||
reverse_words((unsigned long *)a_ints, a, longwords);
|
||||
reverse_words((unsigned long *)b_ints, b, longwords);
|
||||
reverse_words((unsigned long *)n_ints, n, longwords);
|
||||
|
||||
::montgomery_multiply(a, b, n, m, (unsigned long)inv, longwords);
|
||||
|
||||
reverse_words(m, (unsigned long *)m_ints, longwords);
|
||||
}
|
||||
|
||||
void SharedRuntime::montgomery_square(jint *a_ints, jint *n_ints,
|
||||
jint len, jlong inv,
|
||||
jint *m_ints) {
|
||||
assert(len % 2 == 0, "array length in montgomery_square must be even");
|
||||
int longwords = len/2;
|
||||
|
||||
// Make very sure we don't use so much space that the stack might
|
||||
// overflow. 512 jints corresponds to an 16384-bit integer and
|
||||
// will use here a total of 6k bytes of stack space.
|
||||
int total_allocation = longwords * sizeof (unsigned long) * 3;
|
||||
guarantee(total_allocation <= 8192, "must be");
|
||||
unsigned long *scratch = (unsigned long *)alloca(total_allocation);
|
||||
|
||||
// Local scratch arrays
|
||||
unsigned long
|
||||
*a = scratch + 0 * longwords,
|
||||
*n = scratch + 1 * longwords,
|
||||
*m = scratch + 2 * longwords;
|
||||
|
||||
reverse_words((unsigned long *)a_ints, a, longwords);
|
||||
reverse_words((unsigned long *)n_ints, n, longwords);
|
||||
|
||||
if (len >= MONTGOMERY_SQUARING_THRESHOLD) {
|
||||
::montgomery_square(a, n, m, (unsigned long)inv, longwords);
|
||||
} else {
|
||||
::montgomery_multiply(a, a, n, m, (unsigned long)inv, longwords);
|
||||
}
|
||||
|
||||
reverse_words(m, (unsigned long *)m_ints, longwords);
|
||||
}
|
||||
|
||||
#endif // WINDOWS
|
||||
|
||||
#ifdef COMPILER2
|
||||
// This is here instead of runtime_x86_64.cpp because it uses SimpleRuntimeFrame
|
||||
//
|
||||
|
@ -4318,7 +4318,18 @@ class StubGenerator: public StubCodeGenerator {
|
||||
if (UseMulAddIntrinsic) {
|
||||
StubRoutines::_mulAdd = generate_mulAdd();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef _WINDOWS
|
||||
if (UseMontgomeryMultiplyIntrinsic) {
|
||||
StubRoutines::_montgomeryMultiply
|
||||
= CAST_FROM_FN_PTR(address, SharedRuntime::montgomery_multiply);
|
||||
}
|
||||
if (UseMontgomerySquareIntrinsic) {
|
||||
StubRoutines::_montgomerySquare
|
||||
= CAST_FROM_FN_PTR(address, SharedRuntime::montgomery_square);
|
||||
}
|
||||
#endif // WINDOWS
|
||||
#endif // COMPILER2
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -692,10 +692,19 @@ void VM_Version::get_processor_features() {
|
||||
warning("SHA instructions are not available on this CPU");
|
||||
FLAG_SET_DEFAULT(UseSHA, false);
|
||||
}
|
||||
if (UseSHA1Intrinsics || UseSHA256Intrinsics || UseSHA512Intrinsics) {
|
||||
warning("SHA intrinsics are not available on this CPU");
|
||||
|
||||
if (UseSHA1Intrinsics) {
|
||||
warning("Intrinsics for SHA-1 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA1Intrinsics, false);
|
||||
}
|
||||
|
||||
if (UseSHA256Intrinsics) {
|
||||
warning("Intrinsics for SHA-224 and SHA-256 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
|
||||
}
|
||||
|
||||
if (UseSHA512Intrinsics) {
|
||||
warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU.");
|
||||
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
|
||||
}
|
||||
|
||||
@ -813,6 +822,12 @@ void VM_Version::get_processor_features() {
|
||||
if (FLAG_IS_DEFAULT(UseMulAddIntrinsic)) {
|
||||
UseMulAddIntrinsic = true;
|
||||
}
|
||||
if (FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) {
|
||||
UseMontgomeryMultiplyIntrinsic = true;
|
||||
}
|
||||
if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) {
|
||||
UseMontgomerySquareIntrinsic = true;
|
||||
}
|
||||
#else
|
||||
if (UseMultiplyToLenIntrinsic) {
|
||||
if (!FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) {
|
||||
@ -820,6 +835,18 @@ void VM_Version::get_processor_features() {
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, false);
|
||||
}
|
||||
if (UseMontgomeryMultiplyIntrinsic) {
|
||||
if (!FLAG_IS_DEFAULT(UseMontgomeryMultiplyIntrinsic)) {
|
||||
warning("montgomeryMultiply intrinsic is not available in 32-bit VM");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseMontgomeryMultiplyIntrinsic, false);
|
||||
}
|
||||
if (UseMontgomerySquareIntrinsic) {
|
||||
if (!FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) {
|
||||
warning("montgomerySquare intrinsic is not available in 32-bit VM");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseMontgomerySquareIntrinsic, false);
|
||||
}
|
||||
if (UseSquareToLenIntrinsic) {
|
||||
if (!FLAG_IS_DEFAULT(UseSquareToLenIntrinsic)) {
|
||||
warning("squareToLen intrinsic is not available in 32-bit VM");
|
||||
|
@ -117,7 +117,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||
masm->flush();
|
||||
|
||||
if (PrintMiscellaneous && (WizardMode || Verbose)) {
|
||||
tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d",
|
||||
tty->print_cr("vtable #%d at " PTR_FORMAT "[%d] left over: %d",
|
||||
vtable_index, p2i(s->entry_point()),
|
||||
(int)(s->code_end() - s->entry_point()),
|
||||
(int)(s->code_end() - __ pc()));
|
||||
@ -198,7 +198,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
masm->flush();
|
||||
|
||||
if (PrintMiscellaneous && (WizardMode || Verbose)) {
|
||||
tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d",
|
||||
tty->print_cr("itable #%d at " PTR_FORMAT "[%d] left over: %d",
|
||||
itable_index, p2i(s->entry_point()),
|
||||
(int)(s->code_end() - s->entry_point()),
|
||||
(int)(s->code_end() - __ pc()));
|
||||
|
@ -112,7 +112,7 @@ VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
|
||||
__ flush();
|
||||
|
||||
if (PrintMiscellaneous && (WizardMode || Verbose)) {
|
||||
tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d",
|
||||
tty->print_cr("vtable #%d at " PTR_FORMAT "[%d] left over: %d",
|
||||
vtable_index, s->entry_point(),
|
||||
(int)(s->code_end() - s->entry_point()),
|
||||
(int)(s->code_end() - __ pc()));
|
||||
@ -205,7 +205,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) {
|
||||
__ flush();
|
||||
|
||||
if (PrintMiscellaneous && (WizardMode || Verbose)) {
|
||||
tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d",
|
||||
tty->print_cr("itable #%d at " PTR_FORMAT "[%d] left over: %d",
|
||||
itable_index, s->entry_point(),
|
||||
(int)(s->code_end() - s->entry_point()),
|
||||
(int)(s->code_end() - __ pc()));
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2009 Red Hat, Inc.
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2009, 2015, Red Hat, Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -28,10 +28,4 @@
|
||||
|
||||
#include <ffi.h>
|
||||
|
||||
// Indicates whether the C calling conventions require that
|
||||
// 32-bit integer argument values are properly extended to 64 bits.
|
||||
// If set, SharedRuntime::c_calling_convention() must adapt
|
||||
// signatures accordingly.
|
||||
const bool CCallingConventionRequiresIntsAsLongs = false;
|
||||
|
||||
#endif // CPU_ZERO_VM_GLOBALDEFINITIONS_ZERO_HPP
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2015, 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
|
||||
@ -42,6 +42,7 @@
|
||||
|
||||
static struct sigaction sact[MAXSIGNUM]; /* saved signal handlers */
|
||||
static unsigned int jvmsigs = 0; /* signals used by jvm */
|
||||
static __thread bool reentry = false; /* prevent reentry deadlock (per-thread) */
|
||||
|
||||
/* used to synchronize the installation of signal handlers */
|
||||
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
@ -76,6 +77,8 @@ static void signal_unlock() {
|
||||
|
||||
static sa_handler_t call_os_signal(int sig, sa_handler_t disp,
|
||||
bool is_sigset) {
|
||||
sa_handler_t res;
|
||||
|
||||
if (os_signal == NULL) {
|
||||
if (!is_sigset) {
|
||||
os_signal = (signal_t)dlsym(RTLD_NEXT, "signal");
|
||||
@ -87,7 +90,10 @@ static sa_handler_t call_os_signal(int sig, sa_handler_t disp,
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
return (*os_signal)(sig, disp);
|
||||
reentry = true;
|
||||
res = (*os_signal)(sig, disp);
|
||||
reentry = false;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void save_signal_handler(int sig, sa_handler_t disp) {
|
||||
@ -161,6 +167,10 @@ int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
|
||||
bool sigused;
|
||||
struct sigaction oldAct;
|
||||
|
||||
if (reentry) {
|
||||
return call_os_sigaction(sig, act, oact);
|
||||
}
|
||||
|
||||
signal_lock();
|
||||
|
||||
sigused = (MASK(sig) & jvmsigs) != 0;
|
||||
|
@ -59,6 +59,7 @@
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadCritical.hpp"
|
||||
#include "runtime/timer.hpp"
|
||||
#include "semaphore_bsd.hpp"
|
||||
#include "services/attachListener.hpp"
|
||||
#include "services/memTracker.hpp"
|
||||
#include "services/runtimeService.hpp"
|
||||
@ -1940,47 +1941,54 @@ typedef sem_t os_semaphore_t;
|
||||
#define SEM_DESTROY(sem) sem_destroy(&sem)
|
||||
#endif
|
||||
|
||||
class Semaphore : public StackObj {
|
||||
public:
|
||||
Semaphore();
|
||||
~Semaphore();
|
||||
void signal();
|
||||
void wait();
|
||||
bool trywait();
|
||||
bool timedwait(unsigned int sec, int nsec);
|
||||
private:
|
||||
jlong currenttime() const;
|
||||
os_semaphore_t _semaphore;
|
||||
};
|
||||
#ifdef __APPLE__
|
||||
// OS X doesn't support unamed POSIX semaphores, so the implementation in os_posix.cpp can't be used.
|
||||
|
||||
Semaphore::Semaphore() : _semaphore(0) {
|
||||
SEM_INIT(_semaphore, 0);
|
||||
static const char* sem_init_strerror(kern_return_t value) {
|
||||
switch (value) {
|
||||
case KERN_INVALID_ARGUMENT: return "Invalid argument";
|
||||
case KERN_RESOURCE_SHORTAGE: return "Resource shortage";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
Semaphore::~Semaphore() {
|
||||
OSXSemaphore::OSXSemaphore(uint value) {
|
||||
kern_return_t ret = SEM_INIT(_semaphore, value);
|
||||
|
||||
guarantee(ret == KERN_SUCCESS, err_msg("Failed to create semaphore: %s", sem_init_strerror(ret)));
|
||||
}
|
||||
|
||||
OSXSemaphore::~OSXSemaphore() {
|
||||
SEM_DESTROY(_semaphore);
|
||||
}
|
||||
|
||||
void Semaphore::signal() {
|
||||
SEM_POST(_semaphore);
|
||||
void OSXSemaphore::signal(uint count) {
|
||||
for (uint i = 0; i < count; i++) {
|
||||
kern_return_t ret = SEM_POST(_semaphore);
|
||||
|
||||
assert(ret == KERN_SUCCESS, "Failed to signal semaphore");
|
||||
}
|
||||
}
|
||||
|
||||
void Semaphore::wait() {
|
||||
SEM_WAIT(_semaphore);
|
||||
void OSXSemaphore::wait() {
|
||||
kern_return_t ret;
|
||||
while ((ret = SEM_WAIT(_semaphore)) == KERN_ABORTED) {
|
||||
// Semaphore was interrupted. Retry.
|
||||
}
|
||||
assert(ret == KERN_SUCCESS, "Failed to wait on semaphore");
|
||||
}
|
||||
|
||||
jlong Semaphore::currenttime() const {
|
||||
jlong OSXSemaphore::currenttime() {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (tv.tv_sec * NANOSECS_PER_SEC) + (tv.tv_usec * 1000);
|
||||
}
|
||||
|
||||
#ifdef __APPLE__
|
||||
bool Semaphore::trywait() {
|
||||
bool OSXSemaphore::trywait() {
|
||||
return timedwait(0, 0);
|
||||
}
|
||||
|
||||
bool Semaphore::timedwait(unsigned int sec, int nsec) {
|
||||
bool OSXSemaphore::timedwait(unsigned int sec, int nsec) {
|
||||
kern_return_t kr = KERN_ABORTED;
|
||||
mach_timespec_t waitspec;
|
||||
waitspec.tv_sec = sec;
|
||||
@ -2011,33 +2019,24 @@ bool Semaphore::timedwait(unsigned int sec, int nsec) {
|
||||
}
|
||||
|
||||
#else
|
||||
// Use POSIX implementation of semaphores.
|
||||
|
||||
bool Semaphore::trywait() {
|
||||
return sem_trywait(&_semaphore) == 0;
|
||||
}
|
||||
|
||||
bool Semaphore::timedwait(unsigned int sec, int nsec) {
|
||||
struct timespec PosixSemaphore::create_timespec(unsigned int sec, int nsec) {
|
||||
struct timespec ts;
|
||||
unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec);
|
||||
|
||||
while (1) {
|
||||
int result = sem_timedwait(&_semaphore, &ts);
|
||||
if (result == 0) {
|
||||
return true;
|
||||
} else if (errno == EINTR) {
|
||||
continue;
|
||||
} else if (errno == ETIMEDOUT) {
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
|
||||
#endif // __APPLE__
|
||||
|
||||
static os_semaphore_t sig_sem;
|
||||
static Semaphore sr_semaphore;
|
||||
|
||||
#ifdef __APPLE__
|
||||
static OSXSemaphore sr_semaphore;
|
||||
#else
|
||||
static PosixSemaphore sr_semaphore;
|
||||
#endif
|
||||
|
||||
void os::signal_init_pd() {
|
||||
// Initialize signal structures
|
||||
|
63
hotspot/src/os/bsd/vm/semaphore_bsd.hpp
Normal file
63
hotspot/src/os/bsd/vm/semaphore_bsd.hpp
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 OS_BSD_VM_SEMAPHORE_BSD_HPP
|
||||
#define OS_BSD_VM_SEMAPHORE_BSD_HPP
|
||||
|
||||
#ifndef __APPLE__
|
||||
// Use POSIX semaphores.
|
||||
# include "semaphore_posix.hpp"
|
||||
|
||||
#else
|
||||
// OS X doesn't support unamed POSIX semaphores, so the implementation in os_posix.cpp can't be used.
|
||||
# include "memory/allocation.hpp"
|
||||
# include <mach/semaphore.h>
|
||||
|
||||
class OSXSemaphore : public CHeapObj<mtInternal>{
|
||||
semaphore_t _semaphore;
|
||||
|
||||
// Prevent copying and assignment.
|
||||
OSXSemaphore(const OSXSemaphore&);
|
||||
OSXSemaphore& operator=(const OSXSemaphore&);
|
||||
|
||||
public:
|
||||
OSXSemaphore(uint value = 0);
|
||||
~OSXSemaphore();
|
||||
|
||||
void signal(uint count = 1);
|
||||
|
||||
void wait();
|
||||
|
||||
bool trywait();
|
||||
bool timedwait(unsigned int sec, int nsec);
|
||||
|
||||
private:
|
||||
static jlong currenttime();
|
||||
};
|
||||
|
||||
typedef OSXSemaphore SemaphoreImpl;
|
||||
|
||||
#endif // __APPLE__
|
||||
|
||||
#endif // OS_BSD_VM_SEMAPHORE_BSD_HPP
|
@ -60,6 +60,7 @@
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "runtime/threadCritical.hpp"
|
||||
#include "runtime/timer.hpp"
|
||||
#include "semaphore_posix.hpp"
|
||||
#include "services/attachListener.hpp"
|
||||
#include "services/memTracker.hpp"
|
||||
#include "services/runtimeService.hpp"
|
||||
@ -2315,40 +2316,7 @@ void* os::user_handler() {
|
||||
return CAST_FROM_FN_PTR(void*, UserHandler);
|
||||
}
|
||||
|
||||
class Semaphore : public StackObj {
|
||||
public:
|
||||
Semaphore();
|
||||
~Semaphore();
|
||||
void signal();
|
||||
void wait();
|
||||
bool trywait();
|
||||
bool timedwait(unsigned int sec, int nsec);
|
||||
private:
|
||||
sem_t _semaphore;
|
||||
};
|
||||
|
||||
Semaphore::Semaphore() {
|
||||
sem_init(&_semaphore, 0, 0);
|
||||
}
|
||||
|
||||
Semaphore::~Semaphore() {
|
||||
sem_destroy(&_semaphore);
|
||||
}
|
||||
|
||||
void Semaphore::signal() {
|
||||
sem_post(&_semaphore);
|
||||
}
|
||||
|
||||
void Semaphore::wait() {
|
||||
sem_wait(&_semaphore);
|
||||
}
|
||||
|
||||
bool Semaphore::trywait() {
|
||||
return sem_trywait(&_semaphore) == 0;
|
||||
}
|
||||
|
||||
bool Semaphore::timedwait(unsigned int sec, int nsec) {
|
||||
|
||||
struct timespec PosixSemaphore::create_timespec(unsigned int sec, int nsec) {
|
||||
struct timespec ts;
|
||||
// Semaphore's are always associated with CLOCK_REALTIME
|
||||
os::Linux::clock_gettime(CLOCK_REALTIME, &ts);
|
||||
@ -2365,18 +2333,7 @@ bool Semaphore::timedwait(unsigned int sec, int nsec) {
|
||||
}
|
||||
}
|
||||
|
||||
while (1) {
|
||||
int result = sem_timedwait(&_semaphore, &ts);
|
||||
if (result == 0) {
|
||||
return true;
|
||||
} else if (errno == EINTR) {
|
||||
continue;
|
||||
} else if (errno == ETIMEDOUT) {
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
@ -2416,7 +2373,7 @@ static volatile jint pending_signals[NSIG+1] = { 0 };
|
||||
|
||||
// Linux(POSIX) specific hand shaking semaphore.
|
||||
static sem_t sig_sem;
|
||||
static Semaphore sr_semaphore;
|
||||
static PosixSemaphore sr_semaphore;
|
||||
|
||||
void os::signal_init_pd() {
|
||||
// Initialize signal structures
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "prims/jvm.h"
|
||||
#include "semaphore_posix.hpp"
|
||||
#include "runtime/frame.inline.hpp"
|
||||
#include "runtime/interfaceSupport.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
@ -34,6 +35,7 @@
|
||||
#include <sys/resource.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <pthread.h>
|
||||
#include <semaphore.h>
|
||||
#include <signal.h>
|
||||
|
||||
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
|
||||
@ -1015,3 +1017,73 @@ void os::WatcherThreadCrashProtection::check_crash_protection(int sig,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define check_with_errno(check_type, cond, msg) \
|
||||
do { \
|
||||
int err = errno; \
|
||||
check_type(cond, err_msg("%s; error='%s' (errno=%d)", msg, strerror(err), err)); \
|
||||
} while (false)
|
||||
|
||||
#define assert_with_errno(cond, msg) check_with_errno(assert, cond, msg)
|
||||
#define guarantee_with_errno(cond, msg) check_with_errno(guarantee, cond, msg)
|
||||
|
||||
// POSIX unamed semaphores are not supported on OS X.
|
||||
#ifndef __APPLE__
|
||||
|
||||
PosixSemaphore::PosixSemaphore(uint value) {
|
||||
int ret = sem_init(&_semaphore, 0, value);
|
||||
|
||||
guarantee_with_errno(ret == 0, "Failed to initialize semaphore");
|
||||
}
|
||||
|
||||
PosixSemaphore::~PosixSemaphore() {
|
||||
sem_destroy(&_semaphore);
|
||||
}
|
||||
|
||||
void PosixSemaphore::signal(uint count) {
|
||||
for (uint i = 0; i < count; i++) {
|
||||
int ret = sem_post(&_semaphore);
|
||||
|
||||
assert_with_errno(ret == 0, "sem_post failed");
|
||||
}
|
||||
}
|
||||
|
||||
void PosixSemaphore::wait() {
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = sem_wait(&_semaphore);
|
||||
} while (ret != 0 && errno == EINTR);
|
||||
|
||||
assert_with_errno(ret == 0, "sem_wait failed");
|
||||
}
|
||||
|
||||
bool PosixSemaphore::trywait() {
|
||||
int ret;
|
||||
|
||||
do {
|
||||
ret = sem_trywait(&_semaphore);
|
||||
} while (ret != 0 && errno == EINTR);
|
||||
|
||||
assert_with_errno(ret == 0 || errno == EAGAIN, "trywait failed");
|
||||
|
||||
return ret == 0;
|
||||
}
|
||||
|
||||
bool PosixSemaphore::timedwait(const struct timespec ts) {
|
||||
while (true) {
|
||||
int result = sem_timedwait(&_semaphore, &ts);
|
||||
if (result == 0) {
|
||||
return true;
|
||||
} else if (errno == EINTR) {
|
||||
continue;
|
||||
} else if (errno == ETIMEDOUT) {
|
||||
return false;
|
||||
} else {
|
||||
assert_with_errno(false, "timedwait failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // __APPLE__
|
||||
|
61
hotspot/src/os/posix/vm/semaphore_posix.hpp
Normal file
61
hotspot/src/os/posix/vm/semaphore_posix.hpp
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 OS_POSIX_VM_SEMAPHORE_POSIX_HPP
|
||||
#define OS_POSIX_VM_SEMAPHORE_POSIX_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
#include <semaphore.h>
|
||||
|
||||
class PosixSemaphore : public CHeapObj<mtInternal> {
|
||||
sem_t _semaphore;
|
||||
|
||||
// Prevent copying and assignment.
|
||||
PosixSemaphore(const PosixSemaphore&);
|
||||
PosixSemaphore& operator=(const PosixSemaphore&);
|
||||
|
||||
public:
|
||||
PosixSemaphore(uint value = 0);
|
||||
~PosixSemaphore();
|
||||
|
||||
void signal(uint count = 1);
|
||||
|
||||
void wait();
|
||||
|
||||
bool trywait();
|
||||
bool timedwait(unsigned int sec, int nsec) {
|
||||
return timedwait(create_timespec(sec, nsec));
|
||||
}
|
||||
|
||||
private:
|
||||
bool timedwait(struct timespec ts);
|
||||
|
||||
// OS specific implementation to create a timespec suitable for semaphores.
|
||||
struct timespec create_timespec(unsigned int set, int nsec);
|
||||
};
|
||||
|
||||
typedef PosixSemaphore SemaphoreImpl;
|
||||
|
||||
#endif // OS_POSIX_VM_SEMAPHORE_POSIX_HPP
|
@ -60,6 +60,7 @@
|
||||
#include "runtime/threadCritical.hpp"
|
||||
#include "runtime/timer.hpp"
|
||||
#include "runtime/vm_version.hpp"
|
||||
#include "semaphore_posix.hpp"
|
||||
#include "services/attachListener.hpp"
|
||||
#include "services/memTracker.hpp"
|
||||
#include "services/runtimeService.hpp"
|
||||
@ -2263,55 +2264,11 @@ void* os::user_handler() {
|
||||
return CAST_FROM_FN_PTR(void*, UserHandler);
|
||||
}
|
||||
|
||||
class Semaphore : public StackObj {
|
||||
public:
|
||||
Semaphore();
|
||||
~Semaphore();
|
||||
void signal();
|
||||
void wait();
|
||||
bool trywait();
|
||||
bool timedwait(unsigned int sec, int nsec);
|
||||
private:
|
||||
sema_t _semaphore;
|
||||
};
|
||||
|
||||
|
||||
Semaphore::Semaphore() {
|
||||
sema_init(&_semaphore, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
Semaphore::~Semaphore() {
|
||||
sema_destroy(&_semaphore);
|
||||
}
|
||||
|
||||
void Semaphore::signal() {
|
||||
sema_post(&_semaphore);
|
||||
}
|
||||
|
||||
void Semaphore::wait() {
|
||||
sema_wait(&_semaphore);
|
||||
}
|
||||
|
||||
bool Semaphore::trywait() {
|
||||
return sema_trywait(&_semaphore) == 0;
|
||||
}
|
||||
|
||||
bool Semaphore::timedwait(unsigned int sec, int nsec) {
|
||||
struct timespec PosixSemaphore::create_timespec(unsigned int sec, int nsec) {
|
||||
struct timespec ts;
|
||||
unpackTime(&ts, false, (sec * NANOSECS_PER_SEC) + nsec);
|
||||
|
||||
while (1) {
|
||||
int result = sema_timedwait(&_semaphore, &ts);
|
||||
if (result == 0) {
|
||||
return true;
|
||||
} else if (errno == EINTR) {
|
||||
continue;
|
||||
} else if (errno == ETIME) {
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return ts;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
@ -3711,7 +3668,7 @@ static void suspend_save_context(OSThread *osthread, ucontext_t* context) {
|
||||
osthread->set_ucontext(context);
|
||||
}
|
||||
|
||||
static Semaphore sr_semaphore;
|
||||
static PosixSemaphore sr_semaphore;
|
||||
|
||||
void os::Solaris::SR_handler(Thread* thread, ucontext_t* uc) {
|
||||
// Save and restore errno to avoid confusing native code with EINTR
|
||||
|
@ -63,6 +63,7 @@
|
||||
#include "runtime/threadCritical.hpp"
|
||||
#include "runtime/timer.hpp"
|
||||
#include "runtime/vm_version.hpp"
|
||||
#include "semaphore_windows.hpp"
|
||||
#include "services/attachListener.hpp"
|
||||
#include "services/memTracker.hpp"
|
||||
#include "services/runtimeService.hpp"
|
||||
@ -1901,6 +1902,30 @@ int os::get_last_error() {
|
||||
return (int)error;
|
||||
}
|
||||
|
||||
WindowsSemaphore::WindowsSemaphore(uint value) {
|
||||
_semaphore = ::CreateSemaphore(NULL, value, LONG_MAX, NULL);
|
||||
|
||||
guarantee(_semaphore != NULL, err_msg("CreateSemaphore failed with error code: %lu", GetLastError()));
|
||||
}
|
||||
|
||||
WindowsSemaphore::~WindowsSemaphore() {
|
||||
::CloseHandle(_semaphore);
|
||||
}
|
||||
|
||||
void WindowsSemaphore::signal(uint count) {
|
||||
if (count > 0) {
|
||||
BOOL ret = ::ReleaseSemaphore(_semaphore, count, NULL);
|
||||
|
||||
assert(ret != 0, err_msg("ReleaseSemaphore failed with error code: %lu", GetLastError()));
|
||||
}
|
||||
}
|
||||
|
||||
void WindowsSemaphore::wait() {
|
||||
DWORD ret = ::WaitForSingleObject(_semaphore, INFINITE);
|
||||
assert(ret != WAIT_FAILED, err_msg("WaitForSingleObject failed with error code: %lu", GetLastError()));
|
||||
assert(ret == WAIT_OBJECT_0, err_msg("WaitForSingleObject failed with return value: %lu", ret));
|
||||
}
|
||||
|
||||
// sun.misc.Signal
|
||||
// NOTE that this is a workaround for an apparent kernel bug where if
|
||||
// a signal handler for SIGBREAK is installed then that signal handler
|
||||
@ -5890,7 +5915,7 @@ void TestReserveMemorySpecial_test() {
|
||||
char* result = os::reserve_memory_special(large_allocation_size, os::large_page_size(), NULL, false);
|
||||
if (result == NULL) {
|
||||
if (VerboseInternalVMTests) {
|
||||
gclog_or_tty->print("Failed to allocate control block with size "SIZE_FORMAT". Skipping remainder of test.",
|
||||
gclog_or_tty->print("Failed to allocate control block with size " SIZE_FORMAT ". Skipping remainder of test.",
|
||||
large_allocation_size);
|
||||
}
|
||||
} else {
|
||||
@ -5903,7 +5928,7 @@ void TestReserveMemorySpecial_test() {
|
||||
char* actual_location = os::reserve_memory_special(expected_allocation_size, os::large_page_size(), expected_location, false);
|
||||
if (actual_location == NULL) {
|
||||
if (VerboseInternalVMTests) {
|
||||
gclog_or_tty->print("Failed to allocate any memory at "PTR_FORMAT" size "SIZE_FORMAT". Skipping remainder of test.",
|
||||
gclog_or_tty->print("Failed to allocate any memory at " PTR_FORMAT " size " SIZE_FORMAT ". Skipping remainder of test.",
|
||||
expected_location, large_allocation_size);
|
||||
}
|
||||
} else {
|
||||
@ -5911,7 +5936,7 @@ void TestReserveMemorySpecial_test() {
|
||||
os::release_memory_special(actual_location, expected_allocation_size);
|
||||
// only now check, after releasing any memory to avoid any leaks.
|
||||
assert(actual_location == expected_location,
|
||||
err_msg("Failed to allocate memory at requested location "PTR_FORMAT" of size "SIZE_FORMAT", is "PTR_FORMAT" instead",
|
||||
err_msg("Failed to allocate memory at requested location " PTR_FORMAT " of size " SIZE_FORMAT ", is " PTR_FORMAT " instead",
|
||||
expected_location, expected_allocation_size, actual_location));
|
||||
}
|
||||
}
|
||||
|
50
hotspot/src/os/windows/vm/semaphore_windows.hpp
Normal file
50
hotspot/src/os/windows/vm/semaphore_windows.hpp
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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 OS_WINDOWS_VM_SEMAPHORE_WINDOWS_HPP
|
||||
#define OS_WINDOWS_VM_SEMAPHORE_WINDOWS_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
#include <windef.h>
|
||||
|
||||
class WindowsSemaphore : public CHeapObj<mtInternal> {
|
||||
HANDLE _semaphore;
|
||||
|
||||
// Prevent copying and assignment.
|
||||
WindowsSemaphore(const WindowsSemaphore&);
|
||||
WindowsSemaphore& operator=(const WindowsSemaphore&);
|
||||
|
||||
public:
|
||||
WindowsSemaphore(uint value = 0);
|
||||
~WindowsSemaphore();
|
||||
|
||||
void signal(uint count = 1);
|
||||
|
||||
void wait();
|
||||
};
|
||||
|
||||
typedef WindowsSemaphore SemaphoreImpl;
|
||||
|
||||
#endif // OS_WINDOWS_VM_SEMAPHORE_WINDOWS_HPP
|
@ -191,7 +191,7 @@ public:
|
||||
return CPUVisitor::visit(nodeh, state);
|
||||
}
|
||||
|
||||
PICL(bool is_fujitsu) : _L1_data_cache_line_size(0), _L2_data_cache_line_size(0), _dl_handle(NULL) {
|
||||
PICL(bool is_fujitsu, bool is_sun4v) : _L1_data_cache_line_size(0), _L2_data_cache_line_size(0), _dl_handle(NULL) {
|
||||
if (!open_library()) {
|
||||
return;
|
||||
}
|
||||
@ -203,7 +203,7 @@ public:
|
||||
if (is_fujitsu) {
|
||||
cpu_class = "core";
|
||||
}
|
||||
CPUVisitor cpu_visitor(this, os::processor_count());
|
||||
CPUVisitor cpu_visitor(this, (is_sun4v && !is_fujitsu) ? 1 : os::processor_count());
|
||||
_picl_walk_tree_by_class(rooth, cpu_class, &cpu_visitor, PICL_visit_cpu_helper);
|
||||
if (cpu_visitor.l1_visitor()->is_assigned()) { // Is there a value?
|
||||
_L1_data_cache_line_size = cpu_visitor.l1_visitor()->value();
|
||||
@ -447,7 +447,7 @@ int VM_Version::platform_features(int features) {
|
||||
}
|
||||
|
||||
// Figure out cache line sizes using PICL
|
||||
PICL picl((features & sparc64_family_m) != 0);
|
||||
PICL picl((features & sparc64_family_m) != 0, (features & sun4v_m) != 0);
|
||||
_L1_data_cache_line_size = picl.L1_data_cache_line_size();
|
||||
_L2_data_cache_line_size = picl.L2_data_cache_line_size();
|
||||
|
||||
|
@ -70,7 +70,8 @@ CONFIGURE_ARGS= --host=$(MINGW) --target=$(MINGW)
|
||||
else #linux
|
||||
CPU = $(shell uname -m)
|
||||
ARCH1=$(CPU:x86_64=amd64)
|
||||
ARCH=$(ARCH1:i686=i386)
|
||||
ARCH2=$(ARCH1:i686=i386)
|
||||
ARCH=$(ARCH2:ppc64le=ppc64)
|
||||
ifdef LP64
|
||||
CFLAGS/sparcv9 += -m64
|
||||
CFLAGS/amd64 += -m64
|
||||
|
@ -1093,9 +1093,11 @@ void CodeStrings::add_comment(intptr_t offset, const char * comment) {
|
||||
|
||||
void CodeStrings::assign(CodeStrings& other) {
|
||||
other.check_valid();
|
||||
// Cannot do following because CodeStrings constructor is not alway run!
|
||||
assert(is_null(), "Cannot assign onto non-empty CodeStrings");
|
||||
_strings = other._strings;
|
||||
#ifdef ASSERT
|
||||
_defunct = false;
|
||||
#endif
|
||||
other.set_null_and_invalidate();
|
||||
}
|
||||
|
||||
@ -1115,13 +1117,15 @@ void CodeStrings::copy(CodeStrings& other) {
|
||||
}
|
||||
}
|
||||
|
||||
const char* CodeStrings::_prefix = " ;; "; // default: can be changed via set_prefix
|
||||
|
||||
void CodeStrings::print_block_comment(outputStream* stream, intptr_t offset) const {
|
||||
check_valid();
|
||||
if (_strings != NULL) {
|
||||
CodeString* c = find(offset);
|
||||
while (c && c->offset() == offset) {
|
||||
stream->bol();
|
||||
stream->print(" ;; ");
|
||||
stream->print("%s", _prefix);
|
||||
stream->print_cr("%s", c->string());
|
||||
c = c->next_comment();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2015, 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
|
||||
@ -249,6 +249,7 @@ private:
|
||||
// Becomes true after copy-out, forbids further use.
|
||||
bool _defunct; // Zero bit pattern is "valid", see memset call in decode_env::decode_env
|
||||
#endif
|
||||
static const char* _prefix; // defaults to " ;; "
|
||||
#endif
|
||||
|
||||
CodeString* find(intptr_t offset) const;
|
||||
@ -289,11 +290,18 @@ public:
|
||||
void assign(CodeStrings& other) PRODUCT_RETURN;
|
||||
// COPY strings from other to this; leave other valid.
|
||||
void copy(CodeStrings& other) PRODUCT_RETURN;
|
||||
// FREE strings; invalidate this.
|
||||
void free() PRODUCT_RETURN;
|
||||
// Guarantee that _strings are used at most once; assign invalidates a buffer.
|
||||
// Guarantee that _strings are used at most once; assign and free invalidate a buffer.
|
||||
inline void check_valid() const {
|
||||
#ifdef ASSERT
|
||||
assert(!_defunct, "Use of invalid CodeStrings");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void set_prefix(const char *prefix) {
|
||||
#ifndef PRODUCT
|
||||
_prefix = prefix;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
@ -379,6 +387,7 @@ class CodeBuffer: public StackObj {
|
||||
_oop_recorder = NULL;
|
||||
_decode_begin = NULL;
|
||||
_overflow_arena = NULL;
|
||||
_code_strings = CodeStrings();
|
||||
}
|
||||
|
||||
void initialize(address code_start, csize_t code_size) {
|
||||
@ -495,6 +504,7 @@ class CodeBuffer: public StackObj {
|
||||
|
||||
// Properties
|
||||
const char* name() const { return _name; }
|
||||
void set_name(const char* name) { _name = name; }
|
||||
CodeBuffer* before_expand() const { return _before_expand; }
|
||||
BufferBlob* blob() const { return _blob; }
|
||||
void set_blob(BufferBlob* blob);
|
||||
|
@ -161,7 +161,7 @@ void CFGPrinterOutput::print_compilation() {
|
||||
|
||||
print("name \"%s\"", method_name(_compilation->method(), true));
|
||||
print("method \"%s\"", method_name(_compilation->method()));
|
||||
print("date "INT64_FORMAT, (int64_t) os::javaTimeMillis());
|
||||
print("date " INT64_FORMAT, (int64_t) os::javaTimeMillis());
|
||||
|
||||
print_end("compilation");
|
||||
}
|
||||
|
@ -3157,6 +3157,9 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope)
|
||||
// code for the inlined version will be different than the root
|
||||
// compiled version which could lead to monotonicity problems on
|
||||
// intel.
|
||||
if (CheckIntrinsics && !scope->method()->intrinsic_candidate()) {
|
||||
BAILOUT("failed to inline intrinsic, method not annotated");
|
||||
}
|
||||
|
||||
// Set up a stream so that appending instructions works properly.
|
||||
ciBytecodeStream s(scope->method());
|
||||
@ -3197,6 +3200,9 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope)
|
||||
// result in the referent being marked live and the reference
|
||||
// object removed from the list of discovered references during
|
||||
// reference processing.
|
||||
if (CheckIntrinsics && !scope->method()->intrinsic_candidate()) {
|
||||
BAILOUT("failed to inline intrinsic, method not annotated");
|
||||
}
|
||||
|
||||
// Also we need intrinsic to prevent commoning reads from this field
|
||||
// across safepoint since GC can change its value.
|
||||
@ -3317,7 +3323,8 @@ bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, Bytecodes::Co
|
||||
}
|
||||
|
||||
// handle intrinsics
|
||||
if (callee->intrinsic_id() != vmIntrinsics::_none) {
|
||||
if (callee->intrinsic_id() != vmIntrinsics::_none &&
|
||||
(CheckIntrinsics ? callee->intrinsic_candidate() : true)) {
|
||||
if (try_inline_intrinsics(callee)) {
|
||||
print_inlining(callee, "intrinsic");
|
||||
return true;
|
||||
@ -4278,7 +4285,7 @@ void GraphBuilder::append_unsafe_CAS(ciMethod* callee) {
|
||||
assert(result_type->is_int(), "int result");
|
||||
Values* args = state()->pop_arguments(callee->arg_size());
|
||||
|
||||
// Pop off some args to speically handle, then push back
|
||||
// Pop off some args to specially handle, then push back
|
||||
Value newval = args->pop();
|
||||
Value cmpval = args->pop();
|
||||
Value offset = args->pop();
|
||||
|
@ -2208,7 +2208,15 @@ void LIRGenerator::do_UnsafePutRaw(UnsafePutRaw* x) {
|
||||
if (log2_scale != 0) {
|
||||
// temporary fix (platform dependent code without shift on Intel would be better)
|
||||
// TODO: ARM also allows embedded shift in the address
|
||||
__ shift_left(index_op, log2_scale, index_op);
|
||||
LIR_Opr tmp = new_pointer_register();
|
||||
if (TwoOperandLIRForm) {
|
||||
__ move(index_op, tmp);
|
||||
index_op = tmp;
|
||||
}
|
||||
__ shift_left(index_op, log2_scale, tmp);
|
||||
if (!TwoOperandLIRForm) {
|
||||
index_op = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
LIR_Address* addr = new LIR_Address(base_op, index_op, x->basic_type());
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "classfile/vmSymbols.hpp"
|
||||
#include "code/codeBlob.hpp"
|
||||
#include "code/codeCacheExtensions.hpp"
|
||||
#include "code/compiledIC.hpp"
|
||||
#include "code/pcDesc.hpp"
|
||||
#include "code/scopeDesc.hpp"
|
||||
@ -183,20 +184,25 @@ void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) {
|
||||
// create code buffer for code storage
|
||||
CodeBuffer code(buffer_blob);
|
||||
|
||||
Compilation::setup_code_buffer(&code, 0);
|
||||
|
||||
// create assembler for code generation
|
||||
StubAssembler* sasm = new StubAssembler(&code, name_for(id), id);
|
||||
// generate code for runtime stub
|
||||
OopMapSet* oop_maps;
|
||||
oop_maps = generate_code_for(id, sasm);
|
||||
assert(oop_maps == NULL || sasm->frame_size() != no_frame_size,
|
||||
"if stub has an oop map it must have a valid frame size");
|
||||
int frame_size;
|
||||
bool must_gc_arguments;
|
||||
|
||||
if (!CodeCacheExtensions::skip_compiler_support()) {
|
||||
// bypass useless code generation
|
||||
Compilation::setup_code_buffer(&code, 0);
|
||||
|
||||
// create assembler for code generation
|
||||
StubAssembler* sasm = new StubAssembler(&code, name_for(id), id);
|
||||
// generate code for runtime stub
|
||||
oop_maps = generate_code_for(id, sasm);
|
||||
assert(oop_maps == NULL || sasm->frame_size() != no_frame_size,
|
||||
"if stub has an oop map it must have a valid frame size");
|
||||
|
||||
#ifdef ASSERT
|
||||
// Make sure that stubs that need oopmaps have them
|
||||
switch (id) {
|
||||
// These stubs don't need to have an oopmap
|
||||
// Make sure that stubs that need oopmaps have them
|
||||
switch (id) {
|
||||
// These stubs don't need to have an oopmap
|
||||
case dtrace_object_alloc_id:
|
||||
case g1_pre_barrier_slow_id:
|
||||
case g1_post_barrier_slow_id:
|
||||
@ -209,23 +215,32 @@ void Runtime1::generate_blob_for(BufferBlob* buffer_blob, StubID id) {
|
||||
#endif
|
||||
break;
|
||||
|
||||
// All other stubs should have oopmaps
|
||||
// All other stubs should have oopmaps
|
||||
default:
|
||||
assert(oop_maps != NULL, "must have an oopmap");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// align so printing shows nop's instead of random code at the end (SimpleStubs are aligned)
|
||||
sasm->align(BytesPerWord);
|
||||
// make sure all code is in code buffer
|
||||
sasm->flush();
|
||||
// align so printing shows nop's instead of random code at the end (SimpleStubs are aligned)
|
||||
sasm->align(BytesPerWord);
|
||||
// make sure all code is in code buffer
|
||||
sasm->flush();
|
||||
|
||||
frame_size = sasm->frame_size();
|
||||
must_gc_arguments = sasm->must_gc_arguments();
|
||||
} else {
|
||||
/* ignored values */
|
||||
oop_maps = NULL;
|
||||
frame_size = 0;
|
||||
must_gc_arguments = false;
|
||||
}
|
||||
// create blob - distinguish a few special cases
|
||||
CodeBlob* blob = RuntimeStub::new_runtime_stub(name_for(id),
|
||||
&code,
|
||||
CodeOffsets::frame_never_safe,
|
||||
sasm->frame_size(),
|
||||
frame_size,
|
||||
oop_maps,
|
||||
sasm->must_gc_arguments());
|
||||
must_gc_arguments);
|
||||
// install blob
|
||||
assert(blob != NULL, "blob must exist");
|
||||
_blobs[id] = blob;
|
||||
@ -399,7 +414,7 @@ static nmethod* counter_overflow_helper(JavaThread* THREAD, int branch_bci, Meth
|
||||
CompLevel level = (CompLevel)nm->comp_level();
|
||||
int bci = InvocationEntryBci;
|
||||
if (branch_bci != InvocationEntryBci) {
|
||||
// Compute desination bci
|
||||
// Compute destination bci
|
||||
address pc = method()->code_base() + branch_bci;
|
||||
Bytecodes::Code branch = Bytecodes::code_at(method(), pc);
|
||||
int offset = 0;
|
||||
|
@ -1185,7 +1185,6 @@ vmIntrinsics::ID BCEscapeAnalyzer::known_intrinsic() {
|
||||
vmIntrinsics::ID iid = method()->intrinsic_id();
|
||||
|
||||
if (iid == vmIntrinsics::_getClass ||
|
||||
iid == vmIntrinsics::_fillInStackTrace ||
|
||||
iid == vmIntrinsics::_hashCode)
|
||||
return iid;
|
||||
else
|
||||
@ -1199,10 +1198,6 @@ bool BCEscapeAnalyzer::compute_escape_for_intrinsic(vmIntrinsics::ID iid) {
|
||||
case vmIntrinsics::_getClass:
|
||||
_return_local = false;
|
||||
break;
|
||||
case vmIntrinsics::_fillInStackTrace:
|
||||
arg.set(0); // 'this'
|
||||
set_returned(arg);
|
||||
break;
|
||||
case vmIntrinsics::_hashCode:
|
||||
// initialized state is correct
|
||||
break;
|
||||
|
@ -178,9 +178,10 @@ class ciMethod : public ciMetadata {
|
||||
// Code size for inlining decisions.
|
||||
int code_size_for_inlining();
|
||||
|
||||
bool caller_sensitive() const { return get_Method()->caller_sensitive(); }
|
||||
bool force_inline() const { return get_Method()->force_inline(); }
|
||||
bool dont_inline() const { return get_Method()->dont_inline(); }
|
||||
bool caller_sensitive() const { return get_Method()->caller_sensitive(); }
|
||||
bool force_inline() const { return get_Method()->force_inline(); }
|
||||
bool dont_inline() const { return get_Method()->dont_inline(); }
|
||||
bool intrinsic_candidate() const { return get_Method()->intrinsic_candidate(); }
|
||||
|
||||
int comp_level();
|
||||
int highest_osr_comp_level();
|
||||
|
@ -1751,6 +1751,10 @@ ClassFileParser::AnnotationCollector::annotation_index(ClassLoaderData* loader_d
|
||||
if (_location != _in_method) break; // only allow for methods
|
||||
if (!privileged) break; // only allow in privileged code
|
||||
return _method_LambdaForm_Hidden;
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_HotSpotIntrinsicCandidate_signature):
|
||||
if (_location != _in_method) break; // only allow for methods
|
||||
if (!privileged) break; // only allow in privileged code
|
||||
return _method_HotSpotIntrinsicCandidate;
|
||||
case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_Stable_signature):
|
||||
if (_location != _in_field) break; // only allow for fields
|
||||
if (!privileged) break; // only allow in privileged code
|
||||
@ -1790,6 +1794,8 @@ void ClassFileParser::MethodAnnotationCollector::apply_to(methodHandle m) {
|
||||
m->set_intrinsic_id(vmIntrinsics::_compiledLambdaForm);
|
||||
if (has_annotation(_method_LambdaForm_Hidden))
|
||||
m->set_hidden(true);
|
||||
if (has_annotation(_method_HotSpotIntrinsicCandidate) && !m->is_synthetic())
|
||||
m->set_intrinsic_candidate(true);
|
||||
}
|
||||
|
||||
void ClassFileParser::ClassAnnotationCollector::apply_to(instanceKlassHandle k) {
|
||||
@ -4132,9 +4138,78 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
|
||||
// (We used to do this lazily, but now we query it in Rewriter,
|
||||
// which is eagerly done for every method, so we might as well do it now,
|
||||
// when everything is fresh in memory.)
|
||||
if (Method::klass_id_for_intrinsics(this_klass()) != vmSymbols::NO_SID) {
|
||||
vmSymbols::SID klass_id = Method::klass_id_for_intrinsics(this_klass());
|
||||
if (klass_id != vmSymbols::NO_SID) {
|
||||
for (int j = 0; j < methods->length(); j++) {
|
||||
methods->at(j)->init_intrinsic_id();
|
||||
Method* method = methods->at(j);
|
||||
method->init_intrinsic_id();
|
||||
|
||||
if (CheckIntrinsics) {
|
||||
// Check if an intrinsic is defined for method 'method',
|
||||
// but the method is not annotated with @HotSpotIntrinsicCandidate.
|
||||
if (method->intrinsic_id() != vmIntrinsics::_none &&
|
||||
!method->intrinsic_candidate()) {
|
||||
tty->print("Compiler intrinsic is defined for method [%s], "
|
||||
"but the method is not annotated with @HotSpotIntrinsicCandidate.%s",
|
||||
method->name_and_sig_as_C_string(),
|
||||
NOT_DEBUG(" Method will not be inlined.") DEBUG_ONLY(" Exiting.")
|
||||
);
|
||||
tty->cr();
|
||||
DEBUG_ONLY(vm_exit(1));
|
||||
}
|
||||
// Check is the method 'method' is annotated with @HotSpotIntrinsicCandidate,
|
||||
// but there is no intrinsic available for it.
|
||||
if (method->intrinsic_candidate() &&
|
||||
method->intrinsic_id() == vmIntrinsics::_none) {
|
||||
tty->print("Method [%s] is annotated with @HotSpotIntrinsicCandidate, "
|
||||
"but no compiler intrinsic is defined for the method.%s",
|
||||
method->name_and_sig_as_C_string(),
|
||||
NOT_DEBUG("") DEBUG_ONLY(" Exiting.")
|
||||
);
|
||||
tty->cr();
|
||||
DEBUG_ONLY(vm_exit(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CheckIntrinsics) {
|
||||
// Check for orphan methods in the current class. A method m
|
||||
// of a class C is orphan if an intrinsic is defined for method m,
|
||||
// but class C does not declare m.
|
||||
|
||||
for (int id = vmIntrinsics::FIRST_ID; id < (int)vmIntrinsics::ID_LIMIT; id++) {
|
||||
if (id == vmIntrinsics::_compiledLambdaForm) {
|
||||
// The _compiledLamdbdaForm intrinsic is a special marker for bytecode
|
||||
// generated for the JVM from a LambdaForm and therefore no method
|
||||
// is defined for it.
|
||||
continue;
|
||||
}
|
||||
|
||||
if (vmIntrinsics::class_for(vmIntrinsics::ID_from(id)) == klass_id) {
|
||||
// Check if the current class contains a method with the same
|
||||
// name, flags, signature.
|
||||
bool match = false;
|
||||
for (int j = 0; j < methods->length(); j++) {
|
||||
Method* method = methods->at(j);
|
||||
if (id == method->intrinsic_id()) {
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!match) {
|
||||
char buf[1000];
|
||||
tty->print("Compiler intrinsic is defined for method [%s], "
|
||||
"but the method is not available in class [%s].%s",
|
||||
vmIntrinsics::short_name_as_C_string(vmIntrinsics::ID_from(id), buf, sizeof(buf)),
|
||||
this_klass->name()->as_C_string(),
|
||||
NOT_DEBUG("") DEBUG_ONLY(" Exiting.")
|
||||
);
|
||||
tty->cr();
|
||||
DEBUG_ONLY(vm_exit(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -130,6 +130,7 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
_method_InjectedProfile,
|
||||
_method_LambdaForm_Compiled,
|
||||
_method_LambdaForm_Hidden,
|
||||
_method_HotSpotIntrinsicCandidate,
|
||||
_sun_misc_Contended,
|
||||
_field_Stable,
|
||||
_annotation_LIMIT
|
||||
|
@ -68,7 +68,6 @@
|
||||
#include "classfile/sharedPathsMiscInfo.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
// Entry points in zip.dll for loading zip/jar file entries and image file entries
|
||||
|
||||
typedef void * * (JNICALL *ZipOpen_t)(const char *name, char **pmsg);
|
||||
@ -157,17 +156,12 @@ ClassPathEntry::ClassPathEntry() {
|
||||
}
|
||||
|
||||
|
||||
bool ClassPathEntry::is_lazy() {
|
||||
return false;
|
||||
}
|
||||
|
||||
ClassPathDirEntry::ClassPathDirEntry(const char* dir) : ClassPathEntry() {
|
||||
char* copy = NEW_C_HEAP_ARRAY(char, strlen(dir)+1, mtClass);
|
||||
strcpy(copy, dir);
|
||||
_dir = copy;
|
||||
}
|
||||
|
||||
|
||||
ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) {
|
||||
// construct full path name
|
||||
char path[JVM_MAXPATHLEN];
|
||||
@ -278,90 +272,25 @@ void ClassPathZipEntry::contents_do(void f(const char* name, void* context), voi
|
||||
}
|
||||
}
|
||||
|
||||
LazyClassPathEntry::LazyClassPathEntry(const char* path, const struct stat* st, bool throw_exception) : ClassPathEntry() {
|
||||
_path = os::strdup_check_oom(path);
|
||||
_st = *st;
|
||||
_resolved_entry = NULL;
|
||||
_has_error = false;
|
||||
_throw_exception = throw_exception;
|
||||
}
|
||||
ClassPathImageEntry::ClassPathImageEntry(ImageFileReader* image) :
|
||||
ClassPathEntry(),
|
||||
_image(image),
|
||||
_module_data(NULL) {
|
||||
guarantee(image != NULL, "image file is null");
|
||||
|
||||
LazyClassPathEntry::~LazyClassPathEntry() {
|
||||
os::free((void*)_path);
|
||||
}
|
||||
|
||||
bool LazyClassPathEntry::is_jar_file() {
|
||||
size_t len = strlen(_path);
|
||||
if (len < 4 || strcmp(_path + len - 4, ".jar") != 0) return false;
|
||||
return ((_st.st_mode & S_IFREG) == S_IFREG);
|
||||
}
|
||||
|
||||
ClassPathEntry* LazyClassPathEntry::resolve_entry(TRAPS) {
|
||||
if (_resolved_entry != NULL) {
|
||||
return (ClassPathEntry*) _resolved_entry;
|
||||
}
|
||||
ClassPathEntry* new_entry = NULL;
|
||||
new_entry = ClassLoader::create_class_path_entry(_path, &_st, false, _throw_exception, CHECK_NULL);
|
||||
if (!_throw_exception && new_entry == NULL) {
|
||||
assert(!HAS_PENDING_EXCEPTION, "must be");
|
||||
return NULL;
|
||||
}
|
||||
{
|
||||
ThreadCritical tc;
|
||||
if (_resolved_entry == NULL) {
|
||||
_resolved_entry = new_entry;
|
||||
return new_entry;
|
||||
}
|
||||
}
|
||||
assert(_resolved_entry != NULL, "bug in MT-safe resolution logic");
|
||||
delete new_entry;
|
||||
return (ClassPathEntry*) _resolved_entry;
|
||||
}
|
||||
|
||||
ClassFileStream* LazyClassPathEntry::open_stream(const char* name, TRAPS) {
|
||||
if (_has_error) {
|
||||
return NULL;
|
||||
}
|
||||
ClassPathEntry* cpe = resolve_entry(THREAD);
|
||||
if (cpe == NULL) {
|
||||
_has_error = true;
|
||||
return NULL;
|
||||
} else {
|
||||
return cpe->open_stream(name, THREAD);
|
||||
}
|
||||
}
|
||||
|
||||
bool LazyClassPathEntry::is_lazy() {
|
||||
return true;
|
||||
}
|
||||
|
||||
u1* LazyClassPathEntry::open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS) {
|
||||
if (_has_error) {
|
||||
return NULL;
|
||||
}
|
||||
ClassPathEntry* cpe = resolve_entry(THREAD);
|
||||
if (cpe == NULL) {
|
||||
_has_error = true;
|
||||
return NULL;
|
||||
} else if (cpe->is_jar_file()) {
|
||||
return ((ClassPathZipEntry*)cpe)->open_entry(name, filesize, nul_terminate,THREAD);
|
||||
} else {
|
||||
ShouldNotReachHere();
|
||||
*filesize = 0;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ClassPathImageEntry::ClassPathImageEntry(char* name) : ClassPathEntry(), _image(new ImageFile(name)) {
|
||||
bool opened = _image->open();
|
||||
if (!opened) {
|
||||
_image = NULL;
|
||||
}
|
||||
char module_data_name[JVM_MAXPATHLEN];
|
||||
ImageModuleData::module_data_name(module_data_name, _image->name());
|
||||
_module_data = new ImageModuleData(_image, module_data_name);
|
||||
}
|
||||
|
||||
ClassPathImageEntry::~ClassPathImageEntry() {
|
||||
if (_image) {
|
||||
_image->close();
|
||||
if (_module_data != NULL) {
|
||||
delete _module_data;
|
||||
_module_data = NULL;
|
||||
}
|
||||
|
||||
if (_image != NULL) {
|
||||
ImageFileReader::close(_image);
|
||||
_image = NULL;
|
||||
}
|
||||
}
|
||||
@ -371,15 +300,39 @@ const char* ClassPathImageEntry::name() {
|
||||
}
|
||||
|
||||
ClassFileStream* ClassPathImageEntry::open_stream(const char* name, TRAPS) {
|
||||
u1* buffer;
|
||||
u8 size;
|
||||
_image->get_resource(name, buffer, size);
|
||||
ImageLocation location;
|
||||
bool found = _image->find_location(name, location);
|
||||
|
||||
if (buffer) {
|
||||
if (!found) {
|
||||
const char *pslash = strrchr(name, '/');
|
||||
int len = pslash - name;
|
||||
|
||||
// NOTE: IMAGE_MAX_PATH is used here since this path is internal to the jimage
|
||||
// (effectively unlimited.) There are several JCK tests that use paths over
|
||||
// 1024 characters long, the limit on Windows systems.
|
||||
if (pslash && 0 < len && len < IMAGE_MAX_PATH) {
|
||||
|
||||
char path[IMAGE_MAX_PATH];
|
||||
strncpy(path, name, len);
|
||||
path[len] = '\0';
|
||||
const char* moduleName = _module_data->package_to_module(path);
|
||||
|
||||
if (moduleName != NULL && (len + strlen(moduleName) + 2) < IMAGE_MAX_PATH) {
|
||||
jio_snprintf(path, IMAGE_MAX_PATH - 1, "/%s/%s", moduleName, name);
|
||||
location.clear_data();
|
||||
found = _image->find_location(path, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found) {
|
||||
u8 size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
|
||||
if (UsePerfData) {
|
||||
ClassLoader::perf_sys_classfile_bytes_read()->inc(size);
|
||||
}
|
||||
return new ClassFileStream(buffer, (int)size, (char*)name); // Resource allocated
|
||||
u1* data = NEW_RESOURCE_ARRAY(u1, size);
|
||||
_image->get_resource(location, data);
|
||||
return new ClassFileStream(data, (int)size, _image->name()); // Resource allocated
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@ -391,20 +344,14 @@ void ClassPathImageEntry::compile_the_world(Handle loader, TRAPS) {
|
||||
tty->cr();
|
||||
const ImageStrings strings = _image->get_strings();
|
||||
// Retrieve each path component string.
|
||||
u4 count = _image->get_location_count();
|
||||
for (u4 i = 0; i < count; i++) {
|
||||
u4 length = _image->table_length();
|
||||
for (u4 i = 0; i < length; i++) {
|
||||
u1* location_data = _image->get_location_data(i);
|
||||
|
||||
if (location_data) {
|
||||
if (location_data != NULL) {
|
||||
ImageLocation location(location_data);
|
||||
const char* parent = location.get_attribute(ImageLocation::ATTRIBUTE_PARENT, strings);
|
||||
const char* base = location.get_attribute(ImageLocation::ATTRIBUTE_BASE, strings);
|
||||
const char* extension = location.get_attribute(ImageLocation::ATTRIBUTE_EXTENSION, strings);
|
||||
assert((strlen(parent) + strlen(base) + strlen(extension)) < JVM_MAXPATHLEN, "path exceeds buffer");
|
||||
char path[JVM_MAXPATHLEN];
|
||||
strcpy(path, parent);
|
||||
strcat(path, base);
|
||||
strcat(path, extension);
|
||||
char path[IMAGE_MAX_PATH];
|
||||
_image->location_path(location, path, IMAGE_MAX_PATH);
|
||||
ClassLoader::compile_the_world_in(path, loader, CHECK);
|
||||
}
|
||||
}
|
||||
@ -420,7 +367,7 @@ void ClassPathImageEntry::compile_the_world(Handle loader, TRAPS) {
|
||||
}
|
||||
|
||||
bool ClassPathImageEntry::is_jrt() {
|
||||
return string_ends_with(name(), "bootmodules.jimage");
|
||||
return string_ends_with(name(), BOOT_IMAGE_NAME);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -539,11 +486,8 @@ void ClassLoader::setup_search_path(const char *class_path) {
|
||||
}
|
||||
|
||||
ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const struct stat* st,
|
||||
bool lazy, bool throw_exception, TRAPS) {
|
||||
bool throw_exception, TRAPS) {
|
||||
JavaThread* thread = JavaThread::current();
|
||||
if (lazy) {
|
||||
return new LazyClassPathEntry(path, st, throw_exception);
|
||||
}
|
||||
ClassPathEntry* new_entry = NULL;
|
||||
if ((st->st_mode & S_IFREG) == S_IFREG) {
|
||||
// Regular file, should be a zip or image file
|
||||
@ -557,39 +501,39 @@ ClassPathEntry* ClassLoader::create_class_path_entry(const char *path, const str
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
// TODO - add proper criteria for selecting image file
|
||||
ClassPathImageEntry* entry = new ClassPathImageEntry(canonical_path);
|
||||
if (entry->is_open()) {
|
||||
new_entry = entry;
|
||||
ImageFileReader* image = ImageFileReader::open(canonical_path);
|
||||
if (image != NULL) {
|
||||
new_entry = new ClassPathImageEntry(image);
|
||||
} else {
|
||||
char* error_msg = NULL;
|
||||
jzfile* zip;
|
||||
{
|
||||
// enable call to C land
|
||||
ThreadToNativeFromVM ttn(thread);
|
||||
HandleMark hm(thread);
|
||||
zip = (*ZipOpen)(canonical_path, &error_msg);
|
||||
}
|
||||
if (zip != NULL && error_msg == NULL) {
|
||||
new_entry = new ClassPathZipEntry(zip, path);
|
||||
} else {
|
||||
ResourceMark rm(thread);
|
||||
char *msg;
|
||||
if (error_msg == NULL) {
|
||||
msg = NEW_RESOURCE_ARRAY(char, strlen(path) + 128); ;
|
||||
jio_snprintf(msg, strlen(path) + 127, "error in opening JAR file %s", path);
|
||||
} else {
|
||||
int len = (int)(strlen(path) + strlen(error_msg) + 128);
|
||||
msg = NEW_RESOURCE_ARRAY(char, len); ;
|
||||
jio_snprintf(msg, len - 1, "error in opening JAR file <%s> %s", error_msg, path);
|
||||
char* error_msg = NULL;
|
||||
jzfile* zip;
|
||||
{
|
||||
// enable call to C land
|
||||
ThreadToNativeFromVM ttn(thread);
|
||||
HandleMark hm(thread);
|
||||
zip = (*ZipOpen)(canonical_path, &error_msg);
|
||||
}
|
||||
if (throw_exception) {
|
||||
THROW_MSG_(vmSymbols::java_lang_ClassNotFoundException(), msg, NULL);
|
||||
if (zip != NULL && error_msg == NULL) {
|
||||
new_entry = new ClassPathZipEntry(zip, path);
|
||||
} else {
|
||||
return NULL;
|
||||
ResourceMark rm(thread);
|
||||
char *msg;
|
||||
if (error_msg == NULL) {
|
||||
msg = NEW_RESOURCE_ARRAY(char, strlen(path) + 128); ;
|
||||
jio_snprintf(msg, strlen(path) + 127, "error in opening JAR file %s", path);
|
||||
} else {
|
||||
int len = (int)(strlen(path) + strlen(error_msg) + 128);
|
||||
msg = NEW_RESOURCE_ARRAY(char, len); ;
|
||||
jio_snprintf(msg, len - 1, "error in opening JAR file <%s> %s", error_msg, path);
|
||||
}
|
||||
// Don't complain about bad jar files added via -Xbootclasspath/a:.
|
||||
if (throw_exception && is_init_completed()) {
|
||||
THROW_MSG_(vmSymbols::java_lang_ClassNotFoundException(), msg, NULL);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (TraceClassLoading || TraceClassPaths) {
|
||||
tty->print_cr("[Opened %s]", path);
|
||||
}
|
||||
@ -666,7 +610,7 @@ bool ClassLoader::update_class_path_entry_list(const char *path,
|
||||
// File or directory found
|
||||
ClassPathEntry* new_entry = NULL;
|
||||
Thread* THREAD = Thread::current();
|
||||
new_entry = create_class_path_entry(path, &st, LazyBootClassLoader, throw_exception, CHECK_(false));
|
||||
new_entry = create_class_path_entry(path, &st, throw_exception, CHECK_(false));
|
||||
if (new_entry == NULL) {
|
||||
return false;
|
||||
}
|
||||
@ -1319,19 +1263,6 @@ bool ClassPathZipEntry::is_jrt() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void LazyClassPathEntry::compile_the_world(Handle loader, TRAPS) {
|
||||
ClassPathEntry* cpe = resolve_entry(THREAD);
|
||||
if (cpe != NULL) {
|
||||
cpe->compile_the_world(loader, CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
bool LazyClassPathEntry::is_jrt() {
|
||||
Thread* THREAD = Thread::current();
|
||||
ClassPathEntry* cpe = resolve_entry(THREAD);
|
||||
return (cpe != NULL) ? cpe->is_jar_file() : false;
|
||||
}
|
||||
|
||||
void ClassLoader::compile_the_world() {
|
||||
EXCEPTION_MARK;
|
||||
HandleMark hm(THREAD);
|
||||
|
@ -32,9 +32,14 @@
|
||||
// The VM class loader.
|
||||
#include <sys/stat.h>
|
||||
|
||||
// Name of boot module image
|
||||
#define BOOT_IMAGE_NAME "bootmodules.jimage"
|
||||
|
||||
// Class path entry (directory or zip file)
|
||||
|
||||
class ImageFileReader;
|
||||
class ImageModuleData;
|
||||
|
||||
class ClassPathEntry: public CHeapObj<mtClass> {
|
||||
private:
|
||||
ClassPathEntry* _next;
|
||||
@ -47,7 +52,7 @@ class ClassPathEntry: public CHeapObj<mtClass> {
|
||||
}
|
||||
virtual bool is_jar_file() = 0;
|
||||
virtual const char* name() = 0;
|
||||
virtual bool is_lazy();
|
||||
virtual ImageFileReader* image() = 0;
|
||||
// Constructor
|
||||
ClassPathEntry();
|
||||
// Attempt to locate file_name through this class path entry.
|
||||
@ -63,8 +68,9 @@ class ClassPathDirEntry: public ClassPathEntry {
|
||||
private:
|
||||
const char* _dir; // Name of directory
|
||||
public:
|
||||
bool is_jar_file() { return false; }
|
||||
const char* name() { return _dir; }
|
||||
bool is_jar_file() { return false; }
|
||||
const char* name() { return _dir; }
|
||||
ImageFileReader* image() { return NULL; }
|
||||
ClassPathDirEntry(const char* dir);
|
||||
ClassFileStream* open_stream(const char* name, TRAPS);
|
||||
// Debugging
|
||||
@ -92,8 +98,9 @@ class ClassPathZipEntry: public ClassPathEntry {
|
||||
jzfile* _zip; // The zip archive
|
||||
const char* _zip_name; // Name of zip archive
|
||||
public:
|
||||
bool is_jar_file() { return true; }
|
||||
const char* name() { return _zip_name; }
|
||||
bool is_jar_file() { return true; }
|
||||
const char* name() { return _zip_name; }
|
||||
ImageFileReader* image() { return NULL; }
|
||||
ClassPathZipEntry(jzfile* zip, const char* zip_name);
|
||||
~ClassPathZipEntry();
|
||||
u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS);
|
||||
@ -105,39 +112,18 @@ class ClassPathZipEntry: public ClassPathEntry {
|
||||
};
|
||||
|
||||
|
||||
// For lazier loading of boot class path entries
|
||||
class LazyClassPathEntry: public ClassPathEntry {
|
||||
private:
|
||||
const char* _path; // dir or file
|
||||
struct stat _st;
|
||||
bool _has_error;
|
||||
bool _throw_exception;
|
||||
volatile ClassPathEntry* _resolved_entry;
|
||||
ClassPathEntry* resolve_entry(TRAPS);
|
||||
public:
|
||||
bool is_jar_file();
|
||||
const char* name() { return _path; }
|
||||
LazyClassPathEntry(const char* path, const struct stat* st, bool throw_exception);
|
||||
virtual ~LazyClassPathEntry();
|
||||
u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS);
|
||||
|
||||
ClassFileStream* open_stream(const char* name, TRAPS);
|
||||
virtual bool is_lazy();
|
||||
// Debugging
|
||||
NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);)
|
||||
NOT_PRODUCT(bool is_jrt();)
|
||||
};
|
||||
|
||||
// For java image files
|
||||
class ImageFile;
|
||||
class ClassPathImageEntry: public ClassPathEntry {
|
||||
private:
|
||||
ImageFile *_image;
|
||||
ImageFileReader* _image;
|
||||
ImageModuleData* _module_data;
|
||||
public:
|
||||
bool is_jar_file() { return false; }
|
||||
bool is_open() { return _image != NULL; }
|
||||
const char* name();
|
||||
ClassPathImageEntry(char* name);
|
||||
ImageFileReader* image() { return _image; }
|
||||
ImageModuleData* module_data() { return _module_data; }
|
||||
ClassPathImageEntry(ImageFileReader* image);
|
||||
~ClassPathImageEntry();
|
||||
ClassFileStream* open_stream(const char* name, TRAPS);
|
||||
|
||||
@ -157,7 +143,6 @@ class ClassLoader: AllStatic {
|
||||
package_hash_table_size = 31 // Number of buckets
|
||||
};
|
||||
protected:
|
||||
friend class LazyClassPathEntry;
|
||||
|
||||
// Performance counters
|
||||
static PerfCounter* _perf_accumulated_time;
|
||||
@ -222,7 +207,7 @@ class ClassLoader: AllStatic {
|
||||
|
||||
static void load_zip_library();
|
||||
static ClassPathEntry* create_class_path_entry(const char *path, const struct stat* st,
|
||||
bool lazy, bool throw_exception, TRAPS);
|
||||
bool throw_exception, TRAPS);
|
||||
|
||||
// Canonicalizes path names, so strcmp will work properly. This is mainly
|
||||
// to avoid confusing the zip library
|
||||
|
@ -494,7 +494,7 @@ const char* ClassLoaderData::loader_name() {
|
||||
|
||||
void ClassLoaderData::dump(outputStream * const out) {
|
||||
ResourceMark rm;
|
||||
out->print("ClassLoaderData CLD: "PTR_FORMAT", loader: "PTR_FORMAT", loader_klass: "PTR_FORMAT" %s {",
|
||||
out->print("ClassLoaderData CLD: " PTR_FORMAT ", loader: " PTR_FORMAT ", loader_klass: " PTR_FORMAT " %s {",
|
||||
p2i(this), p2i((void *)class_loader()),
|
||||
p2i(class_loader() != NULL ? class_loader()->klass() : NULL), loader_name());
|
||||
if (claimed()) out->print(" claimed ");
|
||||
@ -513,7 +513,7 @@ void ClassLoaderData::dump(outputStream * const out) {
|
||||
ResourceMark rm;
|
||||
Klass* k = _klasses;
|
||||
while (k != NULL) {
|
||||
out->print_cr("klass "PTR_FORMAT", %s, CT: %d, MUT: %d", k, k->name()->as_C_string(),
|
||||
out->print_cr("klass " PTR_FORMAT ", %s, CT: %d, MUT: %d", k, k->name()->as_C_string(),
|
||||
k->has_modified_oops(), k->has_accumulated_modified_oops());
|
||||
assert(k != k->next_link(), "no loops!");
|
||||
k = k->next_link();
|
||||
|
@ -557,7 +557,7 @@ void ProtectionDomainCacheTable::print() {
|
||||
}
|
||||
|
||||
void ProtectionDomainCacheEntry::print() {
|
||||
tty->print_cr("entry "PTR_FORMAT" value "PTR_FORMAT" strongly_reachable %d next "PTR_FORMAT,
|
||||
tty->print_cr("entry " PTR_FORMAT " value " PTR_FORMAT " strongly_reachable %d next " PTR_FORMAT,
|
||||
this, (void*)literal(), _strongly_reachable, next());
|
||||
}
|
||||
#endif
|
||||
|
@ -370,7 +370,7 @@ class SymbolPropertyEntry : public HashtableEntry<Symbol*, mtSymbol> {
|
||||
|
||||
void print_on(outputStream* st) const {
|
||||
symbol()->print_value_on(st);
|
||||
st->print("/mode="INTX_FORMAT, symbol_mode());
|
||||
st->print("/mode=" INTX_FORMAT, symbol_mode());
|
||||
st->print(" -> ");
|
||||
bool printed = false;
|
||||
if (method() != NULL) {
|
||||
|
121
hotspot/src/share/vm/classfile/imageDecompressor.cpp
Normal file
121
hotspot/src/share/vm/classfile/imageDecompressor.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/imageDecompressor.hpp"
|
||||
#include "runtime/thread.hpp"
|
||||
#include "utilities/bytes.hpp"
|
||||
|
||||
/*
|
||||
* Allocate in C Heap not in resource area, otherwise JVM crashes.
|
||||
* This array life time is the VM life time. Array is never freed and
|
||||
* is not expected to contain more than few references.
|
||||
*/
|
||||
GrowableArray<ImageDecompressor*>* ImageDecompressor::_decompressors =
|
||||
new(ResourceObj::C_HEAP, mtInternal) GrowableArray<ImageDecompressor*>(2, true);
|
||||
|
||||
static Symbol* createSymbol(const char* str) {
|
||||
Thread* THREAD = Thread::current();
|
||||
Symbol* sym = SymbolTable::lookup(str, (int) strlen(str), THREAD);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
warning("can't create symbol\n");
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
return NULL;
|
||||
}
|
||||
return sym;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the array of decompressors.
|
||||
*/
|
||||
bool image_decompressor_init() {
|
||||
Symbol* zipSymbol = createSymbol("zip");
|
||||
if (zipSymbol == NULL) {
|
||||
return false;
|
||||
}
|
||||
ImageDecompressor::add_decompressor(new ZipDecompressor(zipSymbol));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decompression entry point. Called from ImageFileReader::get_resource.
|
||||
*/
|
||||
void ImageDecompressor::decompress_resource(u1* compressed, u1* uncompressed,
|
||||
u4 uncompressed_size, const ImageStrings* strings, bool is_C_heap) {
|
||||
bool has_header = false;
|
||||
u1* decompressed_resource = compressed;
|
||||
u1* compressed_resource = compressed;
|
||||
|
||||
// Resource could have been transformed by a stack of decompressors.
|
||||
// Iterate and decompress resources until there is no more header.
|
||||
do {
|
||||
ResourceHeader _header;
|
||||
memcpy(&_header, compressed_resource, sizeof (ResourceHeader));
|
||||
has_header = _header._magic == ResourceHeader::resource_header_magic;
|
||||
if (has_header) {
|
||||
// decompressed_resource array contains the result of decompression
|
||||
// when a resource content is terminal, it means that it is an actual resource,
|
||||
// not an intermediate not fully uncompressed content. In this case
|
||||
// the resource is allocated as an mtClass, otherwise as an mtOther
|
||||
decompressed_resource = is_C_heap && _header._is_terminal ?
|
||||
NEW_C_HEAP_ARRAY(u1, _header._uncompressed_size, mtClass) :
|
||||
NEW_C_HEAP_ARRAY(u1, _header._uncompressed_size, mtOther);
|
||||
// Retrieve the decompressor name
|
||||
const char* decompressor_name = strings->get(_header._decompressor_name_offset);
|
||||
if (decompressor_name == NULL) warning("image decompressor not found\n");
|
||||
guarantee(decompressor_name, "image decompressor not found");
|
||||
// Retrieve the decompressor instance
|
||||
ImageDecompressor* decompressor = get_decompressor(decompressor_name);
|
||||
if (decompressor == NULL) {
|
||||
warning("image decompressor %s not found\n", decompressor_name);
|
||||
}
|
||||
guarantee(decompressor, "image decompressor not found");
|
||||
u1* compressed_resource_base = compressed_resource;
|
||||
compressed_resource += ResourceHeader::resource_header_length;
|
||||
// Ask the decompressor to decompress the compressed content
|
||||
decompressor->decompress_resource(compressed_resource, decompressed_resource,
|
||||
&_header, strings);
|
||||
if (compressed_resource_base != compressed) {
|
||||
FREE_C_HEAP_ARRAY(char, compressed_resource_base);
|
||||
}
|
||||
compressed_resource = decompressed_resource;
|
||||
}
|
||||
} while (has_header);
|
||||
memcpy(uncompressed, decompressed_resource, uncompressed_size);
|
||||
}
|
||||
|
||||
// Zip decompressor
|
||||
|
||||
void ZipDecompressor::decompress_resource(u1* data, u1* uncompressed,
|
||||
ResourceHeader* header, const ImageStrings* strings) {
|
||||
char* msg = NULL;
|
||||
jboolean res = ClassLoader::decompress(data, header->_size, uncompressed,
|
||||
header->_uncompressed_size, &msg);
|
||||
if (!res) warning("decompression failed due to %s\n", msg);
|
||||
guarantee(res, "decompression failed");
|
||||
}
|
||||
|
||||
// END Zip Decompressor
|
137
hotspot/src/share/vm/classfile/imageDecompressor.hpp
Normal file
137
hotspot/src/share/vm/classfile/imageDecompressor.hpp
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_CLASSFILE_IMAGEDECOMPRESSOR_HPP
|
||||
#define SHARE_VM_CLASSFILE_IMAGEDECOMPRESSOR_HPP
|
||||
|
||||
#include "runtime/thread.inline.hpp"
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/classLoader.hpp"
|
||||
#include "classfile/imageFile.hpp"
|
||||
#include "classfile/symbolTable.hpp"
|
||||
#include "oops/symbol.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
|
||||
/*
|
||||
* Compressed resources located in image have an header.
|
||||
* This header contains:
|
||||
* - _magic: A magic u4, required to retrieved the header in the compressed content
|
||||
* - _size: The size of the compressed resource.
|
||||
* - _uncompressed_size: The uncompressed size of the compressed resource.
|
||||
* - _decompressor_name_offset: The ImageDecompressor instance name StringsTable offset.
|
||||
* - _decompressor_config_offset: StringsTable offset of configuration that could be needed by
|
||||
* the decompressor in order to decompress.
|
||||
* - _is_terminal: 1: the compressed content is terminal. Uncompressing it would
|
||||
* create the actual resource. 0: the compressed content is not terminal. Uncompressing it
|
||||
* will result in a compressed content to be decompressed (This occurs when a stack of compressors
|
||||
* have been used to compress the resource.
|
||||
*/
|
||||
struct ResourceHeader {
|
||||
/* Length of header, needed to retrieve content offset */
|
||||
static const u1 resource_header_length = 21;
|
||||
/* magic bytes that identifies a compressed resource header*/
|
||||
static const u4 resource_header_magic = 0xCAFEFAFA;
|
||||
u4 _magic; // Resource header
|
||||
u4 _size; // Resource size
|
||||
u4 _uncompressed_size; // Expected uncompressed size
|
||||
u4 _decompressor_name_offset; // Strings table decompressor offset
|
||||
u4 _decompressor_config_offset; // Strings table config offset
|
||||
u1 _is_terminal; // Last decompressor 1, otherwise 0.
|
||||
};
|
||||
|
||||
/*
|
||||
* Resources located in jimage file can be compressed. Compression occurs at
|
||||
* jimage file creation time. When compressed a resource is added an header that
|
||||
* contains the name of the compressor that compressed it.
|
||||
* Various compression strategies can be applied to compress a resource.
|
||||
* The same resource can even be compressed multiple time by a stack of compressors.
|
||||
* At runtime, a resource is decompressed in a loop until there is no more header
|
||||
* meaning that the resource is equivalent to the not compressed resource.
|
||||
* In each iteration, the name of the compressor located in the current header
|
||||
* is used to retrieve the associated instance of ImageDecompressor.
|
||||
* For example “zip” is the name of the compressor that compresses resources
|
||||
* using the zip algorithm. The ZipDecompressor class name is also “zip”.
|
||||
* ImageDecompressor instances are retrieved from a static array in which
|
||||
* they are registered.
|
||||
*/
|
||||
class ImageDecompressor: public CHeapObj<mtClass> {
|
||||
|
||||
private:
|
||||
const Symbol* _name;
|
||||
|
||||
/*
|
||||
* Array of concrete decompressors. This array is used to retrieve the decompressor
|
||||
* that can handle resource decompression.
|
||||
*/
|
||||
static GrowableArray<ImageDecompressor*>* _decompressors;
|
||||
|
||||
/*
|
||||
* Identifier of a decompressor. This name is the identification key to retrieve
|
||||
* decompressor from a resource header.
|
||||
*/
|
||||
inline const Symbol* get_name() const { return _name; }
|
||||
|
||||
protected:
|
||||
ImageDecompressor(const Symbol* name) : _name(name) {
|
||||
}
|
||||
virtual void decompress_resource(u1* data, u1* uncompressed,
|
||||
ResourceHeader* header, const ImageStrings* strings) = 0;
|
||||
|
||||
public:
|
||||
inline static void add_decompressor(ImageDecompressor* decompressor) {
|
||||
_decompressors->append(decompressor);
|
||||
}
|
||||
inline static ImageDecompressor* get_decompressor(const char * decompressor_name) {
|
||||
Thread* THREAD = Thread::current();
|
||||
TempNewSymbol sym = SymbolTable::new_symbol(decompressor_name,
|
||||
(int) strlen(decompressor_name), CHECK_NULL);
|
||||
if (HAS_PENDING_EXCEPTION) {
|
||||
warning("can't create symbol\n");
|
||||
CLEAR_PENDING_EXCEPTION;
|
||||
return NULL;
|
||||
}
|
||||
for (int i = 0; i < _decompressors->length(); i++) {
|
||||
ImageDecompressor* decompressor = _decompressors->at(i);
|
||||
if (decompressor->get_name()->fast_compare(sym) == 0) {
|
||||
return decompressor;
|
||||
}
|
||||
}
|
||||
guarantee(false, "No decompressor found.");
|
||||
return NULL;
|
||||
}
|
||||
static void decompress_resource(u1* compressed, u1* uncompressed,
|
||||
u4 uncompressed_size, const ImageStrings* strings, bool is_C_heap);
|
||||
};
|
||||
|
||||
/**
|
||||
* Zip decompressor.
|
||||
*/
|
||||
class ZipDecompressor : public ImageDecompressor {
|
||||
public:
|
||||
ZipDecompressor(const Symbol* sym) : ImageDecompressor(sym) { }
|
||||
void decompress_resource(u1* data, u1* uncompressed, ResourceHeader* header,
|
||||
const ImageStrings* strings);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_CLASSFILE_IMAGEDECOMPRESSOR_HPP
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 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
|
||||
@ -23,77 +23,311 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/imageDecompressor.hpp"
|
||||
#include "classfile/imageFile.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/mutex.hpp"
|
||||
#include "runtime/mutexLocker.hpp"
|
||||
#include "runtime/os.inline.hpp"
|
||||
#include "utilities/bytes.hpp"
|
||||
#include "utilities/endian.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
|
||||
// Image files are an alternate file format for storing classes and resources. The
|
||||
// goal is to supply file access which is faster and smaller than the jar format.
|
||||
//
|
||||
// (More detailed nodes in the header.)
|
||||
//
|
||||
|
||||
// Compute the Perfect Hashing hash code for the supplied string.
|
||||
u4 ImageStrings::hash_code(const char* string, u4 seed) {
|
||||
// Compute the Perfect Hashing hash code for the supplied UTF-8 string.
|
||||
s4 ImageStrings::hash_code(const char* string, s4 seed) {
|
||||
// Access bytes as unsigned.
|
||||
u1* bytes = (u1*)string;
|
||||
|
||||
// Compute hash code.
|
||||
for (u1 byte = *bytes++; byte; byte = *bytes++) {
|
||||
seed = (seed * HASH_MULTIPLIER) ^ byte;
|
||||
}
|
||||
|
||||
// Ensure the result is unsigned.
|
||||
// Ensure the result is not signed.
|
||||
return seed & 0x7FFFFFFF;
|
||||
}
|
||||
|
||||
// Test to see if string begins with start. If so returns remaining portion
|
||||
// of string. Otherwise, NULL.
|
||||
// Match up a string in a perfect hash table. Result still needs validation
|
||||
// for precise match (false positive.)
|
||||
s4 ImageStrings::find(Endian* endian, const char* name, s4* redirect, u4 length) {
|
||||
// If the table is empty, then short cut.
|
||||
if (redirect == NULL || length == 0) {
|
||||
return NOT_FOUND;
|
||||
}
|
||||
// Compute the basic perfect hash for name.
|
||||
s4 hash_code = ImageStrings::hash_code(name);
|
||||
// Modulo table size.
|
||||
s4 index = hash_code % length;
|
||||
// Get redirect entry.
|
||||
// value == 0 then not found
|
||||
// value < 0 then -1 - value is true index
|
||||
// value > 0 then value is seed for recomputing hash.
|
||||
s4 value = endian->get(redirect[index]);
|
||||
// if recompute is required.
|
||||
if (value > 0) {
|
||||
// Entry collision value, need to recompute hash.
|
||||
hash_code = ImageStrings::hash_code(name, value);
|
||||
// Modulo table size.
|
||||
return hash_code % length;
|
||||
} else if (value < 0) {
|
||||
// Compute direct index.
|
||||
return -1 - value;
|
||||
}
|
||||
// No entry found.
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
// Test to see if UTF-8 string begins with the start UTF-8 string. If so,
|
||||
// return non-NULL address of remaining portion of string. Otherwise, return
|
||||
// NULL. Used to test sections of a path without copying from image string
|
||||
// table.
|
||||
const char* ImageStrings::starts_with(const char* string, const char* start) {
|
||||
char ch1, ch2;
|
||||
|
||||
// Match up the strings the best we can.
|
||||
while ((ch1 = *string) && (ch2 = *start)) {
|
||||
if (ch1 != ch2) {
|
||||
// Mismatch, return NULL.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Next characters.
|
||||
string++, start++;
|
||||
}
|
||||
|
||||
// Return remainder of string.
|
||||
return string;
|
||||
}
|
||||
|
||||
ImageLocation::ImageLocation(u1* data) {
|
||||
// Inflates the attribute stream into individual values stored in the long
|
||||
// array _attributes. This allows an attribute value to be quickly accessed by
|
||||
// direct indexing. Unspecified values default to zero (from constructor.)
|
||||
void ImageLocation::set_data(u1* data) {
|
||||
// Deflate the attribute stream into an array of attributes.
|
||||
memset(_attributes, 0, sizeof(_attributes));
|
||||
u1 byte;
|
||||
|
||||
while ((byte = *data) != ATTRIBUTE_END) {
|
||||
// Repeat until end header is found.
|
||||
while ((byte = *data)) {
|
||||
// Extract kind from header byte.
|
||||
u1 kind = attribute_kind(byte);
|
||||
guarantee(kind < ATTRIBUTE_COUNT, "invalid image location attribute");
|
||||
// Extract length of data (in bytes).
|
||||
u1 n = attribute_length(byte);
|
||||
assert(kind < ATTRIBUTE_COUNT, "invalid image location attribute");
|
||||
// Read value (most significant first.)
|
||||
_attributes[kind] = attribute_value(data + 1, n);
|
||||
// Position to next attribute by skipping attribute header and data bytes.
|
||||
data += n + 1;
|
||||
}
|
||||
}
|
||||
|
||||
ImageFile::ImageFile(const char* name) {
|
||||
// Copy the image file name.
|
||||
_name = NEW_C_HEAP_ARRAY(char, strlen(name)+1, mtClass);
|
||||
strcpy(_name, name);
|
||||
// Zero all attribute values.
|
||||
void ImageLocation::clear_data() {
|
||||
// Set defaults to zero.
|
||||
memset(_attributes, 0, sizeof(_attributes));
|
||||
}
|
||||
|
||||
// ImageModuleData constructor maps out sub-tables for faster access.
|
||||
ImageModuleData::ImageModuleData(const ImageFileReader* image_file,
|
||||
const char* module_data_name) :
|
||||
_image_file(image_file),
|
||||
_endian(image_file->endian()),
|
||||
_strings(image_file->get_strings()) {
|
||||
// Retrieve the resource containing the module data for the image file.
|
||||
ImageLocation location;
|
||||
bool found = image_file->find_location(module_data_name, location);
|
||||
guarantee(found, "missing module data");
|
||||
u8 data_size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
|
||||
_data = (u1*)NEW_C_HEAP_ARRAY(char, data_size, mtClass);
|
||||
_image_file->get_resource(location, _data);
|
||||
// Map out the header.
|
||||
_header = (Header*)_data;
|
||||
// Get the package to module entry count.
|
||||
u4 ptm_count = _header->ptm_count(_endian);
|
||||
// Get the module to package entry count.
|
||||
u4 mtp_count = _header->mtp_count(_endian);
|
||||
// Compute the offset of the package to module perfect hash redirect.
|
||||
u4 ptm_redirect_offset = sizeof(Header);
|
||||
// Compute the offset of the package to module data.
|
||||
u4 ptm_data_offset = ptm_redirect_offset + ptm_count * sizeof(s4);
|
||||
// Compute the offset of the module to package perfect hash redirect.
|
||||
u4 mtp_redirect_offset = ptm_data_offset + ptm_count * sizeof(PTMData);
|
||||
// Compute the offset of the module to package data.
|
||||
u4 mtp_data_offset = mtp_redirect_offset + mtp_count * sizeof(s4);
|
||||
// Compute the offset of the module to package tables.
|
||||
u4 mtp_packages_offset = mtp_data_offset + mtp_count * sizeof(MTPData);
|
||||
// Compute the address of the package to module perfect hash redirect.
|
||||
_ptm_redirect = (s4*)(_data + ptm_redirect_offset);
|
||||
// Compute the address of the package to module data.
|
||||
_ptm_data = (PTMData*)(_data + ptm_data_offset);
|
||||
// Compute the address of the module to package perfect hash redirect.
|
||||
_mtp_redirect = (s4*)(_data + mtp_redirect_offset);
|
||||
// Compute the address of the module to package data.
|
||||
_mtp_data = (MTPData*)(_data + mtp_data_offset);
|
||||
// Compute the address of the module to package tables.
|
||||
_mtp_packages = (s4*)(_data + mtp_packages_offset);
|
||||
}
|
||||
|
||||
// Release module data resource.
|
||||
ImageModuleData::~ImageModuleData() {
|
||||
if (_data != NULL) {
|
||||
FREE_C_HEAP_ARRAY(u1, _data);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the name of the module data resource. Ex. "./lib/modules/file.jimage"
|
||||
// yields "file.jdata"
|
||||
void ImageModuleData::module_data_name(char* buffer, const char* image_file_name) {
|
||||
// Locate the last slash in the file name path.
|
||||
const char* slash = strrchr(image_file_name, os::file_separator()[0]);
|
||||
// Trim the path to name and extension.
|
||||
const char* name = slash != NULL ? slash + 1 : (char *)image_file_name;
|
||||
// Locate the extension period.
|
||||
const char* dot = strrchr(name, '.');
|
||||
guarantee(dot, "missing extension on jimage name");
|
||||
// Trim to only base name.
|
||||
int length = dot - name;
|
||||
strncpy(buffer, name, length);
|
||||
buffer[length] = '\0';
|
||||
// Append extension.
|
||||
strcat(buffer, ".jdata");
|
||||
}
|
||||
|
||||
// Return the module in which a package resides. Returns NULL if not found.
|
||||
const char* ImageModuleData::package_to_module(const char* package_name) {
|
||||
// Search the package to module table.
|
||||
s4 index = ImageStrings::find(_endian, package_name, _ptm_redirect,
|
||||
_header->ptm_count(_endian));
|
||||
// If entry is found.
|
||||
if (index != ImageStrings::NOT_FOUND) {
|
||||
// Retrieve the package to module entry.
|
||||
PTMData* data = _ptm_data + index;
|
||||
// Verify that it is the correct data.
|
||||
if (strcmp(package_name, get_string(data->name_offset(_endian))) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
// Return the module name.
|
||||
return get_string(data->module_name_offset(_endian));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Returns all the package names in a module. Returns NULL if module not found.
|
||||
GrowableArray<const char*>* ImageModuleData::module_to_packages(const char* module_name) {
|
||||
// Search the module to package table.
|
||||
s4 index = ImageStrings::find(_endian, module_name, _mtp_redirect,
|
||||
_header->mtp_count(_endian));
|
||||
// If entry is found.
|
||||
if (index != ImageStrings::NOT_FOUND) {
|
||||
// Retrieve the module to package entry.
|
||||
MTPData* data = _mtp_data + index;
|
||||
// Verify that it is the correct data.
|
||||
if (strcmp(module_name, get_string(data->name_offset(_endian))) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
// Construct an array of all the package entries.
|
||||
GrowableArray<const char*>* packages = new GrowableArray<const char*>();
|
||||
s4 package_offset = data->package_offset(_endian);
|
||||
for (u4 i = 0; i < data->package_count(_endian); i++) {
|
||||
u4 package_name_offset = mtp_package(package_offset + i);
|
||||
const char* package_name = get_string(package_name_offset);
|
||||
packages->append(package_name);
|
||||
}
|
||||
return packages;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Table to manage multiple opens of an image file.
|
||||
GrowableArray<ImageFileReader*>* ImageFileReader::_reader_table =
|
||||
new(ResourceObj::C_HEAP, mtInternal) GrowableArray<ImageFileReader*>(2, true);
|
||||
|
||||
// Open an image file, reuse structure if file already open.
|
||||
ImageFileReader* ImageFileReader::open(const char* name, bool big_endian) {
|
||||
// Lock out _reader_table.
|
||||
MutexLocker ml(ImageFileReaderTable_lock);
|
||||
ImageFileReader* reader;
|
||||
// Search for an exist image file.
|
||||
for (int i = 0; i < _reader_table->length(); i++) {
|
||||
// Retrieve table entry.
|
||||
reader = _reader_table->at(i);
|
||||
// If name matches, then reuse (bump up use count.)
|
||||
if (strcmp(reader->name(), name) == 0) {
|
||||
reader->inc_use();
|
||||
return reader;
|
||||
}
|
||||
}
|
||||
// Need a new image reader.
|
||||
reader = new ImageFileReader(name, big_endian);
|
||||
bool opened = reader->open();
|
||||
// If failed to open.
|
||||
if (!opened) {
|
||||
delete reader;
|
||||
return NULL;
|
||||
}
|
||||
// Bump use count and add to table.
|
||||
reader->inc_use();
|
||||
_reader_table->append(reader);
|
||||
return reader;
|
||||
}
|
||||
|
||||
// Close an image file if the file is not in use elsewhere.
|
||||
void ImageFileReader::close(ImageFileReader *reader) {
|
||||
// Lock out _reader_table.
|
||||
MutexLocker ml(ImageFileReaderTable_lock);
|
||||
// If last use then remove from table and then close.
|
||||
if (reader->dec_use()) {
|
||||
_reader_table->remove(reader);
|
||||
delete reader;
|
||||
}
|
||||
}
|
||||
|
||||
// Return an id for the specifed ImageFileReader.
|
||||
u8 ImageFileReader::readerToID(ImageFileReader *reader) {
|
||||
// ID is just the cloaked reader address.
|
||||
return (u8)reader;
|
||||
}
|
||||
|
||||
// Validate the image id.
|
||||
bool ImageFileReader::idCheck(u8 id) {
|
||||
// Make sure the ID is a managed (_reader_table) reader.
|
||||
MutexLocker ml(ImageFileReaderTable_lock);
|
||||
return _reader_table->contains((ImageFileReader*)id);
|
||||
}
|
||||
|
||||
// Return an id for the specifed ImageFileReader.
|
||||
ImageFileReader* ImageFileReader::idToReader(u8 id) {
|
||||
#ifdef PRODUCT
|
||||
// Fast convert.
|
||||
return (ImageFileReader*)id;
|
||||
#else
|
||||
// Do a slow check before fast convert.
|
||||
return idCheck(id) ? (ImageFileReader*)id : NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Constructor intializes to a closed state.
|
||||
ImageFileReader::ImageFileReader(const char* name, bool big_endian) {
|
||||
// Copy the image file name.
|
||||
_name = NEW_C_HEAP_ARRAY(char, strlen(name) + 1, mtClass);
|
||||
strcpy(_name, name);
|
||||
// Initialize for a closed file.
|
||||
_fd = -1;
|
||||
_memory_mapped = true;
|
||||
_endian = Endian::get_handler(big_endian);
|
||||
_index_data = NULL;
|
||||
}
|
||||
|
||||
ImageFile::~ImageFile() {
|
||||
// Close image and free up data structures.
|
||||
ImageFileReader::~ImageFileReader() {
|
||||
// Ensure file is closed.
|
||||
close();
|
||||
|
||||
// Free up name.
|
||||
FREE_C_HEAP_ARRAY(char, _name);
|
||||
if (_name != NULL) {
|
||||
FREE_C_HEAP_ARRAY(char, _name);
|
||||
_name = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool ImageFile::open() {
|
||||
// Open image file for read access.
|
||||
bool ImageFileReader::open() {
|
||||
// If file exists open for reading.
|
||||
struct stat st;
|
||||
if (os::stat(_name, &st) != 0 ||
|
||||
@ -101,186 +335,212 @@ bool ImageFile::open() {
|
||||
(_fd = os::open(_name, 0, O_RDONLY)) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read image file header and verify.
|
||||
u8 header_size = sizeof(ImageHeader);
|
||||
if (os::read(_fd, &_header, header_size) != header_size ||
|
||||
_header._magic != IMAGE_MAGIC ||
|
||||
_header._major_version != MAJOR_VERSION ||
|
||||
_header._minor_version != MINOR_VERSION) {
|
||||
// Retrieve the file size.
|
||||
_file_size = (u8)st.st_size;
|
||||
// Read image file header and verify it has a valid header.
|
||||
size_t header_size = sizeof(ImageHeader);
|
||||
if (_file_size < header_size ||
|
||||
!read_at((u1*)&_header, header_size, 0) ||
|
||||
_header.magic(_endian) != IMAGE_MAGIC ||
|
||||
_header.major_version(_endian) != MAJOR_VERSION ||
|
||||
_header.minor_version(_endian) != MINOR_VERSION) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Memory map index.
|
||||
// Size of image index.
|
||||
_index_size = index_size();
|
||||
_index_data = (u1*)os::map_memory(_fd, _name, 0, NULL, _index_size, true, false);
|
||||
|
||||
// Failing that, read index into C memory.
|
||||
if (_index_data == NULL) {
|
||||
_memory_mapped = false;
|
||||
_index_data = NEW_RESOURCE_ARRAY(u1, _index_size);
|
||||
|
||||
if (os::seek_to_file_offset(_fd, 0) == -1) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (os::read(_fd, _index_data, _index_size) != _index_size) {
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
// Make sure file is large enough to contain the index.
|
||||
if (_file_size < _index_size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Used to advance a pointer, unstructured.
|
||||
#undef nextPtr
|
||||
#define nextPtr(base, fromType, count, toType) (toType*)((fromType*)(base) + (count))
|
||||
// Pull tables out from the index.
|
||||
_redirect_table = nextPtr(_index_data, u1, header_size, s4);
|
||||
_offsets_table = nextPtr(_redirect_table, s4, _header._location_count, u4);
|
||||
_location_bytes = nextPtr(_offsets_table, u4, _header._location_count, u1);
|
||||
_string_bytes = nextPtr(_location_bytes, u1, _header._locations_size, u1);
|
||||
#undef nextPtr
|
||||
|
||||
// Determine how much of the image is memory mapped.
|
||||
off_t map_size = (off_t)(MemoryMapImage ? _file_size : _index_size);
|
||||
// Memory map image (minimally the index.)
|
||||
_index_data = (u1*)os::map_memory(_fd, _name, 0, NULL, map_size, true, false);
|
||||
guarantee(_index_data, "image file not memory mapped");
|
||||
// Retrieve length of index perfect hash table.
|
||||
u4 length = table_length();
|
||||
// Compute offset of the perfect hash table redirect table.
|
||||
u4 redirect_table_offset = (u4)header_size;
|
||||
// Compute offset of index attribute offsets.
|
||||
u4 offsets_table_offset = redirect_table_offset + length * sizeof(s4);
|
||||
// Compute offset of index location attribute data.
|
||||
u4 location_bytes_offset = offsets_table_offset + length * sizeof(u4);
|
||||
// Compute offset of index string table.
|
||||
u4 string_bytes_offset = location_bytes_offset + locations_size();
|
||||
// Compute address of the perfect hash table redirect table.
|
||||
_redirect_table = (s4*)(_index_data + redirect_table_offset);
|
||||
// Compute address of index attribute offsets.
|
||||
_offsets_table = (u4*)(_index_data + offsets_table_offset);
|
||||
// Compute address of index location attribute data.
|
||||
_location_bytes = _index_data + location_bytes_offset;
|
||||
// Compute address of index string table.
|
||||
_string_bytes = _index_data + string_bytes_offset;
|
||||
// Successful open.
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImageFile::close() {
|
||||
// Close image file.
|
||||
void ImageFileReader::close() {
|
||||
// Dealllocate the index.
|
||||
if (_index_data) {
|
||||
if (_memory_mapped) {
|
||||
os::unmap_memory((char*)_index_data, _index_size);
|
||||
} else {
|
||||
FREE_RESOURCE_ARRAY(u1, _index_data, _index_size);
|
||||
}
|
||||
|
||||
if (_index_data != NULL) {
|
||||
os::unmap_memory((char*)_index_data, _index_size);
|
||||
_index_data = NULL;
|
||||
}
|
||||
|
||||
// close file.
|
||||
// Close file.
|
||||
if (_fd != -1) {
|
||||
os::close(_fd);
|
||||
_fd = -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Return the attribute stream for a named resourced.
|
||||
u1* ImageFile::find_location_data(const char* path) const {
|
||||
// Compute hash.
|
||||
u4 hash = ImageStrings::hash_code(path) % _header._location_count;
|
||||
s4 redirect = _redirect_table[hash];
|
||||
|
||||
if (!redirect) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u4 index;
|
||||
|
||||
if (redirect < 0) {
|
||||
// If no collision.
|
||||
index = -redirect - 1;
|
||||
} else {
|
||||
// If collision, recompute hash code.
|
||||
index = ImageStrings::hash_code(path, redirect) % _header._location_count;
|
||||
}
|
||||
|
||||
assert(index < _header._location_count, "index exceeds location count");
|
||||
u4 offset = _offsets_table[index];
|
||||
assert(offset < _header._locations_size, "offset exceeds location attributes size");
|
||||
|
||||
if (offset == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return _location_bytes + offset;
|
||||
// Read directly from the file.
|
||||
bool ImageFileReader::read_at(u1* data, u8 size, u8 offset) const {
|
||||
return os::read_at(_fd, data, size, offset) == size;
|
||||
}
|
||||
|
||||
// Verify that a found location matches the supplied path.
|
||||
bool ImageFile::verify_location(ImageLocation& location, const char* path) const {
|
||||
// Retrieve each path component string.
|
||||
ImageStrings strings(_string_bytes, _header._strings_size);
|
||||
// Match a path with each subcomponent without concatenation (copy).
|
||||
// Match up path parent.
|
||||
// Find the location attributes associated with the path. Returns true if
|
||||
// the location is found, false otherwise.
|
||||
bool ImageFileReader::find_location(const char* path, ImageLocation& location) const {
|
||||
// Locate the entry in the index perfect hash table.
|
||||
s4 index = ImageStrings::find(_endian, path, _redirect_table, table_length());
|
||||
// If is found.
|
||||
if (index != ImageStrings::NOT_FOUND) {
|
||||
// Get address of first byte of location attribute stream.
|
||||
u1* data = get_location_data(index);
|
||||
// Expand location attributes.
|
||||
location.set_data(data);
|
||||
// Make sure result is not a false positive.
|
||||
return verify_location(location, path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Assemble the location path from the string fragments indicated in the location attributes.
|
||||
void ImageFileReader::location_path(ImageLocation& location, char* path, size_t max) const {
|
||||
// Manage the image string table.
|
||||
ImageStrings strings(_string_bytes, _header.strings_size(_endian));
|
||||
// Position to first character of the path buffer.
|
||||
char* next = path;
|
||||
// Temp for string length.
|
||||
size_t length;
|
||||
// Get module string.
|
||||
const char* module = location.get_attribute(ImageLocation::ATTRIBUTE_MODULE, strings);
|
||||
// If module string is not empty string.
|
||||
if (*module != '\0') {
|
||||
// Get length of module name.
|
||||
length = strlen(module);
|
||||
// Make sure there is no buffer overflow.
|
||||
guarantee(next - path + length + 2 < max, "buffer overflow");
|
||||
// Append '/module/'.
|
||||
*next++ = '/';
|
||||
strcpy(next, module); next += length;
|
||||
*next++ = '/';
|
||||
}
|
||||
// Get parent (package) string.
|
||||
const char* parent = location.get_attribute(ImageLocation::ATTRIBUTE_PARENT, strings);
|
||||
const char* next = ImageStrings::starts_with(path, parent);
|
||||
// Continue only if a complete match.
|
||||
if (!next) return false;
|
||||
// Match up path base.
|
||||
// If parent string is not empty string.
|
||||
if (*parent != '\0') {
|
||||
// Get length of module string.
|
||||
length = strlen(parent);
|
||||
// Make sure there is no buffer overflow.
|
||||
guarantee(next - path + length + 1 < max, "buffer overflow");
|
||||
// Append 'patent/' .
|
||||
strcpy(next, parent); next += length;
|
||||
*next++ = '/';
|
||||
}
|
||||
// Get base name string.
|
||||
const char* base = location.get_attribute(ImageLocation::ATTRIBUTE_BASE, strings);
|
||||
next = ImageStrings::starts_with(next, base);
|
||||
// Continue only if a complete match.
|
||||
if (!next) return false;
|
||||
// Match up path extension.
|
||||
// Get length of base name.
|
||||
length = strlen(base);
|
||||
// Make sure there is no buffer overflow.
|
||||
guarantee(next - path + length < max, "buffer overflow");
|
||||
// Append base name.
|
||||
strcpy(next, base); next += length;
|
||||
// Get extension string.
|
||||
const char* extension = location.get_attribute(ImageLocation::ATTRIBUTE_EXTENSION, strings);
|
||||
next = ImageStrings::starts_with(next, extension);
|
||||
// If extension string is not empty string.
|
||||
if (*extension != '\0') {
|
||||
// Get length of extension string.
|
||||
length = strlen(extension);
|
||||
// Make sure there is no buffer overflow.
|
||||
guarantee(next - path + length + 1 < max, "buffer overflow");
|
||||
// Append '.extension' .
|
||||
*next++ = '.';
|
||||
strcpy(next, extension); next += length;
|
||||
}
|
||||
// Make sure there is no buffer overflow.
|
||||
guarantee((size_t)(next - path) < max, "buffer overflow");
|
||||
// Terminate string.
|
||||
*next = '\0';
|
||||
}
|
||||
|
||||
// Verify that a found location matches the supplied path (without copying.)
|
||||
bool ImageFileReader::verify_location(ImageLocation& location, const char* path) const {
|
||||
// Manage the image string table.
|
||||
ImageStrings strings(_string_bytes, _header.strings_size(_endian));
|
||||
// Position to first character of the path string.
|
||||
const char* next = path;
|
||||
// Get module name string.
|
||||
const char* module = location.get_attribute(ImageLocation::ATTRIBUTE_MODULE, strings);
|
||||
// If module string is not empty.
|
||||
if (*module != '\0') {
|
||||
// Compare '/module/' .
|
||||
if (*next++ != '/') return false;
|
||||
if (!(next = ImageStrings::starts_with(next, module))) return false;
|
||||
if (*next++ != '/') return false;
|
||||
}
|
||||
// Get parent (package) string
|
||||
const char* parent = location.get_attribute(ImageLocation::ATTRIBUTE_PARENT, strings);
|
||||
// If parent string is not empty string.
|
||||
if (*parent != '\0') {
|
||||
// Compare 'parent/' .
|
||||
if (!(next = ImageStrings::starts_with(next, parent))) return false;
|
||||
if (*next++ != '/') return false;
|
||||
}
|
||||
// Get base name string.
|
||||
const char* base = location.get_attribute(ImageLocation::ATTRIBUTE_BASE, strings);
|
||||
// Compare with basne name.
|
||||
if (!(next = ImageStrings::starts_with(next, base))) return false;
|
||||
// Get extension string.
|
||||
const char* extension = location.get_attribute(ImageLocation::ATTRIBUTE_EXTENSION, strings);
|
||||
// If extension is not empty.
|
||||
if (*extension != '\0') {
|
||||
// Compare '.extension' .
|
||||
if (*next++ != '.') return false;
|
||||
if (!(next = ImageStrings::starts_with(next, extension))) return false;
|
||||
}
|
||||
// True only if complete match and no more characters.
|
||||
return next && *next == '\0';
|
||||
return *next == '\0';
|
||||
}
|
||||
|
||||
// Return the resource for the supplied location.
|
||||
u1* ImageFile::get_resource(ImageLocation& location) const {
|
||||
// Return the resource data for the supplied location.
|
||||
void ImageFileReader::get_resource(ImageLocation& location, u1* uncompressed_data) const {
|
||||
// Retrieve the byte offset and size of the resource.
|
||||
u8 offset = _index_size + location.get_attribute(ImageLocation::ATTRIBUTE_OFFSET);
|
||||
u8 size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
|
||||
u8 offset = location.get_attribute(ImageLocation::ATTRIBUTE_OFFSET);
|
||||
u8 uncompressed_size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
|
||||
u8 compressed_size = location.get_attribute(ImageLocation::ATTRIBUTE_COMPRESSED);
|
||||
u8 read_size = compressed_size ? compressed_size : size;
|
||||
|
||||
// Allocate space for the resource.
|
||||
u1* data = NEW_RESOURCE_ARRAY(u1, read_size);
|
||||
|
||||
bool is_read = os::read_at(_fd, data, read_size, offset) == read_size;
|
||||
guarantee(is_read, "error reading from image or short read");
|
||||
|
||||
// If not compressed, just return the data.
|
||||
if (!compressed_size) {
|
||||
return data;
|
||||
}
|
||||
|
||||
u1* uncompressed = NEW_RESOURCE_ARRAY(u1, size);
|
||||
char* msg = NULL;
|
||||
jboolean res = ClassLoader::decompress(data, compressed_size, uncompressed, size, &msg);
|
||||
if (!res) warning("decompression failed due to %s\n", msg);
|
||||
guarantee(res, "decompression failed");
|
||||
|
||||
return uncompressed;
|
||||
}
|
||||
|
||||
void ImageFile::get_resource(const char* path, u1*& buffer, u8& size) const {
|
||||
buffer = NULL;
|
||||
size = 0;
|
||||
u1* data = find_location_data(path);
|
||||
if (data) {
|
||||
ImageLocation location(data);
|
||||
if (verify_location(location, path)) {
|
||||
size = location.get_attribute(ImageLocation::ATTRIBUTE_UNCOMPRESSED);
|
||||
buffer = get_resource(location);
|
||||
if (compressed_size != 0) {
|
||||
ResourceMark rm;
|
||||
u1* compressed_data;
|
||||
// If not memory mapped read in bytes.
|
||||
if (!MemoryMapImage) {
|
||||
// Allocate buffer for compression.
|
||||
compressed_data = NEW_RESOURCE_ARRAY(u1, compressed_size);
|
||||
// Read bytes from offset beyond the image index.
|
||||
bool is_read = read_at(compressed_data, compressed_size, _index_size + offset);
|
||||
guarantee(is_read, "error reading from image or short read");
|
||||
} else {
|
||||
compressed_data = get_data_address() + offset;
|
||||
}
|
||||
// Get image string table.
|
||||
const ImageStrings strings = get_strings();
|
||||
// Decompress resource.
|
||||
ImageDecompressor::decompress_resource(compressed_data, uncompressed_data, uncompressed_size,
|
||||
&strings, false);
|
||||
} else {
|
||||
// Read bytes from offset beyond the image index.
|
||||
bool is_read = read_at(uncompressed_data, uncompressed_size, _index_size + offset);
|
||||
guarantee(is_read, "error reading from image or short read");
|
||||
}
|
||||
}
|
||||
|
||||
GrowableArray<const char*>* ImageFile::packages(const char* name) {
|
||||
char entry[JVM_MAXPATHLEN];
|
||||
bool overflow = jio_snprintf(entry, sizeof(entry), "%s/packages.offsets", name) == -1;
|
||||
guarantee(!overflow, "package name overflow");
|
||||
|
||||
u1* buffer;
|
||||
u8 size;
|
||||
|
||||
get_resource(entry, buffer, size);
|
||||
guarantee(buffer, "missing module packages reource");
|
||||
ImageStrings strings(_string_bytes, _header._strings_size);
|
||||
GrowableArray<const char*>* pkgs = new GrowableArray<const char*>();
|
||||
int count = size / 4;
|
||||
for (int i = 0; i < count; i++) {
|
||||
u4 offset = Bytes::get_Java_u4(buffer + (i*4));
|
||||
const char* p = strings.get(offset);
|
||||
pkgs->append(p);
|
||||
}
|
||||
|
||||
return pkgs;
|
||||
}
|
||||
|
@ -28,13 +28,15 @@
|
||||
#include "classfile/classLoader.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "memory/allocation.inline.hpp"
|
||||
#include "utilities/endian.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
|
||||
// Image files are an alternate file format for storing classes and resources. The
|
||||
// goal is to supply file access which is faster and smaller that the jar format.
|
||||
// It should be noted that unlike jars information stored in an image is in native
|
||||
// endian format. This allows the image to be memory mapped into memory without
|
||||
// endian translation. This also means that images are platform dependent.
|
||||
// goal is to supply file access which is faster and smaller than the jar format.
|
||||
// It should be noted that unlike jars, information stored in an image is in native
|
||||
// endian format. This allows the image to be mapped into memory without endian
|
||||
// translation. This also means that images are platform dependent.
|
||||
//
|
||||
// Image files are structured as three sections;
|
||||
//
|
||||
@ -42,7 +44,7 @@
|
||||
// | Header |
|
||||
// +-----------+
|
||||
// | |
|
||||
// | Directory |
|
||||
// | Index |
|
||||
// | |
|
||||
// +-----------+
|
||||
// | |
|
||||
@ -60,7 +62,11 @@
|
||||
// +------------+------------+
|
||||
// | Major Vers | Minor Vers |
|
||||
// +------------+------------+
|
||||
// | Location Count |
|
||||
// | Flags |
|
||||
// +-------------------------+
|
||||
// | Resource Count |
|
||||
// +-------------------------+
|
||||
// | Table Length |
|
||||
// +-------------------------+
|
||||
// | Attributes Size |
|
||||
// +-------------------------+
|
||||
@ -71,23 +77,24 @@
|
||||
// special file extension.
|
||||
// Major vers, minor vers - differences in version numbers indicate structural
|
||||
// changes in the image.
|
||||
// Location count - number of locations/resources in the file. This count is also
|
||||
// the length of lookup tables used in the directory.
|
||||
// Flags - various image wide flags (future).
|
||||
// Resource count - number of resources in the file.
|
||||
// Table length - the length of lookup tables used in the index.
|
||||
// Attributes size - number of bytes in the region used to store location attribute
|
||||
// streams.
|
||||
// Strings size - the size of the region used to store strings used by the
|
||||
// directory and meta data.
|
||||
// index and meta data.
|
||||
//
|
||||
// The directory contains information related to resource lookup. The algorithm
|
||||
// The index contains information related to resource lookup. The algorithm
|
||||
// used for lookup is "A Practical Minimal Perfect Hashing Method"
|
||||
// (http://homepages.dcc.ufmg.br/~nivio/papers/wea05.pdf). Given a path string
|
||||
// in the form <package>/<base>.<extension> return the resource location
|
||||
// in the form /<module>/<package>/<base>.<extension> return the resource location
|
||||
// information;
|
||||
//
|
||||
// redirectIndex = hash(path, DEFAULT_SEED) % count;
|
||||
// redirectIndex = hash(path, DEFAULT_SEED) % table_length;
|
||||
// redirect = redirectTable[redirectIndex];
|
||||
// if (redirect == 0) return not found;
|
||||
// locationIndex = redirect < 0 ? -1 - redirect : hash(path, redirect) % count;
|
||||
// locationIndex = redirect < 0 ? -1 - redirect : hash(path, redirect) % table_length;
|
||||
// location = locationTable[locationIndex];
|
||||
// if (!verify(location, path)) return not found;
|
||||
// return location;
|
||||
@ -97,7 +104,7 @@
|
||||
// other seeds. The verify function guarantees the found resource location is
|
||||
// indeed the resource we are looking for.
|
||||
//
|
||||
// The following is the format of the directory;
|
||||
// The following is the format of the index;
|
||||
//
|
||||
// +-------------------+
|
||||
// | Redirect Table |
|
||||
@ -117,54 +124,74 @@
|
||||
// offsets. Zero indicates not found.
|
||||
// Attribute Offsets - Array of 32-bit unsigned values representing offsets into
|
||||
// attribute data. Attribute offsets can be iterated to do a
|
||||
// full survey of resources in the image.
|
||||
// full survey of resources in the image. Offset of zero
|
||||
// indicates no attributes.
|
||||
// Attribute Data - Bytes representing compact attribute data for locations. (See
|
||||
// comments in ImageLocation.)
|
||||
// Strings - Collection of zero terminated UTF-8 strings used by the directory and
|
||||
// Strings - Collection of zero terminated UTF-8 strings used by the index and
|
||||
// image meta data. Each string is accessed by offset. Each string is
|
||||
// unique. Offset zero is reserved for the empty string.
|
||||
//
|
||||
// Note that the memory mapped directory assumes 32 bit alignment of the image
|
||||
// header, the redirect table and the attribute offsets.
|
||||
// Note that the memory mapped index assumes 32 bit alignment of each component
|
||||
// in the index.
|
||||
//
|
||||
// Endianness of an image.
|
||||
// An image booted by hotspot is always in native endian. However, it is possible
|
||||
// to read (by the JDK) in alternate endian format. Primarily, this is during
|
||||
// cross platform scenarios. Ex, where javac needs to read an embedded image
|
||||
// to access classes for crossing compilation.
|
||||
//
|
||||
|
||||
class ImageFileReader; // forward declaration
|
||||
|
||||
// Manage image file string table.
|
||||
class ImageStrings {
|
||||
class ImageStrings VALUE_OBJ_CLASS_SPEC {
|
||||
private:
|
||||
// Data bytes for strings.
|
||||
u1* _data;
|
||||
// Number of bytes in the string table.
|
||||
u4 _size;
|
||||
|
||||
u1* _data; // Data bytes for strings.
|
||||
u4 _size; // Number of bytes in the string table.
|
||||
public:
|
||||
// Prime used to generate hash for Perfect Hashing.
|
||||
static const u4 HASH_MULTIPLIER = 0x01000193;
|
||||
enum {
|
||||
// Not found result from find routine.
|
||||
NOT_FOUND = -1,
|
||||
// Prime used to generate hash for Perfect Hashing.
|
||||
HASH_MULTIPLIER = 0x01000193
|
||||
};
|
||||
|
||||
ImageStrings(u1* data, u4 size) : _data(data), _size(size) {}
|
||||
|
||||
// Return the UTF-8 string beginning at offset.
|
||||
inline const char* get(u4 offset) const {
|
||||
assert(offset < _size, "offset exceeds string table size");
|
||||
guarantee(offset < _size, "offset exceeds string table size");
|
||||
return (const char*)(_data + offset);
|
||||
}
|
||||
|
||||
// Compute the Perfect Hashing hash code for the supplied string.
|
||||
// Compute the Perfect Hashing hash code for the supplied UTF-8 string.
|
||||
inline static u4 hash_code(const char* string) {
|
||||
return hash_code(string, HASH_MULTIPLIER);
|
||||
}
|
||||
|
||||
// Compute the Perfect Hashing hash code for the supplied string, starting at seed.
|
||||
static u4 hash_code(const char* string, u4 seed);
|
||||
static s4 hash_code(const char* string, s4 seed);
|
||||
|
||||
// Test to see if string begins with start. If so returns remaining portion
|
||||
// of string. Otherwise, NULL. Used to test sections of a path without
|
||||
// copying.
|
||||
// Match up a string in a perfect hash table. Result still needs validation
|
||||
// for precise match.
|
||||
static s4 find(Endian* endian, const char* name, s4* redirect, u4 length);
|
||||
|
||||
// Test to see if UTF-8 string begins with the start UTF-8 string. If so,
|
||||
// return non-NULL address of remaining portion of string. Otherwise, return
|
||||
// NULL. Used to test sections of a path without copying from image string
|
||||
// table.
|
||||
static const char* starts_with(const char* string, const char* start);
|
||||
|
||||
// Test to see if UTF-8 string begins with start char. If so, return non-NULL
|
||||
// address of remaining portion of string. Otherwise, return NULL. Used
|
||||
// to test a character of a path without copying.
|
||||
inline static const char* starts_with(const char* string, const char ch) {
|
||||
return *string == ch ? string + 1 : NULL;
|
||||
}
|
||||
};
|
||||
|
||||
// Manage image file location attribute streams. Within an image, a location's
|
||||
// Manage image file location attribute data. Within an image, a location's
|
||||
// attributes are compressed into a stream of bytes. An attribute stream is
|
||||
// composed of individual attribute sequences. Each attribute sequence begins with
|
||||
// a header byte containing the attribute 'kind' (upper 5 bits of header) and the
|
||||
@ -188,7 +215,7 @@ public:
|
||||
// stream.
|
||||
// - ATTRIBUTE_OFFSET represents the number of bytes from the beginning of the region
|
||||
// storing the resources. Thus, in an image this represents the number of bytes
|
||||
// after the directory.
|
||||
// after the index.
|
||||
// - Currently, compressed resources are represented by having a non-zero
|
||||
// ATTRIBUTE_COMPRESSED value. This represents the number of bytes stored in the
|
||||
// image, and the value of ATTRIBUTE_UNCOMPRESSED represents number of bytes of the
|
||||
@ -198,17 +225,19 @@ public:
|
||||
// represented differently.
|
||||
// - Package strings include trailing slash and extensions include prefix period.
|
||||
//
|
||||
class ImageLocation {
|
||||
class ImageLocation VALUE_OBJ_CLASS_SPEC {
|
||||
public:
|
||||
// Attribute kind enumeration.
|
||||
static const u1 ATTRIBUTE_END = 0; // End of attribute stream marker
|
||||
static const u1 ATTRIBUTE_BASE = 1; // String table offset of resource path base
|
||||
static const u1 ATTRIBUTE_PARENT = 2; // String table offset of resource path parent
|
||||
static const u1 ATTRIBUTE_EXTENSION = 3; // String table offset of resource path extension
|
||||
static const u1 ATTRIBUTE_OFFSET = 4; // Container byte offset of resource
|
||||
static const u1 ATTRIBUTE_COMPRESSED = 5; // In image byte size of the compressed resource
|
||||
static const u1 ATTRIBUTE_UNCOMPRESSED = 6; // In memory byte size of the uncompressed resource
|
||||
static const u1 ATTRIBUTE_COUNT = 7; // Number of attribute kinds
|
||||
enum {
|
||||
ATTRIBUTE_END, // End of attribute stream marker
|
||||
ATTRIBUTE_MODULE, // String table offset of module name
|
||||
ATTRIBUTE_PARENT, // String table offset of resource path parent
|
||||
ATTRIBUTE_BASE, // String table offset of resource path base
|
||||
ATTRIBUTE_EXTENSION, // String table offset of resource path extension
|
||||
ATTRIBUTE_OFFSET, // Container byte offset of resource
|
||||
ATTRIBUTE_COMPRESSED, // In image byte size of the compressed resource
|
||||
ATTRIBUTE_UNCOMPRESSED, // In memory byte size of the uncompressed resource
|
||||
ATTRIBUTE_COUNT // Number of attribute kinds
|
||||
};
|
||||
|
||||
private:
|
||||
// Values of inflated attributes.
|
||||
@ -222,30 +251,43 @@ private:
|
||||
// Return the attribute kind.
|
||||
inline static u1 attribute_kind(u1 data) {
|
||||
u1 kind = data >> 3;
|
||||
assert(kind < ATTRIBUTE_COUNT, "invalid attribute kind");
|
||||
guarantee(kind < ATTRIBUTE_COUNT, "invalid attribute kind");
|
||||
return kind;
|
||||
}
|
||||
|
||||
// Return the attribute length.
|
||||
inline static u8 attribute_value(u1* data, u1 n) {
|
||||
assert(0 < n && n <= 8, "invalid attribute value length");
|
||||
guarantee(0 < n && n <= 8, "invalid attribute value length");
|
||||
u8 value = 0;
|
||||
|
||||
// Most significant bytes first.
|
||||
for (u1 i = 0; i < n; i++) {
|
||||
value <<= 8;
|
||||
value |= data[i];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public:
|
||||
ImageLocation(u1* data);
|
||||
ImageLocation() {
|
||||
clear_data();
|
||||
}
|
||||
|
||||
ImageLocation(u1* data) {
|
||||
clear_data();
|
||||
set_data(data);
|
||||
}
|
||||
|
||||
// Inflates the attribute stream into individual values stored in the long
|
||||
// array _attributes. This allows an attribute value to be quickly accessed by
|
||||
// direct indexing. Unspecified values default to zero.
|
||||
void set_data(u1* data);
|
||||
|
||||
// Zero all attribute values.
|
||||
void clear_data();
|
||||
|
||||
// Retrieve an attribute value from the inflated array.
|
||||
inline u8 get_attribute(u1 kind) const {
|
||||
assert(ATTRIBUTE_END < kind && kind < ATTRIBUTE_COUNT, "invalid attribute kind");
|
||||
guarantee(ATTRIBUTE_END < kind && kind < ATTRIBUTE_COUNT, "invalid attribute kind");
|
||||
return _attributes[kind];
|
||||
}
|
||||
|
||||
@ -255,89 +297,306 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
// Manage the image file.
|
||||
class ImageFile: public CHeapObj<mtClass> {
|
||||
private:
|
||||
// Image file marker.
|
||||
static const u4 IMAGE_MAGIC = 0xCAFEDADA;
|
||||
// Image file major version number.
|
||||
static const u2 MAJOR_VERSION = 0;
|
||||
// Image file minor version number.
|
||||
static const u2 MINOR_VERSION = 1;
|
||||
|
||||
struct ImageHeader {
|
||||
u4 _magic; // Image file marker
|
||||
u2 _major_version; // Image file major version number
|
||||
u2 _minor_version; // Image file minor version number
|
||||
u4 _location_count; // Number of locations managed in index.
|
||||
u4 _locations_size; // Number of bytes in attribute table.
|
||||
u4 _strings_size; // Number of bytes in string table.
|
||||
//
|
||||
// NOTE: needs revision.
|
||||
// Each loader requires set of module meta data to identify which modules and
|
||||
// packages are managed by that loader. Currently, there is one image file per
|
||||
// builtin loader, so only one module meta data resource per file.
|
||||
//
|
||||
// Each element in the module meta data is a native endian 4 byte integer. Note
|
||||
// that entries with zero offsets for string table entries should be ignored (
|
||||
// padding for hash table lookup.)
|
||||
//
|
||||
// Format:
|
||||
// Count of package to module entries
|
||||
// Count of module to package entries
|
||||
// Perfect Hash redirect table[Count of package to module entries]
|
||||
// Package to module entries[Count of package to module entries]
|
||||
// Offset to package name in string table
|
||||
// Offset to module name in string table
|
||||
// Perfect Hash redirect table[Count of module to package entries]
|
||||
// Module to package entries[Count of module to package entries]
|
||||
// Offset to module name in string table
|
||||
// Count of packages in module
|
||||
// Offset to first package in packages table
|
||||
// Packages[]
|
||||
// Offset to package name in string table
|
||||
//
|
||||
// Manage the image module meta data.
|
||||
class ImageModuleData : public CHeapObj<mtClass> {
|
||||
class Header VALUE_OBJ_CLASS_SPEC {
|
||||
private:
|
||||
u4 _ptm_count; // Count of package to module entries
|
||||
u4 _mtp_count; // Count of module to package entries
|
||||
public:
|
||||
inline u4 ptm_count(Endian* endian) const { return endian->get(_ptm_count); }
|
||||
inline u4 mtp_count(Endian* endian) const { return endian->get(_mtp_count); }
|
||||
};
|
||||
|
||||
char* _name; // Name of image
|
||||
int _fd; // File descriptor
|
||||
bool _memory_mapped; // Is file memory mapped
|
||||
ImageHeader _header; // Image header
|
||||
u8 _index_size; // Total size of index
|
||||
u1* _index_data; // Raw index data
|
||||
s4* _redirect_table; // Perfect hash redirect table
|
||||
u4* _offsets_table; // Location offset table
|
||||
u1* _location_bytes; // Location attributes
|
||||
u1* _string_bytes; // String table
|
||||
// Hashtable entry
|
||||
class HashData VALUE_OBJ_CLASS_SPEC {
|
||||
private:
|
||||
u4 _name_offset; // Name offset in string table
|
||||
public:
|
||||
inline s4 name_offset(Endian* endian) const { return endian->get(_name_offset); }
|
||||
};
|
||||
|
||||
// Package to module hashtable entry
|
||||
class PTMData : public HashData {
|
||||
private:
|
||||
u4 _module_name_offset; // Module name offset in string table
|
||||
public:
|
||||
inline s4 module_name_offset(Endian* endian) const { return endian->get(_module_name_offset); }
|
||||
};
|
||||
|
||||
// Module to package hashtable entry
|
||||
class MTPData : public HashData {
|
||||
private:
|
||||
u4 _package_count; // Number of packages in module
|
||||
u4 _package_offset; // Offset in package list
|
||||
public:
|
||||
inline u4 package_count(Endian* endian) const { return endian->get(_package_count); }
|
||||
inline u4 package_offset(Endian* endian) const { return endian->get(_package_offset); }
|
||||
};
|
||||
|
||||
const ImageFileReader* _image_file; // Source image file
|
||||
Endian* _endian; // Endian handler
|
||||
ImageStrings _strings; // Image file strings
|
||||
u1* _data; // Module data resource data
|
||||
u8 _data_size; // Size of resource data
|
||||
Header* _header; // Module data header
|
||||
s4* _ptm_redirect; // Package to module hashtable redirect
|
||||
PTMData* _ptm_data; // Package to module data
|
||||
s4* _mtp_redirect; // Module to packages hashtable redirect
|
||||
MTPData* _mtp_data; // Module to packages data
|
||||
s4* _mtp_packages; // Package data (name offsets)
|
||||
|
||||
// Return a string from the string table.
|
||||
inline const char* get_string(u4 offset) {
|
||||
return _strings.get(offset);
|
||||
}
|
||||
|
||||
inline u4 mtp_package(u4 index) {
|
||||
return _endian->get(_mtp_packages[index]);
|
||||
}
|
||||
|
||||
public:
|
||||
ImageModuleData(const ImageFileReader* image_file, const char* module_data_name);
|
||||
~ImageModuleData();
|
||||
|
||||
// Return the name of the module data resource.
|
||||
static void module_data_name(char* buffer, const char* image_file_name);
|
||||
|
||||
// Return the module in which a package resides. Returns NULL if not found.
|
||||
const char* package_to_module(const char* package_name);
|
||||
|
||||
// Returns all the package names in a module. Returns NULL if module not found.
|
||||
GrowableArray<const char*>* module_to_packages(const char* module_name);
|
||||
};
|
||||
|
||||
// Image file header, starting at offset 0.
|
||||
class ImageHeader VALUE_OBJ_CLASS_SPEC {
|
||||
private:
|
||||
u4 _magic; // Image file marker
|
||||
u4 _version; // Image file major version number
|
||||
u4 _flags; // Image file flags
|
||||
u4 _resource_count; // Number of resources in file
|
||||
u4 _table_length; // Number of slots in index tables
|
||||
u4 _locations_size; // Number of bytes in attribute table
|
||||
u4 _strings_size; // Number of bytes in string table
|
||||
|
||||
public:
|
||||
u4 magic() const { return _magic; }
|
||||
u4 magic(Endian* endian) const { return endian->get(_magic); }
|
||||
void set_magic(Endian* endian, u4 magic) { return endian->set(_magic, magic); }
|
||||
|
||||
u4 major_version(Endian* endian) const { return endian->get(_version) >> 16; }
|
||||
u4 minor_version(Endian* endian) const { return endian->get(_version) & 0xFFFF; }
|
||||
void set_version(Endian* endian, u4 major_version, u4 minor_version) {
|
||||
return endian->set(_version, major_version << 16 | minor_version);
|
||||
}
|
||||
|
||||
u4 flags(Endian* endian) const { return endian->get(_flags); }
|
||||
void set_flags(Endian* endian, u4 value) { return endian->set(_flags, value); }
|
||||
|
||||
u4 resource_count(Endian* endian) const { return endian->get(_resource_count); }
|
||||
void set_resource_count(Endian* endian, u4 count) { return endian->set(_resource_count, count); }
|
||||
|
||||
u4 table_length(Endian* endian) const { return endian->get(_table_length); }
|
||||
void set_table_length(Endian* endian, u4 count) { return endian->set(_table_length, count); }
|
||||
|
||||
u4 locations_size(Endian* endian) const { return endian->get(_locations_size); }
|
||||
void set_locations_size(Endian* endian, u4 size) { return endian->set(_locations_size, size); }
|
||||
|
||||
u4 strings_size(Endian* endian) const { return endian->get(_strings_size); }
|
||||
void set_strings_size(Endian* endian, u4 size) { return endian->set(_strings_size, size); }
|
||||
};
|
||||
|
||||
// Max path length limit independent of platform. Windows max path is 1024,
|
||||
// other platforms use 4096. The JCK fails several tests when 1024 is used.
|
||||
#define IMAGE_MAX_PATH 4096
|
||||
|
||||
// Manage the image file.
|
||||
// ImageFileReader manages the content of an image file.
|
||||
// Initially, the header of the image file is read for validation. If valid,
|
||||
// values in the header are used calculate the size of the image index. The
|
||||
// index is then memory mapped to allow load on demand and sharing. The
|
||||
// -XX:+MemoryMapImage flag determines if the entire file is loaded (server use.)
|
||||
// An image can be used by Hotspot and multiple reference points in the JDK, thus
|
||||
// it is desirable to share a reader. To accomodate sharing, a share table is
|
||||
// defined (see ImageFileReaderTable in imageFile.cpp) To track the number of
|
||||
// uses, ImageFileReader keeps a use count (_use). Use is incremented when
|
||||
// 'opened' by reference point and decremented when 'closed'. Use of zero
|
||||
// leads the ImageFileReader to be actually closed and discarded.
|
||||
class ImageFileReader : public CHeapObj<mtClass> {
|
||||
private:
|
||||
// Manage a number of image files such that an image can be shared across
|
||||
// multiple uses (ex. loader.)
|
||||
static GrowableArray<ImageFileReader*>* _reader_table;
|
||||
|
||||
char* _name; // Name of image
|
||||
s4 _use; // Use count
|
||||
int _fd; // File descriptor
|
||||
Endian* _endian; // Endian handler
|
||||
u8 _file_size; // File size in bytes
|
||||
ImageHeader _header; // Image header
|
||||
size_t _index_size; // Total size of index
|
||||
u1* _index_data; // Raw index data
|
||||
s4* _redirect_table; // Perfect hash redirect table
|
||||
u4* _offsets_table; // Location offset table
|
||||
u1* _location_bytes; // Location attributes
|
||||
u1* _string_bytes; // String table
|
||||
|
||||
ImageFileReader(const char* name, bool big_endian);
|
||||
~ImageFileReader();
|
||||
|
||||
// Compute number of bytes in image file index.
|
||||
inline u8 index_size() {
|
||||
return sizeof(ImageHeader) +
|
||||
_header._location_count * sizeof(u4) * 2 +
|
||||
_header._locations_size +
|
||||
_header._strings_size;
|
||||
table_length() * sizeof(u4) * 2 + locations_size() + strings_size();
|
||||
}
|
||||
|
||||
public:
|
||||
ImageFile(const char* name);
|
||||
~ImageFile();
|
||||
enum {
|
||||
// Image file marker.
|
||||
IMAGE_MAGIC = 0xCAFEDADA,
|
||||
// Endian inverted Image file marker.
|
||||
IMAGE_MAGIC_INVERT = 0xDADAFECA,
|
||||
// Image file major version number.
|
||||
MAJOR_VERSION = 1,
|
||||
// Image file minor version number.
|
||||
MINOR_VERSION = 0
|
||||
};
|
||||
|
||||
// Open image file for access.
|
||||
// Open an image file, reuse structure if file already open.
|
||||
static ImageFileReader* open(const char* name, bool big_endian = Endian::is_big_endian());
|
||||
|
||||
// Close an image file if the file is not in use elsewhere.
|
||||
static void close(ImageFileReader *reader);
|
||||
|
||||
// Return an id for the specifed ImageFileReader.
|
||||
static u8 readerToID(ImageFileReader *reader);
|
||||
|
||||
// Validate the image id.
|
||||
static bool idCheck(u8 id);
|
||||
|
||||
// Return an id for the specifed ImageFileReader.
|
||||
static ImageFileReader* idToReader(u8 id);
|
||||
|
||||
// Open image file for read access.
|
||||
bool open();
|
||||
|
||||
// Close image file.
|
||||
void close();
|
||||
|
||||
// Read directly from the file.
|
||||
bool read_at(u1* data, u8 size, u8 offset) const;
|
||||
|
||||
inline Endian* endian() const { return _endian; }
|
||||
|
||||
// Retrieve name of image file.
|
||||
inline const char* name() const {
|
||||
return _name;
|
||||
}
|
||||
|
||||
// Retrieve size of image file.
|
||||
inline u8 file_size() const {
|
||||
return _file_size;
|
||||
}
|
||||
|
||||
// Return first address of index data.
|
||||
inline u1* get_index_address() const {
|
||||
return _index_data;
|
||||
}
|
||||
|
||||
// Return first address of resource data.
|
||||
inline u1* get_data_address() const {
|
||||
return _index_data + _index_size;
|
||||
}
|
||||
|
||||
// Get the size of the index data.
|
||||
size_t get_index_size() const {
|
||||
return _index_size;
|
||||
}
|
||||
|
||||
inline u4 table_length() const {
|
||||
return _header.table_length(_endian);
|
||||
}
|
||||
|
||||
inline u4 locations_size() const {
|
||||
return _header.locations_size(_endian);
|
||||
}
|
||||
|
||||
inline u4 strings_size()const {
|
||||
return _header.strings_size(_endian);
|
||||
}
|
||||
|
||||
inline u4* offsets_table() const {
|
||||
return _offsets_table;
|
||||
}
|
||||
|
||||
// Increment use count.
|
||||
inline void inc_use() {
|
||||
_use++;
|
||||
}
|
||||
|
||||
// Decrement use count.
|
||||
inline bool dec_use() {
|
||||
return --_use == 0;
|
||||
}
|
||||
|
||||
// Return a string table accessor.
|
||||
inline const ImageStrings get_strings() const {
|
||||
return ImageStrings(_string_bytes, _header._strings_size);
|
||||
return ImageStrings(_string_bytes, _header.strings_size(_endian));
|
||||
}
|
||||
|
||||
// Return number of locations in image file index.
|
||||
inline u4 get_location_count() const {
|
||||
return _header._location_count;
|
||||
}
|
||||
|
||||
// Return location attribute stream for location i.
|
||||
inline u1* get_location_data(u4 i) const {
|
||||
u4 offset = _offsets_table[i];
|
||||
|
||||
// Return location attribute stream at offset.
|
||||
inline u1* get_location_offset_data(u4 offset) const {
|
||||
guarantee((u4)offset < _header.locations_size(_endian),
|
||||
"offset exceeds location attributes size");
|
||||
return offset != 0 ? _location_bytes + offset : NULL;
|
||||
}
|
||||
|
||||
// Return the attribute stream for a named resourced.
|
||||
u1* find_location_data(const char* path) const;
|
||||
// Return location attribute stream for location i.
|
||||
inline u1* get_location_data(u4 index) const {
|
||||
guarantee((u4)index < _header.table_length(_endian),
|
||||
"index exceeds location count");
|
||||
u4 offset = _endian->get(_offsets_table[index]);
|
||||
|
||||
return get_location_offset_data(offset);
|
||||
}
|
||||
|
||||
// Find the location attributes associated with the path. Returns true if
|
||||
// the location is found, false otherwise.
|
||||
bool find_location(const char* path, ImageLocation& location) const;
|
||||
|
||||
// Assemble the location path.
|
||||
void location_path(ImageLocation& location, char* path, size_t max) const;
|
||||
|
||||
// Verify that a found location matches the supplied path.
|
||||
bool verify_location(ImageLocation& location, const char* path) const;
|
||||
|
||||
// Return the resource for the supplied location info.
|
||||
u1* get_resource(ImageLocation& location) const;
|
||||
|
||||
// Return the resource associated with the path else NULL if not found.
|
||||
void get_resource(const char* path, u1*& buffer, u8& size) const;
|
||||
|
||||
// Return an array of packages for a given module
|
||||
GrowableArray<const char*>* packages(const char* name);
|
||||
// Return the resource for the supplied path.
|
||||
void get_resource(ImageLocation& location, u1* uncompressed_data) const;
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_CLASSFILE_IMAGEFILE_HPP
|
||||
|
@ -1707,8 +1707,7 @@ void java_lang_Throwable::fill_in_stack_trace(Handle throwable, methodHandle met
|
||||
// - rest of the stack
|
||||
|
||||
if (!skip_fillInStackTrace_check) {
|
||||
if ((method->name() == vmSymbols::fillInStackTrace_name() ||
|
||||
method->name() == vmSymbols::fillInStackTrace0_name()) &&
|
||||
if (method->name() == vmSymbols::fillInStackTrace_name() &&
|
||||
throwable->is_a(method->method_holder())) {
|
||||
continue;
|
||||
}
|
||||
|
@ -2346,9 +2346,6 @@ methodHandle SystemDictionary::find_method_handle_invoker(Symbol* name,
|
||||
assert(!THREAD->is_Compiler_thread(), "");
|
||||
Handle method_type =
|
||||
SystemDictionary::find_method_handle_type(signature, accessing_klass, CHECK_(empty));
|
||||
if (false) { // FIXME: Decide if the Java upcall should resolve signatures.
|
||||
method_type = java_lang_String::create_from_symbol(signature, CHECK_(empty));
|
||||
}
|
||||
|
||||
KlassHandle mh_klass = SystemDictionary::MethodHandle_klass();
|
||||
int ref_kind = JVM_REF_invokeVirtual;
|
||||
@ -2380,6 +2377,24 @@ methodHandle SystemDictionary::find_method_handle_invoker(Symbol* name,
|
||||
return unpack_method_and_appendix(mname, accessing_klass, appendix_box, appendix_result, THREAD);
|
||||
}
|
||||
|
||||
// Decide if we can globally cache a lookup of this class, to be returned to any client that asks.
|
||||
// We must ensure that all class loaders everywhere will reach this class, for any client.
|
||||
// This is a safe bet for public classes in java.lang, such as Object and String.
|
||||
// We also include public classes in java.lang.invoke, because they appear frequently in system-level method types.
|
||||
// Out of an abundance of caution, we do not include any other classes, not even for packages like java.util.
|
||||
static bool is_always_visible_class(oop mirror) {
|
||||
Klass* klass = java_lang_Class::as_Klass(mirror);
|
||||
if (klass->oop_is_objArray()) {
|
||||
klass = ObjArrayKlass::cast(klass)->bottom_klass(); // check element type
|
||||
}
|
||||
if (klass->oop_is_typeArray()) {
|
||||
return true; // primitive array
|
||||
}
|
||||
assert(klass->oop_is_instance(), klass->external_name());
|
||||
return klass->is_public() &&
|
||||
(InstanceKlass::cast(klass)->is_same_class_package(SystemDictionary::Object_klass()) || // java.lang
|
||||
InstanceKlass::cast(klass)->is_same_class_package(SystemDictionary::MethodHandle_klass())); // java.lang.invoke
|
||||
}
|
||||
|
||||
// Ask Java code to find or construct a java.lang.invoke.MethodType for the given
|
||||
// signature, as interpreted relative to the given class loader.
|
||||
@ -2402,32 +2417,33 @@ Handle SystemDictionary::find_method_handle_type(Symbol* signature,
|
||||
}
|
||||
|
||||
Handle class_loader, protection_domain;
|
||||
bool is_on_bcp = true; // keep this true as long as we can materialize from the boot classloader
|
||||
if (accessing_klass.not_null()) {
|
||||
class_loader = Handle(THREAD, InstanceKlass::cast(accessing_klass())->class_loader());
|
||||
protection_domain = Handle(THREAD, InstanceKlass::cast(accessing_klass())->protection_domain());
|
||||
}
|
||||
bool can_be_cached = true;
|
||||
int npts = ArgumentCount(signature).size();
|
||||
objArrayHandle pts = oopFactory::new_objArray(SystemDictionary::Class_klass(), npts, CHECK_(empty));
|
||||
int arg = 0;
|
||||
Handle rt; // the return type from the signature
|
||||
Handle rt; // the return type from the signature
|
||||
ResourceMark rm(THREAD);
|
||||
for (SignatureStream ss(signature); !ss.is_done(); ss.next()) {
|
||||
oop mirror = NULL;
|
||||
if (is_on_bcp) {
|
||||
// Note: class_loader & protection_domain are both null at this point.
|
||||
mirror = ss.as_java_mirror(class_loader, protection_domain,
|
||||
if (can_be_cached) {
|
||||
// Use neutral class loader to lookup candidate classes to be placed in the cache.
|
||||
mirror = ss.as_java_mirror(Handle(), Handle(),
|
||||
SignatureStream::ReturnNull, CHECK_(empty));
|
||||
if (mirror == NULL) {
|
||||
// fall back from BCP to accessing_klass
|
||||
if (accessing_klass.not_null()) {
|
||||
class_loader = Handle(THREAD, InstanceKlass::cast(accessing_klass())->class_loader());
|
||||
protection_domain = Handle(THREAD, InstanceKlass::cast(accessing_klass())->protection_domain());
|
||||
}
|
||||
is_on_bcp = false;
|
||||
if (mirror == NULL || (ss.is_object() && !is_always_visible_class(mirror))) {
|
||||
// Fall back to accessing_klass context.
|
||||
can_be_cached = false;
|
||||
}
|
||||
}
|
||||
if (!is_on_bcp) {
|
||||
if (!can_be_cached) {
|
||||
// Resolve, throwing a real error if it doesn't work.
|
||||
mirror = ss.as_java_mirror(class_loader, protection_domain,
|
||||
SignatureStream::NCDFError, CHECK_(empty));
|
||||
}
|
||||
assert(!oopDesc::is_null(mirror), ss.as_symbol(THREAD)->as_C_string());
|
||||
if (ss.at_return_type())
|
||||
rt = Handle(THREAD, mirror);
|
||||
else
|
||||
@ -2459,7 +2475,7 @@ Handle SystemDictionary::find_method_handle_type(Symbol* signature,
|
||||
&args, CHECK_(empty));
|
||||
Handle method_type(THREAD, (oop) result.get_jobject());
|
||||
|
||||
if (is_on_bcp) {
|
||||
if (can_be_cached) {
|
||||
// We can cache this MethodType inside the JVM.
|
||||
MutexLocker ml(SystemDictionary_lock, THREAD);
|
||||
spe = invoke_method_table()->find_entry(index, hash, signature, null_iid);
|
||||
|
@ -258,6 +258,8 @@
|
||||
/* Type Annotations (JDK 8 and above) */ \
|
||||
template(type_annotations_name, "typeAnnotations") \
|
||||
\
|
||||
/* Intrinsic Annotation (JDK 9 and above) */ \
|
||||
template(jdk_internal_HotSpotIntrinsicCandidate_signature, "Ljdk/internal/HotSpotIntrinsicCandidate;") \
|
||||
\
|
||||
/* Support for JSR 292 & invokedynamic (JDK 1.7 and above) */ \
|
||||
template(java_lang_invoke_CallSite, "java/lang/invoke/CallSite") \
|
||||
@ -345,7 +347,6 @@
|
||||
template(dispatch_name, "dispatch") \
|
||||
template(getSystemClassLoader_name, "getSystemClassLoader") \
|
||||
template(fillInStackTrace_name, "fillInStackTrace") \
|
||||
template(fillInStackTrace0_name, "fillInStackTrace0") \
|
||||
template(getCause_name, "getCause") \
|
||||
template(initCause_name, "initCause") \
|
||||
template(setProperty_name, "setProperty") \
|
||||
@ -635,7 +636,43 @@
|
||||
// The F_xx is one of the Flags enum; see below.
|
||||
//
|
||||
// for Emacs: (let ((c-backslash-column 120) (c-backslash-max-column 120)) (c-backslash-region (point) (point-max) nil t))
|
||||
//
|
||||
//
|
||||
// There are two types of intrinsic methods: (1) Library intrinsics and (2) bytecode intrinsics.
|
||||
//
|
||||
// (1) A library intrinsic method may be replaced with hand-crafted assembly code,
|
||||
// with hand-crafted compiler IR, or with a combination of the two. The semantics
|
||||
// of the replacement code may differ from the semantics of the replaced code.
|
||||
//
|
||||
// (2) Bytecode intrinsic methods are not replaced by special code, but they are
|
||||
// treated in some other special way by the compiler. For example, the compiler
|
||||
// may delay inlining for some String-related intrinsic methods (e.g., some methods
|
||||
// defined in the StringBuilder and StringBuffer classes, see
|
||||
// Compile::should_delay_string_inlining() for more details).
|
||||
//
|
||||
// Due to the difference between the semantics of an intrinsic method as defined
|
||||
// in the (Java) source code and the semantics of the method as defined
|
||||
// by the code in the VM, intrinsic methods must be explicitly marked.
|
||||
//
|
||||
// Intrinsic methods are marked by the jdk.internal.HotSpotIntrinsicCandidate
|
||||
// annotation. If CheckIntrinsics is enabled, the VM performs the following
|
||||
// checks when a class C is loaded: (1) all intrinsics defined by the VM for
|
||||
// class C are present in the loaded class file and are marked;
|
||||
// (2) an intrinsic is defined by the VM for all marked methods of class C.
|
||||
//
|
||||
// If a mismatch is detected for a method, the VM behaves differently depending
|
||||
// on the type of build. A fastdebug build exits and reports an error on a mismatch.
|
||||
// A product build will not replace an unmarked library intrinsic method with
|
||||
// hand-crafted code, that is, unmarked library intrinsics are treated as ordinary
|
||||
// methods in a product build. The special treatment of a bytecode intrinsic method
|
||||
// persists even if the method not marked.
|
||||
//
|
||||
// When adding an intrinsic for a method, please make sure to appropriately
|
||||
// annotate the method in the source code. The list below contains all
|
||||
// library intrinsics followed by bytecode intrinsics. Please also make sure to
|
||||
// add the declaration of the intrinsic to the approriate section of the list.
|
||||
#define VM_INTRINSICS_DO(do_intrinsic, do_class, do_name, do_signature, do_alias) \
|
||||
/* (1) Library intrinsics */ \
|
||||
do_intrinsic(_hashCode, java_lang_Object, hashCode_name, void_int_signature, F_R) \
|
||||
do_name( hashCode_name, "hashCode") \
|
||||
do_intrinsic(_getClass, java_lang_Object, getClass_name, void_class_signature, F_R) \
|
||||
@ -792,12 +829,12 @@
|
||||
\
|
||||
do_class(sun_nio_cs_iso8859_1_Encoder, "sun/nio/cs/ISO_8859_1$Encoder") \
|
||||
do_intrinsic(_encodeISOArray, sun_nio_cs_iso8859_1_Encoder, encodeISOArray_name, encodeISOArray_signature, F_S) \
|
||||
do_name( encodeISOArray_name, "encodeISOArray") \
|
||||
do_name( encodeISOArray_name, "implEncodeISOArray") \
|
||||
do_signature(encodeISOArray_signature, "([CI[BII)I") \
|
||||
\
|
||||
do_class(java_math_BigInteger, "java/math/BigInteger") \
|
||||
do_intrinsic(_multiplyToLen, java_math_BigInteger, multiplyToLen_name, multiplyToLen_signature, F_R) \
|
||||
do_name( multiplyToLen_name, "multiplyToLen") \
|
||||
do_intrinsic(_multiplyToLen, java_math_BigInteger, multiplyToLen_name, multiplyToLen_signature, F_S) \
|
||||
do_name( multiplyToLen_name, "implMultiplyToLen") \
|
||||
do_signature(multiplyToLen_signature, "([II[II[I)[I") \
|
||||
\
|
||||
do_intrinsic(_squareToLen, java_math_BigInteger, squareToLen_name, squareToLen_signature, F_S) \
|
||||
@ -808,6 +845,14 @@
|
||||
do_name( mulAdd_name, "implMulAdd") \
|
||||
do_signature(mulAdd_signature, "([I[IIII)I") \
|
||||
\
|
||||
do_intrinsic(_montgomeryMultiply, java_math_BigInteger, montgomeryMultiply_name, montgomeryMultiply_signature, F_S) \
|
||||
do_name( montgomeryMultiply_name, "implMontgomeryMultiply") \
|
||||
do_signature(montgomeryMultiply_signature, "([I[I[IIJ[I)[I") \
|
||||
\
|
||||
do_intrinsic(_montgomerySquare, java_math_BigInteger, montgomerySquare_name, montgomerySquare_signature, F_S) \
|
||||
do_name( montgomerySquare_name, "implMontgomerySquare") \
|
||||
do_signature(montgomerySquare_signature, "([I[IIJ[I)[I") \
|
||||
\
|
||||
/* java/lang/ref/Reference */ \
|
||||
do_intrinsic(_Reference_get, java_lang_ref_Reference, get_name, void_object_signature, F_R) \
|
||||
\
|
||||
@ -815,21 +860,21 @@
|
||||
do_class(com_sun_crypto_provider_aescrypt, "com/sun/crypto/provider/AESCrypt") \
|
||||
do_intrinsic(_aescrypt_encryptBlock, com_sun_crypto_provider_aescrypt, encryptBlock_name, byteArray_int_byteArray_int_signature, F_R) \
|
||||
do_intrinsic(_aescrypt_decryptBlock, com_sun_crypto_provider_aescrypt, decryptBlock_name, byteArray_int_byteArray_int_signature, F_R) \
|
||||
do_name( encryptBlock_name, "encryptBlock") \
|
||||
do_name( decryptBlock_name, "decryptBlock") \
|
||||
do_name( encryptBlock_name, "implEncryptBlock") \
|
||||
do_name( decryptBlock_name, "implDecryptBlock") \
|
||||
do_signature(byteArray_int_byteArray_int_signature, "([BI[BI)V") \
|
||||
\
|
||||
do_class(com_sun_crypto_provider_cipherBlockChaining, "com/sun/crypto/provider/CipherBlockChaining") \
|
||||
do_intrinsic(_cipherBlockChaining_encryptAESCrypt, com_sun_crypto_provider_cipherBlockChaining, encrypt_name, byteArray_int_int_byteArray_int_signature, F_R) \
|
||||
do_intrinsic(_cipherBlockChaining_decryptAESCrypt, com_sun_crypto_provider_cipherBlockChaining, decrypt_name, byteArray_int_int_byteArray_int_signature, F_R) \
|
||||
do_name( encrypt_name, "encrypt") \
|
||||
do_name( decrypt_name, "decrypt") \
|
||||
do_name( encrypt_name, "implEncrypt") \
|
||||
do_name( decrypt_name, "implDecrypt") \
|
||||
do_signature(byteArray_int_int_byteArray_int_signature, "([BII[BI)I") \
|
||||
\
|
||||
/* support for sun.security.provider.SHA */ \
|
||||
do_class(sun_security_provider_sha, "sun/security/provider/SHA") \
|
||||
do_intrinsic(_sha_implCompress, sun_security_provider_sha, implCompress_name, implCompress_signature, F_R) \
|
||||
do_name( implCompress_name, "implCompress") \
|
||||
do_name( implCompress_name, "implCompress0") \
|
||||
do_signature(implCompress_signature, "([BI)V") \
|
||||
\
|
||||
/* support for sun.security.provider.SHA2 */ \
|
||||
@ -843,7 +888,7 @@
|
||||
/* support for sun.security.provider.DigestBase */ \
|
||||
do_class(sun_security_provider_digestbase, "sun/security/provider/DigestBase") \
|
||||
do_intrinsic(_digestBase_implCompressMB, sun_security_provider_digestbase, implCompressMB_name, implCompressMB_signature, F_R) \
|
||||
do_name( implCompressMB_name, "implCompressMultiBlock") \
|
||||
do_name( implCompressMB_name, "implCompressMultiBlock0") \
|
||||
do_signature(implCompressMB_signature, "([BII)I") \
|
||||
\
|
||||
/* support for com.sun.crypto.provider.GHASH */ \
|
||||
@ -857,17 +902,18 @@
|
||||
do_intrinsic(_updateCRC32, java_util_zip_CRC32, update_name, int2_int_signature, F_SN) \
|
||||
do_name( update_name, "update") \
|
||||
do_intrinsic(_updateBytesCRC32, java_util_zip_CRC32, updateBytes_name, updateBytes_signature, F_SN) \
|
||||
do_name( updateBytes_name, "updateBytes") \
|
||||
do_name( updateBytes_name, "updateBytes0") \
|
||||
do_signature(updateBytes_signature, "(I[BII)I") \
|
||||
do_intrinsic(_updateByteBufferCRC32, java_util_zip_CRC32, updateByteBuffer_name, updateByteBuffer_signature, F_SN) \
|
||||
do_name( updateByteBuffer_name, "updateByteBuffer") \
|
||||
do_name( updateByteBuffer_name, "updateByteBuffer0") \
|
||||
do_signature(updateByteBuffer_signature, "(IJII)I") \
|
||||
\
|
||||
/* support for java.util.zip.CRC32C */ \
|
||||
do_class(java_util_zip_CRC32C, "java/util/zip/CRC32C") \
|
||||
do_intrinsic(_updateBytesCRC32C, java_util_zip_CRC32C, updateBytes_name, updateBytes_signature, F_S) \
|
||||
do_intrinsic(_updateDirectByteBufferCRC32C, java_util_zip_CRC32C, updateDirectByteBuffer_name, updateByteBuffer_signature, F_S) \
|
||||
do_name( updateDirectByteBuffer_name, "updateDirectByteBuffer") \
|
||||
do_intrinsic(_updateBytesCRC32C, java_util_zip_CRC32C, updateBytes_C_name, updateBytes_signature, F_S) \
|
||||
do_name( updateBytes_C_name, "updateBytes") \
|
||||
do_intrinsic(_updateDirectByteBufferCRC32C, java_util_zip_CRC32C, updateDirectByteBuffer_C_name, updateByteBuffer_signature, F_S) \
|
||||
do_name( updateDirectByteBuffer_C_name, "updateDirectByteBuffer") \
|
||||
\
|
||||
/* support for sun.misc.Unsafe */ \
|
||||
do_class(sun_misc_Unsafe, "sun/misc/Unsafe") \
|
||||
@ -878,12 +924,6 @@
|
||||
do_intrinsic(_copyMemory, sun_misc_Unsafe, copyMemory_name, copyMemory_signature, F_RN) \
|
||||
do_name( copyMemory_name, "copyMemory") \
|
||||
do_signature(copyMemory_signature, "(Ljava/lang/Object;JLjava/lang/Object;JJ)V") \
|
||||
do_intrinsic(_park, sun_misc_Unsafe, park_name, park_signature, F_RN) \
|
||||
do_name( park_name, "park") \
|
||||
do_signature(park_signature, "(ZJ)V") \
|
||||
do_intrinsic(_unpark, sun_misc_Unsafe, unpark_name, unpark_signature, F_RN) \
|
||||
do_name( unpark_name, "unpark") \
|
||||
do_alias( unpark_signature, /*(LObject;)V*/ object_void_signature) \
|
||||
do_intrinsic(_loadFence, sun_misc_Unsafe, loadFence_name, loadFence_signature, F_RN) \
|
||||
do_name( loadFence_name, "loadFence") \
|
||||
do_alias( loadFence_signature, void_method_signature) \
|
||||
@ -1066,11 +1106,15 @@
|
||||
do_intrinsic(_getAndSetObject, sun_misc_Unsafe, getAndSetObject_name, getAndSetObject_signature, F_R)\
|
||||
do_name( getAndSetObject_name, "getAndSetObject") \
|
||||
do_signature(getAndSetObject_signature, "(Ljava/lang/Object;JLjava/lang/Object;)Ljava/lang/Object;" ) \
|
||||
/*== LAST_COMPILER_INLINE*/ \
|
||||
/*the compiler does have special inlining code for these; bytecode inline is just fine */ \
|
||||
\
|
||||
do_intrinsic(_fillInStackTrace, java_lang_Throwable, fillInStackTrace_name, void_throwable_signature, F_RNY) \
|
||||
\
|
||||
/* (2) Bytecode intrinsics */ \
|
||||
\
|
||||
do_intrinsic(_park, sun_misc_Unsafe, park_name, park_signature, F_RN) \
|
||||
do_name( park_name, "park") \
|
||||
do_signature(park_signature, "(ZJ)V") \
|
||||
do_intrinsic(_unpark, sun_misc_Unsafe, unpark_name, unpark_signature, F_RN) \
|
||||
do_name( unpark_name, "unpark") \
|
||||
do_alias( unpark_signature, /*(LObject;)V*/ object_void_signature) \
|
||||
do_intrinsic(_StringBuilder_void, java_lang_StringBuilder, object_initializer_name, void_method_signature, F_R) \
|
||||
do_intrinsic(_StringBuilder_int, java_lang_StringBuilder, object_initializer_name, int_void_signature, F_R) \
|
||||
do_intrinsic(_StringBuilder_String, java_lang_StringBuilder, object_initializer_name, string_void_signature, F_R) \
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,6 +25,7 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "code/codeBlob.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "code/codeCacheExtensions.hpp"
|
||||
#include "code/relocInfo.hpp"
|
||||
#include "compiler/disassembler.hpp"
|
||||
#include "interpreter/bytecode.hpp"
|
||||
@ -88,6 +89,7 @@ CodeBlob::CodeBlob(const char* name, int header_size, int size, int frame_comple
|
||||
_data_offset = size;
|
||||
_frame_size = 0;
|
||||
set_oop_maps(NULL);
|
||||
_strings = CodeStrings();
|
||||
}
|
||||
|
||||
|
||||
@ -114,6 +116,7 @@ CodeBlob::CodeBlob(
|
||||
_code_offset = _content_offset + cb->total_offset_of(cb->insts());
|
||||
_data_offset = _content_offset + round_to(cb->total_content_size(), oopSize);
|
||||
assert(_data_offset <= size, "codeBlob is too small");
|
||||
_strings = CodeStrings();
|
||||
|
||||
cb->copy_code_and_locs_to(this);
|
||||
set_oop_maps(oop_maps);
|
||||
@ -192,6 +195,7 @@ BufferBlob* BufferBlob::create(const char* name, int buffer_size) {
|
||||
|
||||
BufferBlob* blob = NULL;
|
||||
unsigned int size = sizeof(BufferBlob);
|
||||
CodeCacheExtensions::size_blob(name, &buffer_size);
|
||||
// align the size to CodeEntryAlignment
|
||||
size = align_code_offset(size);
|
||||
size += round_to(buffer_size, oopSize);
|
||||
@ -275,6 +279,7 @@ MethodHandlesAdapterBlob* MethodHandlesAdapterBlob::create(int buffer_size) {
|
||||
|
||||
MethodHandlesAdapterBlob* blob = NULL;
|
||||
unsigned int size = sizeof(MethodHandlesAdapterBlob);
|
||||
CodeCacheExtensions::size_blob("MethodHandles adapters", &buffer_size);
|
||||
// align the size to CodeEntryAlignment
|
||||
size = align_code_offset(size);
|
||||
size += round_to(buffer_size, oopSize);
|
||||
@ -315,11 +320,13 @@ RuntimeStub* RuntimeStub::new_runtime_stub(const char* stub_name,
|
||||
{
|
||||
RuntimeStub* stub = NULL;
|
||||
ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock
|
||||
{
|
||||
if (!CodeCacheExtensions::skip_code_generation()) {
|
||||
// bypass useless code generation
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
unsigned int size = allocation_size(cb, sizeof(RuntimeStub));
|
||||
stub = new (size) RuntimeStub(stub_name, cb, size, frame_complete, frame_size, oop_maps, caller_must_gc_arguments);
|
||||
}
|
||||
stub = (RuntimeStub*) CodeCacheExtensions::handle_generated_blob(stub, stub_name);
|
||||
|
||||
trace_new_stub(stub, "RuntimeStub - ", stub_name);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -38,7 +38,8 @@ struct CodeBlobType {
|
||||
MethodProfiled = 1, // Execution level 2 and 3 (profiled) nmethods
|
||||
NonNMethod = 2, // Non-nmethods like Buffers, Adapters and Runtime Stubs
|
||||
All = 3, // All types (No code cache segmentation)
|
||||
NumTypes = 4 // Number of CodeBlobTypes
|
||||
Pregenerated = 4, // Special blobs, managed by CodeCacheExtensions
|
||||
NumTypes = 5 // Number of CodeBlobTypes
|
||||
};
|
||||
};
|
||||
|
||||
@ -63,6 +64,7 @@ class DeoptimizationBlob;
|
||||
class CodeBlob VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
friend class VMStructs;
|
||||
friend class CodeCacheDumper;
|
||||
|
||||
private:
|
||||
const char* _name;
|
||||
@ -206,6 +208,14 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
|
||||
void set_strings(CodeStrings& strings) {
|
||||
_strings.assign(strings);
|
||||
}
|
||||
|
||||
static ByteSize name_field_offset() {
|
||||
return byte_offset_of(CodeBlob, _name);
|
||||
}
|
||||
|
||||
static ByteSize oop_maps_field_offset() {
|
||||
return byte_offset_of(CodeBlob, _oop_maps);
|
||||
}
|
||||
};
|
||||
|
||||
class WhiteBox;
|
||||
|
@ -409,7 +409,7 @@ CodeBlob* CodeCache::allocate(int size, int code_blob_type, bool strict) {
|
||||
}
|
||||
if (PrintCodeCacheExtension) {
|
||||
ResourceMark rm;
|
||||
if (SegmentedCodeCache) {
|
||||
if (_heaps->length() >= 1) {
|
||||
tty->print("%s", heap->name());
|
||||
} else {
|
||||
tty->print("CodeCache");
|
||||
@ -1211,7 +1211,7 @@ void CodeCache::print_internals() {
|
||||
|
||||
int i = 0;
|
||||
FOR_ALL_HEAPS(heap) {
|
||||
if (SegmentedCodeCache && Verbose) {
|
||||
if ((_heaps->length() >= 1) && Verbose) {
|
||||
tty->print_cr("-- %s --", (*heap)->name());
|
||||
}
|
||||
FOR_ALL_BLOBS(cb, *heap) {
|
||||
@ -1360,7 +1360,7 @@ void CodeCache::print_summary(outputStream* st, bool detailed) {
|
||||
FOR_ALL_HEAPS(heap_iterator) {
|
||||
CodeHeap* heap = (*heap_iterator);
|
||||
size_t total = (heap->high_boundary() - heap->low_boundary());
|
||||
if (SegmentedCodeCache) {
|
||||
if (_heaps->length() >= 1) {
|
||||
st->print("%s:", heap->name());
|
||||
} else {
|
||||
st->print("CodeCache:");
|
||||
@ -1397,7 +1397,7 @@ void CodeCache::print_codelist(outputStream* st) {
|
||||
nmethod* nm = iter.method();
|
||||
ResourceMark rm;
|
||||
char *method_name = nm->method()->name_and_sig_as_C_string();
|
||||
st->print_cr("%d %d %s ["INTPTR_FORMAT", "INTPTR_FORMAT" - "INTPTR_FORMAT"]",
|
||||
st->print_cr("%d %d %s [" INTPTR_FORMAT ", " INTPTR_FORMAT " - " INTPTR_FORMAT "]",
|
||||
nm->compile_id(), nm->comp_level(), method_name, (intptr_t)nm->header_begin(),
|
||||
(intptr_t)nm->code_begin(), (intptr_t)nm->code_end());
|
||||
}
|
||||
|
@ -78,6 +78,7 @@ class CodeCache : AllStatic {
|
||||
friend class VMStructs;
|
||||
friend class NMethodIterator;
|
||||
friend class WhiteBox;
|
||||
friend class CodeCacheLoader;
|
||||
private:
|
||||
// CodeHeaps of the cache
|
||||
static GrowableArray<CodeHeap*>* _heaps;
|
||||
|
52
hotspot/src/share/vm/code/codeCacheExtensions.hpp
Normal file
52
hotspot/src/share/vm/code/codeCacheExtensions.hpp
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_HPP
|
||||
#define SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class CodeCacheExtensionsSteps: AllStatic {
|
||||
public:
|
||||
enum Step {
|
||||
// Support for optional fine grain initialization hooks
|
||||
// Note: these hooks must support refining the granularity
|
||||
// (e.g. adding intermediate steps in the ordered enum
|
||||
// if needed for future features)
|
||||
Start,
|
||||
VMVersion,
|
||||
StubRoutines1,
|
||||
Universe,
|
||||
TemplateInterpreter,
|
||||
Interpreter,
|
||||
StubRoutines2,
|
||||
InitGlobals,
|
||||
CreateVM,
|
||||
LastStep
|
||||
};
|
||||
};
|
||||
|
||||
#include "code/codeCacheExtensions_ext.hpp"
|
||||
|
||||
#endif // SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_HPP
|
130
hotspot/src/share/vm/code/codeCacheExtensions_ext.hpp
Normal file
130
hotspot/src/share/vm/code/codeCacheExtensions_ext.hpp
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_EXT_HPP
|
||||
#define SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_EXT_HPP
|
||||
|
||||
#include "utilities/macros.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/globalDefinitions.hpp"
|
||||
#include "interpreter/bytecodes.hpp"
|
||||
|
||||
class AdapterHandlerEntry;
|
||||
class CodeBlob;
|
||||
class CodeBuffer;
|
||||
class InterpreterMacroAssembler;
|
||||
class Template;
|
||||
|
||||
// All the methods defined here are placeholders for possible extensions.
|
||||
|
||||
class CodeCacheExtensions: AllStatic {
|
||||
friend class CodeCacheDumper;
|
||||
|
||||
public:
|
||||
// init both code saving and loading
|
||||
// Must be called very early, before any code is generated.
|
||||
static void initialize() {}
|
||||
|
||||
// Check whether the generated interpreter will be saved.
|
||||
static bool saving_generated_interpreter() { return false; }
|
||||
|
||||
// Check whether a pregenerated interpreter is used.
|
||||
static bool use_pregenerated_interpreter() { return false; }
|
||||
|
||||
// Placeholder for additional VM initialization code
|
||||
static void complete_step(CodeCacheExtensionsSteps::Step phase) {}
|
||||
|
||||
// Return false for newly generated code, on systems where it is not
|
||||
// executable.
|
||||
static bool is_executable(void *pc) { return true; }
|
||||
|
||||
// Return whether dynamically generated code can be executable
|
||||
static bool support_dynamic_code() { return true; }
|
||||
|
||||
// Skip new code generation when known to be useless.
|
||||
static bool skip_code_generation() { return false; }
|
||||
|
||||
// Skip stubs used only for compiled code support.
|
||||
static bool skip_compiler_support() { return false; }
|
||||
|
||||
// Ignore UseFastSignatureHandlers when returning false
|
||||
static bool support_fast_signature_handlers() { return true; }
|
||||
|
||||
/////////////////////////
|
||||
// Handle generated code:
|
||||
// - allow newly generated code to be shared
|
||||
// - allow pregenerated code to be used in place of the newly generated one
|
||||
// (modifying pc).
|
||||
// - support remapping when doing both save and load
|
||||
// 'remap' can be set to false if the addresses handled are not referenced
|
||||
// from code generated later.
|
||||
|
||||
// Associate a name to a generated codelet and possibly modify the pc
|
||||
// Note: use instead the specialized versions when they exist:
|
||||
// - handle_generated_blob for CodeBlob
|
||||
// - handle_generated_handler for SignatureHandlers
|
||||
// See also the optimized calls below that handle several PCs at once.
|
||||
static void handle_generated_pc(address &pc, const char *name) {}
|
||||
|
||||
// Adds a safe definition of the codelet, for codelets used right after
|
||||
// generation (else we would need to immediately stop the JVM and convert
|
||||
// the generated code to executable format before being able to go further).
|
||||
static void handle_generated_pc(address &pc, const char *name, address default_entry) {}
|
||||
|
||||
// Special cases
|
||||
|
||||
// Special case for CodeBlobs, which may require blob specific actions.
|
||||
static CodeBlob* handle_generated_blob(CodeBlob* blob, const char *name = NULL) { return blob; }
|
||||
|
||||
// Special case for Signature Handlers.
|
||||
static void handle_generated_handler(address &handler_start, const char *name, address handler_end) {}
|
||||
|
||||
// Support for generating different variants of the interpreter
|
||||
// that can be dynamically selected after reload.
|
||||
//
|
||||
// - init_interpreter_assembler allows to configure the assembler for
|
||||
// the current variant
|
||||
//
|
||||
// - needs_other_interpreter_variant returns true as long as other
|
||||
// variants are needed.
|
||||
//
|
||||
// - skip_template_interpreter_entries returns true if new entries
|
||||
// need not be generated for this masm setup and this bytecode
|
||||
//
|
||||
// - completed_template_interpreter_entries is called after new
|
||||
// entries have been generated and installed, for any non skipped
|
||||
// bytecode.
|
||||
static void init_interpreter_assembler(InterpreterMacroAssembler* masm, CodeBuffer* code) {}
|
||||
static bool needs_other_interpreter_variant() { return false; }
|
||||
static bool skip_template_interpreter_entries(Bytecodes::Code code) { return false; }
|
||||
static void completed_template_interpreter_entries(InterpreterMacroAssembler* masm, Bytecodes::Code code) {}
|
||||
|
||||
// Code size optimization. May optimize the requested size.
|
||||
static void size_blob(const char* name, int *updatable_size) {}
|
||||
|
||||
// ergonomics
|
||||
static void set_ergonomics_flags() {}
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_CODE_CODE_CACHE_EXTENSIONS_EXT_HPP
|
@ -186,7 +186,7 @@ uint ImplicitExceptionTable::at( uint exec_off ) const {
|
||||
void ImplicitExceptionTable::print(address base) const {
|
||||
tty->print("{");
|
||||
for( uint i=0; i<len(); i++ )
|
||||
tty->print("< "INTPTR_FORMAT", "INTPTR_FORMAT" > ",base + *adr(i), base + *(adr(i)+1));
|
||||
tty->print("< " INTPTR_FORMAT ", " INTPTR_FORMAT " > ",base + *adr(i), base + *(adr(i)+1));
|
||||
tty->print_cr("}");
|
||||
}
|
||||
|
||||
|
@ -2118,7 +2118,7 @@ public:
|
||||
void maybe_print(oop* p) {
|
||||
if (_print_nm == NULL) return;
|
||||
if (!_detected_scavenge_root) _print_nm->print_on(tty, "new scavenge root");
|
||||
tty->print_cr(""PTR_FORMAT"[offset=%d] detected scavengable oop "PTR_FORMAT" (found at "PTR_FORMAT")",
|
||||
tty->print_cr("" PTR_FORMAT "[offset=%d] detected scavengable oop " PTR_FORMAT " (found at " PTR_FORMAT ")",
|
||||
_print_nm, (int)((intptr_t)p - (intptr_t)_print_nm),
|
||||
(void *)(*p), (intptr_t)p);
|
||||
(*p)->print();
|
||||
@ -2518,7 +2518,7 @@ public:
|
||||
_nm->print_nmethod(true);
|
||||
_ok = false;
|
||||
}
|
||||
tty->print_cr("*** non-oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)",
|
||||
tty->print_cr("*** non-oop " PTR_FORMAT " found at " PTR_FORMAT " (offset %d)",
|
||||
(void *)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm));
|
||||
}
|
||||
virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
|
||||
@ -2642,7 +2642,7 @@ public:
|
||||
_nm->print_nmethod(true);
|
||||
_ok = false;
|
||||
}
|
||||
tty->print_cr("*** scavengable oop "PTR_FORMAT" found at "PTR_FORMAT" (offset %d)",
|
||||
tty->print_cr("*** scavengable oop " PTR_FORMAT " found at " PTR_FORMAT " (offset %d)",
|
||||
(void *)(*p), (intptr_t)p, (int)((intptr_t)p - (intptr_t)_nm));
|
||||
(*p)->print();
|
||||
}
|
||||
@ -2687,7 +2687,7 @@ void nmethod::print() const {
|
||||
print_on(tty, NULL);
|
||||
|
||||
if (WizardMode) {
|
||||
tty->print("((nmethod*) "INTPTR_FORMAT ") ", this);
|
||||
tty->print("((nmethod*) " INTPTR_FORMAT ") ", this);
|
||||
tty->print(" for method " INTPTR_FORMAT , (address)method());
|
||||
tty->print(" { ");
|
||||
if (is_in_use()) tty->print("in_use ");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2015, 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
|
||||
@ -261,3 +261,17 @@ void StubQueue::print() {
|
||||
stub_print(s);
|
||||
}
|
||||
}
|
||||
|
||||
// Fixup for pregenerated code
|
||||
void StubQueue::fix_buffer(address buffer, address queue_end, address buffer_end, int number_of_stubs) {
|
||||
const int extra_bytes = CodeEntryAlignment;
|
||||
_stub_buffer = buffer;
|
||||
_queue_begin = 0;
|
||||
_queue_end = queue_end - buffer;
|
||||
_number_of_stubs = number_of_stubs;
|
||||
int size = buffer_end - buffer;
|
||||
// Note: _buffer_limit must differ from _queue_end in the iteration loops
|
||||
// => add extra space at the end (preserving alignment for asserts) if needed
|
||||
if (buffer_end == queue_end) size += extra_bytes;
|
||||
_buffer_limit = _buffer_size = size;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2015, 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
|
||||
@ -216,6 +216,9 @@ class StubQueue: public CHeapObj<mtCode> {
|
||||
// Debugging/printing
|
||||
void verify(); // verifies the stub queue
|
||||
void print(); // prints information about the stub queue
|
||||
|
||||
// Fixup for pregenerated code
|
||||
void fix_buffer(address buffer, address queue_end, address buffer_end, int number_of_stubs);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_CODE_STUBS_HPP
|
||||
|
@ -172,7 +172,7 @@ class CompilationLog : public StringEventLog {
|
||||
}
|
||||
|
||||
void log_nmethod(JavaThread* thread, nmethod* nm) {
|
||||
log(thread, "nmethod %d%s " INTPTR_FORMAT " code ["INTPTR_FORMAT ", " INTPTR_FORMAT "]",
|
||||
log(thread, "nmethod %d%s " INTPTR_FORMAT " code [" INTPTR_FORMAT ", " INTPTR_FORMAT "]",
|
||||
nm->compile_id(), nm->is_osr_method() ? "%" : "",
|
||||
p2i(nm), p2i(nm->code_begin()), p2i(nm->code_end()));
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2015, 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
|
||||
@ -578,7 +578,7 @@ static bool scan_line(const char * line,
|
||||
int* bytes_read, const char*& error_msg) {
|
||||
*bytes_read = 0;
|
||||
error_msg = NULL;
|
||||
if (2 == sscanf(line, "%*[ \t]%255" RANGESLASH "%*[ ]" "%255" RANGE0 "%n", class_name, method_name, bytes_read)) {
|
||||
if (2 == sscanf(line, "%*[ \t]%255" RANGESLASH "%*[ ]" "%255" RANGE0 "%n", class_name, method_name, bytes_read)) {
|
||||
*c_mode = check_mode(class_name, error_msg);
|
||||
*m_mode = check_mode(method_name, error_msg);
|
||||
return *c_mode != MethodMatcher::Unknown && *m_mode != MethodMatcher::Unknown;
|
||||
@ -586,8 +586,6 @@ static bool scan_line(const char * line,
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Scan next flag and value in line, return MethodMatcher object on success, NULL on failure.
|
||||
// On failure, error_msg contains description for the first error.
|
||||
// For future extensions: set error_msg on first error.
|
||||
@ -665,7 +663,7 @@ static MethodMatcher* scan_flag_and_value(const char* type, const char* line, in
|
||||
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type);
|
||||
}
|
||||
} else {
|
||||
jio_snprintf(errorbuf, sizeof(errorbuf), " Value cannot be read for flag %s of type %s", flag, type);
|
||||
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type);
|
||||
}
|
||||
} else if (strcmp(type, "double") == 0) {
|
||||
char buffer[2][256];
|
||||
@ -680,10 +678,10 @@ static MethodMatcher* scan_flag_and_value(const char* type, const char* line, in
|
||||
jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type);
|
||||
}
|
||||
} else {
|
||||
jio_snprintf(errorbuf, sizeof(errorbuf), " Type %s not supported ", type);
|
||||
jio_snprintf(errorbuf, buf_size, " Type %s not supported ", type);
|
||||
}
|
||||
} else {
|
||||
jio_snprintf(errorbuf, sizeof(errorbuf), " Flag name for type %s should be alphanumeric ", type);
|
||||
jio_snprintf(errorbuf, buf_size, " Flag name for type %s should be alphanumeric ", type);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ bool Disassembler::_tried_to_load_library = false;
|
||||
Disassembler::decode_func_virtual Disassembler::_decode_instructions_virtual = NULL;
|
||||
Disassembler::decode_func Disassembler::_decode_instructions = NULL;
|
||||
|
||||
static const char hsdis_library_name[] = "hsdis-"HOTSPOT_LIB_ARCH;
|
||||
static const char hsdis_library_name[] = "hsdis-" HOTSPOT_LIB_ARCH;
|
||||
static const char decode_instructions_virtual_name[] = "decode_instructions_virtual";
|
||||
static const char decode_instructions_name[] = "decode_instructions";
|
||||
static bool use_new_version = true;
|
||||
|
@ -688,18 +688,18 @@ void ConcurrentMarkSweepGeneration::printOccupancy(const char *s) {
|
||||
"The CMS generation should be the old generation");
|
||||
uint level = 1;
|
||||
if (Verbose) {
|
||||
gclog_or_tty->print("[%u %s-%s: "SIZE_FORMAT"("SIZE_FORMAT")]",
|
||||
gclog_or_tty->print("[%u %s-%s: " SIZE_FORMAT "(" SIZE_FORMAT ")]",
|
||||
level, short_name(), s, used(), capacity());
|
||||
} else {
|
||||
gclog_or_tty->print("[%u %s-%s: "SIZE_FORMAT"K("SIZE_FORMAT"K)]",
|
||||
gclog_or_tty->print("[%u %s-%s: " SIZE_FORMAT "K(" SIZE_FORMAT "K)]",
|
||||
level, short_name(), s, used() / K, capacity() / K);
|
||||
}
|
||||
}
|
||||
if (Verbose) {
|
||||
gclog_or_tty->print(" "SIZE_FORMAT"("SIZE_FORMAT")",
|
||||
gclog_or_tty->print(" " SIZE_FORMAT "(" SIZE_FORMAT ")",
|
||||
gch->used(), gch->capacity());
|
||||
} else {
|
||||
gclog_or_tty->print(" "SIZE_FORMAT"K("SIZE_FORMAT"K)",
|
||||
gclog_or_tty->print(" " SIZE_FORMAT "K(" SIZE_FORMAT "K)",
|
||||
gch->used() / K, gch->capacity() / K);
|
||||
}
|
||||
}
|
||||
@ -729,8 +729,8 @@ bool ConcurrentMarkSweepGeneration::promotion_attempt_is_safe(size_t max_promoti
|
||||
bool res = (available >= av_promo) || (available >= max_promotion_in_bytes);
|
||||
if (Verbose && PrintGCDetails) {
|
||||
gclog_or_tty->print_cr(
|
||||
"CMS: promo attempt is%s safe: available("SIZE_FORMAT") %s av_promo("SIZE_FORMAT"),"
|
||||
"max_promo("SIZE_FORMAT")",
|
||||
"CMS: promo attempt is%s safe: available(" SIZE_FORMAT ") %s av_promo(" SIZE_FORMAT "),"
|
||||
"max_promo(" SIZE_FORMAT ")",
|
||||
res? "":" not", available, res? ">=":"<",
|
||||
av_promo, max_promotion_in_bytes);
|
||||
}
|
||||
@ -805,18 +805,18 @@ void ConcurrentMarkSweepGeneration::compute_new_size_free_list() {
|
||||
desired_free_percentage);
|
||||
gclog_or_tty->print_cr(" Maximum free fraction %f",
|
||||
maximum_free_percentage);
|
||||
gclog_or_tty->print_cr(" Capacity "SIZE_FORMAT, capacity()/1000);
|
||||
gclog_or_tty->print_cr(" Desired capacity "SIZE_FORMAT,
|
||||
gclog_or_tty->print_cr(" Capacity " SIZE_FORMAT, capacity()/1000);
|
||||
gclog_or_tty->print_cr(" Desired capacity " SIZE_FORMAT,
|
||||
desired_capacity/1000);
|
||||
GenCollectedHeap* gch = GenCollectedHeap::heap();
|
||||
assert(gch->is_old_gen(this), "The CMS generation should always be the old generation");
|
||||
size_t young_size = gch->young_gen()->capacity();
|
||||
gclog_or_tty->print_cr(" Young gen size " SIZE_FORMAT, young_size / 1000);
|
||||
gclog_or_tty->print_cr(" unsafe_max_alloc_nogc "SIZE_FORMAT,
|
||||
gclog_or_tty->print_cr(" unsafe_max_alloc_nogc " SIZE_FORMAT,
|
||||
unsafe_max_alloc_nogc()/1000);
|
||||
gclog_or_tty->print_cr(" contiguous available "SIZE_FORMAT,
|
||||
gclog_or_tty->print_cr(" contiguous available " SIZE_FORMAT,
|
||||
contiguous_available()/1000);
|
||||
gclog_or_tty->print_cr(" Expand by "SIZE_FORMAT" (bytes)",
|
||||
gclog_or_tty->print_cr(" Expand by " SIZE_FORMAT " (bytes)",
|
||||
expand_bytes);
|
||||
}
|
||||
// safe if expansion fails
|
||||
@ -1182,8 +1182,8 @@ bool CMSCollector::shouldConcurrentCollect() {
|
||||
stats().print_on(gclog_or_tty);
|
||||
gclog_or_tty->print_cr("time_until_cms_gen_full %3.7f",
|
||||
stats().time_until_cms_gen_full());
|
||||
gclog_or_tty->print_cr("free="SIZE_FORMAT, _cmsGen->free());
|
||||
gclog_or_tty->print_cr("contiguous_available="SIZE_FORMAT,
|
||||
gclog_or_tty->print_cr("free=" SIZE_FORMAT, _cmsGen->free());
|
||||
gclog_or_tty->print_cr("contiguous_available=" SIZE_FORMAT,
|
||||
_cmsGen->contiguous_available());
|
||||
gclog_or_tty->print_cr("promotion_rate=%g", stats().promotion_rate());
|
||||
gclog_or_tty->print_cr("cms_allocation_rate=%g", stats().cms_allocation_rate());
|
||||
@ -2160,8 +2160,8 @@ void ConcurrentMarkSweepGeneration::gc_prologue_work(bool full,
|
||||
assert(_numObjectsPromoted == 0, "check");
|
||||
assert(_numWordsPromoted == 0, "check");
|
||||
if (Verbose && PrintGC) {
|
||||
gclog_or_tty->print("Allocated "SIZE_FORMAT" objects, "
|
||||
SIZE_FORMAT" bytes concurrently",
|
||||
gclog_or_tty->print("Allocated " SIZE_FORMAT " objects, "
|
||||
SIZE_FORMAT " bytes concurrently",
|
||||
_numObjectsAllocated, _numWordsAllocated*sizeof(HeapWord));
|
||||
}
|
||||
_numObjectsAllocated = 0;
|
||||
@ -2241,8 +2241,8 @@ void ConcurrentMarkSweepGeneration::gc_epilogue_work(bool full) {
|
||||
assert(_numObjectsAllocated == 0, "check");
|
||||
assert(_numWordsAllocated == 0, "check");
|
||||
if (Verbose && PrintGC) {
|
||||
gclog_or_tty->print("Promoted "SIZE_FORMAT" objects, "
|
||||
SIZE_FORMAT" bytes",
|
||||
gclog_or_tty->print("Promoted " SIZE_FORMAT " objects, "
|
||||
SIZE_FORMAT " bytes",
|
||||
_numObjectsPromoted, _numWordsPromoted*sizeof(HeapWord));
|
||||
}
|
||||
_numObjectsPromoted = 0;
|
||||
@ -2252,7 +2252,7 @@ void ConcurrentMarkSweepGeneration::gc_epilogue_work(bool full) {
|
||||
if (PrintGC && Verbose) {
|
||||
// Call down the chain in contiguous_available needs the freelistLock
|
||||
// so print this out before releasing the freeListLock.
|
||||
gclog_or_tty->print(" Contiguous available "SIZE_FORMAT" bytes ",
|
||||
gclog_or_tty->print(" Contiguous available " SIZE_FORMAT " bytes ",
|
||||
contiguous_available());
|
||||
}
|
||||
}
|
||||
@ -2340,7 +2340,7 @@ class VerifyMarkedClosure: public BitMapClosure {
|
||||
HeapWord* addr = _marks->offsetToHeapWord(offset);
|
||||
if (!_marks->isMarked(addr)) {
|
||||
oop(addr)->print_on(gclog_or_tty);
|
||||
gclog_or_tty->print_cr(" ("INTPTR_FORMAT" should have been marked)", p2i(addr));
|
||||
gclog_or_tty->print_cr(" (" INTPTR_FORMAT " should have been marked)", p2i(addr));
|
||||
_failed = true;
|
||||
}
|
||||
return true;
|
||||
@ -2702,9 +2702,11 @@ void CMSCollector::setup_cms_unloading_and_verification_state() {
|
||||
// Not unloading classes this cycle
|
||||
assert(!should_unload_classes(), "Inconsistency!");
|
||||
|
||||
// If we are not unloading classes then add SO_AllCodeCache to root
|
||||
// scanning options.
|
||||
add_root_scanning_option(rso);
|
||||
|
||||
if ((!verifying() || unloaded_classes_last_cycle()) && should_verify) {
|
||||
// Include symbols, strings and code cache elements to prevent their resurrection.
|
||||
add_root_scanning_option(rso);
|
||||
set_verifying(true);
|
||||
} else if (verifying() && !should_verify) {
|
||||
// We were verifying, but some verification flags got disabled.
|
||||
@ -4269,7 +4271,7 @@ void CMSCollector::checkpointRootsFinal() {
|
||||
verify_overflow_empty();
|
||||
|
||||
if (PrintGCDetails) {
|
||||
gclog_or_tty->print("[YG occupancy: "SIZE_FORMAT" K ("SIZE_FORMAT" K)]",
|
||||
gclog_or_tty->print("[YG occupancy: " SIZE_FORMAT " K (" SIZE_FORMAT " K)]",
|
||||
_young_gen->used() / K,
|
||||
_young_gen->capacity() / K);
|
||||
}
|
||||
@ -4381,8 +4383,8 @@ void CMSCollector::checkpointRootsFinalWork() {
|
||||
if (ser_ovflw > 0) {
|
||||
if (PrintCMSStatistics != 0) {
|
||||
gclog_or_tty->print_cr("Marking stack overflow (benign) "
|
||||
"(pmc_pc="SIZE_FORMAT", pmc_rm="SIZE_FORMAT", kac="SIZE_FORMAT
|
||||
", kac_preclean="SIZE_FORMAT")",
|
||||
"(pmc_pc=" SIZE_FORMAT ", pmc_rm=" SIZE_FORMAT ", kac=" SIZE_FORMAT
|
||||
", kac_preclean=" SIZE_FORMAT ")",
|
||||
_ser_pmc_preclean_ovflw, _ser_pmc_remark_ovflw,
|
||||
_ser_kac_ovflw, _ser_kac_preclean_ovflw);
|
||||
}
|
||||
@ -4395,7 +4397,7 @@ void CMSCollector::checkpointRootsFinalWork() {
|
||||
if (_par_pmc_remark_ovflw > 0 || _par_kac_ovflw > 0) {
|
||||
if (PrintCMSStatistics != 0) {
|
||||
gclog_or_tty->print_cr("Work queue overflow (benign) "
|
||||
"(pmc_rm="SIZE_FORMAT", kac="SIZE_FORMAT")",
|
||||
"(pmc_rm=" SIZE_FORMAT ", kac=" SIZE_FORMAT ")",
|
||||
_par_pmc_remark_ovflw, _par_kac_ovflw);
|
||||
}
|
||||
_par_pmc_remark_ovflw = 0;
|
||||
@ -4403,12 +4405,12 @@ void CMSCollector::checkpointRootsFinalWork() {
|
||||
}
|
||||
if (PrintCMSStatistics != 0) {
|
||||
if (_markStack._hit_limit > 0) {
|
||||
gclog_or_tty->print_cr(" (benign) Hit max stack size limit ("SIZE_FORMAT")",
|
||||
gclog_or_tty->print_cr(" (benign) Hit max stack size limit (" SIZE_FORMAT ")",
|
||||
_markStack._hit_limit);
|
||||
}
|
||||
if (_markStack._failed_double > 0) {
|
||||
gclog_or_tty->print_cr(" (benign) Failed stack doubling ("SIZE_FORMAT"),"
|
||||
" current capacity "SIZE_FORMAT,
|
||||
gclog_or_tty->print_cr(" (benign) Failed stack doubling (" SIZE_FORMAT "),"
|
||||
" current capacity " SIZE_FORMAT,
|
||||
_markStack._failed_double,
|
||||
_markStack.capacity());
|
||||
}
|
||||
@ -5161,7 +5163,7 @@ void CMSCollector::do_remark_non_parallel() {
|
||||
&markFromDirtyCardsClosure);
|
||||
verify_work_stacks_empty();
|
||||
if (PrintCMSStatistics != 0) {
|
||||
gclog_or_tty->print(" (re-scanned "SIZE_FORMAT" dirty cards in cms gen) ",
|
||||
gclog_or_tty->print(" (re-scanned " SIZE_FORMAT " dirty cards in cms gen) ",
|
||||
markFromDirtyCardsClosure.num_dirty_cards());
|
||||
}
|
||||
}
|
||||
@ -6035,8 +6037,8 @@ void CMSMarkStack::expand() {
|
||||
} else if (_failed_double++ == 0 && !CMSConcurrentMTEnabled && PrintGCDetails) {
|
||||
// Failed to double capacity, continue;
|
||||
// we print a detail message only once per CMS cycle.
|
||||
gclog_or_tty->print(" (benign) Failed to expand marking stack from "SIZE_FORMAT"K to "
|
||||
SIZE_FORMAT"K",
|
||||
gclog_or_tty->print(" (benign) Failed to expand marking stack from " SIZE_FORMAT "K to "
|
||||
SIZE_FORMAT "K",
|
||||
_capacity / K, new_capacity / K);
|
||||
}
|
||||
}
|
||||
@ -7335,25 +7337,25 @@ SweepClosure::~SweepClosure() {
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
if (Verbose && PrintGC) {
|
||||
gclog_or_tty->print("Collected "SIZE_FORMAT" objects, " SIZE_FORMAT " bytes",
|
||||
gclog_or_tty->print("Collected " SIZE_FORMAT " objects, " SIZE_FORMAT " bytes",
|
||||
_numObjectsFreed, _numWordsFreed*sizeof(HeapWord));
|
||||
gclog_or_tty->print_cr("\nLive "SIZE_FORMAT" objects, "
|
||||
SIZE_FORMAT" bytes "
|
||||
"Already free "SIZE_FORMAT" objects, "SIZE_FORMAT" bytes",
|
||||
gclog_or_tty->print_cr("\nLive " SIZE_FORMAT " objects, "
|
||||
SIZE_FORMAT " bytes "
|
||||
"Already free " SIZE_FORMAT " objects, " SIZE_FORMAT " bytes",
|
||||
_numObjectsLive, _numWordsLive*sizeof(HeapWord),
|
||||
_numObjectsAlreadyFree, _numWordsAlreadyFree*sizeof(HeapWord));
|
||||
size_t totalBytes = (_numWordsFreed + _numWordsLive + _numWordsAlreadyFree)
|
||||
* sizeof(HeapWord);
|
||||
gclog_or_tty->print_cr("Total sweep: "SIZE_FORMAT" bytes", totalBytes);
|
||||
gclog_or_tty->print_cr("Total sweep: " SIZE_FORMAT " bytes", totalBytes);
|
||||
|
||||
if (PrintCMSStatistics && CMSVerifyReturnedBytes) {
|
||||
size_t indexListReturnedBytes = _sp->sumIndexedFreeListArrayReturnedBytes();
|
||||
size_t dict_returned_bytes = _sp->dictionary()->sum_dict_returned_bytes();
|
||||
size_t returned_bytes = indexListReturnedBytes + dict_returned_bytes;
|
||||
gclog_or_tty->print("Returned "SIZE_FORMAT" bytes", returned_bytes);
|
||||
gclog_or_tty->print(" Indexed List Returned "SIZE_FORMAT" bytes",
|
||||
gclog_or_tty->print("Returned " SIZE_FORMAT " bytes", returned_bytes);
|
||||
gclog_or_tty->print(" Indexed List Returned " SIZE_FORMAT " bytes",
|
||||
indexListReturnedBytes);
|
||||
gclog_or_tty->print_cr(" Dictionary Returned "SIZE_FORMAT" bytes",
|
||||
gclog_or_tty->print_cr(" Dictionary Returned " SIZE_FORMAT " bytes",
|
||||
dict_returned_bytes);
|
||||
}
|
||||
}
|
||||
@ -7432,12 +7434,12 @@ size_t SweepClosure::do_blk_careful(HeapWord* addr) {
|
||||
// coalesced chunk to the appropriate free list.
|
||||
if (inFreeRange()) {
|
||||
assert(freeFinger() >= _sp->bottom() && freeFinger() < _limit,
|
||||
err_msg("freeFinger() " PTR_FORMAT" is out-of-bounds", p2i(freeFinger())));
|
||||
err_msg("freeFinger() " PTR_FORMAT " is out-of-bounds", p2i(freeFinger())));
|
||||
flush_cur_free_chunk(freeFinger(),
|
||||
pointer_delta(addr, freeFinger()));
|
||||
if (CMSTraceSweeper) {
|
||||
gclog_or_tty->print("Sweep: last chunk: ");
|
||||
gclog_or_tty->print("put_free_blk " PTR_FORMAT " ("SIZE_FORMAT") "
|
||||
gclog_or_tty->print("put_free_blk " PTR_FORMAT " (" SIZE_FORMAT ") "
|
||||
"[coalesced:%d]\n",
|
||||
p2i(freeFinger()), pointer_delta(addr, freeFinger()),
|
||||
lastFreeRangeCoalesced() ? 1 : 0);
|
||||
|
@ -1021,7 +1021,7 @@ void ParNewGeneration::collect(bool full,
|
||||
to()->set_concurrent_iteration_safe_limit(to()->top());
|
||||
|
||||
if (ResizePLAB) {
|
||||
plab_stats()->adjust_desired_plab_sz(active_workers);
|
||||
plab_stats()->adjust_desired_plab_sz();
|
||||
}
|
||||
|
||||
if (PrintGC && !PrintGCDetails) {
|
||||
@ -1059,6 +1059,10 @@ void ParNewGeneration::collect(bool full,
|
||||
_gc_tracer.report_gc_end(_gc_timer->gc_end(), _gc_timer->time_partitions());
|
||||
}
|
||||
|
||||
size_t ParNewGeneration::desired_plab_sz() {
|
||||
return _plab_stats.desired_plab_sz(GenCollectedHeap::heap()->workers()->active_workers());
|
||||
}
|
||||
|
||||
static int sum;
|
||||
void ParNewGeneration::waste_some_time() {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
|
@ -411,9 +411,7 @@ class ParNewGeneration: public DefNewGeneration {
|
||||
return &_plab_stats;
|
||||
}
|
||||
|
||||
size_t desired_plab_sz() {
|
||||
return _plab_stats.desired_plab_sz();
|
||||
}
|
||||
size_t desired_plab_sz();
|
||||
|
||||
const ParNewTracer* gc_tracer() const {
|
||||
return &_gc_tracer;
|
||||
|
@ -119,7 +119,7 @@ void CollectionSetChooser::verify() {
|
||||
}
|
||||
guarantee(sum_of_reclaimable_bytes == _remaining_reclaimable_bytes,
|
||||
err_msg("reclaimable bytes inconsistent, "
|
||||
"remaining: "SIZE_FORMAT" sum: "SIZE_FORMAT,
|
||||
"remaining: " SIZE_FORMAT " sum: " SIZE_FORMAT,
|
||||
_remaining_reclaimable_bytes, sum_of_reclaimable_bytes));
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
|
@ -92,7 +92,7 @@ public:
|
||||
regions_at_put(_curr_index, NULL);
|
||||
assert(hr->reclaimable_bytes() <= _remaining_reclaimable_bytes,
|
||||
err_msg("remaining reclaimable bytes inconsistent "
|
||||
"from region: "SIZE_FORMAT" remaining: "SIZE_FORMAT,
|
||||
"from region: " SIZE_FORMAT " remaining: " SIZE_FORMAT,
|
||||
hr->reclaimable_bytes(), _remaining_reclaimable_bytes));
|
||||
_remaining_reclaimable_bytes -= hr->reclaimable_bytes();
|
||||
_curr_index += 1;
|
||||
|
@ -307,7 +307,7 @@ void CMMarkStack::expand() {
|
||||
if (PrintGCDetails && Verbose) {
|
||||
// Failed to double capacity, continue;
|
||||
gclog_or_tty->print(" (benign) Failed to expand marking stack capacity from "
|
||||
SIZE_FORMAT"K to " SIZE_FORMAT"K",
|
||||
SIZE_FORMAT "K to " SIZE_FORMAT "K",
|
||||
_capacity / K, new_capacity / K);
|
||||
}
|
||||
}
|
||||
@ -555,7 +555,7 @@ ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, G1RegionToSpaceMapper* prev
|
||||
_verbose_level = verbose_level;
|
||||
|
||||
if (verbose_low()) {
|
||||
gclog_or_tty->print_cr("[global] init, heap start = "PTR_FORMAT", "
|
||||
gclog_or_tty->print_cr("[global] init, heap start = " PTR_FORMAT ", "
|
||||
"heap end = " PTR_FORMAT, p2i(_heap_start), p2i(_heap_end));
|
||||
}
|
||||
|
||||
@ -802,7 +802,7 @@ void ConcurrentMark::set_concurrency_and_phase(uint active_tasks, bool concurren
|
||||
// in a STW phase.
|
||||
assert(!concurrent_marking_in_progress(), "invariant");
|
||||
assert(out_of_regions(),
|
||||
err_msg("only way to get here: _finger: "PTR_FORMAT", _heap_end: "PTR_FORMAT,
|
||||
err_msg("only way to get here: _finger: " PTR_FORMAT ", _heap_end: " PTR_FORMAT,
|
||||
p2i(_finger), p2i(_heap_end)));
|
||||
}
|
||||
}
|
||||
@ -1424,7 +1424,7 @@ public:
|
||||
|
||||
assert(start <= hr->end() && start <= ntams && ntams <= hr->end(),
|
||||
err_msg("Preconditions not met - "
|
||||
"start: "PTR_FORMAT", ntams: "PTR_FORMAT", end: "PTR_FORMAT,
|
||||
"start: " PTR_FORMAT ", ntams: " PTR_FORMAT ", end: " PTR_FORMAT,
|
||||
p2i(start), p2i(ntams), p2i(hr->end())));
|
||||
|
||||
// Find the first marked object at or after "start".
|
||||
@ -1725,10 +1725,10 @@ class FinalCountDataUpdateClosure: public CMCountDataClosureBase {
|
||||
}
|
||||
|
||||
assert(end_idx <= _card_bm->size(),
|
||||
err_msg("oob: end_idx= "SIZE_FORMAT", bitmap size= "SIZE_FORMAT,
|
||||
err_msg("oob: end_idx= " SIZE_FORMAT ", bitmap size= " SIZE_FORMAT,
|
||||
end_idx, _card_bm->size()));
|
||||
assert(start_idx < _card_bm->size(),
|
||||
err_msg("oob: start_idx= "SIZE_FORMAT", bitmap size= "SIZE_FORMAT,
|
||||
err_msg("oob: start_idx= " SIZE_FORMAT ", bitmap size= " SIZE_FORMAT,
|
||||
start_idx, _card_bm->size()));
|
||||
|
||||
_cm->set_card_bitmap_range(_card_bm, start_idx, end_idx, true /* is_par */);
|
||||
@ -2133,7 +2133,7 @@ class G1CMKeepAliveAndDrainClosure: public OopClosure {
|
||||
oop obj = oopDesc::load_decode_heap_oop(p);
|
||||
if (_cm->verbose_high()) {
|
||||
gclog_or_tty->print_cr("\t[%u] we're looking at location "
|
||||
"*"PTR_FORMAT" = "PTR_FORMAT,
|
||||
"*" PTR_FORMAT " = " PTR_FORMAT,
|
||||
_task->worker_id(), p2i(p), p2i((void*) obj));
|
||||
}
|
||||
|
||||
@ -2660,9 +2660,9 @@ ConcurrentMark::claim_region(uint worker_id) {
|
||||
HeapWord* limit = curr_region->next_top_at_mark_start();
|
||||
|
||||
if (verbose_low()) {
|
||||
gclog_or_tty->print_cr("[%u] curr_region = "PTR_FORMAT" "
|
||||
"["PTR_FORMAT", "PTR_FORMAT"), "
|
||||
"limit = "PTR_FORMAT,
|
||||
gclog_or_tty->print_cr("[%u] curr_region = " PTR_FORMAT " "
|
||||
"[" PTR_FORMAT ", " PTR_FORMAT "), "
|
||||
"limit = " PTR_FORMAT,
|
||||
worker_id, p2i(curr_region), p2i(bottom), p2i(end), p2i(limit));
|
||||
}
|
||||
|
||||
@ -2677,7 +2677,7 @@ ConcurrentMark::claim_region(uint worker_id) {
|
||||
|
||||
if (limit > bottom) {
|
||||
if (verbose_low()) {
|
||||
gclog_or_tty->print_cr("[%u] region "PTR_FORMAT" is not empty, "
|
||||
gclog_or_tty->print_cr("[%u] region " PTR_FORMAT " is not empty, "
|
||||
"returning it ", worker_id, p2i(curr_region));
|
||||
}
|
||||
return curr_region;
|
||||
@ -2685,7 +2685,7 @@ ConcurrentMark::claim_region(uint worker_id) {
|
||||
assert(limit == bottom,
|
||||
"the region limit should be at bottom");
|
||||
if (verbose_low()) {
|
||||
gclog_or_tty->print_cr("[%u] region "PTR_FORMAT" is empty, "
|
||||
gclog_or_tty->print_cr("[%u] region " PTR_FORMAT " is empty, "
|
||||
"returning NULL", worker_id, p2i(curr_region));
|
||||
}
|
||||
// we return NULL and the caller should try calling
|
||||
@ -2697,13 +2697,13 @@ ConcurrentMark::claim_region(uint worker_id) {
|
||||
if (verbose_low()) {
|
||||
if (curr_region == NULL) {
|
||||
gclog_or_tty->print_cr("[%u] found uncommitted region, moving finger, "
|
||||
"global finger = "PTR_FORMAT", "
|
||||
"our finger = "PTR_FORMAT,
|
||||
"global finger = " PTR_FORMAT ", "
|
||||
"our finger = " PTR_FORMAT,
|
||||
worker_id, p2i(_finger), p2i(finger));
|
||||
} else {
|
||||
gclog_or_tty->print_cr("[%u] somebody else moved the finger, "
|
||||
"global finger = "PTR_FORMAT", "
|
||||
"our finger = "PTR_FORMAT,
|
||||
"global finger = " PTR_FORMAT ", "
|
||||
"our finger = " PTR_FORMAT,
|
||||
worker_id, p2i(_finger), p2i(finger));
|
||||
}
|
||||
}
|
||||
@ -2739,7 +2739,7 @@ private:
|
||||
|
||||
void do_object_work(oop obj) {
|
||||
guarantee(!_g1h->obj_in_cs(obj),
|
||||
err_msg("obj: "PTR_FORMAT" in CSet, phase: %s, info: %d",
|
||||
err_msg("obj: " PTR_FORMAT " in CSet, phase: %s, info: %d",
|
||||
p2i((void*) obj), phase_str(), _info));
|
||||
}
|
||||
|
||||
@ -2800,7 +2800,7 @@ void ConcurrentMark::verify_no_cset_oops() {
|
||||
// here.
|
||||
HeapRegion* global_hr = _g1h->heap_region_containing_raw(global_finger);
|
||||
guarantee(global_hr == NULL || global_finger == global_hr->bottom(),
|
||||
err_msg("global finger: "PTR_FORMAT" region: "HR_FORMAT,
|
||||
err_msg("global finger: " PTR_FORMAT " region: " HR_FORMAT,
|
||||
p2i(global_finger), HR_FORMAT_PARAMS(global_hr)));
|
||||
}
|
||||
|
||||
@ -2814,7 +2814,7 @@ void ConcurrentMark::verify_no_cset_oops() {
|
||||
HeapRegion* task_hr = _g1h->heap_region_containing_raw(task_finger);
|
||||
guarantee(task_hr == NULL || task_finger == task_hr->bottom() ||
|
||||
!task_hr->in_collection_set(),
|
||||
err_msg("task finger: "PTR_FORMAT" region: "HR_FORMAT,
|
||||
err_msg("task finger: " PTR_FORMAT " region: " HR_FORMAT,
|
||||
p2i(task_finger), HR_FORMAT_PARAMS(task_hr)));
|
||||
}
|
||||
}
|
||||
@ -2856,8 +2856,8 @@ class AggregateCountDataHRClosure: public HeapRegionClosure {
|
||||
|
||||
assert(start <= limit && limit <= hr->top() && hr->top() <= hr->end(),
|
||||
err_msg("Preconditions not met - "
|
||||
"start: "PTR_FORMAT", limit: "PTR_FORMAT", "
|
||||
"top: "PTR_FORMAT", end: "PTR_FORMAT,
|
||||
"start: " PTR_FORMAT ", limit: " PTR_FORMAT ", "
|
||||
"top: " PTR_FORMAT ", end: " PTR_FORMAT,
|
||||
p2i(start), p2i(limit), p2i(hr->top()), p2i(hr->end())));
|
||||
|
||||
assert(hr->next_marked_bytes() == 0, "Precondition");
|
||||
@ -3118,7 +3118,7 @@ bool ConcurrentMark::do_yield_check(uint worker_id) {
|
||||
#ifndef PRODUCT
|
||||
// for debugging purposes
|
||||
void ConcurrentMark::print_finger() {
|
||||
gclog_or_tty->print_cr("heap ["PTR_FORMAT", "PTR_FORMAT"), global finger = "PTR_FORMAT,
|
||||
gclog_or_tty->print_cr("heap [" PTR_FORMAT ", " PTR_FORMAT "), global finger = " PTR_FORMAT,
|
||||
p2i(_heap_start), p2i(_heap_end), p2i(_finger));
|
||||
for (uint i = 0; i < _max_worker_id; ++i) {
|
||||
gclog_or_tty->print(" %u: " PTR_FORMAT, i, p2i(_tasks[i]->finger()));
|
||||
@ -3203,7 +3203,7 @@ void CMTask::setup_for_region(HeapRegion* hr) {
|
||||
"claim_region() should have filtered out continues humongous regions");
|
||||
|
||||
if (_cm->verbose_low()) {
|
||||
gclog_or_tty->print_cr("[%u] setting up for region "PTR_FORMAT,
|
||||
gclog_or_tty->print_cr("[%u] setting up for region " PTR_FORMAT,
|
||||
_worker_id, p2i(hr));
|
||||
}
|
||||
|
||||
@ -3220,7 +3220,7 @@ void CMTask::update_region_limit() {
|
||||
if (limit == bottom) {
|
||||
if (_cm->verbose_low()) {
|
||||
gclog_or_tty->print_cr("[%u] found an empty region "
|
||||
"["PTR_FORMAT", "PTR_FORMAT")",
|
||||
"[" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
_worker_id, p2i(bottom), p2i(limit));
|
||||
}
|
||||
// The region was collected underneath our feet.
|
||||
@ -3252,7 +3252,7 @@ void CMTask::update_region_limit() {
|
||||
void CMTask::giveup_current_region() {
|
||||
assert(_curr_region != NULL, "invariant");
|
||||
if (_cm->verbose_low()) {
|
||||
gclog_or_tty->print_cr("[%u] giving up region "PTR_FORMAT,
|
||||
gclog_or_tty->print_cr("[%u] giving up region " PTR_FORMAT,
|
||||
_worker_id, p2i(_curr_region));
|
||||
}
|
||||
clear_region_fields();
|
||||
@ -3374,7 +3374,7 @@ void CMTask::regular_clock_call() {
|
||||
|
||||
if (_cm->verbose_medium()) {
|
||||
gclog_or_tty->print_cr("[%u] regular clock, interval = %1.2lfms, "
|
||||
"scanned = "SIZE_FORMAT"%s, refs reached = "SIZE_FORMAT"%s",
|
||||
"scanned = " SIZE_FORMAT "%s, refs reached = " SIZE_FORMAT "%s",
|
||||
_worker_id, last_interval_ms,
|
||||
_words_scanned,
|
||||
(_words_scanned >= _words_scanned_limit) ? " (*)" : "",
|
||||
@ -3543,7 +3543,7 @@ void CMTask::drain_local_queue(bool partially) {
|
||||
statsOnly( ++_local_pops );
|
||||
|
||||
if (_cm->verbose_high()) {
|
||||
gclog_or_tty->print_cr("[%u] popped "PTR_FORMAT, _worker_id,
|
||||
gclog_or_tty->print_cr("[%u] popped " PTR_FORMAT, _worker_id,
|
||||
p2i((void*) obj));
|
||||
}
|
||||
|
||||
@ -3900,8 +3900,8 @@ void CMTask::do_marking_step(double time_target_ms,
|
||||
|
||||
if (_cm->verbose_low()) {
|
||||
gclog_or_tty->print_cr("[%u] we're scanning part "
|
||||
"["PTR_FORMAT", "PTR_FORMAT") "
|
||||
"of region "HR_FORMAT,
|
||||
"[" PTR_FORMAT ", " PTR_FORMAT ") "
|
||||
"of region " HR_FORMAT,
|
||||
_worker_id, p2i(_finger), p2i(_region_limit),
|
||||
HR_FORMAT_PARAMS(_curr_region));
|
||||
}
|
||||
@ -3988,7 +3988,7 @@ void CMTask::do_marking_step(double time_target_ms,
|
||||
|
||||
if (_cm->verbose_low()) {
|
||||
gclog_or_tty->print_cr("[%u] we successfully claimed "
|
||||
"region "PTR_FORMAT,
|
||||
"region " PTR_FORMAT,
|
||||
_worker_id, p2i(claimed_region));
|
||||
}
|
||||
|
||||
@ -4049,7 +4049,7 @@ void CMTask::do_marking_step(double time_target_ms,
|
||||
|
||||
if (_cm->try_stealing(_worker_id, &_hash_seed, obj)) {
|
||||
if (_cm->verbose_medium()) {
|
||||
gclog_or_tty->print_cr("[%u] stolen "PTR_FORMAT" successfully",
|
||||
gclog_or_tty->print_cr("[%u] stolen " PTR_FORMAT " successfully",
|
||||
_worker_id, p2i((void*) obj));
|
||||
}
|
||||
|
||||
@ -4257,7 +4257,7 @@ CMTask::CMTask(uint worker_id,
|
||||
// identify them easily in a large log file.
|
||||
#define G1PPRL_LINE_PREFIX "###"
|
||||
|
||||
#define G1PPRL_ADDR_BASE_FORMAT " "PTR_FORMAT"-"PTR_FORMAT
|
||||
#define G1PPRL_ADDR_BASE_FORMAT " " PTR_FORMAT "-" PTR_FORMAT
|
||||
#ifdef _LP64
|
||||
#define G1PPRL_ADDR_BASE_H_FORMAT " %37s"
|
||||
#else // _LP64
|
||||
@ -4267,16 +4267,16 @@ CMTask::CMTask(uint worker_id,
|
||||
// For per-region info
|
||||
#define G1PPRL_TYPE_FORMAT " %-4s"
|
||||
#define G1PPRL_TYPE_H_FORMAT " %4s"
|
||||
#define G1PPRL_BYTE_FORMAT " "SIZE_FORMAT_W(9)
|
||||
#define G1PPRL_BYTE_FORMAT " " SIZE_FORMAT_W(9)
|
||||
#define G1PPRL_BYTE_H_FORMAT " %9s"
|
||||
#define G1PPRL_DOUBLE_FORMAT " %14.1f"
|
||||
#define G1PPRL_DOUBLE_H_FORMAT " %14s"
|
||||
|
||||
// For summary info
|
||||
#define G1PPRL_SUM_ADDR_FORMAT(tag) " "tag":"G1PPRL_ADDR_BASE_FORMAT
|
||||
#define G1PPRL_SUM_BYTE_FORMAT(tag) " "tag": "SIZE_FORMAT
|
||||
#define G1PPRL_SUM_MB_FORMAT(tag) " "tag": %1.2f MB"
|
||||
#define G1PPRL_SUM_MB_PERC_FORMAT(tag) G1PPRL_SUM_MB_FORMAT(tag)" / %1.2f %%"
|
||||
#define G1PPRL_SUM_ADDR_FORMAT(tag) " " tag ":" G1PPRL_ADDR_BASE_FORMAT
|
||||
#define G1PPRL_SUM_BYTE_FORMAT(tag) " " tag ": " SIZE_FORMAT
|
||||
#define G1PPRL_SUM_MB_FORMAT(tag) " " tag ": %1.2f MB"
|
||||
#define G1PPRL_SUM_MB_PERC_FORMAT(tag) G1PPRL_SUM_MB_FORMAT(tag) " / %1.2f %%"
|
||||
|
||||
G1PrintRegionLivenessInfoClosure::
|
||||
G1PrintRegionLivenessInfoClosure(outputStream* out, const char* phase_name)
|
||||
|
@ -197,8 +197,8 @@ inline bool CMBitMapRO::iterate(BitMapClosure* cl) {
|
||||
assert(_bmStartWord <= (addr) && (addr) < (_bmStartWord + _bmWordSize), \
|
||||
"outside underlying space?"); \
|
||||
assert(G1CollectedHeap::heap()->is_in_exact(addr), \
|
||||
err_msg("Trying to access not available bitmap "PTR_FORMAT \
|
||||
" corresponding to "PTR_FORMAT" (%u)", \
|
||||
err_msg("Trying to access not available bitmap " PTR_FORMAT \
|
||||
" corresponding to " PTR_FORMAT " (%u)", \
|
||||
p2i(this), p2i(addr), G1CollectedHeap::heap()->addr_to_region(addr)));
|
||||
|
||||
inline void CMBitMap::mark(HeapWord* addr) {
|
||||
@ -344,7 +344,7 @@ inline void CMTask::make_reference_grey(oop obj, HeapRegion* hr) {
|
||||
|
||||
inline void CMTask::deal_with_reference(oop obj) {
|
||||
if (_cm->verbose_high()) {
|
||||
gclog_or_tty->print_cr("[%u] we're dealing with reference = "PTR_FORMAT,
|
||||
gclog_or_tty->print_cr("[%u] we're dealing with reference = " PTR_FORMAT,
|
||||
_worker_id, p2i((void*) obj));
|
||||
}
|
||||
|
||||
@ -393,7 +393,7 @@ inline void ConcurrentMark::grayRoot(oop obj, size_t word_size,
|
||||
// assert that word_size is under an upper bound which is its
|
||||
// containing region's capacity.
|
||||
assert(word_size * HeapWordSize <= hr->capacity(),
|
||||
err_msg("size: "SIZE_FORMAT" capacity: "SIZE_FORMAT" "HR_FORMAT,
|
||||
err_msg("size: " SIZE_FORMAT " capacity: " SIZE_FORMAT " " HR_FORMAT,
|
||||
word_size * HeapWordSize, hr->capacity(),
|
||||
HR_FORMAT_PARAMS(hr)));
|
||||
|
||||
|
@ -44,8 +44,7 @@ SurrogateLockerThread*
|
||||
ConcurrentMarkThread::ConcurrentMarkThread(ConcurrentMark* cm) :
|
||||
ConcurrentGCThread(),
|
||||
_cm(cm),
|
||||
_started(false),
|
||||
_in_progress(false),
|
||||
_state(Idle),
|
||||
_vtime_accum(0.0),
|
||||
_vtime_mark_accum(0.0) {
|
||||
|
||||
@ -307,7 +306,6 @@ void ConcurrentMarkThread::sleepBeforeNextCycle() {
|
||||
|
||||
if (started()) {
|
||||
set_in_progress();
|
||||
clear_started();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -47,8 +47,14 @@ class ConcurrentMarkThread: public ConcurrentGCThread {
|
||||
|
||||
private:
|
||||
ConcurrentMark* _cm;
|
||||
volatile bool _started;
|
||||
volatile bool _in_progress;
|
||||
|
||||
enum State {
|
||||
Idle,
|
||||
Started,
|
||||
InProgress
|
||||
};
|
||||
|
||||
volatile State _state;
|
||||
|
||||
void sleepBeforeNextCycle();
|
||||
|
||||
@ -68,23 +74,22 @@ class ConcurrentMarkThread: public ConcurrentGCThread {
|
||||
|
||||
ConcurrentMark* cm() { return _cm; }
|
||||
|
||||
void set_started() { assert(!_in_progress, "cycle in progress"); _started = true; }
|
||||
void clear_started() { assert(_in_progress, "must be starting a cycle"); _started = false; }
|
||||
bool started() { return _started; }
|
||||
void set_idle() { assert(_state != Started, "must not be starting a new cycle"); _state = Idle; }
|
||||
bool idle() { return _state == Idle; }
|
||||
void set_started() { assert(_state == Idle, "cycle in progress"); _state = Started; }
|
||||
bool started() { return _state == Started; }
|
||||
void set_in_progress() { assert(_state == Started, "must be starting a cycle"); _state = InProgress; }
|
||||
bool in_progress() { return _state == InProgress; }
|
||||
|
||||
void set_in_progress() { assert(_started, "must be starting a cycle"); _in_progress = true; }
|
||||
void clear_in_progress() { assert(!_started, "must not be starting a new cycle"); _in_progress = false; }
|
||||
bool in_progress() { return _in_progress; }
|
||||
|
||||
// This flag returns true from the moment a marking cycle is
|
||||
// Returns true from the moment a marking cycle is
|
||||
// initiated (during the initial-mark pause when started() is set)
|
||||
// to the moment when the cycle completes (just after the next
|
||||
// marking bitmap has been cleared and in_progress() is
|
||||
// cleared). While this flag is true we will not start another cycle
|
||||
// cleared). While during_cycle() is true we will not start another cycle
|
||||
// so that cycles do not overlap. We cannot use just in_progress()
|
||||
// as the CM thread might take some time to wake up before noticing
|
||||
// that started() is set and set in_progress().
|
||||
bool during_cycle() { return started() || in_progress(); }
|
||||
bool during_cycle() { return !idle(); }
|
||||
|
||||
// shutdown
|
||||
void stop();
|
||||
|
@ -140,7 +140,7 @@ HeapWord* G1AllocRegion::new_alloc_region_and_allocate(size_t word_size,
|
||||
}
|
||||
|
||||
void G1AllocRegion::fill_in_ext_msg(ar_ext_msg* msg, const char* message) {
|
||||
msg->append("[%s] %s c: %u b: %s r: "PTR_FORMAT" u: "SIZE_FORMAT,
|
||||
msg->append("[%s] %s c: %u b: %s r: " PTR_FORMAT " u: " SIZE_FORMAT,
|
||||
_name, message, _count, BOOL_TO_STR(_bot_updates),
|
||||
p2i(_alloc_region), _used_bytes_before);
|
||||
}
|
||||
@ -217,7 +217,7 @@ void G1AllocRegion::trace(const char* str, size_t word_size, HeapWord* result) {
|
||||
|
||||
if (G1_ALLOC_REGION_TRACING > 1) {
|
||||
if (result != NULL) {
|
||||
jio_snprintf(rest_buffer, buffer_length, SIZE_FORMAT" "PTR_FORMAT,
|
||||
jio_snprintf(rest_buffer, buffer_length, SIZE_FORMAT " " PTR_FORMAT,
|
||||
word_size, result);
|
||||
} else if (word_size != 0) {
|
||||
jio_snprintf(rest_buffer, buffer_length, SIZE_FORMAT, word_size);
|
||||
|
@ -86,7 +86,7 @@ void G1DefaultAllocator::init_gc_alloc_regions(EvacuationInfo& evacuation_info)
|
||||
&_retained_old_gc_alloc_region);
|
||||
}
|
||||
|
||||
void G1DefaultAllocator::release_gc_alloc_regions(uint no_of_gc_workers, EvacuationInfo& evacuation_info) {
|
||||
void G1DefaultAllocator::release_gc_alloc_regions(EvacuationInfo& evacuation_info) {
|
||||
AllocationContext_t context = AllocationContext::current();
|
||||
evacuation_info.set_allocation_regions(survivor_gc_alloc_region(context)->count() +
|
||||
old_gc_alloc_region(context)->count());
|
||||
@ -102,8 +102,8 @@ void G1DefaultAllocator::release_gc_alloc_regions(uint no_of_gc_workers, Evacuat
|
||||
}
|
||||
|
||||
if (ResizePLAB) {
|
||||
_g1h->alloc_buffer_stats(InCSetState::Young)->adjust_desired_plab_sz(no_of_gc_workers);
|
||||
_g1h->alloc_buffer_stats(InCSetState::Old)->adjust_desired_plab_sz(no_of_gc_workers);
|
||||
_g1h->alloc_buffer_stats(InCSetState::Young)->adjust_desired_plab_sz();
|
||||
_g1h->alloc_buffer_stats(InCSetState::Old)->adjust_desired_plab_sz();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ public:
|
||||
virtual void release_mutator_alloc_region() = 0;
|
||||
|
||||
virtual void init_gc_alloc_regions(EvacuationInfo& evacuation_info) = 0;
|
||||
virtual void release_gc_alloc_regions(uint no_of_gc_workers, EvacuationInfo& evacuation_info) = 0;
|
||||
virtual void release_gc_alloc_regions(EvacuationInfo& evacuation_info) = 0;
|
||||
virtual void abandon_gc_alloc_regions() = 0;
|
||||
|
||||
virtual MutatorAllocRegion* mutator_alloc_region(AllocationContext_t context) = 0;
|
||||
@ -76,7 +76,7 @@ public:
|
||||
|
||||
void decrease_used(size_t bytes) {
|
||||
assert(_summary_bytes_used >= bytes,
|
||||
err_msg("invariant: _summary_bytes_used: "SIZE_FORMAT" should be >= bytes: "SIZE_FORMAT,
|
||||
err_msg("invariant: _summary_bytes_used: " SIZE_FORMAT " should be >= bytes: " SIZE_FORMAT,
|
||||
_summary_bytes_used, bytes));
|
||||
_summary_bytes_used -= bytes;
|
||||
}
|
||||
@ -114,7 +114,7 @@ public:
|
||||
virtual void release_mutator_alloc_region();
|
||||
|
||||
virtual void init_gc_alloc_regions(EvacuationInfo& evacuation_info);
|
||||
virtual void release_gc_alloc_regions(uint no_of_gc_workers, EvacuationInfo& evacuation_info);
|
||||
virtual void release_gc_alloc_regions(EvacuationInfo& evacuation_info);
|
||||
virtual void abandon_gc_alloc_regions();
|
||||
|
||||
virtual bool is_retained_old_region(HeapRegion* hr) {
|
||||
|
@ -36,19 +36,19 @@ address G1BiasedMappedArrayBase::create_new_base_array(size_t length, size_t ele
|
||||
#ifndef PRODUCT
|
||||
void G1BiasedMappedArrayBase::verify_index(idx_t index) const {
|
||||
guarantee(_base != NULL, "Array not initialized");
|
||||
guarantee(index < length(), err_msg("Index out of bounds index: "SIZE_FORMAT" length: "SIZE_FORMAT, index, length()));
|
||||
guarantee(index < length(), err_msg("Index out of bounds index: " SIZE_FORMAT " length: " SIZE_FORMAT, index, length()));
|
||||
}
|
||||
|
||||
void G1BiasedMappedArrayBase::verify_biased_index(idx_t biased_index) const {
|
||||
guarantee(_biased_base != NULL, "Array not initialized");
|
||||
guarantee(biased_index >= bias() && biased_index < (bias() + length()),
|
||||
err_msg("Biased index out of bounds, index: "SIZE_FORMAT" bias: "SIZE_FORMAT" length: "SIZE_FORMAT, biased_index, bias(), length()));
|
||||
err_msg("Biased index out of bounds, index: " SIZE_FORMAT " bias: " SIZE_FORMAT " length: " SIZE_FORMAT, biased_index, bias(), length()));
|
||||
}
|
||||
|
||||
void G1BiasedMappedArrayBase::verify_biased_index_inclusive_end(idx_t biased_index) const {
|
||||
guarantee(_biased_base != NULL, "Array not initialized");
|
||||
guarantee(biased_index >= bias() && biased_index <= (bias() + length()),
|
||||
err_msg("Biased index out of inclusive bounds, index: "SIZE_FORMAT" bias: "SIZE_FORMAT" length: "SIZE_FORMAT, biased_index, bias(), length()));
|
||||
err_msg("Biased index out of inclusive bounds, index: " SIZE_FORMAT " bias: " SIZE_FORMAT " length: " SIZE_FORMAT, biased_index, bias(), length()));
|
||||
}
|
||||
|
||||
class TestMappedArray : public G1BiasedMappedArray<int> {
|
||||
|
@ -71,10 +71,10 @@ protected:
|
||||
assert(is_power_of_2(mapping_granularity_in_bytes),
|
||||
err_msg("mapping granularity must be power of 2, is %zd", mapping_granularity_in_bytes));
|
||||
assert((uintptr_t)bottom % mapping_granularity_in_bytes == 0,
|
||||
err_msg("bottom mapping area address must be a multiple of mapping granularity %zd, is "PTR_FORMAT,
|
||||
err_msg("bottom mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT,
|
||||
mapping_granularity_in_bytes, p2i(bottom)));
|
||||
assert((uintptr_t)end % mapping_granularity_in_bytes == 0,
|
||||
err_msg("end mapping area address must be a multiple of mapping granularity %zd, is "PTR_FORMAT,
|
||||
err_msg("end mapping area address must be a multiple of mapping granularity %zd, is " PTR_FORMAT,
|
||||
mapping_granularity_in_bytes, p2i(end)));
|
||||
size_t num_target_elems = pointer_delta(end, bottom, mapping_granularity_in_bytes);
|
||||
idx_t bias = (uintptr_t)bottom / mapping_granularity_in_bytes;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user