Merge
This commit is contained in:
commit
4bc795f2db
1
.hgtags
1
.hgtags
@ -248,3 +248,4 @@ b32e2219736e42baaf45daf0ad67ed34f6033799 jdk9-b02
|
|||||||
7f655f31f9bcee618cf832f08176ad8c1ed3fdd3 jdk9-b03
|
7f655f31f9bcee618cf832f08176ad8c1ed3fdd3 jdk9-b03
|
||||||
099891b1d86f3719e116ac717ffdafc90d037fb7 jdk9-b04
|
099891b1d86f3719e116ac717ffdafc90d037fb7 jdk9-b04
|
||||||
dd311791ad6895a3989020dd6c6c46db87972ab8 jdk9-b05
|
dd311791ad6895a3989020dd6c6c46db87972ab8 jdk9-b05
|
||||||
|
85dbdc227c5e11429b4fc4a8ba763f50107edd6e jdk9-b06
|
||||||
|
@ -248,3 +248,4 @@ cd3825b2983045784d6fc6d1729c799b08215752 jdk8-b120
|
|||||||
fd8d51bdf9aadf7ae83e65e8655c53581017c363 jdk9-b03
|
fd8d51bdf9aadf7ae83e65e8655c53581017c363 jdk9-b03
|
||||||
cb4c3440bc2748101923e2488506e61009ab1bf5 jdk9-b04
|
cb4c3440bc2748101923e2488506e61009ab1bf5 jdk9-b04
|
||||||
8c63f0b6ada282f27e3a80125e53c3be603f9af7 jdk9-b05
|
8c63f0b6ada282f27e3a80125e53c3be603f9af7 jdk9-b05
|
||||||
|
d0b525cd31b87abeb6d5b7e3516953eeb13b323c jdk9-b06
|
||||||
|
@ -248,3 +248,4 @@ a7d3638deb2f4e33217b1ecf889479e90f9e5b50 jdk9-b00
|
|||||||
d338b892a13db19b093f85cf5f949a4504e4d31f jdk9-b03
|
d338b892a13db19b093f85cf5f949a4504e4d31f jdk9-b03
|
||||||
1ed19de263e1e0772da0269118cdd9deeb9fff04 jdk9-b04
|
1ed19de263e1e0772da0269118cdd9deeb9fff04 jdk9-b04
|
||||||
167c39eb44731a5d66770d0f00e231164653a2ff jdk9-b05
|
167c39eb44731a5d66770d0f00e231164653a2ff jdk9-b05
|
||||||
|
a4bf701ac316946c2e5e83138ad8e687da6a4b30 jdk9-b06
|
||||||
|
@ -408,3 +408,4 @@ b188446de75bda5fc52d102cddf242c3ef5ecbdf jdk9-b02
|
|||||||
b2fee789d23f3cdabb3db4e51af43038e5692d3a jdk9-b03
|
b2fee789d23f3cdabb3db4e51af43038e5692d3a jdk9-b03
|
||||||
3812c088b9456ee22c933e88aee1ece71f4e783a jdk9-b04
|
3812c088b9456ee22c933e88aee1ece71f4e783a jdk9-b04
|
||||||
bdc5311e1db7598589b77015119b821bf8c828bd jdk9-b05
|
bdc5311e1db7598589b77015119b821bf8c828bd jdk9-b05
|
||||||
|
52377a30a3f87b62d6135706997b8c7a47366e37 jdk9-b06
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -162,30 +162,29 @@ open_debug_file (const char *pathname, unsigned int crc)
|
|||||||
static struct elf_section *find_section_by_name(char *name,
|
static struct elf_section *find_section_by_name(char *name,
|
||||||
int fd,
|
int fd,
|
||||||
ELF_EHDR *ehdr,
|
ELF_EHDR *ehdr,
|
||||||
ELF_SHDR *shbuf,
|
|
||||||
struct elf_section *scn_cache)
|
struct elf_section *scn_cache)
|
||||||
{
|
{
|
||||||
ELF_SHDR* cursct = NULL;
|
|
||||||
char *strtab;
|
char *strtab;
|
||||||
int cnt;
|
int cnt;
|
||||||
|
int strtab_size;
|
||||||
|
|
||||||
|
// Section cache have to already contain data for e_shstrndx section.
|
||||||
|
// If it's not true - elf file is broken, so just bail out
|
||||||
if (scn_cache[ehdr->e_shstrndx].c_data == NULL) {
|
if (scn_cache[ehdr->e_shstrndx].c_data == NULL) {
|
||||||
if ((scn_cache[ehdr->e_shstrndx].c_data
|
|
||||||
= read_section_data(fd, ehdr, cursct)) == NULL) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
strtab = scn_cache[ehdr->e_shstrndx].c_data;
|
strtab = scn_cache[ehdr->e_shstrndx].c_data;
|
||||||
|
strtab_size = scn_cache[ehdr->e_shstrndx].c_shdr->sh_size;
|
||||||
|
|
||||||
for (cursct = shbuf, cnt = 0;
|
for (cnt = 0; cnt < ehdr->e_shnum; ++cnt) {
|
||||||
cnt < ehdr->e_shnum;
|
if (scn_cache[cnt].c_shdr->sh_name < strtab_size) {
|
||||||
cnt++, cursct++) {
|
if (strcmp(scn_cache[cnt].c_shdr->sh_name + strtab, name) == 0) {
|
||||||
if (strcmp(cursct->sh_name + strtab, name) == 0) {
|
scn_cache[cnt].c_data = read_section_data(fd, ehdr, scn_cache[cnt].c_shdr);
|
||||||
scn_cache[cnt].c_data = read_section_data(fd, ehdr, cursct);
|
|
||||||
return &scn_cache[cnt];
|
return &scn_cache[cnt];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -195,12 +194,11 @@ static struct elf_section *find_section_by_name(char *name,
|
|||||||
static int open_file_from_debug_link(const char *name,
|
static int open_file_from_debug_link(const char *name,
|
||||||
int fd,
|
int fd,
|
||||||
ELF_EHDR *ehdr,
|
ELF_EHDR *ehdr,
|
||||||
ELF_SHDR *shbuf,
|
|
||||||
struct elf_section *scn_cache)
|
struct elf_section *scn_cache)
|
||||||
{
|
{
|
||||||
int debug_fd;
|
int debug_fd;
|
||||||
struct elf_section *debug_link = find_section_by_name(".gnu_debuglink", fd, ehdr,
|
struct elf_section *debug_link = find_section_by_name(".gnu_debuglink", fd, ehdr,
|
||||||
shbuf, scn_cache);
|
scn_cache);
|
||||||
if (debug_link == NULL)
|
if (debug_link == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
char *debug_filename = debug_link->c_data;
|
char *debug_filename = debug_link->c_data;
|
||||||
@ -221,7 +219,6 @@ static int open_file_from_debug_link(const char *name,
|
|||||||
|
|
||||||
/* Look in the same directory as the object. */
|
/* Look in the same directory as the object. */
|
||||||
strcpy(last_slash+1, debug_filename);
|
strcpy(last_slash+1, debug_filename);
|
||||||
|
|
||||||
debug_fd = open_debug_file(debug_pathname, crc);
|
debug_fd = open_debug_file(debug_pathname, crc);
|
||||||
if (debug_fd >= 0) {
|
if (debug_fd >= 0) {
|
||||||
free(debug_pathname);
|
free(debug_pathname);
|
||||||
@ -261,10 +258,9 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t
|
|||||||
static struct symtab *build_symtab_from_debug_link(const char *name,
|
static struct symtab *build_symtab_from_debug_link(const char *name,
|
||||||
int fd,
|
int fd,
|
||||||
ELF_EHDR *ehdr,
|
ELF_EHDR *ehdr,
|
||||||
ELF_SHDR *shbuf,
|
|
||||||
struct elf_section *scn_cache)
|
struct elf_section *scn_cache)
|
||||||
{
|
{
|
||||||
fd = open_file_from_debug_link(name, fd, ehdr, shbuf, scn_cache);
|
fd = open_file_from_debug_link(name, fd, ehdr, scn_cache);
|
||||||
|
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
struct symtab *symtab = build_symtab_internal(fd, NULL, /* try_debuginfo */ false);
|
struct symtab *symtab = build_symtab_internal(fd, NULL, /* try_debuginfo */ false);
|
||||||
@ -463,7 +459,7 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t
|
|||||||
|
|
||||||
// Then, if that doesn't work, the debug link
|
// Then, if that doesn't work, the debug link
|
||||||
if (symtab == NULL) {
|
if (symtab == NULL) {
|
||||||
symtab = build_symtab_from_debug_link(filename, fd, &ehdr, shbuf,
|
symtab = build_symtab_from_debug_link(filename, fd, &ehdr,
|
||||||
scn_cache);
|
scn_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,8 +66,8 @@ ifndef CC_INTERP
|
|||||||
FORCE_TIERED=1
|
FORCE_TIERED=1
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
# C1 is not ported on ppc64(le), so we cannot build a tiered VM:
|
# C1 is not ported on ppc64, so we cannot build a tiered VM:
|
||||||
ifneq (,$(filter $(ARCH),ppc64 pp64le))
|
ifeq ($(ARCH),ppc64)
|
||||||
FORCE_TIERED=0
|
FORCE_TIERED=0
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -33,6 +33,11 @@ SLASH_JAVA ?= /java
|
|||||||
# ARCH can be set explicitly in spec.gmk
|
# ARCH can be set explicitly in spec.gmk
|
||||||
ifndef ARCH
|
ifndef ARCH
|
||||||
ARCH := $(shell uname -m)
|
ARCH := $(shell uname -m)
|
||||||
|
# Fold little endian PowerPC64 into big-endian (if ARCH is set in
|
||||||
|
# hotspot-spec.gmk, this will be done by the configure script).
|
||||||
|
ifeq ($(ARCH),ppc64le)
|
||||||
|
ARCH := ppc64
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
PATH_SEP ?= :
|
PATH_SEP ?= :
|
||||||
|
@ -26,14 +26,26 @@
|
|||||||
# make c code know it is on a 64 bit platform.
|
# make c code know it is on a 64 bit platform.
|
||||||
CFLAGS += -D_LP64=1
|
CFLAGS += -D_LP64=1
|
||||||
|
|
||||||
|
ifeq ($(origin OPENJDK_TARGET_CPU_ENDIAN),undefined)
|
||||||
|
# This can happen during hotspot standalone build. Set endianness from
|
||||||
|
# uname. We assume build and target machines are the same.
|
||||||
|
OPENJDK_TARGET_CPU_ENDIAN:=$(if $(filter ppc64le,$(shell uname -m)),little,big)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(filter $(OPENJDK_TARGET_CPU_ENDIAN),big little),)
|
||||||
|
$(error OPENJDK_TARGET_CPU_ENDIAN value should be 'big' or 'little')
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(OPENJDK_TARGET_CPU_ENDIAN),big)
|
||||||
# fixes `relocation truncated to fit' error for gcc 4.1.
|
# fixes `relocation truncated to fit' error for gcc 4.1.
|
||||||
CFLAGS += -mminimal-toc
|
CFLAGS += -mminimal-toc
|
||||||
|
|
||||||
# finds use ppc64 instructions, but schedule for power5
|
# finds use ppc64 instructions, but schedule for power5
|
||||||
CFLAGS += -mcpu=powerpc64 -mtune=power5 -minsert-sched-nops=regroup_exact -mno-multiple -mno-string
|
CFLAGS += -mcpu=powerpc64 -mtune=power5 -minsert-sched-nops=regroup_exact -mno-multiple -mno-string
|
||||||
|
else
|
||||||
|
# Little endian machine uses ELFv2 ABI.
|
||||||
|
CFLAGS += -DVM_LITTLE_ENDIAN -DABI_ELFv2
|
||||||
|
|
||||||
# let linker find external 64 bit libs.
|
# Use Power8, this is the first CPU to support PPC64 LE with ELFv2 ABI.
|
||||||
LFLAGS_VM += -L/lib64
|
CFLAGS += -mcpu=power7 -mtune=power8 -minsert-sched-nops=regroup_exact -mno-multiple -mno-string
|
||||||
|
endif
|
||||||
# specify lib format.
|
|
||||||
LFLAGS_VM += -Wl,-melf64ppc
|
|
||||||
|
@ -260,7 +260,6 @@ ifeq ($(JVM_VARIANT_SERVER),true)
|
|||||||
EXPORT_LIST += $(EXPORT_SERVER_DIR)/jvm.map
|
EXPORT_LIST += $(EXPORT_SERVER_DIR)/jvm.map
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
EXPORT_LIST += $(EXPORT_LIB_DIR)/jvm.lib
|
|
||||||
endif
|
endif
|
||||||
ifeq ($(JVM_VARIANT_CLIENT),true)
|
ifeq ($(JVM_VARIANT_CLIENT),true)
|
||||||
EXPORT_LIST += $(EXPORT_CLIENT_DIR)/Xusage.txt
|
EXPORT_LIST += $(EXPORT_CLIENT_DIR)/Xusage.txt
|
||||||
@ -275,6 +274,8 @@ ifeq ($(JVM_VARIANT_CLIENT),true)
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
EXPORT_LIST += $(EXPORT_LIB_DIR)/jvm.lib
|
||||||
|
|
||||||
ifeq ($(BUILD_WIN_SA), 1)
|
ifeq ($(BUILD_WIN_SA), 1)
|
||||||
EXPORT_LIST += $(EXPORT_JRE_BIN_DIR)/sawindbg.$(LIBRARY_SUFFIX)
|
EXPORT_LIST += $(EXPORT_JRE_BIN_DIR)/sawindbg.$(LIBRARY_SUFFIX)
|
||||||
ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
|
ifeq ($(ENABLE_FULL_DEBUG_SYMBOLS),1)
|
||||||
|
@ -1025,15 +1025,14 @@ class Assembler : public AbstractAssembler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void set_imm(int* instr, short s) {
|
static void set_imm(int* instr, short s) {
|
||||||
short* p = ((short *)instr) + 1;
|
// imm is always in the lower 16 bits of the instruction,
|
||||||
*p = s;
|
// so this is endian-neutral. Same for the get_imm below.
|
||||||
|
uint32_t w = *(uint32_t *)instr;
|
||||||
|
*instr = (int)((w & ~0x0000FFFF) | (s & 0x0000FFFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_imm(address a, int instruction_number) {
|
static int get_imm(address a, int instruction_number) {
|
||||||
short imm;
|
return (short)((int *)a)[instruction_number];
|
||||||
short *p =((short *)a)+2*instruction_number+1;
|
|
||||||
imm = *p;
|
|
||||||
return (int)imm;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int hi16_signed( int x) { return (int)(int16_t)(x >> 16); }
|
static inline int hi16_signed( int x) { return (int)(int16_t)(x >> 16); }
|
||||||
|
@ -35,6 +35,126 @@ class Bytes: AllStatic {
|
|||||||
|
|
||||||
// Can I count on address always being a pointer to an unsigned char? Yes.
|
// Can I count on address always being a pointer to an unsigned char? Yes.
|
||||||
|
|
||||||
|
#if defined(VM_LITTLE_ENDIAN)
|
||||||
|
|
||||||
|
// Returns true, if the byte ordering used by Java is different from the native byte ordering
|
||||||
|
// of the underlying machine. For example, true for Intel x86, False, for Solaris on Sparc.
|
||||||
|
static inline bool is_Java_byte_ordering_different() { return true; }
|
||||||
|
|
||||||
|
// Forward declarations of the compiler-dependent implementation
|
||||||
|
static inline u2 swap_u2(u2 x);
|
||||||
|
static inline u4 swap_u4(u4 x);
|
||||||
|
static inline u8 swap_u8(u8 x);
|
||||||
|
|
||||||
|
static inline u2 get_native_u2(address p) {
|
||||||
|
return (intptr_t(p) & 1) == 0
|
||||||
|
? *(u2*)p
|
||||||
|
: ( u2(p[1]) << 8 )
|
||||||
|
| ( u2(p[0]) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u4 get_native_u4(address p) {
|
||||||
|
switch (intptr_t(p) & 3) {
|
||||||
|
case 0: return *(u4*)p;
|
||||||
|
|
||||||
|
case 2: return ( u4( ((u2*)p)[1] ) << 16 )
|
||||||
|
| ( u4( ((u2*)p)[0] ) );
|
||||||
|
|
||||||
|
default: return ( u4(p[3]) << 24 )
|
||||||
|
| ( u4(p[2]) << 16 )
|
||||||
|
| ( u4(p[1]) << 8 )
|
||||||
|
| u4(p[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u8 get_native_u8(address p) {
|
||||||
|
switch (intptr_t(p) & 7) {
|
||||||
|
case 0: return *(u8*)p;
|
||||||
|
|
||||||
|
case 4: return ( u8( ((u4*)p)[1] ) << 32 )
|
||||||
|
| ( u8( ((u4*)p)[0] ) );
|
||||||
|
|
||||||
|
case 2: return ( u8( ((u2*)p)[3] ) << 48 )
|
||||||
|
| ( u8( ((u2*)p)[2] ) << 32 )
|
||||||
|
| ( u8( ((u2*)p)[1] ) << 16 )
|
||||||
|
| ( u8( ((u2*)p)[0] ) );
|
||||||
|
|
||||||
|
default: return ( u8(p[7]) << 56 )
|
||||||
|
| ( u8(p[6]) << 48 )
|
||||||
|
| ( u8(p[5]) << 40 )
|
||||||
|
| ( u8(p[4]) << 32 )
|
||||||
|
| ( u8(p[3]) << 24 )
|
||||||
|
| ( u8(p[2]) << 16 )
|
||||||
|
| ( u8(p[1]) << 8 )
|
||||||
|
| u8(p[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static inline void put_native_u2(address p, u2 x) {
|
||||||
|
if ( (intptr_t(p) & 1) == 0 ) *(u2*)p = x;
|
||||||
|
else {
|
||||||
|
p[1] = x >> 8;
|
||||||
|
p[0] = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void put_native_u4(address p, u4 x) {
|
||||||
|
switch ( intptr_t(p) & 3 ) {
|
||||||
|
case 0: *(u4*)p = x;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: ((u2*)p)[1] = x >> 16;
|
||||||
|
((u2*)p)[0] = x;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: ((u1*)p)[3] = x >> 24;
|
||||||
|
((u1*)p)[2] = x >> 16;
|
||||||
|
((u1*)p)[1] = x >> 8;
|
||||||
|
((u1*)p)[0] = x;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void put_native_u8(address p, u8 x) {
|
||||||
|
switch ( intptr_t(p) & 7 ) {
|
||||||
|
case 0: *(u8*)p = x;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4: ((u4*)p)[1] = x >> 32;
|
||||||
|
((u4*)p)[0] = x;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: ((u2*)p)[3] = x >> 48;
|
||||||
|
((u2*)p)[2] = x >> 32;
|
||||||
|
((u2*)p)[1] = x >> 16;
|
||||||
|
((u2*)p)[0] = x;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: ((u1*)p)[7] = x >> 56;
|
||||||
|
((u1*)p)[6] = x >> 48;
|
||||||
|
((u1*)p)[5] = x >> 40;
|
||||||
|
((u1*)p)[4] = x >> 32;
|
||||||
|
((u1*)p)[3] = x >> 24;
|
||||||
|
((u1*)p)[2] = x >> 16;
|
||||||
|
((u1*)p)[1] = x >> 8;
|
||||||
|
((u1*)p)[0] = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Efficient reading and writing of unaligned unsigned data in Java byte ordering (i.e. big-endian ordering)
|
||||||
|
// (no byte-order reversal is needed since Power CPUs are big-endian oriented).
|
||||||
|
static inline u2 get_Java_u2(address p) { return swap_u2(get_native_u2(p)); }
|
||||||
|
static inline u4 get_Java_u4(address p) { return swap_u4(get_native_u4(p)); }
|
||||||
|
static inline u8 get_Java_u8(address p) { return swap_u8(get_native_u8(p)); }
|
||||||
|
|
||||||
|
static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, swap_u2(x)); }
|
||||||
|
static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, swap_u4(x)); }
|
||||||
|
static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, swap_u8(x)); }
|
||||||
|
|
||||||
|
#else // !defined(VM_LITTLE_ENDIAN)
|
||||||
|
|
||||||
// Returns true, if the byte ordering used by Java is different from the nativ byte ordering
|
// Returns true, if the byte ordering used by Java is different from the nativ byte ordering
|
||||||
// of the underlying machine. For example, true for Intel x86, False, for Solaris on Sparc.
|
// of the underlying machine. For example, true for Intel x86, False, for Solaris on Sparc.
|
||||||
static inline bool is_Java_byte_ordering_different() { return false; }
|
static inline bool is_Java_byte_ordering_different() { return false; }
|
||||||
@ -150,6 +270,12 @@ class Bytes: AllStatic {
|
|||||||
static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, x); }
|
static inline void put_Java_u2(address p, u2 x) { put_native_u2(p, x); }
|
||||||
static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, x); }
|
static inline void put_Java_u4(address p, u4 x) { put_native_u4(p, x); }
|
||||||
static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, x); }
|
static inline void put_Java_u8(address p, u8 x) { put_native_u8(p, x); }
|
||||||
|
|
||||||
|
#endif // VM_LITTLE_ENDIAN
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined(TARGET_OS_ARCH_linux_ppc)
|
||||||
|
#include "bytes_linux_ppc.inline.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // CPU_PPC_VM_BYTES_PPC_HPP
|
#endif // CPU_PPC_VM_BYTES_PPC_HPP
|
||||||
|
@ -1672,7 +1672,7 @@ address TemplateInterpreterGenerator::generate_trace_code(TosState state) {
|
|||||||
//__ flush_bundle();
|
//__ flush_bundle();
|
||||||
address entry = __ pc();
|
address entry = __ pc();
|
||||||
|
|
||||||
char *bname = NULL;
|
const char *bname = NULL;
|
||||||
uint tsize = 0;
|
uint tsize = 0;
|
||||||
switch(state) {
|
switch(state) {
|
||||||
case ftos:
|
case ftos:
|
||||||
|
@ -799,7 +799,13 @@ void LIR_Assembler::const2mem(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmi
|
|||||||
if (UseCompressedOops && !wide) {
|
if (UseCompressedOops && !wide) {
|
||||||
__ movl(as_Address(addr), (int32_t)NULL_WORD);
|
__ movl(as_Address(addr), (int32_t)NULL_WORD);
|
||||||
} else {
|
} else {
|
||||||
|
#ifdef _LP64
|
||||||
|
__ xorptr(rscratch1, rscratch1);
|
||||||
|
null_check_here = code_offset();
|
||||||
|
__ movptr(as_Address(addr), rscratch1);
|
||||||
|
#else
|
||||||
__ movptr(as_Address(addr), NULL_WORD);
|
__ movptr(as_Address(addr), NULL_WORD);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (is_literal_address(addr)) {
|
if (is_literal_address(addr)) {
|
||||||
|
@ -59,9 +59,9 @@ static BufferBlob* stub_blob;
|
|||||||
static const int stub_size = 600;
|
static const int stub_size = 600;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
typedef void (*getPsrInfo_stub_t)(void*);
|
typedef void (*get_cpu_info_stub_t)(void*);
|
||||||
}
|
}
|
||||||
static getPsrInfo_stub_t getPsrInfo_stub = NULL;
|
static get_cpu_info_stub_t get_cpu_info_stub = NULL;
|
||||||
|
|
||||||
|
|
||||||
class VM_Version_StubGenerator: public StubCodeGenerator {
|
class VM_Version_StubGenerator: public StubCodeGenerator {
|
||||||
@ -69,7 +69,7 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
|||||||
|
|
||||||
VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {}
|
VM_Version_StubGenerator(CodeBuffer *c) : StubCodeGenerator(c) {}
|
||||||
|
|
||||||
address generate_getPsrInfo() {
|
address generate_get_cpu_info() {
|
||||||
// Flags to test CPU type.
|
// Flags to test CPU type.
|
||||||
const uint32_t HS_EFL_AC = 0x40000;
|
const uint32_t HS_EFL_AC = 0x40000;
|
||||||
const uint32_t HS_EFL_ID = 0x200000;
|
const uint32_t HS_EFL_ID = 0x200000;
|
||||||
@ -81,13 +81,13 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
|||||||
Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4;
|
Label detect_486, cpu486, detect_586, std_cpuid1, std_cpuid4;
|
||||||
Label sef_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7, done;
|
Label sef_cpuid, ext_cpuid, ext_cpuid1, ext_cpuid5, ext_cpuid7, done;
|
||||||
|
|
||||||
StubCodeMark mark(this, "VM_Version", "getPsrInfo_stub");
|
StubCodeMark mark(this, "VM_Version", "get_cpu_info_stub");
|
||||||
# define __ _masm->
|
# define __ _masm->
|
||||||
|
|
||||||
address start = __ pc();
|
address start = __ pc();
|
||||||
|
|
||||||
//
|
//
|
||||||
// void getPsrInfo(VM_Version::CpuidInfo* cpuid_info);
|
// void get_cpu_info(VM_Version::CpuidInfo* cpuid_info);
|
||||||
//
|
//
|
||||||
// LP64: rcx and rdx are first and second argument registers on windows
|
// LP64: rcx and rdx are first and second argument registers on windows
|
||||||
|
|
||||||
@ -385,6 +385,14 @@ class VM_Version_StubGenerator: public StubCodeGenerator {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void VM_Version::get_cpu_info_wrapper() {
|
||||||
|
get_cpu_info_stub(&_cpuid_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED
|
||||||
|
#define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) f()
|
||||||
|
#endif
|
||||||
|
|
||||||
void VM_Version::get_processor_features() {
|
void VM_Version::get_processor_features() {
|
||||||
|
|
||||||
_cpu = 4; // 486 by default
|
_cpu = 4; // 486 by default
|
||||||
@ -395,7 +403,11 @@ void VM_Version::get_processor_features() {
|
|||||||
|
|
||||||
if (!Use486InstrsOnly) {
|
if (!Use486InstrsOnly) {
|
||||||
// Get raw processor info
|
// Get raw processor info
|
||||||
getPsrInfo_stub(&_cpuid_info);
|
|
||||||
|
// Some platforms (like Win*) need a wrapper around here
|
||||||
|
// in order to properly handle SEGV for YMM registers test.
|
||||||
|
CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(get_cpu_info_wrapper);
|
||||||
|
|
||||||
assert_is_initialized();
|
assert_is_initialized();
|
||||||
_cpu = extended_cpu_family();
|
_cpu = extended_cpu_family();
|
||||||
_model = extended_cpu_model();
|
_model = extended_cpu_model();
|
||||||
@ -986,14 +998,14 @@ void VM_Version::initialize() {
|
|||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
// Making this stub must be FIRST use of assembler
|
// Making this stub must be FIRST use of assembler
|
||||||
|
|
||||||
stub_blob = BufferBlob::create("getPsrInfo_stub", stub_size);
|
stub_blob = BufferBlob::create("get_cpu_info_stub", stub_size);
|
||||||
if (stub_blob == NULL) {
|
if (stub_blob == NULL) {
|
||||||
vm_exit_during_initialization("Unable to allocate getPsrInfo_stub");
|
vm_exit_during_initialization("Unable to allocate get_cpu_info_stub");
|
||||||
}
|
}
|
||||||
CodeBuffer c(stub_blob);
|
CodeBuffer c(stub_blob);
|
||||||
VM_Version_StubGenerator g(&c);
|
VM_Version_StubGenerator g(&c);
|
||||||
getPsrInfo_stub = CAST_TO_FN_PTR(getPsrInfo_stub_t,
|
get_cpu_info_stub = CAST_TO_FN_PTR(get_cpu_info_stub_t,
|
||||||
g.generate_getPsrInfo());
|
g.generate_get_cpu_info());
|
||||||
|
|
||||||
get_processor_features();
|
get_processor_features();
|
||||||
}
|
}
|
||||||
|
@ -507,6 +507,7 @@ public:
|
|||||||
// The value used to check ymm register after signal handle
|
// The value used to check ymm register after signal handle
|
||||||
static int ymm_test_value() { return 0xCAFEBABE; }
|
static int ymm_test_value() { return 0xCAFEBABE; }
|
||||||
|
|
||||||
|
static void get_cpu_info_wrapper();
|
||||||
static void set_cpuinfo_segv_addr(address pc) { _cpuinfo_segv_addr = pc; }
|
static void set_cpuinfo_segv_addr(address pc) { _cpuinfo_segv_addr = pc; }
|
||||||
static bool is_cpuinfo_segv_addr(address pc) { return _cpuinfo_segv_addr == pc; }
|
static bool is_cpuinfo_segv_addr(address pc) { return _cpuinfo_segv_addr == pc; }
|
||||||
static void set_cpuinfo_cont_addr(address pc) { _cpuinfo_cont_addr = pc; }
|
static void set_cpuinfo_cont_addr(address pc) { _cpuinfo_cont_addr = pc; }
|
||||||
|
@ -60,8 +60,8 @@
|
|||||||
#include "runtime/sharedRuntime.hpp"
|
#include "runtime/sharedRuntime.hpp"
|
||||||
#include "runtime/statSampler.hpp"
|
#include "runtime/statSampler.hpp"
|
||||||
#include "runtime/stubRoutines.hpp"
|
#include "runtime/stubRoutines.hpp"
|
||||||
#include "runtime/threadCritical.hpp"
|
|
||||||
#include "runtime/thread.inline.hpp"
|
#include "runtime/thread.inline.hpp"
|
||||||
|
#include "runtime/threadCritical.hpp"
|
||||||
#include "runtime/timer.hpp"
|
#include "runtime/timer.hpp"
|
||||||
#include "services/attachListener.hpp"
|
#include "services/attachListener.hpp"
|
||||||
#include "services/runtimeService.hpp"
|
#include "services/runtimeService.hpp"
|
||||||
@ -70,16 +70,6 @@
|
|||||||
#include "utilities/events.hpp"
|
#include "utilities/events.hpp"
|
||||||
#include "utilities/growableArray.hpp"
|
#include "utilities/growableArray.hpp"
|
||||||
#include "utilities/vmError.hpp"
|
#include "utilities/vmError.hpp"
|
||||||
#ifdef TARGET_ARCH_ppc
|
|
||||||
# include "assembler_ppc.inline.hpp"
|
|
||||||
# include "nativeInst_ppc.hpp"
|
|
||||||
#endif
|
|
||||||
#ifdef COMPILER1
|
|
||||||
#include "c1/c1_Runtime1.hpp"
|
|
||||||
#endif
|
|
||||||
#ifdef COMPILER2
|
|
||||||
#include "opto/runtime.hpp"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// put OS-includes here (sorted alphabetically)
|
// put OS-includes here (sorted alphabetically)
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -378,13 +368,14 @@ void os::Aix::query_multipage_support() {
|
|||||||
assert(_page_size == SIZE_4K, "surprise!");
|
assert(_page_size == SIZE_4K, "surprise!");
|
||||||
|
|
||||||
|
|
||||||
// query default data page size (default page size for C-Heap, pthread stacks and .bss).
|
// Query default data page size (default page size for C-Heap, pthread stacks and .bss).
|
||||||
// Default data page size is influenced either by linker options (-bdatapsize)
|
// Default data page size is influenced either by linker options (-bdatapsize)
|
||||||
// or by environment variable LDR_CNTRL (suboption DATAPSIZE). If none is given,
|
// or by environment variable LDR_CNTRL (suboption DATAPSIZE). If none is given,
|
||||||
// default should be 4K.
|
// default should be 4K.
|
||||||
size_t data_page_size = SIZE_4K;
|
size_t data_page_size = SIZE_4K;
|
||||||
{
|
{
|
||||||
void* p = ::malloc(SIZE_16M);
|
void* p = ::malloc(SIZE_16M);
|
||||||
|
guarantee(p != NULL, "malloc failed");
|
||||||
data_page_size = os::Aix::query_pagesize(p);
|
data_page_size = os::Aix::query_pagesize(p);
|
||||||
::free(p);
|
::free(p);
|
||||||
}
|
}
|
||||||
@ -511,85 +502,76 @@ query_multipage_support_end:
|
|||||||
|
|
||||||
} // end os::Aix::query_multipage_support()
|
} // end os::Aix::query_multipage_support()
|
||||||
|
|
||||||
|
// The code for this method was initially derived from the version in os_linux.cpp.
|
||||||
// The code for this method was initially derived from the version in os_linux.cpp
|
|
||||||
void os::init_system_properties_values() {
|
void os::init_system_properties_values() {
|
||||||
// The next few definitions allow the code to be verbatim:
|
|
||||||
#define malloc(n) (char*)NEW_C_HEAP_ARRAY(char, (n), mtInternal)
|
|
||||||
#define DEFAULT_LIBPATH "/usr/lib:/lib"
|
#define DEFAULT_LIBPATH "/usr/lib:/lib"
|
||||||
#define EXTENSIONS_DIR "/lib/ext"
|
#define EXTENSIONS_DIR "/lib/ext"
|
||||||
#define ENDORSED_DIR "/lib/endorsed"
|
#define ENDORSED_DIR "/lib/endorsed"
|
||||||
|
|
||||||
|
// Buffer that fits several sprintfs.
|
||||||
|
// Note that the space for the trailing null is provided
|
||||||
|
// by the nulls included by the sizeof operator.
|
||||||
|
const size_t bufsize =
|
||||||
|
MAX3((size_t)MAXPATHLEN, // For dll_dir & friends.
|
||||||
|
(size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR), // extensions dir
|
||||||
|
(size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir
|
||||||
|
char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal);
|
||||||
|
|
||||||
// sysclasspath, java_home, dll_dir
|
// sysclasspath, java_home, dll_dir
|
||||||
char *home_path;
|
{
|
||||||
char *dll_path;
|
|
||||||
char *pslash;
|
char *pslash;
|
||||||
char buf[MAXPATHLEN];
|
os::jvm_path(buf, bufsize);
|
||||||
os::jvm_path(buf, sizeof(buf));
|
|
||||||
|
|
||||||
// Found the full path to libjvm.so.
|
// Found the full path to libjvm.so.
|
||||||
// Now cut the path to <java_home>/jre if we can.
|
// Now cut the path to <java_home>/jre if we can.
|
||||||
*(strrchr(buf, '/')) = '\0'; // get rid of /libjvm.so
|
*(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so.
|
||||||
pslash = strrchr(buf, '/');
|
pslash = strrchr(buf, '/');
|
||||||
if (pslash != NULL) {
|
if (pslash != NULL) {
|
||||||
*pslash = '\0'; // get rid of /{client|server|hotspot}
|
*pslash = '\0'; // Get rid of /{client|server|hotspot}.
|
||||||
}
|
}
|
||||||
|
Arguments::set_dll_dir(buf);
|
||||||
dll_path = malloc(strlen(buf) + 1);
|
|
||||||
strcpy(dll_path, buf);
|
|
||||||
Arguments::set_dll_dir(dll_path);
|
|
||||||
|
|
||||||
if (pslash != NULL) {
|
if (pslash != NULL) {
|
||||||
pslash = strrchr(buf, '/');
|
pslash = strrchr(buf, '/');
|
||||||
if (pslash != NULL) {
|
if (pslash != NULL) {
|
||||||
*pslash = '\0'; // get rid of /<arch>
|
*pslash = '\0'; // Get rid of /<arch>.
|
||||||
pslash = strrchr(buf, '/');
|
pslash = strrchr(buf, '/');
|
||||||
if (pslash != NULL) {
|
if (pslash != NULL) {
|
||||||
*pslash = '\0'; // get rid of /lib
|
*pslash = '\0'; // Get rid of /lib.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Arguments::set_java_home(buf);
|
||||||
|
set_boot_path('/', ':');
|
||||||
|
}
|
||||||
|
|
||||||
home_path = malloc(strlen(buf) + 1);
|
// Where to look for native libraries.
|
||||||
strcpy(home_path, buf);
|
|
||||||
Arguments::set_java_home(home_path);
|
|
||||||
|
|
||||||
if (!set_boot_path('/', ':')) return;
|
// On Aix we get the user setting of LIBPATH.
|
||||||
|
|
||||||
// Where to look for native libraries
|
|
||||||
|
|
||||||
// On Aix we get the user setting of LIBPATH
|
|
||||||
// Eventually, all the library path setting will be done here.
|
// Eventually, all the library path setting will be done here.
|
||||||
char *ld_library_path;
|
// Get the user setting of LIBPATH.
|
||||||
|
const char *v = ::getenv("LIBPATH");
|
||||||
// Construct the invariant part of ld_library_path.
|
const char *v_colon = ":";
|
||||||
ld_library_path = (char *) malloc(sizeof(DEFAULT_LIBPATH));
|
if (v == NULL) { v = ""; v_colon = ""; }
|
||||||
sprintf(ld_library_path, DEFAULT_LIBPATH);
|
|
||||||
|
|
||||||
// Get the user setting of LIBPATH, and prepended it.
|
|
||||||
char *v = ::getenv("LIBPATH");
|
|
||||||
if (v == NULL) {
|
|
||||||
v = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
char *t = ld_library_path;
|
|
||||||
// That's +1 for the colon and +1 for the trailing '\0'
|
|
||||||
ld_library_path = (char *) malloc(strlen(v) + 1 + strlen(t) + 1);
|
|
||||||
sprintf(ld_library_path, "%s:%s", v, t);
|
|
||||||
|
|
||||||
|
// Concatenate user and invariant part of ld_library_path.
|
||||||
|
// That's +1 for the colon and +1 for the trailing '\0'.
|
||||||
|
char *ld_library_path = (char *)NEW_C_HEAP_ARRAY(char, strlen(v) + 1 + sizeof(DEFAULT_LIBPATH) + 1, mtInternal);
|
||||||
|
sprintf(ld_library_path, "%s%s" DEFAULT_LIBPATH, v, v_colon);
|
||||||
Arguments::set_library_path(ld_library_path);
|
Arguments::set_library_path(ld_library_path);
|
||||||
|
FREE_C_HEAP_ARRAY(char, ld_library_path, mtInternal);
|
||||||
|
|
||||||
// Extensions directories
|
// Extensions directories.
|
||||||
char* cbuf = malloc(strlen(Arguments::get_java_home()) + sizeof(EXTENSIONS_DIR));
|
sprintf(buf, "%s" EXTENSIONS_DIR, Arguments::get_java_home());
|
||||||
sprintf(cbuf, "%s" EXTENSIONS_DIR, Arguments::get_java_home());
|
Arguments::set_ext_dirs(buf);
|
||||||
Arguments::set_ext_dirs(cbuf);
|
|
||||||
|
|
||||||
// Endorsed standards default directory.
|
// Endorsed standards default directory.
|
||||||
cbuf = malloc(strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR));
|
sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home());
|
||||||
sprintf(cbuf, "%s" ENDORSED_DIR, Arguments::get_java_home());
|
Arguments::set_endorsed_dirs(buf);
|
||||||
Arguments::set_endorsed_dirs(cbuf);
|
|
||||||
|
FREE_C_HEAP_ARRAY(char, buf, mtInternal);
|
||||||
|
|
||||||
#undef malloc
|
|
||||||
#undef DEFAULT_LIBPATH
|
#undef DEFAULT_LIBPATH
|
||||||
#undef EXTENSIONS_DIR
|
#undef EXTENSIONS_DIR
|
||||||
#undef ENDORSED_DIR
|
#undef ENDORSED_DIR
|
||||||
|
@ -306,9 +306,6 @@ static const char *get_home() {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
void os::init_system_properties_values() {
|
void os::init_system_properties_values() {
|
||||||
// char arch[12];
|
|
||||||
// sysinfo(SI_ARCHITECTURE, arch, sizeof(arch));
|
|
||||||
|
|
||||||
// The next steps are taken in the product version:
|
// The next steps are taken in the product version:
|
||||||
//
|
//
|
||||||
// Obtain the JAVA_HOME value from the location of libjvm.so.
|
// Obtain the JAVA_HOME value from the location of libjvm.so.
|
||||||
@ -335,137 +332,164 @@ void os::init_system_properties_values() {
|
|||||||
// Important note: if the location of libjvm.so changes this
|
// Important note: if the location of libjvm.so changes this
|
||||||
// code needs to be changed accordingly.
|
// code needs to be changed accordingly.
|
||||||
|
|
||||||
// The next few definitions allow the code to be verbatim:
|
// See ld(1):
|
||||||
#define malloc(n) (char*)NEW_C_HEAP_ARRAY(char, (n), mtInternal)
|
// The linker uses the following search paths to locate required
|
||||||
#define getenv(n) ::getenv(n)
|
// shared libraries:
|
||||||
|
// 1: ...
|
||||||
/*
|
// ...
|
||||||
* See ld(1):
|
// 7: The default directories, normally /lib and /usr/lib.
|
||||||
* The linker uses the following search paths to locate required
|
|
||||||
* shared libraries:
|
|
||||||
* 1: ...
|
|
||||||
* ...
|
|
||||||
* 7: The default directories, normally /lib and /usr/lib.
|
|
||||||
*/
|
|
||||||
#ifndef DEFAULT_LIBPATH
|
#ifndef DEFAULT_LIBPATH
|
||||||
#define DEFAULT_LIBPATH "/lib:/usr/lib"
|
#define DEFAULT_LIBPATH "/lib:/usr/lib"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Base path of extensions installed on the system.
|
||||||
|
#define SYS_EXT_DIR "/usr/java/packages"
|
||||||
#define EXTENSIONS_DIR "/lib/ext"
|
#define EXTENSIONS_DIR "/lib/ext"
|
||||||
#define ENDORSED_DIR "/lib/endorsed"
|
#define ENDORSED_DIR "/lib/endorsed"
|
||||||
#define REG_DIR "/usr/java/packages"
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
#ifndef __APPLE__
|
||||||
#define SYS_EXTENSIONS_DIR "/Library/Java/Extensions"
|
|
||||||
#define SYS_EXTENSIONS_DIRS SYS_EXTENSIONS_DIR ":/Network" SYS_EXTENSIONS_DIR ":/System" SYS_EXTENSIONS_DIR ":/usr/lib/java"
|
|
||||||
const char *user_home_dir = get_home();
|
|
||||||
// the null in SYS_EXTENSIONS_DIRS counts for the size of the colon after user_home_dir
|
|
||||||
int system_ext_size = strlen(user_home_dir) + sizeof(SYS_EXTENSIONS_DIR) +
|
|
||||||
sizeof(SYS_EXTENSIONS_DIRS);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
// Buffer that fits several sprintfs.
|
||||||
|
// Note that the space for the colon and the trailing null are provided
|
||||||
|
// by the nulls included by the sizeof operator.
|
||||||
|
const size_t bufsize =
|
||||||
|
MAX3((size_t)MAXPATHLEN, // For dll_dir & friends.
|
||||||
|
(size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR), // extensions dir
|
||||||
|
(size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir
|
||||||
|
char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal);
|
||||||
|
|
||||||
|
// sysclasspath, java_home, dll_dir
|
||||||
{
|
{
|
||||||
/* sysclasspath, java_home, dll_dir */
|
|
||||||
{
|
|
||||||
char *home_path;
|
|
||||||
char *dll_path;
|
|
||||||
char *pslash;
|
char *pslash;
|
||||||
char buf[MAXPATHLEN];
|
os::jvm_path(buf, bufsize);
|
||||||
os::jvm_path(buf, sizeof(buf));
|
|
||||||
|
|
||||||
// Found the full path to libjvm.so.
|
// Found the full path to libjvm.so.
|
||||||
// Now cut the path to <java_home>/jre if we can.
|
// Now cut the path to <java_home>/jre if we can.
|
||||||
*(strrchr(buf, '/')) = '\0'; /* get rid of /libjvm.so */
|
*(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so.
|
||||||
pslash = strrchr(buf, '/');
|
pslash = strrchr(buf, '/');
|
||||||
if (pslash != NULL)
|
if (pslash != NULL) {
|
||||||
*pslash = '\0'; /* get rid of /{client|server|hotspot} */
|
*pslash = '\0'; // Get rid of /{client|server|hotspot}.
|
||||||
dll_path = malloc(strlen(buf) + 1);
|
}
|
||||||
if (dll_path == NULL)
|
Arguments::set_dll_dir(buf);
|
||||||
return;
|
|
||||||
strcpy(dll_path, buf);
|
|
||||||
Arguments::set_dll_dir(dll_path);
|
|
||||||
|
|
||||||
if (pslash != NULL) {
|
if (pslash != NULL) {
|
||||||
pslash = strrchr(buf, '/');
|
pslash = strrchr(buf, '/');
|
||||||
if (pslash != NULL) {
|
if (pslash != NULL) {
|
||||||
*pslash = '\0'; /* get rid of /<arch> (/lib on macosx) */
|
*pslash = '\0'; // Get rid of /<arch>.
|
||||||
#ifndef __APPLE__
|
|
||||||
pslash = strrchr(buf, '/');
|
pslash = strrchr(buf, '/');
|
||||||
if (pslash != NULL)
|
if (pslash != NULL) {
|
||||||
*pslash = '\0'; /* get rid of /lib */
|
*pslash = '\0'; // Get rid of /lib.
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
home_path = malloc(strlen(buf) + 1);
|
Arguments::set_java_home(buf);
|
||||||
if (home_path == NULL)
|
set_boot_path('/', ':');
|
||||||
return;
|
|
||||||
strcpy(home_path, buf);
|
|
||||||
Arguments::set_java_home(home_path);
|
|
||||||
|
|
||||||
if (!set_boot_path('/', ':'))
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Where to look for native libraries.
|
||||||
* Where to look for native libraries
|
//
|
||||||
*
|
// Note: Due to a legacy implementation, most of the library path
|
||||||
* Note: Due to a legacy implementation, most of the library path
|
// is set in the launcher. This was to accomodate linking restrictions
|
||||||
* is set in the launcher. This was to accomodate linking restrictions
|
// on legacy Bsd implementations (which are no longer supported).
|
||||||
* on legacy Bsd implementations (which are no longer supported).
|
// Eventually, all the library path setting will be done here.
|
||||||
* Eventually, all the library path setting will be done here.
|
//
|
||||||
*
|
// However, to prevent the proliferation of improperly built native
|
||||||
* However, to prevent the proliferation of improperly built native
|
// libraries, the new path component /usr/java/packages is added here.
|
||||||
* libraries, the new path component /usr/java/packages is added here.
|
// Eventually, all the library path setting will be done here.
|
||||||
* Eventually, all the library path setting will be done here.
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
char *ld_library_path;
|
// Get the user setting of LD_LIBRARY_PATH, and prepended it. It
|
||||||
|
// should always exist (until the legacy problem cited above is
|
||||||
/*
|
// addressed).
|
||||||
* Construct the invariant part of ld_library_path. Note that the
|
const char *v = ::getenv("LD_LIBRARY_PATH");
|
||||||
* space for the colon and the trailing null are provided by the
|
const char *v_colon = ":";
|
||||||
* nulls included by the sizeof operator (so actually we allocate
|
if (v == NULL) { v = ""; v_colon = ""; }
|
||||||
* a byte more than necessary).
|
// That's +1 for the colon and +1 for the trailing '\0'.
|
||||||
*/
|
char *ld_library_path = (char *)NEW_C_HEAP_ARRAY(char,
|
||||||
#ifdef __APPLE__
|
strlen(v) + 1 +
|
||||||
ld_library_path = (char *) malloc(system_ext_size);
|
sizeof(SYS_EXT_DIR) + sizeof("/lib/") + strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH) + 1,
|
||||||
sprintf(ld_library_path, "%s" SYS_EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS, user_home_dir);
|
mtInternal);
|
||||||
#else
|
sprintf(ld_library_path, "%s%s" SYS_EXT_DIR "/lib/%s:" DEFAULT_LIBPATH, v, v_colon, cpu_arch);
|
||||||
ld_library_path = (char *) malloc(sizeof(REG_DIR) + sizeof("/lib/") +
|
Arguments::set_library_path(ld_library_path);
|
||||||
strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH));
|
FREE_C_HEAP_ARRAY(char, ld_library_path, mtInternal);
|
||||||
sprintf(ld_library_path, REG_DIR "/lib/%s:" DEFAULT_LIBPATH, cpu_arch);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the user setting of LD_LIBRARY_PATH, and prepended it. It
|
|
||||||
* should always exist (until the legacy problem cited above is
|
|
||||||
* addressed).
|
|
||||||
*/
|
|
||||||
#ifdef __APPLE__
|
|
||||||
// Prepend the default path with the JAVA_LIBRARY_PATH so that the app launcher code can specify a directory inside an app wrapper
|
|
||||||
char *l = getenv("JAVA_LIBRARY_PATH");
|
|
||||||
if (l != NULL) {
|
|
||||||
char *t = ld_library_path;
|
|
||||||
/* That's +1 for the colon and +1 for the trailing '\0' */
|
|
||||||
ld_library_path = (char *) malloc(strlen(l) + 1 + strlen(t) + 1);
|
|
||||||
sprintf(ld_library_path, "%s:%s", l, t);
|
|
||||||
free(t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char *v = getenv("DYLD_LIBRARY_PATH");
|
// Extensions directories.
|
||||||
#else
|
sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home());
|
||||||
char *v = getenv("LD_LIBRARY_PATH");
|
Arguments::set_ext_dirs(buf);
|
||||||
#endif
|
|
||||||
if (v != NULL) {
|
// Endorsed standards default directory.
|
||||||
char *t = ld_library_path;
|
sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home());
|
||||||
/* That's +1 for the colon and +1 for the trailing '\0' */
|
Arguments::set_endorsed_dirs(buf);
|
||||||
ld_library_path = (char *) malloc(strlen(v) + 1 + strlen(t) + 1);
|
|
||||||
sprintf(ld_library_path, "%s:%s", v, t);
|
FREE_C_HEAP_ARRAY(char, buf, mtInternal);
|
||||||
free(t);
|
|
||||||
|
#else // __APPLE__
|
||||||
|
|
||||||
|
#define SYS_EXTENSIONS_DIR "/Library/Java/Extensions"
|
||||||
|
#define SYS_EXTENSIONS_DIRS SYS_EXTENSIONS_DIR ":/Network" SYS_EXTENSIONS_DIR ":/System" SYS_EXTENSIONS_DIR ":/usr/lib/java"
|
||||||
|
|
||||||
|
const char *user_home_dir = get_home();
|
||||||
|
// The null in SYS_EXTENSIONS_DIRS counts for the size of the colon after user_home_dir.
|
||||||
|
size_t system_ext_size = strlen(user_home_dir) + sizeof(SYS_EXTENSIONS_DIR) +
|
||||||
|
sizeof(SYS_EXTENSIONS_DIRS);
|
||||||
|
|
||||||
|
// Buffer that fits several sprintfs.
|
||||||
|
// Note that the space for the colon and the trailing null are provided
|
||||||
|
// by the nulls included by the sizeof operator.
|
||||||
|
const size_t bufsize =
|
||||||
|
MAX3((size_t)MAXPATHLEN, // for dll_dir & friends.
|
||||||
|
(size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + system_ext_size, // extensions dir
|
||||||
|
(size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir
|
||||||
|
char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal);
|
||||||
|
|
||||||
|
// sysclasspath, java_home, dll_dir
|
||||||
|
{
|
||||||
|
char *pslash;
|
||||||
|
os::jvm_path(buf, bufsize);
|
||||||
|
|
||||||
|
// Found the full path to libjvm.so.
|
||||||
|
// Now cut the path to <java_home>/jre if we can.
|
||||||
|
*(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so.
|
||||||
|
pslash = strrchr(buf, '/');
|
||||||
|
if (pslash != NULL) {
|
||||||
|
*pslash = '\0'; // Get rid of /{client|server|hotspot}.
|
||||||
|
}
|
||||||
|
Arguments::set_dll_dir(buf);
|
||||||
|
|
||||||
|
if (pslash != NULL) {
|
||||||
|
pslash = strrchr(buf, '/');
|
||||||
|
if (pslash != NULL) {
|
||||||
|
*pslash = '\0'; // Get rid of /lib.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Arguments::set_java_home(buf);
|
||||||
|
set_boot_path('/', ':');
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __APPLE__
|
// Where to look for native libraries.
|
||||||
|
//
|
||||||
|
// Note: Due to a legacy implementation, most of the library path
|
||||||
|
// is set in the launcher. This was to accomodate linking restrictions
|
||||||
|
// on legacy Bsd implementations (which are no longer supported).
|
||||||
|
// Eventually, all the library path setting will be done here.
|
||||||
|
//
|
||||||
|
// However, to prevent the proliferation of improperly built native
|
||||||
|
// libraries, the new path component /usr/java/packages is added here.
|
||||||
|
// Eventually, all the library path setting will be done here.
|
||||||
|
{
|
||||||
|
// Get the user setting of LD_LIBRARY_PATH, and prepended it. It
|
||||||
|
// should always exist (until the legacy problem cited above is
|
||||||
|
// addressed).
|
||||||
|
// Prepend the default path with the JAVA_LIBRARY_PATH so that the app launcher code
|
||||||
|
// can specify a directory inside an app wrapper
|
||||||
|
const char *l = ::getenv("JAVA_LIBRARY_PATH");
|
||||||
|
const char *l_colon = ":";
|
||||||
|
if (l == NULL) { l = ""; l_colon = ""; }
|
||||||
|
|
||||||
|
const char *v = ::getenv("DYLD_LIBRARY_PATH");
|
||||||
|
const char *v_colon = ":";
|
||||||
|
if (v == NULL) { v = ""; v_colon = ""; }
|
||||||
|
|
||||||
// Apple's Java6 has "." at the beginning of java.library.path.
|
// Apple's Java6 has "." at the beginning of java.library.path.
|
||||||
// OpenJDK on Windows has "." at the end of java.library.path.
|
// OpenJDK on Windows has "." at the end of java.library.path.
|
||||||
// OpenJDK on Linux and Solaris don't have "." in java.library.path
|
// OpenJDK on Linux and Solaris don't have "." in java.library.path
|
||||||
@ -474,60 +498,39 @@ void os::init_system_properties_values() {
|
|||||||
// could cause a change in behavior, but Apple's Java6 behavior
|
// could cause a change in behavior, but Apple's Java6 behavior
|
||||||
// can be achieved by putting "." at the beginning of the
|
// can be achieved by putting "." at the beginning of the
|
||||||
// JAVA_LIBRARY_PATH environment variable.
|
// JAVA_LIBRARY_PATH environment variable.
|
||||||
{
|
char *ld_library_path = (char *)NEW_C_HEAP_ARRAY(char,
|
||||||
char *t = ld_library_path;
|
strlen(v) + 1 + strlen(l) + 1 +
|
||||||
// that's +3 for appending ":." and the trailing '\0'
|
system_ext_size + 3,
|
||||||
ld_library_path = (char *) malloc(strlen(t) + 3);
|
mtInternal);
|
||||||
sprintf(ld_library_path, "%s:%s", t, ".");
|
sprintf(ld_library_path, "%s%s%s%s%s" SYS_EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS ":.",
|
||||||
free(t);
|
v, v_colon, l, l_colon, user_home_dir);
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Arguments::set_library_path(ld_library_path);
|
Arguments::set_library_path(ld_library_path);
|
||||||
|
FREE_C_HEAP_ARRAY(char, ld_library_path, mtInternal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Extensions directories.
|
||||||
* Extensions directories.
|
//
|
||||||
*
|
// Note that the space for the colon and the trailing null are provided
|
||||||
* Note that the space for the colon and the trailing null are provided
|
// by the nulls included by the sizeof operator (so actually one byte more
|
||||||
* by the nulls included by the sizeof operator (so actually one byte more
|
// than necessary is allocated).
|
||||||
* than necessary is allocated).
|
sprintf(buf, "%s" SYS_EXTENSIONS_DIR ":%s" EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS,
|
||||||
*/
|
user_home_dir, Arguments::get_java_home());
|
||||||
{
|
|
||||||
#ifdef __APPLE__
|
|
||||||
char *buf = malloc(strlen(Arguments::get_java_home()) +
|
|
||||||
sizeof(EXTENSIONS_DIR) + system_ext_size);
|
|
||||||
sprintf(buf, "%s" SYS_EXTENSIONS_DIR ":%s" EXTENSIONS_DIR ":"
|
|
||||||
SYS_EXTENSIONS_DIRS, user_home_dir, Arguments::get_java_home());
|
|
||||||
#else
|
|
||||||
char *buf = malloc(strlen(Arguments::get_java_home()) +
|
|
||||||
sizeof(EXTENSIONS_DIR) + sizeof(REG_DIR) + sizeof(EXTENSIONS_DIR));
|
|
||||||
sprintf(buf, "%s" EXTENSIONS_DIR ":" REG_DIR EXTENSIONS_DIR,
|
|
||||||
Arguments::get_java_home());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Arguments::set_ext_dirs(buf);
|
Arguments::set_ext_dirs(buf);
|
||||||
}
|
|
||||||
|
|
||||||
/* Endorsed standards default directory. */
|
// Endorsed standards default directory.
|
||||||
{
|
|
||||||
char * buf;
|
|
||||||
buf = malloc(strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR));
|
|
||||||
sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home());
|
sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home());
|
||||||
Arguments::set_endorsed_dirs(buf);
|
Arguments::set_endorsed_dirs(buf);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __APPLE__
|
FREE_C_HEAP_ARRAY(char, buf, mtInternal);
|
||||||
|
|
||||||
#undef SYS_EXTENSIONS_DIR
|
#undef SYS_EXTENSIONS_DIR
|
||||||
#endif
|
#undef SYS_EXTENSIONS_DIRS
|
||||||
#undef malloc
|
|
||||||
#undef getenv
|
#endif // __APPLE__
|
||||||
|
|
||||||
|
#undef SYS_EXT_DIR
|
||||||
#undef EXTENSIONS_DIR
|
#undef EXTENSIONS_DIR
|
||||||
#undef ENDORSED_DIR
|
#undef ENDORSED_DIR
|
||||||
|
|
||||||
// Done
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -3091,7 +3094,7 @@ void os::Bsd::set_signal_handler(int sig, bool set_installed) {
|
|||||||
sigAct.sa_sigaction = signalHandler;
|
sigAct.sa_sigaction = signalHandler;
|
||||||
sigAct.sa_flags = SA_SIGINFO|SA_RESTART;
|
sigAct.sa_flags = SA_SIGINFO|SA_RESTART;
|
||||||
}
|
}
|
||||||
#if __APPLE__
|
#ifdef __APPLE__
|
||||||
// Needed for main thread as XNU (Mac OS X kernel) will only deliver SIGSEGV
|
// Needed for main thread as XNU (Mac OS X kernel) will only deliver SIGSEGV
|
||||||
// (which starts as SIGBUS) on main thread with faulting address inside "stack+guard pages"
|
// (which starts as SIGBUS) on main thread with faulting address inside "stack+guard pages"
|
||||||
// if the signal handler declares it will handle it on alternate stack.
|
// if the signal handler declares it will handle it on alternate stack.
|
||||||
|
@ -319,9 +319,6 @@ void os::Linux::initialize_system_info() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void os::init_system_properties_values() {
|
void os::init_system_properties_values() {
|
||||||
// char arch[12];
|
|
||||||
// sysinfo(SI_ARCHITECTURE, arch, sizeof(arch));
|
|
||||||
|
|
||||||
// The next steps are taken in the product version:
|
// The next steps are taken in the product version:
|
||||||
//
|
//
|
||||||
// Obtain the JAVA_HOME value from the location of libjvm.so.
|
// Obtain the JAVA_HOME value from the location of libjvm.so.
|
||||||
@ -348,140 +345,101 @@ void os::init_system_properties_values() {
|
|||||||
// Important note: if the location of libjvm.so changes this
|
// Important note: if the location of libjvm.so changes this
|
||||||
// code needs to be changed accordingly.
|
// code needs to be changed accordingly.
|
||||||
|
|
||||||
// The next few definitions allow the code to be verbatim:
|
// See ld(1):
|
||||||
#define malloc(n) (char*)NEW_C_HEAP_ARRAY(char, (n), mtInternal)
|
// The linker uses the following search paths to locate required
|
||||||
#define getenv(n) ::getenv(n)
|
// shared libraries:
|
||||||
|
// 1: ...
|
||||||
/*
|
// ...
|
||||||
* See ld(1):
|
// 7: The default directories, normally /lib and /usr/lib.
|
||||||
* The linker uses the following search paths to locate required
|
|
||||||
* shared libraries:
|
|
||||||
* 1: ...
|
|
||||||
* ...
|
|
||||||
* 7: The default directories, normally /lib and /usr/lib.
|
|
||||||
*/
|
|
||||||
#if defined(AMD64) || defined(_LP64) && (defined(SPARC) || defined(PPC) || defined(S390))
|
#if defined(AMD64) || defined(_LP64) && (defined(SPARC) || defined(PPC) || defined(S390))
|
||||||
#define DEFAULT_LIBPATH "/usr/lib64:/lib64:/lib:/usr/lib"
|
#define DEFAULT_LIBPATH "/usr/lib64:/lib64:/lib:/usr/lib"
|
||||||
#else
|
#else
|
||||||
#define DEFAULT_LIBPATH "/lib:/usr/lib"
|
#define DEFAULT_LIBPATH "/lib:/usr/lib"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Base path of extensions installed on the system.
|
||||||
|
#define SYS_EXT_DIR "/usr/java/packages"
|
||||||
#define EXTENSIONS_DIR "/lib/ext"
|
#define EXTENSIONS_DIR "/lib/ext"
|
||||||
#define ENDORSED_DIR "/lib/endorsed"
|
#define ENDORSED_DIR "/lib/endorsed"
|
||||||
#define REG_DIR "/usr/java/packages"
|
|
||||||
|
|
||||||
|
// Buffer that fits several sprintfs.
|
||||||
|
// Note that the space for the colon and the trailing null are provided
|
||||||
|
// by the nulls included by the sizeof operator.
|
||||||
|
const size_t bufsize =
|
||||||
|
MAX3((size_t)MAXPATHLEN, // For dll_dir & friends.
|
||||||
|
(size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR), // extensions dir
|
||||||
|
(size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir
|
||||||
|
char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal);
|
||||||
|
|
||||||
|
// sysclasspath, java_home, dll_dir
|
||||||
{
|
{
|
||||||
/* sysclasspath, java_home, dll_dir */
|
|
||||||
{
|
|
||||||
char *home_path;
|
|
||||||
char *dll_path;
|
|
||||||
char *pslash;
|
char *pslash;
|
||||||
char buf[MAXPATHLEN];
|
os::jvm_path(buf, bufsize);
|
||||||
os::jvm_path(buf, sizeof(buf));
|
|
||||||
|
|
||||||
// Found the full path to libjvm.so.
|
// Found the full path to libjvm.so.
|
||||||
// Now cut the path to <java_home>/jre if we can.
|
// Now cut the path to <java_home>/jre if we can.
|
||||||
*(strrchr(buf, '/')) = '\0'; /* get rid of /libjvm.so */
|
*(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so.
|
||||||
pslash = strrchr(buf, '/');
|
pslash = strrchr(buf, '/');
|
||||||
if (pslash != NULL)
|
if (pslash != NULL) {
|
||||||
*pslash = '\0'; /* get rid of /{client|server|hotspot} */
|
*pslash = '\0'; // Get rid of /{client|server|hotspot}.
|
||||||
dll_path = malloc(strlen(buf) + 1);
|
}
|
||||||
if (dll_path == NULL)
|
Arguments::set_dll_dir(buf);
|
||||||
return;
|
|
||||||
strcpy(dll_path, buf);
|
|
||||||
Arguments::set_dll_dir(dll_path);
|
|
||||||
|
|
||||||
if (pslash != NULL) {
|
if (pslash != NULL) {
|
||||||
pslash = strrchr(buf, '/');
|
pslash = strrchr(buf, '/');
|
||||||
if (pslash != NULL) {
|
if (pslash != NULL) {
|
||||||
*pslash = '\0'; /* get rid of /<arch> */
|
*pslash = '\0'; // Get rid of /<arch>.
|
||||||
pslash = strrchr(buf, '/');
|
pslash = strrchr(buf, '/');
|
||||||
if (pslash != NULL)
|
if (pslash != NULL) {
|
||||||
*pslash = '\0'; /* get rid of /lib */
|
*pslash = '\0'; // Get rid of /lib.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
home_path = malloc(strlen(buf) + 1);
|
Arguments::set_java_home(buf);
|
||||||
if (home_path == NULL)
|
set_boot_path('/', ':');
|
||||||
return;
|
|
||||||
strcpy(home_path, buf);
|
|
||||||
Arguments::set_java_home(home_path);
|
|
||||||
|
|
||||||
if (!set_boot_path('/', ':'))
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Where to look for native libraries.
|
||||||
* Where to look for native libraries
|
//
|
||||||
*
|
// Note: Due to a legacy implementation, most of the library path
|
||||||
* Note: Due to a legacy implementation, most of the library path
|
// is set in the launcher. This was to accomodate linking restrictions
|
||||||
* is set in the launcher. This was to accomodate linking restrictions
|
// on legacy Linux implementations (which are no longer supported).
|
||||||
* on legacy Linux implementations (which are no longer supported).
|
// Eventually, all the library path setting will be done here.
|
||||||
* Eventually, all the library path setting will be done here.
|
//
|
||||||
*
|
// However, to prevent the proliferation of improperly built native
|
||||||
* However, to prevent the proliferation of improperly built native
|
// libraries, the new path component /usr/java/packages is added here.
|
||||||
* libraries, the new path component /usr/java/packages is added here.
|
// Eventually, all the library path setting will be done here.
|
||||||
* Eventually, all the library path setting will be done here.
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
char *ld_library_path;
|
// Get the user setting of LD_LIBRARY_PATH, and prepended it. It
|
||||||
|
// should always exist (until the legacy problem cited above is
|
||||||
/*
|
// addressed).
|
||||||
* Construct the invariant part of ld_library_path. Note that the
|
const char *v = ::getenv("LD_LIBRARY_PATH");
|
||||||
* space for the colon and the trailing null are provided by the
|
const char *v_colon = ":";
|
||||||
* nulls included by the sizeof operator (so actually we allocate
|
if (v == NULL) { v = ""; v_colon = ""; }
|
||||||
* a byte more than necessary).
|
// That's +1 for the colon and +1 for the trailing '\0'.
|
||||||
*/
|
char *ld_library_path = (char *)NEW_C_HEAP_ARRAY(char,
|
||||||
ld_library_path = (char *) malloc(sizeof(REG_DIR) + sizeof("/lib/") +
|
strlen(v) + 1 +
|
||||||
strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH));
|
sizeof(SYS_EXT_DIR) + sizeof("/lib/") + strlen(cpu_arch) + sizeof(DEFAULT_LIBPATH) + 1,
|
||||||
sprintf(ld_library_path, REG_DIR "/lib/%s:" DEFAULT_LIBPATH, cpu_arch);
|
mtInternal);
|
||||||
|
sprintf(ld_library_path, "%s%s" SYS_EXT_DIR "/lib/%s:" DEFAULT_LIBPATH, v, v_colon, cpu_arch);
|
||||||
/*
|
|
||||||
* Get the user setting of LD_LIBRARY_PATH, and prepended it. It
|
|
||||||
* should always exist (until the legacy problem cited above is
|
|
||||||
* addressed).
|
|
||||||
*/
|
|
||||||
char *v = getenv("LD_LIBRARY_PATH");
|
|
||||||
if (v != NULL) {
|
|
||||||
char *t = ld_library_path;
|
|
||||||
/* That's +1 for the colon and +1 for the trailing '\0' */
|
|
||||||
ld_library_path = (char *) malloc(strlen(v) + 1 + strlen(t) + 1);
|
|
||||||
sprintf(ld_library_path, "%s:%s", v, t);
|
|
||||||
}
|
|
||||||
Arguments::set_library_path(ld_library_path);
|
Arguments::set_library_path(ld_library_path);
|
||||||
|
FREE_C_HEAP_ARRAY(char, ld_library_path, mtInternal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Extensions directories.
|
||||||
* Extensions directories.
|
sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home());
|
||||||
*
|
|
||||||
* Note that the space for the colon and the trailing null are provided
|
|
||||||
* by the nulls included by the sizeof operator (so actually one byte more
|
|
||||||
* than necessary is allocated).
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
char *buf = malloc(strlen(Arguments::get_java_home()) +
|
|
||||||
sizeof(EXTENSIONS_DIR) + sizeof(REG_DIR) + sizeof(EXTENSIONS_DIR));
|
|
||||||
sprintf(buf, "%s" EXTENSIONS_DIR ":" REG_DIR EXTENSIONS_DIR,
|
|
||||||
Arguments::get_java_home());
|
|
||||||
Arguments::set_ext_dirs(buf);
|
Arguments::set_ext_dirs(buf);
|
||||||
}
|
|
||||||
|
|
||||||
/* Endorsed standards default directory. */
|
// Endorsed standards default directory.
|
||||||
{
|
|
||||||
char * buf;
|
|
||||||
buf = malloc(strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR));
|
|
||||||
sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home());
|
sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home());
|
||||||
Arguments::set_endorsed_dirs(buf);
|
Arguments::set_endorsed_dirs(buf);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef malloc
|
FREE_C_HEAP_ARRAY(char, buf, mtInternal);
|
||||||
#undef getenv
|
|
||||||
|
#undef DEFAULT_LIBPATH
|
||||||
|
#undef SYS_EXT_DIR
|
||||||
#undef EXTENSIONS_DIR
|
#undef EXTENSIONS_DIR
|
||||||
#undef ENDORSED_DIR
|
#undef ENDORSED_DIR
|
||||||
|
|
||||||
// Done
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -1963,7 +1921,11 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen)
|
|||||||
{EM_SPARC32PLUS, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"},
|
{EM_SPARC32PLUS, EM_SPARC, ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"},
|
||||||
{EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"},
|
{EM_SPARCV9, EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"},
|
||||||
{EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"},
|
{EM_PPC, EM_PPC, ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"},
|
||||||
|
#if defined(VM_LITTLE_ENDIAN)
|
||||||
|
{EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2LSB, (char*)"Power PC 64"},
|
||||||
|
#else
|
||||||
{EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"},
|
{EM_PPC64, EM_PPC64, ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"},
|
||||||
|
#endif
|
||||||
{EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"},
|
{EM_ARM, EM_ARM, ELFCLASS32, ELFDATA2LSB, (char*)"ARM"},
|
||||||
{EM_S390, EM_S390, ELFCLASSNONE, ELFDATA2MSB, (char*)"IBM System/390"},
|
{EM_S390, EM_S390, ELFCLASSNONE, ELFDATA2MSB, (char*)"IBM System/390"},
|
||||||
{EM_ALPHA, EM_ALPHA, ELFCLASS64, ELFDATA2LSB, (char*)"Alpha"},
|
{EM_ALPHA, EM_ALPHA, ELFCLASS64, ELFDATA2LSB, (char*)"Alpha"},
|
||||||
|
@ -580,9 +580,6 @@ bool os::have_special_privileges() {
|
|||||||
|
|
||||||
|
|
||||||
void os::init_system_properties_values() {
|
void os::init_system_properties_values() {
|
||||||
char arch[12];
|
|
||||||
sysinfo(SI_ARCHITECTURE, arch, sizeof(arch));
|
|
||||||
|
|
||||||
// The next steps are taken in the product version:
|
// The next steps are taken in the product version:
|
||||||
//
|
//
|
||||||
// Obtain the JAVA_HOME value from the location of libjvm.so.
|
// Obtain the JAVA_HOME value from the location of libjvm.so.
|
||||||
@ -609,59 +606,51 @@ void os::init_system_properties_values() {
|
|||||||
// Important note: if the location of libjvm.so changes this
|
// Important note: if the location of libjvm.so changes this
|
||||||
// code needs to be changed accordingly.
|
// code needs to be changed accordingly.
|
||||||
|
|
||||||
// The next few definitions allow the code to be verbatim:
|
// Base path of extensions installed on the system.
|
||||||
#define malloc(n) (char*)NEW_C_HEAP_ARRAY(char, (n), mtInternal)
|
#define SYS_EXT_DIR "/usr/jdk/packages"
|
||||||
#define free(p) FREE_C_HEAP_ARRAY(char, p, mtInternal)
|
|
||||||
#define getenv(n) ::getenv(n)
|
|
||||||
|
|
||||||
#define EXTENSIONS_DIR "/lib/ext"
|
#define EXTENSIONS_DIR "/lib/ext"
|
||||||
#define ENDORSED_DIR "/lib/endorsed"
|
#define ENDORSED_DIR "/lib/endorsed"
|
||||||
#define COMMON_DIR "/usr/jdk/packages"
|
|
||||||
|
|
||||||
|
char cpu_arch[12];
|
||||||
|
// Buffer that fits several sprintfs.
|
||||||
|
// Note that the space for the colon and the trailing null are provided
|
||||||
|
// by the nulls included by the sizeof operator.
|
||||||
|
const size_t bufsize =
|
||||||
|
MAX4((size_t)MAXPATHLEN, // For dll_dir & friends.
|
||||||
|
sizeof(SYS_EXT_DIR) + sizeof("/lib/") + strlen(cpu_arch), // invariant ld_library_path
|
||||||
|
(size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR), // extensions dir
|
||||||
|
(size_t)MAXPATHLEN + sizeof(ENDORSED_DIR)); // endorsed dir
|
||||||
|
char *buf = (char *)NEW_C_HEAP_ARRAY(char, bufsize, mtInternal);
|
||||||
|
|
||||||
|
// sysclasspath, java_home, dll_dir
|
||||||
{
|
{
|
||||||
/* sysclasspath, java_home, dll_dir */
|
|
||||||
{
|
|
||||||
char *home_path;
|
|
||||||
char *dll_path;
|
|
||||||
char *pslash;
|
char *pslash;
|
||||||
char buf[MAXPATHLEN];
|
os::jvm_path(buf, bufsize);
|
||||||
os::jvm_path(buf, sizeof(buf));
|
|
||||||
|
|
||||||
// Found the full path to libjvm.so.
|
// Found the full path to libjvm.so.
|
||||||
// Now cut the path to <java_home>/jre if we can.
|
// Now cut the path to <java_home>/jre if we can.
|
||||||
*(strrchr(buf, '/')) = '\0'; /* get rid of /libjvm.so */
|
*(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so.
|
||||||
pslash = strrchr(buf, '/');
|
pslash = strrchr(buf, '/');
|
||||||
if (pslash != NULL)
|
if (pslash != NULL) {
|
||||||
*pslash = '\0'; /* get rid of /{client|server|hotspot} */
|
*pslash = '\0'; // Get rid of /{client|server|hotspot}.
|
||||||
dll_path = malloc(strlen(buf) + 1);
|
}
|
||||||
if (dll_path == NULL)
|
Arguments::set_dll_dir(buf);
|
||||||
return;
|
|
||||||
strcpy(dll_path, buf);
|
|
||||||
Arguments::set_dll_dir(dll_path);
|
|
||||||
|
|
||||||
if (pslash != NULL) {
|
if (pslash != NULL) {
|
||||||
pslash = strrchr(buf, '/');
|
pslash = strrchr(buf, '/');
|
||||||
if (pslash != NULL) {
|
if (pslash != NULL) {
|
||||||
*pslash = '\0'; /* get rid of /<arch> */
|
*pslash = '\0'; // Get rid of /<arch>.
|
||||||
pslash = strrchr(buf, '/');
|
pslash = strrchr(buf, '/');
|
||||||
if (pslash != NULL)
|
if (pslash != NULL) {
|
||||||
*pslash = '\0'; /* get rid of /lib */
|
*pslash = '\0'; // Get rid of /lib.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
home_path = malloc(strlen(buf) + 1);
|
Arguments::set_java_home(buf);
|
||||||
if (home_path == NULL)
|
set_boot_path('/', ':');
|
||||||
return;
|
|
||||||
strcpy(home_path, buf);
|
|
||||||
Arguments::set_java_home(home_path);
|
|
||||||
|
|
||||||
if (!set_boot_path('/', ':'))
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Where to look for native libraries.
|
||||||
* Where to look for native libraries
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
// Use dlinfo() to determine the correct java.library.path.
|
// Use dlinfo() to determine the correct java.library.path.
|
||||||
//
|
//
|
||||||
@ -679,29 +668,26 @@ void os::init_system_properties_values() {
|
|||||||
// get here with any/all of the LD_LIBRARY_PATH[_32|64]
|
// get here with any/all of the LD_LIBRARY_PATH[_32|64]
|
||||||
// settings. Again, dlinfo does exactly what we want.
|
// settings. Again, dlinfo does exactly what we want.
|
||||||
|
|
||||||
Dl_serinfo _info, *info = &_info;
|
Dl_serinfo info_sz, *info = &info_sz;
|
||||||
Dl_serpath *path;
|
Dl_serpath *path;
|
||||||
char *library_path;
|
char *library_path;
|
||||||
char *common_path;
|
char *common_path = buf;
|
||||||
int i;
|
|
||||||
|
|
||||||
// determine search path count and required buffer size
|
// Determine search path count and required buffer size.
|
||||||
if (dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info) == -1) {
|
if (dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info) == -1) {
|
||||||
|
FREE_C_HEAP_ARRAY(char, buf, mtInternal);
|
||||||
vm_exit_during_initialization("dlinfo SERINFOSIZE request", dlerror());
|
vm_exit_during_initialization("dlinfo SERINFOSIZE request", dlerror());
|
||||||
}
|
}
|
||||||
|
|
||||||
// allocate new buffer and initialize
|
// Allocate new buffer and initialize.
|
||||||
info = (Dl_serinfo*)malloc(_info.dls_size);
|
info = (Dl_serinfo*)NEW_C_HEAP_ARRAY(char, info_sz.dls_size, mtInternal);
|
||||||
if (info == NULL) {
|
info->dls_size = info_sz.dls_size;
|
||||||
vm_exit_out_of_memory(_info.dls_size, OOM_MALLOC_ERROR,
|
info->dls_cnt = info_sz.dls_cnt;
|
||||||
"init_system_properties_values info");
|
|
||||||
}
|
|
||||||
info->dls_size = _info.dls_size;
|
|
||||||
info->dls_cnt = _info.dls_cnt;
|
|
||||||
|
|
||||||
// obtain search path information
|
// Obtain search path information.
|
||||||
if (dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info) == -1) {
|
if (dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info) == -1) {
|
||||||
free(info);
|
FREE_C_HEAP_ARRAY(char, buf, mtInternal);
|
||||||
|
FREE_C_HEAP_ARRAY(char, info, mtInternal);
|
||||||
vm_exit_during_initialization("dlinfo SERINFO request", dlerror());
|
vm_exit_during_initialization("dlinfo SERINFO request", dlerror());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -716,41 +702,26 @@ void os::init_system_properties_values() {
|
|||||||
// libraries, the new path component /usr/jdk/packages is added here.
|
// libraries, the new path component /usr/jdk/packages is added here.
|
||||||
|
|
||||||
// Determine the actual CPU architecture.
|
// Determine the actual CPU architecture.
|
||||||
char cpu_arch[12];
|
|
||||||
sysinfo(SI_ARCHITECTURE, cpu_arch, sizeof(cpu_arch));
|
sysinfo(SI_ARCHITECTURE, cpu_arch, sizeof(cpu_arch));
|
||||||
#ifdef _LP64
|
#ifdef _LP64
|
||||||
// If we are a 64-bit vm, perform the following translations:
|
// If we are a 64-bit vm, perform the following translations:
|
||||||
// sparc -> sparcv9
|
// sparc -> sparcv9
|
||||||
// i386 -> amd64
|
// i386 -> amd64
|
||||||
if (strcmp(cpu_arch, "sparc") == 0)
|
if (strcmp(cpu_arch, "sparc") == 0) {
|
||||||
strcat(cpu_arch, "v9");
|
strcat(cpu_arch, "v9");
|
||||||
else if (strcmp(cpu_arch, "i386") == 0)
|
} else if (strcmp(cpu_arch, "i386") == 0) {
|
||||||
strcpy(cpu_arch, "amd64");
|
strcpy(cpu_arch, "amd64");
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Construct the invariant part of ld_library_path. Note that the
|
// Construct the invariant part of ld_library_path.
|
||||||
// space for the colon and the trailing null are provided by the
|
sprintf(common_path, SYS_EXT_DIR "/lib/%s", cpu_arch);
|
||||||
// nulls included by the sizeof operator.
|
|
||||||
size_t bufsize = sizeof(COMMON_DIR) + sizeof("/lib/") + strlen(cpu_arch);
|
|
||||||
common_path = malloc(bufsize);
|
|
||||||
if (common_path == NULL) {
|
|
||||||
free(info);
|
|
||||||
vm_exit_out_of_memory(bufsize, OOM_MALLOC_ERROR,
|
|
||||||
"init_system_properties_values common_path");
|
|
||||||
}
|
|
||||||
sprintf(common_path, COMMON_DIR "/lib/%s", cpu_arch);
|
|
||||||
|
|
||||||
// struct size is more than sufficient for the path components obtained
|
// Struct size is more than sufficient for the path components obtained
|
||||||
// through the dlinfo() call, so only add additional space for the path
|
// through the dlinfo() call, so only add additional space for the path
|
||||||
// components explicitly added here.
|
// components explicitly added here.
|
||||||
bufsize = info->dls_size + strlen(common_path);
|
size_t library_path_size = info->dls_size + strlen(common_path);
|
||||||
library_path = malloc(bufsize);
|
library_path = (char *)NEW_C_HEAP_ARRAY(char, library_path_size, mtInternal);
|
||||||
if (library_path == NULL) {
|
|
||||||
free(info);
|
|
||||||
free(common_path);
|
|
||||||
vm_exit_out_of_memory(bufsize, OOM_MALLOC_ERROR,
|
|
||||||
"init_system_properties_values library_path");
|
|
||||||
}
|
|
||||||
library_path[0] = '\0';
|
library_path[0] = '\0';
|
||||||
|
|
||||||
// Construct the desired Java library path from the linker's library
|
// Construct the desired Java library path from the linker's library
|
||||||
@ -760,10 +731,11 @@ void os::init_system_properties_values() {
|
|||||||
// components specific to the Java VM after those components specified
|
// components specific to the Java VM after those components specified
|
||||||
// in LD_LIBRARY_PATH (if any) but before those added by the ld.so
|
// in LD_LIBRARY_PATH (if any) but before those added by the ld.so
|
||||||
// infrastructure.
|
// infrastructure.
|
||||||
if (info->dls_cnt == 0) { // Not sure this can happen, but allow for it
|
if (info->dls_cnt == 0) { // Not sure this can happen, but allow for it.
|
||||||
strcpy(library_path, common_path);
|
strcpy(library_path, common_path);
|
||||||
} else {
|
} else {
|
||||||
int inserted = 0;
|
int inserted = 0;
|
||||||
|
int i;
|
||||||
for (i = 0; i < info->dls_cnt; i++, path++) {
|
for (i = 0; i < info->dls_cnt; i++, path++) {
|
||||||
uint_t flags = path->dls_flags & LA_SER_MASK;
|
uint_t flags = path->dls_flags & LA_SER_MASK;
|
||||||
if (((flags & LA_SER_LIBPATH) == 0) && !inserted) {
|
if (((flags & LA_SER_LIBPATH) == 0) && !inserted) {
|
||||||
@ -774,7 +746,7 @@ void os::init_system_properties_values() {
|
|||||||
strcat(library_path, path->dls_name);
|
strcat(library_path, path->dls_name);
|
||||||
strcat(library_path, os::path_separator());
|
strcat(library_path, os::path_separator());
|
||||||
}
|
}
|
||||||
// eliminate trailing path separator
|
// Eliminate trailing path separator.
|
||||||
library_path[strlen(library_path)-1] = '\0';
|
library_path[strlen(library_path)-1] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -782,45 +754,26 @@ void os::init_system_properties_values() {
|
|||||||
// tty->print_raw("init_system_properties_values: native lib path: ");
|
// tty->print_raw("init_system_properties_values: native lib path: ");
|
||||||
// tty->print_raw_cr(library_path);
|
// tty->print_raw_cr(library_path);
|
||||||
|
|
||||||
// callee copies into its own buffer
|
// Callee copies into its own buffer.
|
||||||
Arguments::set_library_path(library_path);
|
Arguments::set_library_path(library_path);
|
||||||
|
|
||||||
free(common_path);
|
FREE_C_HEAP_ARRAY(char, library_path, mtInternal);
|
||||||
free(library_path);
|
FREE_C_HEAP_ARRAY(char, info, mtInternal);
|
||||||
free(info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// Extensions directories.
|
||||||
* Extensions directories.
|
sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home());
|
||||||
*
|
|
||||||
* Note that the space for the colon and the trailing null are provided
|
|
||||||
* by the nulls included by the sizeof operator (so actually one byte more
|
|
||||||
* than necessary is allocated).
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
char *buf = (char *) malloc(strlen(Arguments::get_java_home()) +
|
|
||||||
sizeof(EXTENSIONS_DIR) + sizeof(COMMON_DIR) +
|
|
||||||
sizeof(EXTENSIONS_DIR));
|
|
||||||
sprintf(buf, "%s" EXTENSIONS_DIR ":" COMMON_DIR EXTENSIONS_DIR,
|
|
||||||
Arguments::get_java_home());
|
|
||||||
Arguments::set_ext_dirs(buf);
|
Arguments::set_ext_dirs(buf);
|
||||||
}
|
|
||||||
|
|
||||||
/* Endorsed standards default directory. */
|
// Endorsed standards default directory.
|
||||||
{
|
|
||||||
char * buf = malloc(strlen(Arguments::get_java_home()) + sizeof(ENDORSED_DIR));
|
|
||||||
sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home());
|
sprintf(buf, "%s" ENDORSED_DIR, Arguments::get_java_home());
|
||||||
Arguments::set_endorsed_dirs(buf);
|
Arguments::set_endorsed_dirs(buf);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef malloc
|
FREE_C_HEAP_ARRAY(char, buf, mtInternal);
|
||||||
#undef free
|
|
||||||
#undef getenv
|
#undef SYS_EXT_DIR
|
||||||
#undef EXTENSIONS_DIR
|
#undef EXTENSIONS_DIR
|
||||||
#undef ENDORSED_DIR
|
#undef ENDORSED_DIR
|
||||||
#undef COMMON_DIR
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void os::breakpoint() {
|
void os::breakpoint() {
|
||||||
|
@ -2702,7 +2702,6 @@ address os::win32::fast_jni_accessor_wrapper(BasicType type) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void os::win32::call_test_func_with_wrapper(void (*funcPtr)(void)) {
|
void os::win32::call_test_func_with_wrapper(void (*funcPtr)(void)) {
|
||||||
// Install a win32 structured exception handler around the test
|
// Install a win32 structured exception handler around the test
|
||||||
// function call so the VM can generate an error dump if needed.
|
// function call so the VM can generate an error dump if needed.
|
||||||
@ -2713,7 +2712,6 @@ void os::win32::call_test_func_with_wrapper(void (*funcPtr)(void)) {
|
|||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// Virtual Memory
|
// Virtual Memory
|
||||||
|
|
||||||
|
@ -101,9 +101,7 @@ class win32 {
|
|||||||
static address fast_jni_accessor_wrapper(BasicType);
|
static address fast_jni_accessor_wrapper(BasicType);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
static void call_test_func_with_wrapper(void (*funcPtr)(void));
|
static void call_test_func_with_wrapper(void (*funcPtr)(void));
|
||||||
#endif
|
|
||||||
|
|
||||||
// filter function to ignore faults on serializations page
|
// filter function to ignore faults on serializations page
|
||||||
static LONG WINAPI serialize_fault_filter(struct _EXCEPTION_POINTERS* e);
|
static LONG WINAPI serialize_fault_filter(struct _EXCEPTION_POINTERS* e);
|
||||||
|
@ -111,9 +111,7 @@ inline bool os::supports_monotonic_clock() {
|
|||||||
return win32::_has_performance_count;
|
return win32::_has_performance_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
#define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) \
|
#define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) \
|
||||||
os::win32::call_test_func_with_wrapper(f)
|
os::win32::call_test_func_with_wrapper(f)
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // OS_WINDOWS_VM_OS_WINDOWS_INLINE_HPP
|
#endif // OS_WINDOWS_VM_OS_WINDOWS_INLINE_HPP
|
||||||
|
39
hotspot/src/os_cpu/linux_ppc/vm/bytes_linux_ppc.inline.hpp
Normal file
39
hotspot/src/os_cpu/linux_ppc/vm/bytes_linux_ppc.inline.hpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* Copyright 2014 Google 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
|
||||||
|
* 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_CPU_LINUX_PPC_VM_BYTES_LINUX_PPC_INLINE_HPP
|
||||||
|
#define OS_CPU_LINUX_PPC_VM_BYTES_LINUX_PPC_INLINE_HPP
|
||||||
|
|
||||||
|
#if defined(VM_LITTLE_ENDIAN)
|
||||||
|
#include <byteswap.h>
|
||||||
|
|
||||||
|
// Efficient swapping of data bytes from Java byte
|
||||||
|
// ordering to native byte ordering and vice versa.
|
||||||
|
inline u2 Bytes::swap_u2(u2 x) { return bswap_16(x); }
|
||||||
|
inline u4 Bytes::swap_u4(u4 x) { return bswap_32(x); }
|
||||||
|
inline u8 Bytes::swap_u8(u8 x) { return bswap_64(x); }
|
||||||
|
#endif // VM_LITTLE_ENDIAN
|
||||||
|
|
||||||
|
#endif // OS_CPU_LINUX_PPC_VM_BYTES_LINUX_PPC_INLINE_HPP
|
@ -243,7 +243,6 @@ int main(int argc, char *argv[])
|
|||||||
AD.addInclude(AD._CPP_file, "vmreg_arm.inline.hpp");
|
AD.addInclude(AD._CPP_file, "vmreg_arm.inline.hpp");
|
||||||
#endif
|
#endif
|
||||||
#ifdef TARGET_ARCH_ppc
|
#ifdef TARGET_ARCH_ppc
|
||||||
AD.addInclude(AD._CPP_file, "assembler_ppc.inline.hpp");
|
|
||||||
AD.addInclude(AD._CPP_file, "nativeInst_ppc.hpp");
|
AD.addInclude(AD._CPP_file, "nativeInst_ppc.hpp");
|
||||||
AD.addInclude(AD._CPP_file, "vmreg_ppc.inline.hpp");
|
AD.addInclude(AD._CPP_file, "vmreg_ppc.inline.hpp");
|
||||||
#endif
|
#endif
|
||||||
@ -274,6 +273,7 @@ int main(int argc, char *argv[])
|
|||||||
AD.addInclude(AD._DFA_file, "opto/cfgnode.hpp"); // Use PROB_MAX in predicate.
|
AD.addInclude(AD._DFA_file, "opto/cfgnode.hpp"); // Use PROB_MAX in predicate.
|
||||||
AD.addInclude(AD._DFA_file, "opto/matcher.hpp");
|
AD.addInclude(AD._DFA_file, "opto/matcher.hpp");
|
||||||
AD.addInclude(AD._DFA_file, "opto/opcodes.hpp");
|
AD.addInclude(AD._DFA_file, "opto/opcodes.hpp");
|
||||||
|
AD.addInclude(AD._DFA_file, "opto/convertnode.hpp");
|
||||||
// Make sure each .cpp file starts with include lines:
|
// Make sure each .cpp file starts with include lines:
|
||||||
// files declaring and defining generators for Mach* Objects (hpp,cpp)
|
// files declaring and defining generators for Mach* Objects (hpp,cpp)
|
||||||
// Generate the result files:
|
// Generate the result files:
|
||||||
|
@ -581,14 +581,14 @@ void ciMethod::assert_call_type_ok(int bci) {
|
|||||||
* Check whether profiling provides a type for the argument i to the
|
* Check whether profiling provides a type for the argument i to the
|
||||||
* call at bci bci
|
* call at bci bci
|
||||||
*
|
*
|
||||||
* @param bci bci of the call
|
* @param [in]bci bci of the call
|
||||||
* @param i argument number
|
* @param [in]i argument number
|
||||||
* @return profiled type
|
* @param [out]type profiled type of argument, NULL if none
|
||||||
|
* @param [out]maybe_null true if null was seen for argument
|
||||||
|
* @return true if profiling exists
|
||||||
*
|
*
|
||||||
* If the profile reports that the argument may be null, return false
|
|
||||||
* at least for now.
|
|
||||||
*/
|
*/
|
||||||
ciKlass* ciMethod::argument_profiled_type(int bci, int i) {
|
bool ciMethod::argument_profiled_type(int bci, int i, ciKlass*& type, bool& maybe_null) {
|
||||||
if (MethodData::profile_parameters() && method_data() != NULL && method_data()->is_mature()) {
|
if (MethodData::profile_parameters() && method_data() != NULL && method_data()->is_mature()) {
|
||||||
ciProfileData* data = method_data()->bci_to_data(bci);
|
ciProfileData* data = method_data()->bci_to_data(bci);
|
||||||
if (data != NULL) {
|
if (data != NULL) {
|
||||||
@ -596,82 +596,77 @@ ciKlass* ciMethod::argument_profiled_type(int bci, int i) {
|
|||||||
assert_virtual_call_type_ok(bci);
|
assert_virtual_call_type_ok(bci);
|
||||||
ciVirtualCallTypeData* call = (ciVirtualCallTypeData*)data->as_VirtualCallTypeData();
|
ciVirtualCallTypeData* call = (ciVirtualCallTypeData*)data->as_VirtualCallTypeData();
|
||||||
if (i >= call->number_of_arguments()) {
|
if (i >= call->number_of_arguments()) {
|
||||||
return NULL;
|
return false;
|
||||||
}
|
|
||||||
ciKlass* type = call->valid_argument_type(i);
|
|
||||||
if (type != NULL && !call->argument_maybe_null(i)) {
|
|
||||||
return type;
|
|
||||||
}
|
}
|
||||||
|
type = call->valid_argument_type(i);
|
||||||
|
maybe_null = call->argument_maybe_null(i);
|
||||||
|
return true;
|
||||||
} else if (data->is_CallTypeData()) {
|
} else if (data->is_CallTypeData()) {
|
||||||
assert_call_type_ok(bci);
|
assert_call_type_ok(bci);
|
||||||
ciCallTypeData* call = (ciCallTypeData*)data->as_CallTypeData();
|
ciCallTypeData* call = (ciCallTypeData*)data->as_CallTypeData();
|
||||||
if (i >= call->number_of_arguments()) {
|
if (i >= call->number_of_arguments()) {
|
||||||
return NULL;
|
return false;
|
||||||
}
|
}
|
||||||
ciKlass* type = call->valid_argument_type(i);
|
type = call->valid_argument_type(i);
|
||||||
if (type != NULL && !call->argument_maybe_null(i)) {
|
maybe_null = call->argument_maybe_null(i);
|
||||||
return type;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether profiling provides a type for the return value from
|
* Check whether profiling provides a type for the return value from
|
||||||
* the call at bci bci
|
* the call at bci bci
|
||||||
*
|
*
|
||||||
* @param bci bci of the call
|
* @param [in]bci bci of the call
|
||||||
* @return profiled type
|
* @param [out]type profiled type of argument, NULL if none
|
||||||
|
* @param [out]maybe_null true if null was seen for argument
|
||||||
|
* @return true if profiling exists
|
||||||
*
|
*
|
||||||
* If the profile reports that the argument may be null, return false
|
|
||||||
* at least for now.
|
|
||||||
*/
|
*/
|
||||||
ciKlass* ciMethod::return_profiled_type(int bci) {
|
bool ciMethod::return_profiled_type(int bci, ciKlass*& type, bool& maybe_null) {
|
||||||
if (MethodData::profile_return() && method_data() != NULL && method_data()->is_mature()) {
|
if (MethodData::profile_return() && method_data() != NULL && method_data()->is_mature()) {
|
||||||
ciProfileData* data = method_data()->bci_to_data(bci);
|
ciProfileData* data = method_data()->bci_to_data(bci);
|
||||||
if (data != NULL) {
|
if (data != NULL) {
|
||||||
if (data->is_VirtualCallTypeData()) {
|
if (data->is_VirtualCallTypeData()) {
|
||||||
assert_virtual_call_type_ok(bci);
|
assert_virtual_call_type_ok(bci);
|
||||||
ciVirtualCallTypeData* call = (ciVirtualCallTypeData*)data->as_VirtualCallTypeData();
|
ciVirtualCallTypeData* call = (ciVirtualCallTypeData*)data->as_VirtualCallTypeData();
|
||||||
ciKlass* type = call->valid_return_type();
|
type = call->valid_return_type();
|
||||||
if (type != NULL && !call->return_maybe_null()) {
|
maybe_null = call->return_maybe_null();
|
||||||
return type;
|
return true;
|
||||||
}
|
|
||||||
} else if (data->is_CallTypeData()) {
|
} else if (data->is_CallTypeData()) {
|
||||||
assert_call_type_ok(bci);
|
assert_call_type_ok(bci);
|
||||||
ciCallTypeData* call = (ciCallTypeData*)data->as_CallTypeData();
|
ciCallTypeData* call = (ciCallTypeData*)data->as_CallTypeData();
|
||||||
ciKlass* type = call->valid_return_type();
|
type = call->valid_return_type();
|
||||||
if (type != NULL && !call->return_maybe_null()) {
|
maybe_null = call->return_maybe_null();
|
||||||
return type;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether profiling provides a type for the parameter i
|
* Check whether profiling provides a type for the parameter i
|
||||||
*
|
*
|
||||||
* @param i parameter number
|
* @param [in]i parameter number
|
||||||
* @return profiled type
|
* @param [out]type profiled type of parameter, NULL if none
|
||||||
|
* @param [out]maybe_null true if null was seen for parameter
|
||||||
|
* @return true if profiling exists
|
||||||
*
|
*
|
||||||
* If the profile reports that the argument may be null, return false
|
|
||||||
* at least for now.
|
|
||||||
*/
|
*/
|
||||||
ciKlass* ciMethod::parameter_profiled_type(int i) {
|
bool ciMethod::parameter_profiled_type(int i, ciKlass*& type, bool& maybe_null) {
|
||||||
if (MethodData::profile_parameters() && method_data() != NULL && method_data()->is_mature()) {
|
if (MethodData::profile_parameters() && method_data() != NULL && method_data()->is_mature()) {
|
||||||
ciParametersTypeData* parameters = method_data()->parameters_type_data();
|
ciParametersTypeData* parameters = method_data()->parameters_type_data();
|
||||||
if (parameters != NULL && i < parameters->number_of_parameters()) {
|
if (parameters != NULL && i < parameters->number_of_parameters()) {
|
||||||
ciKlass* type = parameters->valid_parameter_type(i);
|
type = parameters->valid_parameter_type(i);
|
||||||
if (type != NULL && !parameters->parameter_maybe_null(i)) {
|
maybe_null = parameters->parameter_maybe_null(i);
|
||||||
return type;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return false;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -234,10 +234,10 @@ class ciMethod : public ciMetadata {
|
|||||||
ciCallProfile call_profile_at_bci(int bci);
|
ciCallProfile call_profile_at_bci(int bci);
|
||||||
int interpreter_call_site_count(int bci);
|
int interpreter_call_site_count(int bci);
|
||||||
|
|
||||||
// Does type profiling provide a useful type at this point?
|
// Does type profiling provide any useful information at this point?
|
||||||
ciKlass* argument_profiled_type(int bci, int i);
|
bool argument_profiled_type(int bci, int i, ciKlass*& type, bool& maybe_null);
|
||||||
ciKlass* parameter_profiled_type(int i);
|
bool parameter_profiled_type(int i, ciKlass*& type, bool& maybe_null);
|
||||||
ciKlass* return_profiled_type(int bci);
|
bool return_profiled_type(int bci, ciKlass*& type, bool& maybe_null);
|
||||||
|
|
||||||
ciField* get_field_at_bci( int bci, bool &will_link);
|
ciField* get_field_at_bci( int bci, bool &will_link);
|
||||||
ciMethod* get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature);
|
ciMethod* get_method_at_bci(int bci, bool &will_link, ciSignature* *declared_signature);
|
||||||
|
@ -135,6 +135,14 @@ void ClassLoaderData::classes_do(void f(Klass * const)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClassLoaderData::methods_do(void f(Method*)) {
|
||||||
|
for (Klass* k = _klasses; k != NULL; k = k->next_link()) {
|
||||||
|
if (k->oop_is_instance()) {
|
||||||
|
InstanceKlass::cast(k)->methods_do(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) {
|
void ClassLoaderData::loaded_classes_do(KlassClosure* klass_closure) {
|
||||||
// Lock to avoid classes being modified/added/removed during iteration
|
// Lock to avoid classes being modified/added/removed during iteration
|
||||||
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
|
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
|
||||||
@ -624,6 +632,12 @@ void ClassLoaderDataGraph::classes_do(void f(Klass* const)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClassLoaderDataGraph::methods_do(void f(Method*)) {
|
||||||
|
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
||||||
|
cld->methods_do(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) {
|
void ClassLoaderDataGraph::loaded_classes_do(KlassClosure* klass_closure) {
|
||||||
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
|
||||||
cld->loaded_classes_do(klass_closure);
|
cld->loaded_classes_do(klass_closure);
|
||||||
|
@ -78,6 +78,7 @@ class ClassLoaderDataGraph : public AllStatic {
|
|||||||
static void keep_alive_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim);
|
static void keep_alive_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim);
|
||||||
static void classes_do(KlassClosure* klass_closure);
|
static void classes_do(KlassClosure* klass_closure);
|
||||||
static void classes_do(void f(Klass* const));
|
static void classes_do(void f(Klass* const));
|
||||||
|
static void methods_do(void f(Method*));
|
||||||
static void loaded_classes_do(KlassClosure* klass_closure);
|
static void loaded_classes_do(KlassClosure* klass_closure);
|
||||||
static void classes_unloading_do(void f(Klass* const));
|
static void classes_unloading_do(void f(Klass* const));
|
||||||
static bool do_unloading(BoolObjectClosure* is_alive);
|
static bool do_unloading(BoolObjectClosure* is_alive);
|
||||||
@ -189,6 +190,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
|||||||
void classes_do(void f(Klass*));
|
void classes_do(void f(Klass*));
|
||||||
void loaded_classes_do(KlassClosure* klass_closure);
|
void loaded_classes_do(KlassClosure* klass_closure);
|
||||||
void classes_do(void f(InstanceKlass*));
|
void classes_do(void f(InstanceKlass*));
|
||||||
|
void methods_do(void f(Method*));
|
||||||
|
|
||||||
// Deallocate free list during class unloading.
|
// Deallocate free list during class unloading.
|
||||||
void free_deallocate_list();
|
void free_deallocate_list();
|
||||||
|
@ -245,7 +245,7 @@ private:
|
|||||||
|
|
||||||
enum ParIterState { Unclaimed, Claimed, Complete };
|
enum ParIterState { Unclaimed, Claimed, Complete };
|
||||||
volatile ParIterState _iter_state;
|
volatile ParIterState _iter_state;
|
||||||
volatile jlong _iter_claimed;
|
volatile size_t _iter_claimed;
|
||||||
|
|
||||||
// Unused unless G1RecordHRRSOops is true.
|
// Unused unless G1RecordHRRSOops is true.
|
||||||
|
|
||||||
@ -319,16 +319,12 @@ public:
|
|||||||
bool iter_is_complete();
|
bool iter_is_complete();
|
||||||
|
|
||||||
// Support for claiming blocks of cards during iteration
|
// Support for claiming blocks of cards during iteration
|
||||||
size_t iter_claimed() const { return (size_t)_iter_claimed; }
|
size_t iter_claimed() const { return _iter_claimed; }
|
||||||
// Claim the next block of cards
|
// Claim the next block of cards
|
||||||
size_t iter_claimed_next(size_t step) {
|
size_t iter_claimed_next(size_t step) {
|
||||||
size_t current, next;
|
return Atomic::add(step, &_iter_claimed) - step;
|
||||||
do {
|
|
||||||
current = iter_claimed();
|
|
||||||
next = current + step;
|
|
||||||
} while (Atomic::cmpxchg((jlong)next, &_iter_claimed, (jlong)current) != (jlong)current);
|
|
||||||
return current;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset_for_par_iteration();
|
void reset_for_par_iteration();
|
||||||
|
|
||||||
bool verify_ready_for_par_iteration() {
|
bool verify_ready_for_par_iteration() {
|
||||||
|
@ -35,8 +35,6 @@
|
|||||||
#include "runtime/timer.hpp"
|
#include "runtime/timer.hpp"
|
||||||
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
|
|
||||||
// Standard closure for BytecodeTracer: prints the current bytecode
|
// Standard closure for BytecodeTracer: prints the current bytecode
|
||||||
// and its attributes using bytecode-specific information.
|
// and its attributes using bytecode-specific information.
|
||||||
|
|
||||||
@ -600,4 +598,3 @@ void BytecodePrinter::bytecode_epilog(int bci, outputStream* st) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // PRODUCT
|
|
||||||
|
@ -34,8 +34,7 @@
|
|||||||
// By specialising the BytecodeClosure, all kinds of bytecode traces can
|
// By specialising the BytecodeClosure, all kinds of bytecode traces can
|
||||||
// be done.
|
// be done.
|
||||||
|
|
||||||
#ifndef PRODUCT
|
// class BytecodeTracer is used by TraceBytecodes option and PrintMethodData
|
||||||
// class BytecodeTracer is only used by TraceBytecodes option
|
|
||||||
|
|
||||||
class BytecodeClosure;
|
class BytecodeClosure;
|
||||||
class BytecodeTracer: AllStatic {
|
class BytecodeTracer: AllStatic {
|
||||||
@ -60,6 +59,4 @@ class BytecodeClosure {
|
|||||||
virtual void trace(methodHandle method, address bcp, outputStream* st) = 0;
|
virtual void trace(methodHandle method, address bcp, outputStream* st) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // !PRODUCT
|
|
||||||
|
|
||||||
#endif // SHARE_VM_INTERPRETER_BYTECODETRACER_HPP
|
#endif // SHARE_VM_INTERPRETER_BYTECODETRACER_HPP
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -32,8 +32,8 @@
|
|||||||
// header: dump of archive instance plus versioning info, datestamp, etc.
|
// header: dump of archive instance plus versioning info, datestamp, etc.
|
||||||
// [magic # = 0xF00BABA2]
|
// [magic # = 0xF00BABA2]
|
||||||
// ... padding to align on page-boundary
|
// ... padding to align on page-boundary
|
||||||
// read-write space from CompactingPermGenGen
|
// read-write space
|
||||||
// read-only space from CompactingPermGenGen
|
// read-only space
|
||||||
// misc data (block offset table, string table, symbols, dictionary, etc.)
|
// misc data (block offset table, string table, symbols, dictionary, etc.)
|
||||||
// tag(666)
|
// tag(666)
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -27,68 +27,61 @@
|
|||||||
|
|
||||||
#include "oops/oop.hpp"
|
#include "oops/oop.hpp"
|
||||||
|
|
||||||
// An ConstMethod* represents portions of a Java method which
|
// An ConstMethod represents portions of a Java method which are not written to after
|
||||||
// do not vary.
|
// the classfile is parsed(*see below). This part of the method can be shared across
|
||||||
|
// processes in a read-only section with Class Data Sharing (CDS). It's important
|
||||||
|
// that this class doesn't have virtual functions because the vptr cannot be shared
|
||||||
|
// with CDS.
|
||||||
|
// (*)RewriteByteCodes and RewriteFrequentPairs is an exception but turned off in CDS
|
||||||
//
|
//
|
||||||
// Memory layout (each line represents a word). Note that most
|
// Note that most applications load thousands of methods, so keeping the size of this
|
||||||
// applications load thousands of methods, so keeping the size of this
|
|
||||||
// structure small has a big impact on footprint.
|
// structure small has a big impact on footprint.
|
||||||
|
|
||||||
|
// The actual bytecodes are inlined after the end of the ConstMethod struct.
|
||||||
//
|
//
|
||||||
// |------------------------------------------------------|
|
// The line number table is compressed and inlined following the byte codes. It is
|
||||||
// | header |
|
// found as the first byte following the byte codes. Note that accessing the line
|
||||||
// | klass |
|
// number and local variable tables is not performance critical at all.
|
||||||
// |------------------------------------------------------|
|
//
|
||||||
// | fingerprint 1 |
|
// The checked exceptions table and the local variable table are inlined after the
|
||||||
// | fingerprint 2 |
|
// line number table, and indexed from the end of the method. We do not compress the
|
||||||
// | constants (oop) |
|
// checked exceptions table since the average length is less than 2, and it is used
|
||||||
// | stackmap_data (oop) |
|
// by reflection so access should be fast. We do not bother to compress the local
|
||||||
// | constMethod_size |
|
// variable table either since it is mostly absent.
|
||||||
// | interp_kind | flags | code_size |
|
//
|
||||||
// | name index | signature index |
|
//
|
||||||
// | method_idnum | max_stack |
|
// ConstMethod embedded field layout (after declared fields):
|
||||||
// | max_locals | size_of_parameters |
|
// [EMBEDDED byte codes]
|
||||||
// |------------------------------------------------------|
|
// [EMBEDDED compressed linenumber table]
|
||||||
// | |
|
// (see class CompressedLineNumberReadStream)
|
||||||
// | byte codes |
|
// (note that length is unknown until decompressed)
|
||||||
// | |
|
// (access flags bit tells whether table is present)
|
||||||
// |------------------------------------------------------|
|
// (indexed from start of ConstMethod)
|
||||||
// | compressed linenumber table |
|
// (elements not necessarily sorted!)
|
||||||
// | (see class CompressedLineNumberReadStream) |
|
// [EMBEDDED localvariable table elements + length (length last)]
|
||||||
// | (note that length is unknown until decompressed) |
|
// (length is u2, elements are 6-tuples of u2)
|
||||||
// | (access flags bit tells whether table is present) |
|
// (see class LocalVariableTableElement)
|
||||||
// | (indexed from start of ConstMethod*) |
|
// (access flags bit tells whether table is present)
|
||||||
// | (elements not necessarily sorted!) |
|
// (indexed from end of ConstMethod*)
|
||||||
// |------------------------------------------------------|
|
// [EMBEDDED exception table + length (length last)]
|
||||||
// | localvariable table elements + length (length last) |
|
// (length is u2, elements are 4-tuples of u2)
|
||||||
// | (length is u2, elements are 6-tuples of u2) |
|
// (see class ExceptionTableElement)
|
||||||
// | (see class LocalVariableTableElement) |
|
// (access flags bit tells whether table is present)
|
||||||
// | (access flags bit tells whether table is present) |
|
// (indexed from end of ConstMethod*)
|
||||||
// | (indexed from end of ConstMethod*) |
|
// [EMBEDDED checked exceptions elements + length (length last)]
|
||||||
// |------------------------------------------------------|
|
// (length is u2, elements are u2)
|
||||||
// | exception table + length (length last) |
|
// (see class CheckedExceptionElement)
|
||||||
// | (length is u2, elements are 4-tuples of u2) |
|
// (access flags bit tells whether table is present)
|
||||||
// | (see class ExceptionTableElement) |
|
// (indexed from end of ConstMethod*)
|
||||||
// | (access flags bit tells whether table is present) |
|
// [EMBEDDED method parameters elements + length (length last)]
|
||||||
// | (indexed from end of ConstMethod*) |
|
// (length is u2, elements are u2, u4 structures)
|
||||||
// |------------------------------------------------------|
|
// (see class MethodParametersElement)
|
||||||
// | checked exceptions elements + length (length last) |
|
// (access flags bit tells whether table is present)
|
||||||
// | (length is u2, elements are u2) |
|
// (indexed from end of ConstMethod*)
|
||||||
// | (see class CheckedExceptionElement) |
|
// [EMBEDDED generic signature index (u2)]
|
||||||
// | (access flags bit tells whether table is present) |
|
// (indexed from end of constMethodOop)
|
||||||
// | (indexed from end of ConstMethod*) |
|
// [EMBEDDED annotations arrays - method, parameter, type, default]
|
||||||
// |------------------------------------------------------|
|
// pointer to Array<u1> if annotation is present
|
||||||
// | method parameters elements + length (length last) |
|
|
||||||
// | (length is u2, elements are u2, u4 structures) |
|
|
||||||
// | (see class MethodParametersElement) |
|
|
||||||
// | (access flags bit tells whether table is present) |
|
|
||||||
// | (indexed from end of ConstMethod*) |
|
|
||||||
// |------------------------------------------------------|
|
|
||||||
// | generic signature index (u2) |
|
|
||||||
// | (indexed from start of constMethodOop) |
|
|
||||||
// |------------------------------------------------------|
|
|
||||||
// | annotations arrays - method, parameter, type, default|
|
|
||||||
// | pointer to Array<u1> if annotation is present |
|
|
||||||
// |------------------------------------------------------|
|
|
||||||
//
|
//
|
||||||
// IMPORTANT: If anything gets added here, there need to be changes to
|
// IMPORTANT: If anything gets added here, there need to be changes to
|
||||||
// ensure that ServicabilityAgent doesn't get broken as a result!
|
// ensure that ServicabilityAgent doesn't get broken as a result!
|
||||||
|
@ -180,12 +180,12 @@ int ConstantPool::cp_to_object_index(int cp_index) {
|
|||||||
return (i < 0) ? _no_index_sentinel : i;
|
return (i < 0) ? _no_index_sentinel : i;
|
||||||
}
|
}
|
||||||
|
|
||||||
Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS) {
|
Klass* ConstantPool::klass_at_impl(constantPoolHandle this_cp, int which, TRAPS) {
|
||||||
// A resolved constantPool entry will contain a Klass*, otherwise a Symbol*.
|
// A resolved constantPool entry will contain a Klass*, otherwise a Symbol*.
|
||||||
// It is not safe to rely on the tag bit's here, since we don't have a lock, and the entry and
|
// It is not safe to rely on the tag bit's here, since we don't have a lock, and the entry and
|
||||||
// tag is not updated atomicly.
|
// tag is not updated atomicly.
|
||||||
|
|
||||||
CPSlot entry = this_oop->slot_at(which);
|
CPSlot entry = this_cp->slot_at(which);
|
||||||
if (entry.is_resolved()) {
|
if (entry.is_resolved()) {
|
||||||
assert(entry.get_klass()->is_klass(), "must be");
|
assert(entry.get_klass()->is_klass(), "must be");
|
||||||
// Already resolved - return entry.
|
// Already resolved - return entry.
|
||||||
@ -204,15 +204,15 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS
|
|||||||
|
|
||||||
Symbol* name = NULL;
|
Symbol* name = NULL;
|
||||||
Handle loader;
|
Handle loader;
|
||||||
{ MonitorLockerEx ml(this_oop->lock());
|
{ MonitorLockerEx ml(this_cp->lock());
|
||||||
|
|
||||||
if (this_oop->tag_at(which).is_unresolved_klass()) {
|
if (this_cp->tag_at(which).is_unresolved_klass()) {
|
||||||
if (this_oop->tag_at(which).is_unresolved_klass_in_error()) {
|
if (this_cp->tag_at(which).is_unresolved_klass_in_error()) {
|
||||||
in_error = true;
|
in_error = true;
|
||||||
} else {
|
} else {
|
||||||
do_resolve = true;
|
do_resolve = true;
|
||||||
name = this_oop->unresolved_klass_at(which);
|
name = this_cp->unresolved_klass_at(which);
|
||||||
loader = Handle(THREAD, this_oop->pool_holder()->class_loader());
|
loader = Handle(THREAD, this_cp->pool_holder()->class_loader());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // unlocking constantPool
|
} // unlocking constantPool
|
||||||
@ -221,26 +221,26 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS
|
|||||||
// The original attempt to resolve this constant pool entry failed so find the
|
// The original attempt to resolve this constant pool entry failed so find the
|
||||||
// original error and throw it again (JVMS 5.4.3).
|
// original error and throw it again (JVMS 5.4.3).
|
||||||
if (in_error) {
|
if (in_error) {
|
||||||
Symbol* error = SystemDictionary::find_resolution_error(this_oop, which);
|
Symbol* error = SystemDictionary::find_resolution_error(this_cp, which);
|
||||||
guarantee(error != (Symbol*)NULL, "tag mismatch with resolution error table");
|
guarantee(error != (Symbol*)NULL, "tag mismatch with resolution error table");
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
// exception text will be the class name
|
// exception text will be the class name
|
||||||
const char* className = this_oop->unresolved_klass_at(which)->as_C_string();
|
const char* className = this_cp->unresolved_klass_at(which)->as_C_string();
|
||||||
THROW_MSG_0(error, className);
|
THROW_MSG_0(error, className);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (do_resolve) {
|
if (do_resolve) {
|
||||||
// this_oop must be unlocked during resolve_or_fail
|
// this_cp must be unlocked during resolve_or_fail
|
||||||
oop protection_domain = this_oop->pool_holder()->protection_domain();
|
oop protection_domain = this_cp->pool_holder()->protection_domain();
|
||||||
Handle h_prot (THREAD, protection_domain);
|
Handle h_prot (THREAD, protection_domain);
|
||||||
Klass* k_oop = SystemDictionary::resolve_or_fail(name, loader, h_prot, true, THREAD);
|
Klass* kk = SystemDictionary::resolve_or_fail(name, loader, h_prot, true, THREAD);
|
||||||
KlassHandle k;
|
KlassHandle k;
|
||||||
if (!HAS_PENDING_EXCEPTION) {
|
if (!HAS_PENDING_EXCEPTION) {
|
||||||
k = KlassHandle(THREAD, k_oop);
|
k = KlassHandle(THREAD, kk);
|
||||||
// preserve the resolved klass.
|
// preserve the resolved klass.
|
||||||
mirror_handle = Handle(THREAD, k_oop->java_mirror());
|
mirror_handle = Handle(THREAD, kk->java_mirror());
|
||||||
// Do access check for klasses
|
// Do access check for klasses
|
||||||
verify_constant_pool_resolve(this_oop, k, THREAD);
|
verify_constant_pool_resolve(this_cp, k, THREAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Failed to resolve class. We must record the errors so that subsequent attempts
|
// Failed to resolve class. We must record the errors so that subsequent attempts
|
||||||
@ -251,12 +251,12 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS
|
|||||||
|
|
||||||
bool throw_orig_error = false;
|
bool throw_orig_error = false;
|
||||||
{
|
{
|
||||||
MonitorLockerEx ml(this_oop->lock());
|
MonitorLockerEx ml(this_cp->lock());
|
||||||
|
|
||||||
// some other thread has beaten us and has resolved the class.
|
// some other thread has beaten us and has resolved the class.
|
||||||
if (this_oop->tag_at(which).is_klass()) {
|
if (this_cp->tag_at(which).is_klass()) {
|
||||||
CLEAR_PENDING_EXCEPTION;
|
CLEAR_PENDING_EXCEPTION;
|
||||||
entry = this_oop->resolved_klass_at(which);
|
entry = this_cp->resolved_klass_at(which);
|
||||||
return entry.get_klass();
|
return entry.get_klass();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -267,12 +267,12 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS
|
|||||||
// and OutOfMemoryError, etc, or if the thread was hit by stop()
|
// and OutOfMemoryError, etc, or if the thread was hit by stop()
|
||||||
// Needs clarification to section 5.4.3 of the VM spec (see 6308271)
|
// Needs clarification to section 5.4.3 of the VM spec (see 6308271)
|
||||||
}
|
}
|
||||||
else if (!this_oop->tag_at(which).is_unresolved_klass_in_error()) {
|
else if (!this_cp->tag_at(which).is_unresolved_klass_in_error()) {
|
||||||
SystemDictionary::add_resolution_error(this_oop, which, error);
|
SystemDictionary::add_resolution_error(this_cp, which, error);
|
||||||
this_oop->tag_at_put(which, JVM_CONSTANT_UnresolvedClassInError);
|
this_cp->tag_at_put(which, JVM_CONSTANT_UnresolvedClassInError);
|
||||||
} else {
|
} else {
|
||||||
// some other thread has put the class in error state.
|
// some other thread has put the class in error state.
|
||||||
error = SystemDictionary::find_resolution_error(this_oop, which);
|
error = SystemDictionary::find_resolution_error(this_cp, which);
|
||||||
assert(error != NULL, "checking");
|
assert(error != NULL, "checking");
|
||||||
throw_orig_error = true;
|
throw_orig_error = true;
|
||||||
}
|
}
|
||||||
@ -281,7 +281,7 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS
|
|||||||
if (throw_orig_error) {
|
if (throw_orig_error) {
|
||||||
CLEAR_PENDING_EXCEPTION;
|
CLEAR_PENDING_EXCEPTION;
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
const char* className = this_oop->unresolved_klass_at(which)->as_C_string();
|
const char* className = this_cp->unresolved_klass_at(which)->as_C_string();
|
||||||
THROW_MSG_0(error, className);
|
THROW_MSG_0(error, className);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,32 +305,32 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (k() != this_oop->pool_holder()) {
|
if (k() != this_cp->pool_holder()) {
|
||||||
// only print something if the classes are different
|
// only print something if the classes are different
|
||||||
if (source_file != NULL) {
|
if (source_file != NULL) {
|
||||||
tty->print("RESOLVE %s %s %s:%d\n",
|
tty->print("RESOLVE %s %s %s:%d\n",
|
||||||
this_oop->pool_holder()->external_name(),
|
this_cp->pool_holder()->external_name(),
|
||||||
InstanceKlass::cast(k())->external_name(), source_file, line_number);
|
InstanceKlass::cast(k())->external_name(), source_file, line_number);
|
||||||
} else {
|
} else {
|
||||||
tty->print("RESOLVE %s %s\n",
|
tty->print("RESOLVE %s %s\n",
|
||||||
this_oop->pool_holder()->external_name(),
|
this_cp->pool_holder()->external_name(),
|
||||||
InstanceKlass::cast(k())->external_name());
|
InstanceKlass::cast(k())->external_name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return k();
|
return k();
|
||||||
} else {
|
} else {
|
||||||
MonitorLockerEx ml(this_oop->lock());
|
MonitorLockerEx ml(this_cp->lock());
|
||||||
// Only updated constant pool - if it is resolved.
|
// Only updated constant pool - if it is resolved.
|
||||||
do_resolve = this_oop->tag_at(which).is_unresolved_klass();
|
do_resolve = this_cp->tag_at(which).is_unresolved_klass();
|
||||||
if (do_resolve) {
|
if (do_resolve) {
|
||||||
ClassLoaderData* this_key = this_oop->pool_holder()->class_loader_data();
|
ClassLoaderData* this_key = this_cp->pool_holder()->class_loader_data();
|
||||||
this_key->record_dependency(k(), CHECK_NULL); // Can throw OOM
|
this_key->record_dependency(k(), CHECK_NULL); // Can throw OOM
|
||||||
this_oop->klass_at_put(which, k());
|
this_cp->klass_at_put(which, k());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entry = this_oop->resolved_klass_at(which);
|
entry = this_cp->resolved_klass_at(which);
|
||||||
assert(entry.is_resolved() && entry.get_klass()->is_klass(), "must be resolved at this point");
|
assert(entry.is_resolved() && entry.get_klass()->is_klass(), "must be resolved at this point");
|
||||||
return entry.get_klass();
|
return entry.get_klass();
|
||||||
}
|
}
|
||||||
@ -340,8 +340,8 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS
|
|||||||
// by compiler and exception handling. Also used to avoid classloads for
|
// by compiler and exception handling. Also used to avoid classloads for
|
||||||
// instanceof operations. Returns NULL if the class has not been loaded or
|
// instanceof operations. Returns NULL if the class has not been loaded or
|
||||||
// if the verification of constant pool failed
|
// if the verification of constant pool failed
|
||||||
Klass* ConstantPool::klass_at_if_loaded(constantPoolHandle this_oop, int which) {
|
Klass* ConstantPool::klass_at_if_loaded(constantPoolHandle this_cp, int which) {
|
||||||
CPSlot entry = this_oop->slot_at(which);
|
CPSlot entry = this_cp->slot_at(which);
|
||||||
if (entry.is_resolved()) {
|
if (entry.is_resolved()) {
|
||||||
assert(entry.get_klass()->is_klass(), "must be");
|
assert(entry.get_klass()->is_klass(), "must be");
|
||||||
return entry.get_klass();
|
return entry.get_klass();
|
||||||
@ -349,8 +349,8 @@ Klass* ConstantPool::klass_at_if_loaded(constantPoolHandle this_oop, int which)
|
|||||||
assert(entry.is_unresolved(), "must be either symbol or klass");
|
assert(entry.is_unresolved(), "must be either symbol or klass");
|
||||||
Thread *thread = Thread::current();
|
Thread *thread = Thread::current();
|
||||||
Symbol* name = entry.get_symbol();
|
Symbol* name = entry.get_symbol();
|
||||||
oop loader = this_oop->pool_holder()->class_loader();
|
oop loader = this_cp->pool_holder()->class_loader();
|
||||||
oop protection_domain = this_oop->pool_holder()->protection_domain();
|
oop protection_domain = this_cp->pool_holder()->protection_domain();
|
||||||
Handle h_prot (thread, protection_domain);
|
Handle h_prot (thread, protection_domain);
|
||||||
Handle h_loader (thread, loader);
|
Handle h_loader (thread, loader);
|
||||||
Klass* k = SystemDictionary::find(name, h_loader, h_prot, thread);
|
Klass* k = SystemDictionary::find(name, h_loader, h_prot, thread);
|
||||||
@ -360,7 +360,7 @@ Klass* ConstantPool::klass_at_if_loaded(constantPoolHandle this_oop, int which)
|
|||||||
EXCEPTION_MARK;
|
EXCEPTION_MARK;
|
||||||
KlassHandle klass(THREAD, k);
|
KlassHandle klass(THREAD, k);
|
||||||
// return NULL if verification fails
|
// return NULL if verification fails
|
||||||
verify_constant_pool_resolve(this_oop, klass, THREAD);
|
verify_constant_pool_resolve(this_cp, klass, THREAD);
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
CLEAR_PENDING_EXCEPTION;
|
CLEAR_PENDING_EXCEPTION;
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -373,8 +373,8 @@ Klass* ConstantPool::klass_at_if_loaded(constantPoolHandle this_oop, int which)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Klass* ConstantPool::klass_ref_at_if_loaded(constantPoolHandle this_oop, int which) {
|
Klass* ConstantPool::klass_ref_at_if_loaded(constantPoolHandle this_cp, int which) {
|
||||||
return klass_at_if_loaded(this_oop, this_oop->klass_ref_index_at(which));
|
return klass_at_if_loaded(this_cp, this_cp->klass_ref_index_at(which));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -486,11 +486,11 @@ int ConstantPool::remap_instruction_operand_from_cache(int operand) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ConstantPool::verify_constant_pool_resolve(constantPoolHandle this_oop, KlassHandle k, TRAPS) {
|
void ConstantPool::verify_constant_pool_resolve(constantPoolHandle this_cp, KlassHandle k, TRAPS) {
|
||||||
if (k->oop_is_instance() || k->oop_is_objArray()) {
|
if (k->oop_is_instance() || k->oop_is_objArray()) {
|
||||||
instanceKlassHandle holder (THREAD, this_oop->pool_holder());
|
instanceKlassHandle holder (THREAD, this_cp->pool_holder());
|
||||||
Klass* elem_oop = k->oop_is_instance() ? k() : ObjArrayKlass::cast(k())->bottom_klass();
|
Klass* elem = k->oop_is_instance() ? k() : ObjArrayKlass::cast(k())->bottom_klass();
|
||||||
KlassHandle element (THREAD, elem_oop);
|
KlassHandle element (THREAD, elem);
|
||||||
|
|
||||||
// The element type could be a typeArray - we only need the access check if it is
|
// The element type could be a typeArray - we only need the access check if it is
|
||||||
// an reference to another class
|
// an reference to another class
|
||||||
@ -559,10 +559,10 @@ BasicType ConstantPool::basic_type_for_signature_at(int which) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void ConstantPool::resolve_string_constants_impl(constantPoolHandle this_oop, TRAPS) {
|
void ConstantPool::resolve_string_constants_impl(constantPoolHandle this_cp, TRAPS) {
|
||||||
for (int index = 1; index < this_oop->length(); index++) { // Index 0 is unused
|
for (int index = 1; index < this_cp->length(); index++) { // Index 0 is unused
|
||||||
if (this_oop->tag_at(index).is_string()) {
|
if (this_cp->tag_at(index).is_string()) {
|
||||||
this_oop->string_at(index, CHECK);
|
this_cp->string_at(index, CHECK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -585,11 +585,11 @@ bool ConstantPool::resolve_class_constants(TRAPS) {
|
|||||||
|
|
||||||
// If resolution for MethodHandle or MethodType fails, save the exception
|
// If resolution for MethodHandle or MethodType fails, save the exception
|
||||||
// in the resolution error table, so that the same exception is thrown again.
|
// in the resolution error table, so that the same exception is thrown again.
|
||||||
void ConstantPool::save_and_throw_exception(constantPoolHandle this_oop, int which,
|
void ConstantPool::save_and_throw_exception(constantPoolHandle this_cp, int which,
|
||||||
int tag, TRAPS) {
|
int tag, TRAPS) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
Symbol* error = PENDING_EXCEPTION->klass()->name();
|
Symbol* error = PENDING_EXCEPTION->klass()->name();
|
||||||
MonitorLockerEx ml(this_oop->lock()); // lock cpool to change tag.
|
MonitorLockerEx ml(this_cp->lock()); // lock cpool to change tag.
|
||||||
|
|
||||||
int error_tag = (tag == JVM_CONSTANT_MethodHandle) ?
|
int error_tag = (tag == JVM_CONSTANT_MethodHandle) ?
|
||||||
JVM_CONSTANT_MethodHandleInError : JVM_CONSTANT_MethodTypeInError;
|
JVM_CONSTANT_MethodHandleInError : JVM_CONSTANT_MethodTypeInError;
|
||||||
@ -601,12 +601,12 @@ void ConstantPool::save_and_throw_exception(constantPoolHandle this_oop, int whi
|
|||||||
// and OutOfMemoryError, etc, or if the thread was hit by stop()
|
// and OutOfMemoryError, etc, or if the thread was hit by stop()
|
||||||
// Needs clarification to section 5.4.3 of the VM spec (see 6308271)
|
// Needs clarification to section 5.4.3 of the VM spec (see 6308271)
|
||||||
|
|
||||||
} else if (this_oop->tag_at(which).value() != error_tag) {
|
} else if (this_cp->tag_at(which).value() != error_tag) {
|
||||||
SystemDictionary::add_resolution_error(this_oop, which, error);
|
SystemDictionary::add_resolution_error(this_cp, which, error);
|
||||||
this_oop->tag_at_put(which, error_tag);
|
this_cp->tag_at_put(which, error_tag);
|
||||||
} else {
|
} else {
|
||||||
// some other thread has put the class in error state.
|
// some other thread has put the class in error state.
|
||||||
error = SystemDictionary::find_resolution_error(this_oop, which);
|
error = SystemDictionary::find_resolution_error(this_cp, which);
|
||||||
assert(error != NULL, "checking");
|
assert(error != NULL, "checking");
|
||||||
CLEAR_PENDING_EXCEPTION;
|
CLEAR_PENDING_EXCEPTION;
|
||||||
THROW_MSG(error, "");
|
THROW_MSG(error, "");
|
||||||
@ -617,7 +617,7 @@ void ConstantPool::save_and_throw_exception(constantPoolHandle this_oop, int whi
|
|||||||
// Called to resolve constants in the constant pool and return an oop.
|
// Called to resolve constants in the constant pool and return an oop.
|
||||||
// Some constant pool entries cache their resolved oop. This is also
|
// Some constant pool entries cache their resolved oop. This is also
|
||||||
// called to create oops from constants to use in arguments for invokedynamic
|
// called to create oops from constants to use in arguments for invokedynamic
|
||||||
oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int index, int cache_index, TRAPS) {
|
oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_cp, int index, int cache_index, TRAPS) {
|
||||||
oop result_oop = NULL;
|
oop result_oop = NULL;
|
||||||
Handle throw_exception;
|
Handle throw_exception;
|
||||||
|
|
||||||
@ -625,23 +625,23 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int inde
|
|||||||
// It is possible that this constant is one which is cached in the objects.
|
// It is possible that this constant is one which is cached in the objects.
|
||||||
// We'll do a linear search. This should be OK because this usage is rare.
|
// We'll do a linear search. This should be OK because this usage is rare.
|
||||||
assert(index > 0, "valid index");
|
assert(index > 0, "valid index");
|
||||||
cache_index = this_oop->cp_to_object_index(index);
|
cache_index = this_cp->cp_to_object_index(index);
|
||||||
}
|
}
|
||||||
assert(cache_index == _no_index_sentinel || cache_index >= 0, "");
|
assert(cache_index == _no_index_sentinel || cache_index >= 0, "");
|
||||||
assert(index == _no_index_sentinel || index >= 0, "");
|
assert(index == _no_index_sentinel || index >= 0, "");
|
||||||
|
|
||||||
if (cache_index >= 0) {
|
if (cache_index >= 0) {
|
||||||
result_oop = this_oop->resolved_references()->obj_at(cache_index);
|
result_oop = this_cp->resolved_references()->obj_at(cache_index);
|
||||||
if (result_oop != NULL) {
|
if (result_oop != NULL) {
|
||||||
return result_oop;
|
return result_oop;
|
||||||
// That was easy...
|
// That was easy...
|
||||||
}
|
}
|
||||||
index = this_oop->object_to_cp_index(cache_index);
|
index = this_cp->object_to_cp_index(cache_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
jvalue prim_value; // temp used only in a few cases below
|
jvalue prim_value; // temp used only in a few cases below
|
||||||
|
|
||||||
int tag_value = this_oop->tag_at(index).value();
|
int tag_value = this_cp->tag_at(index).value();
|
||||||
|
|
||||||
switch (tag_value) {
|
switch (tag_value) {
|
||||||
|
|
||||||
@ -650,7 +650,7 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int inde
|
|||||||
case JVM_CONSTANT_Class:
|
case JVM_CONSTANT_Class:
|
||||||
{
|
{
|
||||||
assert(cache_index == _no_index_sentinel, "should not have been set");
|
assert(cache_index == _no_index_sentinel, "should not have been set");
|
||||||
Klass* resolved = klass_at_impl(this_oop, index, CHECK_NULL);
|
Klass* resolved = klass_at_impl(this_cp, index, CHECK_NULL);
|
||||||
// ldc wants the java mirror.
|
// ldc wants the java mirror.
|
||||||
result_oop = resolved->java_mirror();
|
result_oop = resolved->java_mirror();
|
||||||
break;
|
break;
|
||||||
@ -658,17 +658,17 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int inde
|
|||||||
|
|
||||||
case JVM_CONSTANT_String:
|
case JVM_CONSTANT_String:
|
||||||
assert(cache_index != _no_index_sentinel, "should have been set");
|
assert(cache_index != _no_index_sentinel, "should have been set");
|
||||||
if (this_oop->is_pseudo_string_at(index)) {
|
if (this_cp->is_pseudo_string_at(index)) {
|
||||||
result_oop = this_oop->pseudo_string_at(index, cache_index);
|
result_oop = this_cp->pseudo_string_at(index, cache_index);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
result_oop = string_at_impl(this_oop, index, cache_index, CHECK_NULL);
|
result_oop = string_at_impl(this_cp, index, cache_index, CHECK_NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JVM_CONSTANT_MethodHandleInError:
|
case JVM_CONSTANT_MethodHandleInError:
|
||||||
case JVM_CONSTANT_MethodTypeInError:
|
case JVM_CONSTANT_MethodTypeInError:
|
||||||
{
|
{
|
||||||
Symbol* error = SystemDictionary::find_resolution_error(this_oop, index);
|
Symbol* error = SystemDictionary::find_resolution_error(this_cp, index);
|
||||||
guarantee(error != (Symbol*)NULL, "tag mismatch with resolution error table");
|
guarantee(error != (Symbol*)NULL, "tag mismatch with resolution error table");
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
THROW_MSG_0(error, "");
|
THROW_MSG_0(error, "");
|
||||||
@ -677,72 +677,72 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int inde
|
|||||||
|
|
||||||
case JVM_CONSTANT_MethodHandle:
|
case JVM_CONSTANT_MethodHandle:
|
||||||
{
|
{
|
||||||
int ref_kind = this_oop->method_handle_ref_kind_at(index);
|
int ref_kind = this_cp->method_handle_ref_kind_at(index);
|
||||||
int callee_index = this_oop->method_handle_klass_index_at(index);
|
int callee_index = this_cp->method_handle_klass_index_at(index);
|
||||||
Symbol* name = this_oop->method_handle_name_ref_at(index);
|
Symbol* name = this_cp->method_handle_name_ref_at(index);
|
||||||
Symbol* signature = this_oop->method_handle_signature_ref_at(index);
|
Symbol* signature = this_cp->method_handle_signature_ref_at(index);
|
||||||
if (PrintMiscellaneous)
|
if (PrintMiscellaneous)
|
||||||
tty->print_cr("resolve JVM_CONSTANT_MethodHandle:%d [%d/%d/%d] %s.%s",
|
tty->print_cr("resolve JVM_CONSTANT_MethodHandle:%d [%d/%d/%d] %s.%s",
|
||||||
ref_kind, index, this_oop->method_handle_index_at(index),
|
ref_kind, index, this_cp->method_handle_index_at(index),
|
||||||
callee_index, name->as_C_string(), signature->as_C_string());
|
callee_index, name->as_C_string(), signature->as_C_string());
|
||||||
KlassHandle callee;
|
KlassHandle callee;
|
||||||
{ Klass* k = klass_at_impl(this_oop, callee_index, CHECK_NULL);
|
{ Klass* k = klass_at_impl(this_cp, callee_index, CHECK_NULL);
|
||||||
callee = KlassHandle(THREAD, k);
|
callee = KlassHandle(THREAD, k);
|
||||||
}
|
}
|
||||||
KlassHandle klass(THREAD, this_oop->pool_holder());
|
KlassHandle klass(THREAD, this_cp->pool_holder());
|
||||||
Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind,
|
Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind,
|
||||||
callee, name, signature,
|
callee, name, signature,
|
||||||
THREAD);
|
THREAD);
|
||||||
result_oop = value();
|
result_oop = value();
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
save_and_throw_exception(this_oop, index, tag_value, CHECK_NULL);
|
save_and_throw_exception(this_cp, index, tag_value, CHECK_NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case JVM_CONSTANT_MethodType:
|
case JVM_CONSTANT_MethodType:
|
||||||
{
|
{
|
||||||
Symbol* signature = this_oop->method_type_signature_at(index);
|
Symbol* signature = this_cp->method_type_signature_at(index);
|
||||||
if (PrintMiscellaneous)
|
if (PrintMiscellaneous)
|
||||||
tty->print_cr("resolve JVM_CONSTANT_MethodType [%d/%d] %s",
|
tty->print_cr("resolve JVM_CONSTANT_MethodType [%d/%d] %s",
|
||||||
index, this_oop->method_type_index_at(index),
|
index, this_cp->method_type_index_at(index),
|
||||||
signature->as_C_string());
|
signature->as_C_string());
|
||||||
KlassHandle klass(THREAD, this_oop->pool_holder());
|
KlassHandle klass(THREAD, this_cp->pool_holder());
|
||||||
Handle value = SystemDictionary::find_method_handle_type(signature, klass, THREAD);
|
Handle value = SystemDictionary::find_method_handle_type(signature, klass, THREAD);
|
||||||
result_oop = value();
|
result_oop = value();
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
save_and_throw_exception(this_oop, index, tag_value, CHECK_NULL);
|
save_and_throw_exception(this_cp, index, tag_value, CHECK_NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case JVM_CONSTANT_Integer:
|
case JVM_CONSTANT_Integer:
|
||||||
assert(cache_index == _no_index_sentinel, "should not have been set");
|
assert(cache_index == _no_index_sentinel, "should not have been set");
|
||||||
prim_value.i = this_oop->int_at(index);
|
prim_value.i = this_cp->int_at(index);
|
||||||
result_oop = java_lang_boxing_object::create(T_INT, &prim_value, CHECK_NULL);
|
result_oop = java_lang_boxing_object::create(T_INT, &prim_value, CHECK_NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JVM_CONSTANT_Float:
|
case JVM_CONSTANT_Float:
|
||||||
assert(cache_index == _no_index_sentinel, "should not have been set");
|
assert(cache_index == _no_index_sentinel, "should not have been set");
|
||||||
prim_value.f = this_oop->float_at(index);
|
prim_value.f = this_cp->float_at(index);
|
||||||
result_oop = java_lang_boxing_object::create(T_FLOAT, &prim_value, CHECK_NULL);
|
result_oop = java_lang_boxing_object::create(T_FLOAT, &prim_value, CHECK_NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JVM_CONSTANT_Long:
|
case JVM_CONSTANT_Long:
|
||||||
assert(cache_index == _no_index_sentinel, "should not have been set");
|
assert(cache_index == _no_index_sentinel, "should not have been set");
|
||||||
prim_value.j = this_oop->long_at(index);
|
prim_value.j = this_cp->long_at(index);
|
||||||
result_oop = java_lang_boxing_object::create(T_LONG, &prim_value, CHECK_NULL);
|
result_oop = java_lang_boxing_object::create(T_LONG, &prim_value, CHECK_NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JVM_CONSTANT_Double:
|
case JVM_CONSTANT_Double:
|
||||||
assert(cache_index == _no_index_sentinel, "should not have been set");
|
assert(cache_index == _no_index_sentinel, "should not have been set");
|
||||||
prim_value.d = this_oop->double_at(index);
|
prim_value.d = this_cp->double_at(index);
|
||||||
result_oop = java_lang_boxing_object::create(T_DOUBLE, &prim_value, CHECK_NULL);
|
result_oop = java_lang_boxing_object::create(T_DOUBLE, &prim_value, CHECK_NULL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d",
|
DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d",
|
||||||
this_oop(), index, cache_index, tag_value) );
|
this_cp(), index, cache_index, tag_value) );
|
||||||
assert(false, "unexpected constant tag");
|
assert(false, "unexpected constant tag");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -750,15 +750,15 @@ oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int inde
|
|||||||
if (cache_index >= 0) {
|
if (cache_index >= 0) {
|
||||||
// Cache the oop here also.
|
// Cache the oop here also.
|
||||||
Handle result_handle(THREAD, result_oop);
|
Handle result_handle(THREAD, result_oop);
|
||||||
MonitorLockerEx ml(this_oop->lock()); // don't know if we really need this
|
MonitorLockerEx ml(this_cp->lock()); // don't know if we really need this
|
||||||
oop result = this_oop->resolved_references()->obj_at(cache_index);
|
oop result = this_cp->resolved_references()->obj_at(cache_index);
|
||||||
// Benign race condition: resolved_references may already be filled in while we were trying to lock.
|
// Benign race condition: resolved_references may already be filled in while we were trying to lock.
|
||||||
// The important thing here is that all threads pick up the same result.
|
// The important thing here is that all threads pick up the same result.
|
||||||
// It doesn't matter which racing thread wins, as long as only one
|
// It doesn't matter which racing thread wins, as long as only one
|
||||||
// result is used by all threads, and all future queries.
|
// result is used by all threads, and all future queries.
|
||||||
// That result may be either a resolved constant or a failure exception.
|
// That result may be either a resolved constant or a failure exception.
|
||||||
if (result == NULL) {
|
if (result == NULL) {
|
||||||
this_oop->resolved_references()->obj_at_put(cache_index, result_handle());
|
this_cp->resolved_references()->obj_at_put(cache_index, result_handle());
|
||||||
return result_handle();
|
return result_handle();
|
||||||
} else {
|
} else {
|
||||||
// Return the winning thread's result. This can be different than
|
// Return the winning thread's result. This can be different than
|
||||||
@ -778,8 +778,8 @@ oop ConstantPool::uncached_string_at(int which, TRAPS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
oop ConstantPool::resolve_bootstrap_specifier_at_impl(constantPoolHandle this_oop, int index, TRAPS) {
|
oop ConstantPool::resolve_bootstrap_specifier_at_impl(constantPoolHandle this_cp, int index, TRAPS) {
|
||||||
assert(this_oop->tag_at(index).is_invoke_dynamic(), "Corrupted constant pool");
|
assert(this_cp->tag_at(index).is_invoke_dynamic(), "Corrupted constant pool");
|
||||||
|
|
||||||
Handle bsm;
|
Handle bsm;
|
||||||
int argc;
|
int argc;
|
||||||
@ -787,14 +787,14 @@ oop ConstantPool::resolve_bootstrap_specifier_at_impl(constantPoolHandle this_oo
|
|||||||
// JVM_CONSTANT_InvokeDynamic is an ordered pair of [bootm, name&type], plus optional arguments
|
// JVM_CONSTANT_InvokeDynamic is an ordered pair of [bootm, name&type], plus optional arguments
|
||||||
// The bootm, being a JVM_CONSTANT_MethodHandle, has its own cache entry.
|
// The bootm, being a JVM_CONSTANT_MethodHandle, has its own cache entry.
|
||||||
// It is accompanied by the optional arguments.
|
// It is accompanied by the optional arguments.
|
||||||
int bsm_index = this_oop->invoke_dynamic_bootstrap_method_ref_index_at(index);
|
int bsm_index = this_cp->invoke_dynamic_bootstrap_method_ref_index_at(index);
|
||||||
oop bsm_oop = this_oop->resolve_possibly_cached_constant_at(bsm_index, CHECK_NULL);
|
oop bsm_oop = this_cp->resolve_possibly_cached_constant_at(bsm_index, CHECK_NULL);
|
||||||
if (!java_lang_invoke_MethodHandle::is_instance(bsm_oop)) {
|
if (!java_lang_invoke_MethodHandle::is_instance(bsm_oop)) {
|
||||||
THROW_MSG_NULL(vmSymbols::java_lang_LinkageError(), "BSM not an MethodHandle");
|
THROW_MSG_NULL(vmSymbols::java_lang_LinkageError(), "BSM not an MethodHandle");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract the optional static arguments.
|
// Extract the optional static arguments.
|
||||||
argc = this_oop->invoke_dynamic_argument_count_at(index);
|
argc = this_cp->invoke_dynamic_argument_count_at(index);
|
||||||
if (argc == 0) return bsm_oop;
|
if (argc == 0) return bsm_oop;
|
||||||
|
|
||||||
bsm = Handle(THREAD, bsm_oop);
|
bsm = Handle(THREAD, bsm_oop);
|
||||||
@ -808,21 +808,21 @@ oop ConstantPool::resolve_bootstrap_specifier_at_impl(constantPoolHandle this_oo
|
|||||||
|
|
||||||
info->obj_at_put(0, bsm());
|
info->obj_at_put(0, bsm());
|
||||||
for (int i = 0; i < argc; i++) {
|
for (int i = 0; i < argc; i++) {
|
||||||
int arg_index = this_oop->invoke_dynamic_argument_index_at(index, i);
|
int arg_index = this_cp->invoke_dynamic_argument_index_at(index, i);
|
||||||
oop arg_oop = this_oop->resolve_possibly_cached_constant_at(arg_index, CHECK_NULL);
|
oop arg_oop = this_cp->resolve_possibly_cached_constant_at(arg_index, CHECK_NULL);
|
||||||
info->obj_at_put(1+i, arg_oop);
|
info->obj_at_put(1+i, arg_oop);
|
||||||
}
|
}
|
||||||
|
|
||||||
return info();
|
return info();
|
||||||
}
|
}
|
||||||
|
|
||||||
oop ConstantPool::string_at_impl(constantPoolHandle this_oop, int which, int obj_index, TRAPS) {
|
oop ConstantPool::string_at_impl(constantPoolHandle this_cp, int which, int obj_index, TRAPS) {
|
||||||
// If the string has already been interned, this entry will be non-null
|
// If the string has already been interned, this entry will be non-null
|
||||||
oop str = this_oop->resolved_references()->obj_at(obj_index);
|
oop str = this_cp->resolved_references()->obj_at(obj_index);
|
||||||
if (str != NULL) return str;
|
if (str != NULL) return str;
|
||||||
Symbol* sym = this_oop->unresolved_string_at(which);
|
Symbol* sym = this_cp->unresolved_string_at(which);
|
||||||
str = StringTable::intern(sym, CHECK_(NULL));
|
str = StringTable::intern(sym, CHECK_(NULL));
|
||||||
this_oop->string_at_put(which, obj_index, str);
|
this_cp->string_at_put(which, obj_index, str);
|
||||||
assert(java_lang_String::is_instance(str), "must be string");
|
assert(java_lang_String::is_instance(str), "must be string");
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -48,7 +48,7 @@
|
|||||||
# include "bytes_ppc.hpp"
|
# include "bytes_ppc.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// A constantPool is an array containing class constants as described in the
|
// A ConstantPool is an array containing class constants as described in the
|
||||||
// class file.
|
// class file.
|
||||||
//
|
//
|
||||||
// Most of the constant pool entries are written during class parsing, which
|
// Most of the constant pool entries are written during class parsing, which
|
||||||
@ -81,9 +81,10 @@ class CPSlot VALUE_OBJ_CLASS_SPEC {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class KlassSizeStats;
|
class KlassSizeStats;
|
||||||
|
|
||||||
class ConstantPool : public Metadata {
|
class ConstantPool : public Metadata {
|
||||||
friend class VMStructs;
|
friend class VMStructs;
|
||||||
friend class BytecodeInterpreter; // Directly extracts an oop in the pool for fast instanceof/checkcast
|
friend class BytecodeInterpreter; // Directly extracts a klass in the pool for fast instanceof/checkcast
|
||||||
friend class Universe; // For null constructor
|
friend class Universe; // For null constructor
|
||||||
private:
|
private:
|
||||||
Array<u1>* _tags; // the tag array describing the constant pool's contents
|
Array<u1>* _tags; // the tag array describing the constant pool's contents
|
||||||
@ -747,13 +748,13 @@ class ConstantPool : public Metadata {
|
|||||||
friend class SystemDictionary;
|
friend class SystemDictionary;
|
||||||
|
|
||||||
// Used by compiler to prevent classloading.
|
// Used by compiler to prevent classloading.
|
||||||
static Method* method_at_if_loaded (constantPoolHandle this_oop, int which);
|
static Method* method_at_if_loaded (constantPoolHandle this_cp, int which);
|
||||||
static bool has_appendix_at_if_loaded (constantPoolHandle this_oop, int which);
|
static bool has_appendix_at_if_loaded (constantPoolHandle this_cp, int which);
|
||||||
static oop appendix_at_if_loaded (constantPoolHandle this_oop, int which);
|
static oop appendix_at_if_loaded (constantPoolHandle this_cp, int which);
|
||||||
static bool has_method_type_at_if_loaded (constantPoolHandle this_oop, int which);
|
static bool has_method_type_at_if_loaded (constantPoolHandle this_cp, int which);
|
||||||
static oop method_type_at_if_loaded (constantPoolHandle this_oop, int which);
|
static oop method_type_at_if_loaded (constantPoolHandle this_cp, int which);
|
||||||
static Klass* klass_at_if_loaded (constantPoolHandle this_oop, int which);
|
static Klass* klass_at_if_loaded (constantPoolHandle this_cp, int which);
|
||||||
static Klass* klass_ref_at_if_loaded (constantPoolHandle this_oop, int which);
|
static Klass* klass_ref_at_if_loaded (constantPoolHandle this_cp, int which);
|
||||||
|
|
||||||
// Routines currently used for annotations (only called by jvm.cpp) but which might be used in the
|
// Routines currently used for annotations (only called by jvm.cpp) but which might be used in the
|
||||||
// future by other Java code. These take constant pool indices rather than
|
// future by other Java code. These take constant pool indices rather than
|
||||||
@ -811,19 +812,19 @@ class ConstantPool : public Metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Performs the LinkResolver checks
|
// Performs the LinkResolver checks
|
||||||
static void verify_constant_pool_resolve(constantPoolHandle this_oop, KlassHandle klass, TRAPS);
|
static void verify_constant_pool_resolve(constantPoolHandle this_cp, KlassHandle klass, TRAPS);
|
||||||
|
|
||||||
// Implementation of methods that needs an exposed 'this' pointer, in order to
|
// Implementation of methods that needs an exposed 'this' pointer, in order to
|
||||||
// handle GC while executing the method
|
// handle GC while executing the method
|
||||||
static Klass* klass_at_impl(constantPoolHandle this_oop, int which, TRAPS);
|
static Klass* klass_at_impl(constantPoolHandle this_cp, int which, TRAPS);
|
||||||
static oop string_at_impl(constantPoolHandle this_oop, int which, int obj_index, TRAPS);
|
static oop string_at_impl(constantPoolHandle this_cp, int which, int obj_index, TRAPS);
|
||||||
|
|
||||||
// Resolve string constants (to prevent allocation during compilation)
|
// Resolve string constants (to prevent allocation during compilation)
|
||||||
static void resolve_string_constants_impl(constantPoolHandle this_oop, TRAPS);
|
static void resolve_string_constants_impl(constantPoolHandle this_cp, TRAPS);
|
||||||
|
|
||||||
static oop resolve_constant_at_impl(constantPoolHandle this_oop, int index, int cache_index, TRAPS);
|
static oop resolve_constant_at_impl(constantPoolHandle this_cp, int index, int cache_index, TRAPS);
|
||||||
static void save_and_throw_exception(constantPoolHandle this_oop, int which, int tag_value, TRAPS);
|
static void save_and_throw_exception(constantPoolHandle this_cp, int which, int tag_value, TRAPS);
|
||||||
static oop resolve_bootstrap_specifier_at_impl(constantPoolHandle this_oop, int index, TRAPS);
|
static oop resolve_bootstrap_specifier_at_impl(constantPoolHandle this_cp, int index, TRAPS);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Merging ConstantPool* support:
|
// Merging ConstantPool* support:
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -328,7 +328,7 @@ void ConstantPoolCacheEntry::set_method_handle_common(constantPoolHandle cpool,
|
|||||||
// the f1 method has signature '(Ljl/Object;Ljl/invoke/MethodType;)Ljl/Object;',
|
// the f1 method has signature '(Ljl/Object;Ljl/invoke/MethodType;)Ljl/Object;',
|
||||||
// not '(Ljava/lang/String;)Ljava/util/List;'.
|
// not '(Ljava/lang/String;)Ljava/util/List;'.
|
||||||
// The fact that String and List are involved is encoded in the MethodType in refs[f2].
|
// The fact that String and List are involved is encoded in the MethodType in refs[f2].
|
||||||
// This allows us to create fewer method oops, while keeping type safety.
|
// This allows us to create fewer Methods, while keeping type safety.
|
||||||
//
|
//
|
||||||
|
|
||||||
objArrayHandle resolved_references = cpool->resolved_references();
|
objArrayHandle resolved_references = cpool->resolved_references();
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -102,8 +102,9 @@ class PSPromotionManager;
|
|||||||
// _f1 = Method* for non-virtual calls, unused by virtual calls.
|
// _f1 = Method* for non-virtual calls, unused by virtual calls.
|
||||||
// for interface calls, which are essentially virtual but need a klass,
|
// for interface calls, which are essentially virtual but need a klass,
|
||||||
// contains Klass* for the corresponding interface.
|
// contains Klass* for the corresponding interface.
|
||||||
// for invokedynamic, f1 contains a site-specific CallSite object (as an appendix)
|
// for invokedynamic and invokehandle, f1 contains the adapter method which
|
||||||
// for invokehandle, f1 contains a site-specific MethodType object (as an appendix)
|
// manages the actual call. The appendix is stored in the ConstantPool
|
||||||
|
// resolved_references array.
|
||||||
// (upcoming metadata changes will move the appendix to a separate array)
|
// (upcoming metadata changes will move the appendix to a separate array)
|
||||||
// _f2 = vtable/itable index (or final Method*) for virtual calls only,
|
// _f2 = vtable/itable index (or final Method*) for virtual calls only,
|
||||||
// unused by non-virtual. The is_vfinal flag indicates this is a
|
// unused by non-virtual. The is_vfinal flag indicates this is a
|
||||||
|
@ -432,8 +432,8 @@ void InstanceKlass::eager_initialize(Thread *thread) {
|
|||||||
if (!InstanceKlass::cast(super)->is_initialized()) return;
|
if (!InstanceKlass::cast(super)->is_initialized()) return;
|
||||||
|
|
||||||
// call body to expose the this pointer
|
// call body to expose the this pointer
|
||||||
instanceKlassHandle this_oop(thread, this);
|
instanceKlassHandle this_k(thread, this);
|
||||||
eager_initialize_impl(this_oop);
|
eager_initialize_impl(this_k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -470,16 +470,16 @@ void InstanceKlass::fence_and_clear_init_lock() {
|
|||||||
assert(!is_not_initialized(), "class must be initialized now");
|
assert(!is_not_initialized(), "class must be initialized now");
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_oop) {
|
void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_k) {
|
||||||
EXCEPTION_MARK;
|
EXCEPTION_MARK;
|
||||||
oop init_lock = this_oop->init_lock();
|
oop init_lock = this_k->init_lock();
|
||||||
ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
|
ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
|
||||||
|
|
||||||
// abort if someone beat us to the initialization
|
// abort if someone beat us to the initialization
|
||||||
if (!this_oop->is_not_initialized()) return; // note: not equivalent to is_initialized()
|
if (!this_k->is_not_initialized()) return; // note: not equivalent to is_initialized()
|
||||||
|
|
||||||
ClassState old_state = this_oop->init_state();
|
ClassState old_state = this_k->init_state();
|
||||||
link_class_impl(this_oop, true, THREAD);
|
link_class_impl(this_k, true, THREAD);
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
CLEAR_PENDING_EXCEPTION;
|
CLEAR_PENDING_EXCEPTION;
|
||||||
// Abort if linking the class throws an exception.
|
// Abort if linking the class throws an exception.
|
||||||
@ -487,16 +487,16 @@ void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_oop) {
|
|||||||
// Use a test to avoid redundantly resetting the state if there's
|
// Use a test to avoid redundantly resetting the state if there's
|
||||||
// no change. Set_init_state() asserts that state changes make
|
// no change. Set_init_state() asserts that state changes make
|
||||||
// progress, whereas here we might just be spinning in place.
|
// progress, whereas here we might just be spinning in place.
|
||||||
if( old_state != this_oop->_init_state )
|
if( old_state != this_k->_init_state )
|
||||||
this_oop->set_init_state (old_state);
|
this_k->set_init_state (old_state);
|
||||||
} else {
|
} else {
|
||||||
// linking successfull, mark class as initialized
|
// linking successfull, mark class as initialized
|
||||||
this_oop->set_init_state (fully_initialized);
|
this_k->set_init_state (fully_initialized);
|
||||||
this_oop->fence_and_clear_init_lock();
|
this_k->fence_and_clear_init_lock();
|
||||||
// trace
|
// trace
|
||||||
if (TraceClassInitialization) {
|
if (TraceClassInitialization) {
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
tty->print_cr("[Initialized %s without side effects]", this_oop->external_name());
|
tty->print_cr("[Initialized %s without side effects]", this_k->external_name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -508,8 +508,8 @@ void InstanceKlass::eager_initialize_impl(instanceKlassHandle this_oop) {
|
|||||||
void InstanceKlass::initialize(TRAPS) {
|
void InstanceKlass::initialize(TRAPS) {
|
||||||
if (this->should_be_initialized()) {
|
if (this->should_be_initialized()) {
|
||||||
HandleMark hm(THREAD);
|
HandleMark hm(THREAD);
|
||||||
instanceKlassHandle this_oop(THREAD, this);
|
instanceKlassHandle this_k(THREAD, this);
|
||||||
initialize_impl(this_oop, CHECK);
|
initialize_impl(this_k, CHECK);
|
||||||
// Note: at this point the class may be initialized
|
// Note: at this point the class may be initialized
|
||||||
// OR it may be in the state of being initialized
|
// OR it may be in the state of being initialized
|
||||||
// in case of recursive initialization!
|
// in case of recursive initialization!
|
||||||
@ -520,11 +520,11 @@ void InstanceKlass::initialize(TRAPS) {
|
|||||||
|
|
||||||
|
|
||||||
bool InstanceKlass::verify_code(
|
bool InstanceKlass::verify_code(
|
||||||
instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS) {
|
instanceKlassHandle this_k, bool throw_verifyerror, TRAPS) {
|
||||||
// 1) Verify the bytecodes
|
// 1) Verify the bytecodes
|
||||||
Verifier::Mode mode =
|
Verifier::Mode mode =
|
||||||
throw_verifyerror ? Verifier::ThrowException : Verifier::NoException;
|
throw_verifyerror ? Verifier::ThrowException : Verifier::NoException;
|
||||||
return Verifier::verify(this_oop, mode, this_oop->should_verify_class(), CHECK_false);
|
return Verifier::verify(this_k, mode, this_k->should_verify_class(), CHECK_false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -540,8 +540,8 @@ void InstanceKlass::link_class(TRAPS) {
|
|||||||
assert(is_loaded(), "must be loaded");
|
assert(is_loaded(), "must be loaded");
|
||||||
if (!is_linked()) {
|
if (!is_linked()) {
|
||||||
HandleMark hm(THREAD);
|
HandleMark hm(THREAD);
|
||||||
instanceKlassHandle this_oop(THREAD, this);
|
instanceKlassHandle this_k(THREAD, this);
|
||||||
link_class_impl(this_oop, true, CHECK);
|
link_class_impl(this_k, true, CHECK);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -551,22 +551,22 @@ bool InstanceKlass::link_class_or_fail(TRAPS) {
|
|||||||
assert(is_loaded(), "must be loaded");
|
assert(is_loaded(), "must be loaded");
|
||||||
if (!is_linked()) {
|
if (!is_linked()) {
|
||||||
HandleMark hm(THREAD);
|
HandleMark hm(THREAD);
|
||||||
instanceKlassHandle this_oop(THREAD, this);
|
instanceKlassHandle this_k(THREAD, this);
|
||||||
link_class_impl(this_oop, false, CHECK_false);
|
link_class_impl(this_k, false, CHECK_false);
|
||||||
}
|
}
|
||||||
return is_linked();
|
return is_linked();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InstanceKlass::link_class_impl(
|
bool InstanceKlass::link_class_impl(
|
||||||
instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS) {
|
instanceKlassHandle this_k, bool throw_verifyerror, TRAPS) {
|
||||||
// check for error state
|
// check for error state
|
||||||
if (this_oop->is_in_error_state()) {
|
if (this_k->is_in_error_state()) {
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
THROW_MSG_(vmSymbols::java_lang_NoClassDefFoundError(),
|
THROW_MSG_(vmSymbols::java_lang_NoClassDefFoundError(),
|
||||||
this_oop->external_name(), false);
|
this_k->external_name(), false);
|
||||||
}
|
}
|
||||||
// return if already verified
|
// return if already verified
|
||||||
if (this_oop->is_linked()) {
|
if (this_k->is_linked()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -576,7 +576,7 @@ bool InstanceKlass::link_class_impl(
|
|||||||
JavaThread* jt = (JavaThread*)THREAD;
|
JavaThread* jt = (JavaThread*)THREAD;
|
||||||
|
|
||||||
// link super class before linking this class
|
// link super class before linking this class
|
||||||
instanceKlassHandle super(THREAD, this_oop->super());
|
instanceKlassHandle super(THREAD, this_k->super());
|
||||||
if (super.not_null()) {
|
if (super.not_null()) {
|
||||||
if (super->is_interface()) { // check if super class is an interface
|
if (super->is_interface()) { // check if super class is an interface
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
@ -584,7 +584,7 @@ bool InstanceKlass::link_class_impl(
|
|||||||
THREAD_AND_LOCATION,
|
THREAD_AND_LOCATION,
|
||||||
vmSymbols::java_lang_IncompatibleClassChangeError(),
|
vmSymbols::java_lang_IncompatibleClassChangeError(),
|
||||||
"class %s has interface %s as super class",
|
"class %s has interface %s as super class",
|
||||||
this_oop->external_name(),
|
this_k->external_name(),
|
||||||
super->external_name()
|
super->external_name()
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
@ -594,7 +594,7 @@ bool InstanceKlass::link_class_impl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// link all interfaces implemented by this class before linking this class
|
// link all interfaces implemented by this class before linking this class
|
||||||
Array<Klass*>* interfaces = this_oop->local_interfaces();
|
Array<Klass*>* interfaces = this_k->local_interfaces();
|
||||||
int num_interfaces = interfaces->length();
|
int num_interfaces = interfaces->length();
|
||||||
for (int index = 0; index < num_interfaces; index++) {
|
for (int index = 0; index < num_interfaces; index++) {
|
||||||
HandleMark hm(THREAD);
|
HandleMark hm(THREAD);
|
||||||
@ -603,7 +603,7 @@ bool InstanceKlass::link_class_impl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// in case the class is linked in the process of linking its superclasses
|
// in case the class is linked in the process of linking its superclasses
|
||||||
if (this_oop->is_linked()) {
|
if (this_k->is_linked()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -618,14 +618,14 @@ bool InstanceKlass::link_class_impl(
|
|||||||
|
|
||||||
// verification & rewriting
|
// verification & rewriting
|
||||||
{
|
{
|
||||||
oop init_lock = this_oop->init_lock();
|
oop init_lock = this_k->init_lock();
|
||||||
ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
|
ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
|
||||||
// rewritten will have been set if loader constraint error found
|
// rewritten will have been set if loader constraint error found
|
||||||
// on an earlier link attempt
|
// on an earlier link attempt
|
||||||
// don't verify or rewrite if already rewritten
|
// don't verify or rewrite if already rewritten
|
||||||
|
|
||||||
if (!this_oop->is_linked()) {
|
if (!this_k->is_linked()) {
|
||||||
if (!this_oop->is_rewritten()) {
|
if (!this_k->is_rewritten()) {
|
||||||
{
|
{
|
||||||
// Timer includes any side effects of class verification (resolution,
|
// Timer includes any side effects of class verification (resolution,
|
||||||
// etc), but not recursive entry into verify_code().
|
// etc), but not recursive entry into verify_code().
|
||||||
@ -635,7 +635,7 @@ bool InstanceKlass::link_class_impl(
|
|||||||
jt->get_thread_stat()->perf_recursion_counts_addr(),
|
jt->get_thread_stat()->perf_recursion_counts_addr(),
|
||||||
jt->get_thread_stat()->perf_timers_addr(),
|
jt->get_thread_stat()->perf_timers_addr(),
|
||||||
PerfClassTraceTime::CLASS_VERIFY);
|
PerfClassTraceTime::CLASS_VERIFY);
|
||||||
bool verify_ok = verify_code(this_oop, throw_verifyerror, THREAD);
|
bool verify_ok = verify_code(this_k, throw_verifyerror, THREAD);
|
||||||
if (!verify_ok) {
|
if (!verify_ok) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -644,39 +644,39 @@ bool InstanceKlass::link_class_impl(
|
|||||||
// Just in case a side-effect of verify linked this class already
|
// Just in case a side-effect of verify linked this class already
|
||||||
// (which can sometimes happen since the verifier loads classes
|
// (which can sometimes happen since the verifier loads classes
|
||||||
// using custom class loaders, which are free to initialize things)
|
// using custom class loaders, which are free to initialize things)
|
||||||
if (this_oop->is_linked()) {
|
if (this_k->is_linked()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// also sets rewritten
|
// also sets rewritten
|
||||||
this_oop->rewrite_class(CHECK_false);
|
this_k->rewrite_class(CHECK_false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// relocate jsrs and link methods after they are all rewritten
|
// relocate jsrs and link methods after they are all rewritten
|
||||||
this_oop->link_methods(CHECK_false);
|
this_k->link_methods(CHECK_false);
|
||||||
|
|
||||||
// Initialize the vtable and interface table after
|
// Initialize the vtable and interface table after
|
||||||
// methods have been rewritten since rewrite may
|
// methods have been rewritten since rewrite may
|
||||||
// fabricate new Method*s.
|
// fabricate new Method*s.
|
||||||
// also does loader constraint checking
|
// also does loader constraint checking
|
||||||
if (!this_oop()->is_shared()) {
|
if (!this_k()->is_shared()) {
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
this_oop->vtable()->initialize_vtable(true, CHECK_false);
|
this_k->vtable()->initialize_vtable(true, CHECK_false);
|
||||||
this_oop->itable()->initialize_itable(true, CHECK_false);
|
this_k->itable()->initialize_itable(true, CHECK_false);
|
||||||
}
|
}
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
else {
|
else {
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
this_oop->vtable()->verify(tty, true);
|
this_k->vtable()->verify(tty, true);
|
||||||
// In case itable verification is ever added.
|
// In case itable verification is ever added.
|
||||||
// this_oop->itable()->verify(tty, true);
|
// this_k->itable()->verify(tty, true);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
this_oop->set_init_state(linked);
|
this_k->set_init_state(linked);
|
||||||
if (JvmtiExport::should_post_class_prepare()) {
|
if (JvmtiExport::should_post_class_prepare()) {
|
||||||
Thread *thread = THREAD;
|
Thread *thread = THREAD;
|
||||||
assert(thread->is_Java_thread(), "thread->is_Java_thread()");
|
assert(thread->is_Java_thread(), "thread->is_Java_thread()");
|
||||||
JvmtiExport::post_class_prepare((JavaThread *) thread, this_oop());
|
JvmtiExport::post_class_prepare((JavaThread *) thread, this_k());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -689,13 +689,13 @@ bool InstanceKlass::link_class_impl(
|
|||||||
// verification but before the first method of the class is executed.
|
// verification but before the first method of the class is executed.
|
||||||
void InstanceKlass::rewrite_class(TRAPS) {
|
void InstanceKlass::rewrite_class(TRAPS) {
|
||||||
assert(is_loaded(), "must be loaded");
|
assert(is_loaded(), "must be loaded");
|
||||||
instanceKlassHandle this_oop(THREAD, this);
|
instanceKlassHandle this_k(THREAD, this);
|
||||||
if (this_oop->is_rewritten()) {
|
if (this_k->is_rewritten()) {
|
||||||
assert(this_oop()->is_shared(), "rewriting an unshared class?");
|
assert(this_k()->is_shared(), "rewriting an unshared class?");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Rewriter::rewrite(this_oop, CHECK);
|
Rewriter::rewrite(this_k, CHECK);
|
||||||
this_oop->set_rewritten();
|
this_k->set_rewritten();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now relocate and link method entry points after class is rewritten.
|
// Now relocate and link method entry points after class is rewritten.
|
||||||
@ -729,19 +729,19 @@ void InstanceKlass::link_methods(TRAPS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) {
|
void InstanceKlass::initialize_impl(instanceKlassHandle this_k, TRAPS) {
|
||||||
// Make sure klass is linked (verified) before initialization
|
// Make sure klass is linked (verified) before initialization
|
||||||
// A class could already be verified, since it has been reflected upon.
|
// A class could already be verified, since it has been reflected upon.
|
||||||
this_oop->link_class(CHECK);
|
this_k->link_class(CHECK);
|
||||||
|
|
||||||
DTRACE_CLASSINIT_PROBE(required, InstanceKlass::cast(this_oop()), -1);
|
DTRACE_CLASSINIT_PROBE(required, InstanceKlass::cast(this_k()), -1);
|
||||||
|
|
||||||
bool wait = false;
|
bool wait = false;
|
||||||
|
|
||||||
// refer to the JVM book page 47 for description of steps
|
// refer to the JVM book page 47 for description of steps
|
||||||
// Step 1
|
// Step 1
|
||||||
{
|
{
|
||||||
oop init_lock = this_oop->init_lock();
|
oop init_lock = this_k->init_lock();
|
||||||
ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
|
ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
|
||||||
|
|
||||||
Thread *self = THREAD; // it's passed the current thread
|
Thread *self = THREAD; // it's passed the current thread
|
||||||
@ -750,29 +750,29 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) {
|
|||||||
// If we were to use wait() instead of waitInterruptibly() then
|
// If we were to use wait() instead of waitInterruptibly() then
|
||||||
// we might end up throwing IE from link/symbol resolution sites
|
// we might end up throwing IE from link/symbol resolution sites
|
||||||
// that aren't expected to throw. This would wreak havoc. See 6320309.
|
// that aren't expected to throw. This would wreak havoc. See 6320309.
|
||||||
while(this_oop->is_being_initialized() && !this_oop->is_reentrant_initialization(self)) {
|
while(this_k->is_being_initialized() && !this_k->is_reentrant_initialization(self)) {
|
||||||
wait = true;
|
wait = true;
|
||||||
ol.waitUninterruptibly(CHECK);
|
ol.waitUninterruptibly(CHECK);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3
|
// Step 3
|
||||||
if (this_oop->is_being_initialized() && this_oop->is_reentrant_initialization(self)) {
|
if (this_k->is_being_initialized() && this_k->is_reentrant_initialization(self)) {
|
||||||
DTRACE_CLASSINIT_PROBE_WAIT(recursive, InstanceKlass::cast(this_oop()), -1,wait);
|
DTRACE_CLASSINIT_PROBE_WAIT(recursive, InstanceKlass::cast(this_k()), -1,wait);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4
|
// Step 4
|
||||||
if (this_oop->is_initialized()) {
|
if (this_k->is_initialized()) {
|
||||||
DTRACE_CLASSINIT_PROBE_WAIT(concurrent, InstanceKlass::cast(this_oop()), -1,wait);
|
DTRACE_CLASSINIT_PROBE_WAIT(concurrent, InstanceKlass::cast(this_k()), -1,wait);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 5
|
// Step 5
|
||||||
if (this_oop->is_in_error_state()) {
|
if (this_k->is_in_error_state()) {
|
||||||
DTRACE_CLASSINIT_PROBE_WAIT(erroneous, InstanceKlass::cast(this_oop()), -1,wait);
|
DTRACE_CLASSINIT_PROBE_WAIT(erroneous, InstanceKlass::cast(this_k()), -1,wait);
|
||||||
ResourceMark rm(THREAD);
|
ResourceMark rm(THREAD);
|
||||||
const char* desc = "Could not initialize class ";
|
const char* desc = "Could not initialize class ";
|
||||||
const char* className = this_oop->external_name();
|
const char* className = this_k->external_name();
|
||||||
size_t msglen = strlen(desc) + strlen(className) + 1;
|
size_t msglen = strlen(desc) + strlen(className) + 1;
|
||||||
char* message = NEW_RESOURCE_ARRAY(char, msglen);
|
char* message = NEW_RESOURCE_ARRAY(char, msglen);
|
||||||
if (NULL == message) {
|
if (NULL == message) {
|
||||||
@ -785,13 +785,13 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 6
|
// Step 6
|
||||||
this_oop->set_init_state(being_initialized);
|
this_k->set_init_state(being_initialized);
|
||||||
this_oop->set_init_thread(self);
|
this_k->set_init_thread(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 7
|
// Step 7
|
||||||
Klass* super_klass = this_oop->super();
|
Klass* super_klass = this_k->super();
|
||||||
if (super_klass != NULL && !this_oop->is_interface() && super_klass->should_be_initialized()) {
|
if (super_klass != NULL && !this_k->is_interface() && super_klass->should_be_initialized()) {
|
||||||
super_klass->initialize(THREAD);
|
super_klass->initialize(THREAD);
|
||||||
|
|
||||||
if (HAS_PENDING_EXCEPTION) {
|
if (HAS_PENDING_EXCEPTION) {
|
||||||
@ -799,18 +799,18 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) {
|
|||||||
CLEAR_PENDING_EXCEPTION;
|
CLEAR_PENDING_EXCEPTION;
|
||||||
{
|
{
|
||||||
EXCEPTION_MARK;
|
EXCEPTION_MARK;
|
||||||
this_oop->set_initialization_state_and_notify(initialization_error, THREAD); // Locks object, set state, and notify all waiting threads
|
this_k->set_initialization_state_and_notify(initialization_error, THREAD); // Locks object, set state, and notify all waiting threads
|
||||||
CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, superclass initialization error is thrown below
|
CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, superclass initialization error is thrown below
|
||||||
}
|
}
|
||||||
DTRACE_CLASSINIT_PROBE_WAIT(super__failed, InstanceKlass::cast(this_oop()), -1,wait);
|
DTRACE_CLASSINIT_PROBE_WAIT(super__failed, InstanceKlass::cast(this_k()), -1,wait);
|
||||||
THROW_OOP(e());
|
THROW_OOP(e());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this_oop->has_default_methods()) {
|
if (this_k->has_default_methods()) {
|
||||||
// Step 7.5: initialize any interfaces which have default methods
|
// Step 7.5: initialize any interfaces which have default methods
|
||||||
for (int i = 0; i < this_oop->local_interfaces()->length(); ++i) {
|
for (int i = 0; i < this_k->local_interfaces()->length(); ++i) {
|
||||||
Klass* iface = this_oop->local_interfaces()->at(i);
|
Klass* iface = this_k->local_interfaces()->at(i);
|
||||||
InstanceKlass* ik = InstanceKlass::cast(iface);
|
InstanceKlass* ik = InstanceKlass::cast(iface);
|
||||||
if (ik->has_default_methods() && ik->should_be_initialized()) {
|
if (ik->has_default_methods() && ik->should_be_initialized()) {
|
||||||
ik->initialize(THREAD);
|
ik->initialize(THREAD);
|
||||||
@ -821,7 +821,7 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) {
|
|||||||
{
|
{
|
||||||
EXCEPTION_MARK;
|
EXCEPTION_MARK;
|
||||||
// Locks object, set state, and notify all waiting threads
|
// Locks object, set state, and notify all waiting threads
|
||||||
this_oop->set_initialization_state_and_notify(
|
this_k->set_initialization_state_and_notify(
|
||||||
initialization_error, THREAD);
|
initialization_error, THREAD);
|
||||||
|
|
||||||
// ignore any exception thrown, superclass initialization error is
|
// ignore any exception thrown, superclass initialization error is
|
||||||
@ -829,7 +829,7 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) {
|
|||||||
CLEAR_PENDING_EXCEPTION;
|
CLEAR_PENDING_EXCEPTION;
|
||||||
}
|
}
|
||||||
DTRACE_CLASSINIT_PROBE_WAIT(
|
DTRACE_CLASSINIT_PROBE_WAIT(
|
||||||
super__failed, InstanceKlass::cast(this_oop()), -1, wait);
|
super__failed, InstanceKlass::cast(this_k()), -1, wait);
|
||||||
THROW_OOP(e());
|
THROW_OOP(e());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -840,7 +840,7 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) {
|
|||||||
{
|
{
|
||||||
assert(THREAD->is_Java_thread(), "non-JavaThread in initialize_impl");
|
assert(THREAD->is_Java_thread(), "non-JavaThread in initialize_impl");
|
||||||
JavaThread* jt = (JavaThread*)THREAD;
|
JavaThread* jt = (JavaThread*)THREAD;
|
||||||
DTRACE_CLASSINIT_PROBE_WAIT(clinit, InstanceKlass::cast(this_oop()), -1,wait);
|
DTRACE_CLASSINIT_PROBE_WAIT(clinit, InstanceKlass::cast(this_k()), -1,wait);
|
||||||
// Timer includes any side effects of class initialization (resolution,
|
// Timer includes any side effects of class initialization (resolution,
|
||||||
// etc), but not recursive entry into call_class_initializer().
|
// etc), but not recursive entry into call_class_initializer().
|
||||||
PerfClassTraceTime timer(ClassLoader::perf_class_init_time(),
|
PerfClassTraceTime timer(ClassLoader::perf_class_init_time(),
|
||||||
@ -849,14 +849,14 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) {
|
|||||||
jt->get_thread_stat()->perf_recursion_counts_addr(),
|
jt->get_thread_stat()->perf_recursion_counts_addr(),
|
||||||
jt->get_thread_stat()->perf_timers_addr(),
|
jt->get_thread_stat()->perf_timers_addr(),
|
||||||
PerfClassTraceTime::CLASS_CLINIT);
|
PerfClassTraceTime::CLASS_CLINIT);
|
||||||
this_oop->call_class_initializer(THREAD);
|
this_k->call_class_initializer(THREAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 9
|
// Step 9
|
||||||
if (!HAS_PENDING_EXCEPTION) {
|
if (!HAS_PENDING_EXCEPTION) {
|
||||||
this_oop->set_initialization_state_and_notify(fully_initialized, CHECK);
|
this_k->set_initialization_state_and_notify(fully_initialized, CHECK);
|
||||||
{ ResourceMark rm(THREAD);
|
{ ResourceMark rm(THREAD);
|
||||||
debug_only(this_oop->vtable()->verify(tty, true);)
|
debug_only(this_k->vtable()->verify(tty, true);)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -868,13 +868,13 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) {
|
|||||||
JvmtiExport::clear_detected_exception((JavaThread*)THREAD);
|
JvmtiExport::clear_detected_exception((JavaThread*)THREAD);
|
||||||
{
|
{
|
||||||
EXCEPTION_MARK;
|
EXCEPTION_MARK;
|
||||||
this_oop->set_initialization_state_and_notify(initialization_error, THREAD);
|
this_k->set_initialization_state_and_notify(initialization_error, THREAD);
|
||||||
CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, class initialization error is thrown below
|
CLEAR_PENDING_EXCEPTION; // ignore any exception thrown, class initialization error is thrown below
|
||||||
// JVMTI has already reported the pending exception
|
// JVMTI has already reported the pending exception
|
||||||
// JVMTI internal flag reset is needed in order to report ExceptionInInitializerError
|
// JVMTI internal flag reset is needed in order to report ExceptionInInitializerError
|
||||||
JvmtiExport::clear_detected_exception((JavaThread*)THREAD);
|
JvmtiExport::clear_detected_exception((JavaThread*)THREAD);
|
||||||
}
|
}
|
||||||
DTRACE_CLASSINIT_PROBE_WAIT(error, InstanceKlass::cast(this_oop()), -1,wait);
|
DTRACE_CLASSINIT_PROBE_WAIT(error, InstanceKlass::cast(this_k()), -1,wait);
|
||||||
if (e->is_a(SystemDictionary::Error_klass())) {
|
if (e->is_a(SystemDictionary::Error_klass())) {
|
||||||
THROW_OOP(e());
|
THROW_OOP(e());
|
||||||
} else {
|
} else {
|
||||||
@ -884,7 +884,7 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) {
|
|||||||
&args);
|
&args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DTRACE_CLASSINIT_PROBE_WAIT(end, InstanceKlass::cast(this_oop()), -1,wait);
|
DTRACE_CLASSINIT_PROBE_WAIT(end, InstanceKlass::cast(this_k()), -1,wait);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -894,11 +894,11 @@ void InstanceKlass::set_initialization_state_and_notify(ClassState state, TRAPS)
|
|||||||
set_initialization_state_and_notify_impl(kh, state, CHECK);
|
set_initialization_state_and_notify_impl(kh, state, CHECK);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceKlass::set_initialization_state_and_notify_impl(instanceKlassHandle this_oop, ClassState state, TRAPS) {
|
void InstanceKlass::set_initialization_state_and_notify_impl(instanceKlassHandle this_k, ClassState state, TRAPS) {
|
||||||
oop init_lock = this_oop->init_lock();
|
oop init_lock = this_k->init_lock();
|
||||||
ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
|
ObjectLocker ol(init_lock, THREAD, init_lock != NULL);
|
||||||
this_oop->set_init_state(state);
|
this_k->set_init_state(state);
|
||||||
this_oop->fence_and_clear_init_lock();
|
this_k->fence_and_clear_init_lock();
|
||||||
ol.notify_all(CHECK);
|
ol.notify_all(CHECK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -952,12 +952,11 @@ void InstanceKlass::init_implementor() {
|
|||||||
|
|
||||||
void InstanceKlass::process_interfaces(Thread *thread) {
|
void InstanceKlass::process_interfaces(Thread *thread) {
|
||||||
// link this class into the implementors list of every interface it implements
|
// link this class into the implementors list of every interface it implements
|
||||||
Klass* this_as_klass_oop = this;
|
|
||||||
for (int i = local_interfaces()->length() - 1; i >= 0; i--) {
|
for (int i = local_interfaces()->length() - 1; i >= 0; i--) {
|
||||||
assert(local_interfaces()->at(i)->is_klass(), "must be a klass");
|
assert(local_interfaces()->at(i)->is_klass(), "must be a klass");
|
||||||
InstanceKlass* interf = InstanceKlass::cast(local_interfaces()->at(i));
|
InstanceKlass* interf = InstanceKlass::cast(local_interfaces()->at(i));
|
||||||
assert(interf->is_interface(), "expected interface");
|
assert(interf->is_interface(), "expected interface");
|
||||||
interf->add_implementor(this_as_klass_oop);
|
interf->add_implementor(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1083,12 +1082,12 @@ void InstanceKlass::check_valid_for_instantiation(bool throwError, TRAPS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Klass* InstanceKlass::array_klass_impl(bool or_null, int n, TRAPS) {
|
Klass* InstanceKlass::array_klass_impl(bool or_null, int n, TRAPS) {
|
||||||
instanceKlassHandle this_oop(THREAD, this);
|
instanceKlassHandle this_k(THREAD, this);
|
||||||
return array_klass_impl(this_oop, or_null, n, THREAD);
|
return array_klass_impl(this_k, or_null, n, THREAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
Klass* InstanceKlass::array_klass_impl(instanceKlassHandle this_oop, bool or_null, int n, TRAPS) {
|
Klass* InstanceKlass::array_klass_impl(instanceKlassHandle this_k, bool or_null, int n, TRAPS) {
|
||||||
if (this_oop->array_klasses() == NULL) {
|
if (this_k->array_klasses() == NULL) {
|
||||||
if (or_null) return NULL;
|
if (or_null) return NULL;
|
||||||
|
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
@ -1099,14 +1098,14 @@ Klass* InstanceKlass::array_klass_impl(instanceKlassHandle this_oop, bool or_nul
|
|||||||
MutexLocker ma(MultiArray_lock, THREAD);
|
MutexLocker ma(MultiArray_lock, THREAD);
|
||||||
|
|
||||||
// Check if update has already taken place
|
// Check if update has already taken place
|
||||||
if (this_oop->array_klasses() == NULL) {
|
if (this_k->array_klasses() == NULL) {
|
||||||
Klass* k = ObjArrayKlass::allocate_objArray_klass(this_oop->class_loader_data(), 1, this_oop, CHECK_NULL);
|
Klass* k = ObjArrayKlass::allocate_objArray_klass(this_k->class_loader_data(), 1, this_k, CHECK_NULL);
|
||||||
this_oop->set_array_klasses(k);
|
this_k->set_array_klasses(k);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// _this will always be set at this point
|
// _this will always be set at this point
|
||||||
ObjArrayKlass* oak = (ObjArrayKlass*)this_oop->array_klasses();
|
ObjArrayKlass* oak = (ObjArrayKlass*)this_k->array_klasses();
|
||||||
if (or_null) {
|
if (or_null) {
|
||||||
return oak->array_klass_or_null(n);
|
return oak->array_klass_or_null(n);
|
||||||
}
|
}
|
||||||
@ -1133,20 +1132,20 @@ Method* InstanceKlass::class_initializer() {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstanceKlass::call_class_initializer_impl(instanceKlassHandle this_oop, TRAPS) {
|
void InstanceKlass::call_class_initializer_impl(instanceKlassHandle this_k, TRAPS) {
|
||||||
if (ReplayCompiles &&
|
if (ReplayCompiles &&
|
||||||
(ReplaySuppressInitializers == 1 ||
|
(ReplaySuppressInitializers == 1 ||
|
||||||
ReplaySuppressInitializers >= 2 && this_oop->class_loader() != NULL)) {
|
ReplaySuppressInitializers >= 2 && this_k->class_loader() != NULL)) {
|
||||||
// Hide the existence of the initializer for the purpose of replaying the compile
|
// Hide the existence of the initializer for the purpose of replaying the compile
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
methodHandle h_method(THREAD, this_oop->class_initializer());
|
methodHandle h_method(THREAD, this_k->class_initializer());
|
||||||
assert(!this_oop->is_initialized(), "we cannot initialize twice");
|
assert(!this_k->is_initialized(), "we cannot initialize twice");
|
||||||
if (TraceClassInitialization) {
|
if (TraceClassInitialization) {
|
||||||
tty->print("%d Initializing ", call_class_initializer_impl_counter++);
|
tty->print("%d Initializing ", call_class_initializer_impl_counter++);
|
||||||
this_oop->name()->print_value();
|
this_k->name()->print_value();
|
||||||
tty->print_cr("%s (" INTPTR_FORMAT ")", h_method() == NULL ? "(no method)" : "", (address)this_oop());
|
tty->print_cr("%s (" INTPTR_FORMAT ")", h_method() == NULL ? "(no method)" : "", (address)this_k());
|
||||||
}
|
}
|
||||||
if (h_method() != NULL) {
|
if (h_method() != NULL) {
|
||||||
JavaCallArguments args; // No arguments
|
JavaCallArguments args; // No arguments
|
||||||
@ -1296,8 +1295,8 @@ void InstanceKlass::do_local_static_fields(void f(fieldDescriptor*, TRAPS), TRAP
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void InstanceKlass::do_local_static_fields_impl(instanceKlassHandle this_oop, void f(fieldDescriptor* fd, TRAPS), TRAPS) {
|
void InstanceKlass::do_local_static_fields_impl(instanceKlassHandle this_k, void f(fieldDescriptor* fd, TRAPS), TRAPS) {
|
||||||
for (JavaFieldStream fs(this_oop()); !fs.done(); fs.next()) {
|
for (JavaFieldStream fs(this_k()); !fs.done(); fs.next()) {
|
||||||
if (fs.access_flags().is_static()) {
|
if (fs.access_flags().is_static()) {
|
||||||
fieldDescriptor& fd = fs.field_descriptor();
|
fieldDescriptor& fd = fs.field_descriptor();
|
||||||
f(&fd, CHECK);
|
f(&fd, CHECK);
|
||||||
@ -1515,14 +1514,14 @@ Method* InstanceKlass::lookup_method_in_all_interfaces(Symbol* name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* jni_id_for_impl for jfieldIds only */
|
/* jni_id_for_impl for jfieldIds only */
|
||||||
JNIid* InstanceKlass::jni_id_for_impl(instanceKlassHandle this_oop, int offset) {
|
JNIid* InstanceKlass::jni_id_for_impl(instanceKlassHandle this_k, int offset) {
|
||||||
MutexLocker ml(JfieldIdCreation_lock);
|
MutexLocker ml(JfieldIdCreation_lock);
|
||||||
// Retry lookup after we got the lock
|
// Retry lookup after we got the lock
|
||||||
JNIid* probe = this_oop->jni_ids() == NULL ? NULL : this_oop->jni_ids()->find(offset);
|
JNIid* probe = this_k->jni_ids() == NULL ? NULL : this_k->jni_ids()->find(offset);
|
||||||
if (probe == NULL) {
|
if (probe == NULL) {
|
||||||
// Slow case, allocate new static field identifier
|
// Slow case, allocate new static field identifier
|
||||||
probe = new JNIid(this_oop(), offset, this_oop->jni_ids());
|
probe = new JNIid(this_k(), offset, this_k->jni_ids());
|
||||||
this_oop->set_jni_ids(probe);
|
this_k->set_jni_ids(probe);
|
||||||
}
|
}
|
||||||
return probe;
|
return probe;
|
||||||
}
|
}
|
||||||
@ -3161,8 +3160,8 @@ void InstanceKlass::verify_on(outputStream* st) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Verify first subklass
|
// Verify first subklass
|
||||||
if (subklass_oop() != NULL) {
|
if (subklass() != NULL) {
|
||||||
guarantee(subklass_oop()->is_klass(), "should be klass");
|
guarantee(subklass()->is_klass(), "should be klass");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify siblings
|
// Verify siblings
|
||||||
|
@ -43,35 +43,7 @@
|
|||||||
// An InstanceKlass is the VM level representation of a Java class.
|
// An InstanceKlass is the VM level representation of a Java class.
|
||||||
// It contains all information needed for at class at execution runtime.
|
// It contains all information needed for at class at execution runtime.
|
||||||
|
|
||||||
// InstanceKlass layout:
|
// InstanceKlass embedded field layout (after declared fields):
|
||||||
// [C++ vtbl pointer ] Klass
|
|
||||||
// [subtype cache ] Klass
|
|
||||||
// [instance size ] Klass
|
|
||||||
// [java mirror ] Klass
|
|
||||||
// [super ] Klass
|
|
||||||
// [access_flags ] Klass
|
|
||||||
// [name ] Klass
|
|
||||||
// [first subklass ] Klass
|
|
||||||
// [next sibling ] Klass
|
|
||||||
// [array klasses ]
|
|
||||||
// [methods ]
|
|
||||||
// [local interfaces ]
|
|
||||||
// [transitive interfaces ]
|
|
||||||
// [fields ]
|
|
||||||
// [constants ]
|
|
||||||
// [class loader ]
|
|
||||||
// [source file name ]
|
|
||||||
// [inner classes ]
|
|
||||||
// [static field size ]
|
|
||||||
// [nonstatic field size ]
|
|
||||||
// [static oop fields size ]
|
|
||||||
// [nonstatic oop maps size ]
|
|
||||||
// [has finalize method ]
|
|
||||||
// [deoptimization mark bit ]
|
|
||||||
// [initialization state ]
|
|
||||||
// [initializing thread ]
|
|
||||||
// [Java vtable length ]
|
|
||||||
// [oop map cache (stack maps) ]
|
|
||||||
// [EMBEDDED Java vtable ] size in words = vtable_len
|
// [EMBEDDED Java vtable ] size in words = vtable_len
|
||||||
// [EMBEDDED nonstatic oop-map blocks] size in words = nonstatic_oop_map_size
|
// [EMBEDDED nonstatic oop-map blocks] size in words = nonstatic_oop_map_size
|
||||||
// The embedded nonstatic oop-map blocks are short pairs (offset, length)
|
// The embedded nonstatic oop-map blocks are short pairs (offset, length)
|
||||||
@ -1031,16 +1003,16 @@ private:
|
|||||||
|
|
||||||
// Static methods that are used to implement member methods where an exposed this pointer
|
// Static methods that are used to implement member methods where an exposed this pointer
|
||||||
// is needed due to possible GCs
|
// is needed due to possible GCs
|
||||||
static bool link_class_impl (instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS);
|
static bool link_class_impl (instanceKlassHandle this_k, bool throw_verifyerror, TRAPS);
|
||||||
static bool verify_code (instanceKlassHandle this_oop, bool throw_verifyerror, TRAPS);
|
static bool verify_code (instanceKlassHandle this_k, bool throw_verifyerror, TRAPS);
|
||||||
static void initialize_impl (instanceKlassHandle this_oop, TRAPS);
|
static void initialize_impl (instanceKlassHandle this_k, TRAPS);
|
||||||
static void eager_initialize_impl (instanceKlassHandle this_oop);
|
static void eager_initialize_impl (instanceKlassHandle this_k);
|
||||||
static void set_initialization_state_and_notify_impl (instanceKlassHandle this_oop, ClassState state, TRAPS);
|
static void set_initialization_state_and_notify_impl (instanceKlassHandle this_k, ClassState state, TRAPS);
|
||||||
static void call_class_initializer_impl (instanceKlassHandle this_oop, TRAPS);
|
static void call_class_initializer_impl (instanceKlassHandle this_k, TRAPS);
|
||||||
static Klass* array_klass_impl (instanceKlassHandle this_oop, bool or_null, int n, TRAPS);
|
static Klass* array_klass_impl (instanceKlassHandle this_k, bool or_null, int n, TRAPS);
|
||||||
static void do_local_static_fields_impl (instanceKlassHandle this_oop, void f(fieldDescriptor* fd, TRAPS), TRAPS);
|
static void do_local_static_fields_impl (instanceKlassHandle this_k, void f(fieldDescriptor* fd, TRAPS), TRAPS);
|
||||||
/* jni_id_for_impl for jfieldID only */
|
/* jni_id_for_impl for jfieldID only */
|
||||||
static JNIid* jni_id_for_impl (instanceKlassHandle this_oop, int offset);
|
static JNIid* jni_id_for_impl (instanceKlassHandle this_k, int offset);
|
||||||
|
|
||||||
// Returns the array class for the n'th dimension
|
// Returns the array class for the n'th dimension
|
||||||
Klass* array_klass_impl(bool or_null, int n, TRAPS);
|
Klass* array_klass_impl(bool or_null, int n, TRAPS);
|
||||||
|
@ -334,19 +334,11 @@ GrowableArray<Klass*>* Klass::compute_secondary_supers(int num_extra_slots) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Klass* Klass::subklass() const {
|
|
||||||
return _subklass == NULL ? NULL : _subklass;
|
|
||||||
}
|
|
||||||
|
|
||||||
InstanceKlass* Klass::superklass() const {
|
InstanceKlass* Klass::superklass() const {
|
||||||
assert(super() == NULL || super()->oop_is_instance(), "must be instance klass");
|
assert(super() == NULL || super()->oop_is_instance(), "must be instance klass");
|
||||||
return _super == NULL ? NULL : InstanceKlass::cast(_super);
|
return _super == NULL ? NULL : InstanceKlass::cast(_super);
|
||||||
}
|
}
|
||||||
|
|
||||||
Klass* Klass::next_sibling() const {
|
|
||||||
return _next_sibling == NULL ? NULL : _next_sibling;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Klass::set_subklass(Klass* s) {
|
void Klass::set_subklass(Klass* s) {
|
||||||
assert(s != this, "sanity check");
|
assert(s != this, "sanity check");
|
||||||
_subklass = s;
|
_subklass = s;
|
||||||
@ -365,7 +357,7 @@ void Klass::append_to_sibling_list() {
|
|||||||
assert((!super->is_interface() // interfaces cannot be supers
|
assert((!super->is_interface() // interfaces cannot be supers
|
||||||
&& (super->superklass() == NULL || !is_interface())),
|
&& (super->superklass() == NULL || !is_interface())),
|
||||||
"an interface can only be a subklass of Object");
|
"an interface can only be a subklass of Object");
|
||||||
Klass* prev_first_subklass = super->subklass_oop();
|
Klass* prev_first_subklass = super->subklass();
|
||||||
if (prev_first_subklass != NULL) {
|
if (prev_first_subklass != NULL) {
|
||||||
// set our sibling to be the superklass' previous first subklass
|
// set our sibling to be the superklass' previous first subklass
|
||||||
set_next_sibling(prev_first_subklass);
|
set_next_sibling(prev_first_subklass);
|
||||||
@ -405,7 +397,7 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive) {
|
|||||||
assert(current->is_loader_alive(is_alive), "just checking, this should be live");
|
assert(current->is_loader_alive(is_alive), "just checking, this should be live");
|
||||||
|
|
||||||
// Find and set the first alive subklass
|
// Find and set the first alive subklass
|
||||||
Klass* sub = current->subklass_oop();
|
Klass* sub = current->subklass();
|
||||||
while (sub != NULL && !sub->is_loader_alive(is_alive)) {
|
while (sub != NULL && !sub->is_loader_alive(is_alive)) {
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (TraceClassUnloading && WizardMode) {
|
if (TraceClassUnloading && WizardMode) {
|
||||||
@ -413,7 +405,7 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive) {
|
|||||||
tty->print_cr("[Unlinking class (subclass) %s]", sub->external_name());
|
tty->print_cr("[Unlinking class (subclass) %s]", sub->external_name());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
sub = sub->next_sibling_oop();
|
sub = sub->next_sibling();
|
||||||
}
|
}
|
||||||
current->set_subklass(sub);
|
current->set_subklass(sub);
|
||||||
if (sub != NULL) {
|
if (sub != NULL) {
|
||||||
@ -421,13 +413,13 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find and set the first alive sibling
|
// Find and set the first alive sibling
|
||||||
Klass* sibling = current->next_sibling_oop();
|
Klass* sibling = current->next_sibling();
|
||||||
while (sibling != NULL && !sibling->is_loader_alive(is_alive)) {
|
while (sibling != NULL && !sibling->is_loader_alive(is_alive)) {
|
||||||
if (TraceClassUnloading && WizardMode) {
|
if (TraceClassUnloading && WizardMode) {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
tty->print_cr("[Unlinking class (sibling) %s]", sibling->external_name());
|
tty->print_cr("[Unlinking class (sibling) %s]", sibling->external_name());
|
||||||
}
|
}
|
||||||
sibling = sibling->next_sibling_oop();
|
sibling = sibling->next_sibling();
|
||||||
}
|
}
|
||||||
current->set_next_sibling(sibling);
|
current->set_next_sibling(sibling);
|
||||||
if (sibling != NULL) {
|
if (sibling != NULL) {
|
||||||
|
@ -56,34 +56,6 @@
|
|||||||
// actual type. (See oop.inline.hpp for some of the forwarding code.)
|
// actual type. (See oop.inline.hpp for some of the forwarding code.)
|
||||||
// ALL FUNCTIONS IMPLEMENTING THIS DISPATCH ARE PREFIXED WITH "oop_"!
|
// ALL FUNCTIONS IMPLEMENTING THIS DISPATCH ARE PREFIXED WITH "oop_"!
|
||||||
|
|
||||||
// Klass layout:
|
|
||||||
// [C++ vtbl ptr ] (contained in Metadata)
|
|
||||||
// [layout_helper ]
|
|
||||||
// [super_check_offset ] for fast subtype checks
|
|
||||||
// [name ]
|
|
||||||
// [secondary_super_cache] for fast subtype checks
|
|
||||||
// [secondary_supers ] array of 2ndary supertypes
|
|
||||||
// [primary_supers 0]
|
|
||||||
// [primary_supers 1]
|
|
||||||
// [primary_supers 2]
|
|
||||||
// ...
|
|
||||||
// [primary_supers 7]
|
|
||||||
// [java_mirror ]
|
|
||||||
// [super ]
|
|
||||||
// [subklass ] first subclass
|
|
||||||
// [next_sibling ] link to chain additional subklasses
|
|
||||||
// [next_link ]
|
|
||||||
// [class_loader_data]
|
|
||||||
// [modifier_flags]
|
|
||||||
// [access_flags ]
|
|
||||||
// [last_biased_lock_bulk_revocation_time] (64 bits)
|
|
||||||
// [prototype_header]
|
|
||||||
// [biased_lock_revocation_count]
|
|
||||||
// [_modified_oops]
|
|
||||||
// [_accumulated_modified_oops]
|
|
||||||
// [trace_id]
|
|
||||||
|
|
||||||
|
|
||||||
// Forward declarations.
|
// Forward declarations.
|
||||||
template <class T> class Array;
|
template <class T> class Array;
|
||||||
template <class T> class GrowableArray;
|
template <class T> class GrowableArray;
|
||||||
@ -257,9 +229,9 @@ class Klass : public Metadata {
|
|||||||
// Use InstanceKlass::contains_field_offset to classify field offsets.
|
// Use InstanceKlass::contains_field_offset to classify field offsets.
|
||||||
|
|
||||||
// sub/superklass links
|
// sub/superklass links
|
||||||
|
Klass* subklass() const { return _subklass; }
|
||||||
|
Klass* next_sibling() const { return _next_sibling; }
|
||||||
InstanceKlass* superklass() const;
|
InstanceKlass* superklass() const;
|
||||||
Klass* subklass() const;
|
|
||||||
Klass* next_sibling() const;
|
|
||||||
void append_to_sibling_list(); // add newly created receiver to superklass' subklass list
|
void append_to_sibling_list(); // add newly created receiver to superklass' subklass list
|
||||||
|
|
||||||
void set_next_link(Klass* k) { _next_link = k; }
|
void set_next_link(Klass* k) { _next_link = k; }
|
||||||
@ -281,8 +253,6 @@ class Klass : public Metadata {
|
|||||||
bool has_accumulated_modified_oops() { return _accumulated_modified_oops == 1; }
|
bool has_accumulated_modified_oops() { return _accumulated_modified_oops == 1; }
|
||||||
|
|
||||||
protected: // internal accessors
|
protected: // internal accessors
|
||||||
Klass* subklass_oop() const { return _subklass; }
|
|
||||||
Klass* next_sibling_oop() const { return _next_sibling; }
|
|
||||||
void set_subklass(Klass* s);
|
void set_subklass(Klass* s);
|
||||||
void set_next_sibling(Klass* s);
|
void set_next_sibling(Klass* s);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -329,14 +329,12 @@ bool Method::was_executed_more_than(int n) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void Method::print_invocation_count() {
|
void Method::print_invocation_count() {
|
||||||
if (is_static()) tty->print("static ");
|
if (is_static()) tty->print("static ");
|
||||||
if (is_final()) tty->print("final ");
|
if (is_final()) tty->print("final ");
|
||||||
if (is_synchronized()) tty->print("synchronized ");
|
if (is_synchronized()) tty->print("synchronized ");
|
||||||
if (is_native()) tty->print("native ");
|
if (is_native()) tty->print("native ");
|
||||||
method_holder()->name()->print_symbol_on(tty);
|
tty->print("%s::", method_holder()->external_name());
|
||||||
tty->print(".");
|
|
||||||
name()->print_symbol_on(tty);
|
name()->print_symbol_on(tty);
|
||||||
signature()->print_symbol_on(tty);
|
signature()->print_symbol_on(tty);
|
||||||
|
|
||||||
@ -349,12 +347,12 @@ void Method::print_invocation_count() {
|
|||||||
tty->print_cr (" interpreter_invocation_count: %8d ", interpreter_invocation_count());
|
tty->print_cr (" interpreter_invocation_count: %8d ", interpreter_invocation_count());
|
||||||
tty->print_cr (" invocation_counter: %8d ", invocation_count());
|
tty->print_cr (" invocation_counter: %8d ", invocation_count());
|
||||||
tty->print_cr (" backedge_counter: %8d ", backedge_count());
|
tty->print_cr (" backedge_counter: %8d ", backedge_count());
|
||||||
|
#ifndef PRODUCT
|
||||||
if (CountCompiledCalls) {
|
if (CountCompiledCalls) {
|
||||||
tty->print_cr (" compiled_invocation_count: %8d ", compiled_invocation_count());
|
tty->print_cr (" compiled_invocation_count: %8d ", compiled_invocation_count());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Build a MethodData* object to hold information about this method
|
// Build a MethodData* object to hold information about this method
|
||||||
// collected in the interpreter.
|
// collected in the interpreter.
|
||||||
@ -577,12 +575,12 @@ bool Method::is_static_initializer() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
objArrayHandle Method::resolved_checked_exceptions_impl(Method* this_oop, TRAPS) {
|
objArrayHandle Method::resolved_checked_exceptions_impl(Method* method, TRAPS) {
|
||||||
int length = this_oop->checked_exceptions_length();
|
int length = method->checked_exceptions_length();
|
||||||
if (length == 0) { // common case
|
if (length == 0) { // common case
|
||||||
return objArrayHandle(THREAD, Universe::the_empty_class_klass_array());
|
return objArrayHandle(THREAD, Universe::the_empty_class_klass_array());
|
||||||
} else {
|
} else {
|
||||||
methodHandle h_this(THREAD, this_oop);
|
methodHandle h_this(THREAD, method);
|
||||||
objArrayOop m_oop = oopFactory::new_objArray(SystemDictionary::Class_klass(), length, CHECK_(objArrayHandle()));
|
objArrayOop m_oop = oopFactory::new_objArray(SystemDictionary::Class_klass(), length, CHECK_(objArrayHandle()));
|
||||||
objArrayHandle mirrors (THREAD, m_oop);
|
objArrayHandle mirrors (THREAD, m_oop);
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
@ -1443,10 +1441,6 @@ void Method::print_name(outputStream* st) {
|
|||||||
#endif // !PRODUCT || INCLUDE_JVMTI
|
#endif // !PRODUCT || INCLUDE_JVMTI
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------------
|
|
||||||
// Non-product code
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void Method::print_codes_on(outputStream* st) const {
|
void Method::print_codes_on(outputStream* st) const {
|
||||||
print_codes_on(0, code_size(), st);
|
print_codes_on(0, code_size(), st);
|
||||||
}
|
}
|
||||||
@ -1460,7 +1454,6 @@ void Method::print_codes_on(int from, int to, outputStream* st) const {
|
|||||||
BytecodeTracer::set_closure(BytecodeTracer::std_closure());
|
BytecodeTracer::set_closure(BytecodeTracer::std_closure());
|
||||||
while (s.next() >= 0) BytecodeTracer::trace(mh, s.bcp(), st);
|
while (s.next() >= 0) BytecodeTracer::trace(mh, s.bcp(), st);
|
||||||
}
|
}
|
||||||
#endif // not PRODUCT
|
|
||||||
|
|
||||||
|
|
||||||
// Simple compression of line number tables. We use a regular compressed stream, except that we compress deltas
|
// Simple compression of line number tables. We use a regular compressed stream, except that we compress deltas
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
|
* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
@ -40,50 +40,15 @@
|
|||||||
|
|
||||||
// A Method represents a Java method.
|
// A Method represents a Java method.
|
||||||
//
|
//
|
||||||
// Memory layout (each line represents a word). Note that most applications load thousands of methods,
|
// Note that most applications load thousands of methods, so keeping the size of this
|
||||||
// so keeping the size of this structure small has a big impact on footprint.
|
// class small has a big impact on footprint.
|
||||||
//
|
//
|
||||||
// The actual bytecodes are inlined after the end of the Method struct.
|
// Note that native_function and signature_handler have to be at fixed offsets
|
||||||
|
// (required by the interpreter)
|
||||||
//
|
//
|
||||||
// There are bits in the access_flags telling whether inlined tables are present.
|
// Method embedded field layout (after declared fields):
|
||||||
// Note that accessing the line number and local variable tables is not performance critical at all.
|
// [EMBEDDED native_function (present only if native) ]
|
||||||
// Accessing the checked exceptions table is used by reflection, so we put that last to make access
|
// [EMBEDDED signature_handler (present only if native) ]
|
||||||
// to it fast.
|
|
||||||
//
|
|
||||||
// The line number table is compressed and inlined following the byte codes. It is found as the first
|
|
||||||
// byte following the byte codes. The checked exceptions table and the local variable table are inlined
|
|
||||||
// after the line number table, and indexed from the end of the method. We do not compress the checked
|
|
||||||
// exceptions table since the average length is less than 2, and do not bother to compress the local
|
|
||||||
// variable table either since it is mostly absent.
|
|
||||||
//
|
|
||||||
// Note that native_function and signature_handler has to be at fixed offsets (required by the interpreter)
|
|
||||||
//
|
|
||||||
// |------------------------------------------------------|
|
|
||||||
// | header |
|
|
||||||
// | klass |
|
|
||||||
// |------------------------------------------------------|
|
|
||||||
// | ConstMethod* (metadata) |
|
|
||||||
// |------------------------------------------------------|
|
|
||||||
// | MethodData* (metadata) |
|
|
||||||
// | MethodCounters |
|
|
||||||
// |------------------------------------------------------|
|
|
||||||
// | access_flags |
|
|
||||||
// | vtable_index |
|
|
||||||
// |------------------------------------------------------|
|
|
||||||
// | result_index (C++ interpreter only) |
|
|
||||||
// |------------------------------------------------------|
|
|
||||||
// | method_size | intrinsic_id | flags |
|
|
||||||
// |------------------------------------------------------|
|
|
||||||
// | code (pointer) |
|
|
||||||
// | i2i (pointer) |
|
|
||||||
// | adapter (pointer) |
|
|
||||||
// | from_compiled_entry (pointer) |
|
|
||||||
// | from_interpreted_entry (pointer) |
|
|
||||||
// |------------------------------------------------------|
|
|
||||||
// | native_function (present only if native) |
|
|
||||||
// | signature_handler (present only if native) |
|
|
||||||
// |------------------------------------------------------|
|
|
||||||
|
|
||||||
|
|
||||||
class CheckedExceptionElement;
|
class CheckedExceptionElement;
|
||||||
class LocalVariableTableElement;
|
class LocalVariableTableElement;
|
||||||
@ -429,6 +394,9 @@ class Method : public Metadata {
|
|||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
int compiled_invocation_count() const { return _compiled_invocation_count; }
|
int compiled_invocation_count() const { return _compiled_invocation_count; }
|
||||||
void set_compiled_invocation_count(int count) { _compiled_invocation_count = count; }
|
void set_compiled_invocation_count(int count) { _compiled_invocation_count = count; }
|
||||||
|
#else
|
||||||
|
// for PrintMethodData in a product build
|
||||||
|
int compiled_invocation_count() const { return 0; }
|
||||||
#endif // not PRODUCT
|
#endif // not PRODUCT
|
||||||
|
|
||||||
// Clear (non-shared space) pointers which could not be relevant
|
// Clear (non-shared space) pointers which could not be relevant
|
||||||
@ -497,10 +465,8 @@ class Method : public Metadata {
|
|||||||
// Interpreter oopmap support
|
// Interpreter oopmap support
|
||||||
void mask_for(int bci, InterpreterOopMap* mask);
|
void mask_for(int bci, InterpreterOopMap* mask);
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
// operations on invocation counter
|
// operations on invocation counter
|
||||||
void print_invocation_count();
|
void print_invocation_count();
|
||||||
#endif
|
|
||||||
|
|
||||||
// byte codes
|
// byte codes
|
||||||
void set_code(address code) { return constMethod()->set_code(code); }
|
void set_code(address code) { return constMethod()->set_code(code); }
|
||||||
@ -509,8 +475,8 @@ class Method : public Metadata {
|
|||||||
|
|
||||||
// prints byte codes
|
// prints byte codes
|
||||||
void print_codes() const { print_codes_on(tty); }
|
void print_codes() const { print_codes_on(tty); }
|
||||||
void print_codes_on(outputStream* st) const PRODUCT_RETURN;
|
void print_codes_on(outputStream* st) const;
|
||||||
void print_codes_on(int from, int to, outputStream* st) const PRODUCT_RETURN;
|
void print_codes_on(int from, int to, outputStream* st) const;
|
||||||
|
|
||||||
// method parameters
|
// method parameters
|
||||||
bool has_method_parameters() const
|
bool has_method_parameters() const
|
||||||
@ -661,7 +627,7 @@ class Method : public Metadata {
|
|||||||
|
|
||||||
// Static methods that are used to implement member methods where an exposed this pointer
|
// Static methods that are used to implement member methods where an exposed this pointer
|
||||||
// is needed due to possible GCs
|
// is needed due to possible GCs
|
||||||
static objArrayHandle resolved_checked_exceptions_impl(Method* this_oop, TRAPS);
|
static objArrayHandle resolved_checked_exceptions_impl(Method* method, TRAPS);
|
||||||
|
|
||||||
// Returns the byte code index from the byte code pointer
|
// Returns the byte code index from the byte code pointer
|
||||||
int bci_from(address bcp) const;
|
int bci_from(address bcp) const;
|
||||||
|
@ -115,7 +115,6 @@ void ProfileData::print_data_on(outputStream* st, const MethodData* md) const {
|
|||||||
print_data_on(st, print_data_on_helper(md));
|
print_data_on(st, print_data_on_helper(md));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void ProfileData::print_shared(outputStream* st, const char* name, const char* extra) const {
|
void ProfileData::print_shared(outputStream* st, const char* name, const char* extra) const {
|
||||||
st->print("bci: %d", bci());
|
st->print("bci: %d", bci());
|
||||||
st->fill_to(tab_width_one);
|
st->fill_to(tab_width_one);
|
||||||
@ -138,7 +137,6 @@ void ProfileData::print_shared(outputStream* st, const char* name, const char* e
|
|||||||
void ProfileData::tab(outputStream* st, bool first) const {
|
void ProfileData::tab(outputStream* st, bool first) const {
|
||||||
st->fill_to(first ? tab_width_one : tab_width_two);
|
st->fill_to(first ? tab_width_one : tab_width_two);
|
||||||
}
|
}
|
||||||
#endif // !PRODUCT
|
|
||||||
|
|
||||||
// ==================================================================
|
// ==================================================================
|
||||||
// BitData
|
// BitData
|
||||||
@ -147,23 +145,19 @@ void ProfileData::tab(outputStream* st, bool first) const {
|
|||||||
// whether a checkcast bytecode has seen a null value.
|
// whether a checkcast bytecode has seen a null value.
|
||||||
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void BitData::print_data_on(outputStream* st, const char* extra) const {
|
void BitData::print_data_on(outputStream* st, const char* extra) const {
|
||||||
print_shared(st, "BitData", extra);
|
print_shared(st, "BitData", extra);
|
||||||
}
|
}
|
||||||
#endif // !PRODUCT
|
|
||||||
|
|
||||||
// ==================================================================
|
// ==================================================================
|
||||||
// CounterData
|
// CounterData
|
||||||
//
|
//
|
||||||
// A CounterData corresponds to a simple counter.
|
// A CounterData corresponds to a simple counter.
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void CounterData::print_data_on(outputStream* st, const char* extra) const {
|
void CounterData::print_data_on(outputStream* st, const char* extra) const {
|
||||||
print_shared(st, "CounterData", extra);
|
print_shared(st, "CounterData", extra);
|
||||||
st->print_cr("count(%u)", count());
|
st->print_cr("count(%u)", count());
|
||||||
}
|
}
|
||||||
#endif // !PRODUCT
|
|
||||||
|
|
||||||
// ==================================================================
|
// ==================================================================
|
||||||
// JumpData
|
// JumpData
|
||||||
@ -188,12 +182,10 @@ void JumpData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
|
|||||||
set_displacement(offset);
|
set_displacement(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void JumpData::print_data_on(outputStream* st, const char* extra) const {
|
void JumpData::print_data_on(outputStream* st, const char* extra) const {
|
||||||
print_shared(st, "JumpData", extra);
|
print_shared(st, "JumpData", extra);
|
||||||
st->print_cr("taken(%u) displacement(%d)", taken(), displacement());
|
st->print_cr("taken(%u) displacement(%d)", taken(), displacement());
|
||||||
}
|
}
|
||||||
#endif // !PRODUCT
|
|
||||||
|
|
||||||
int TypeStackSlotEntries::compute_cell_count(Symbol* signature, bool include_receiver, int max) {
|
int TypeStackSlotEntries::compute_cell_count(Symbol* signature, bool include_receiver, int max) {
|
||||||
// Parameter profiling include the receiver
|
// Parameter profiling include the receiver
|
||||||
@ -342,7 +334,6 @@ bool TypeEntriesAtCall::arguments_profiling_enabled() {
|
|||||||
return MethodData::profile_arguments();
|
return MethodData::profile_arguments();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void TypeEntries::print_klass(outputStream* st, intptr_t k) {
|
void TypeEntries::print_klass(outputStream* st, intptr_t k) {
|
||||||
if (is_type_none(k)) {
|
if (is_type_none(k)) {
|
||||||
st->print("none");
|
st->print("none");
|
||||||
@ -398,7 +389,6 @@ void VirtualCallTypeData::print_data_on(outputStream* st, const char* extra) con
|
|||||||
_ret.print_data_on(st);
|
_ret.print_data_on(st);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// ==================================================================
|
// ==================================================================
|
||||||
// ReceiverTypeData
|
// ReceiverTypeData
|
||||||
@ -417,7 +407,6 @@ void ReceiverTypeData::clean_weak_klass_links(BoolObjectClosure* is_alive_cl) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void ReceiverTypeData::print_receiver_data_on(outputStream* st) const {
|
void ReceiverTypeData::print_receiver_data_on(outputStream* st) const {
|
||||||
uint row;
|
uint row;
|
||||||
int entries = 0;
|
int entries = 0;
|
||||||
@ -447,7 +436,6 @@ void VirtualCallData::print_data_on(outputStream* st, const char* extra) const {
|
|||||||
print_shared(st, "VirtualCallData", extra);
|
print_shared(st, "VirtualCallData", extra);
|
||||||
print_receiver_data_on(st);
|
print_receiver_data_on(st);
|
||||||
}
|
}
|
||||||
#endif // !PRODUCT
|
|
||||||
|
|
||||||
// ==================================================================
|
// ==================================================================
|
||||||
// RetData
|
// RetData
|
||||||
@ -499,7 +487,6 @@ DataLayout* RetData::advance(MethodData *md, int bci) {
|
|||||||
}
|
}
|
||||||
#endif // CC_INTERP
|
#endif // CC_INTERP
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void RetData::print_data_on(outputStream* st, const char* extra) const {
|
void RetData::print_data_on(outputStream* st, const char* extra) const {
|
||||||
print_shared(st, "RetData", extra);
|
print_shared(st, "RetData", extra);
|
||||||
uint row;
|
uint row;
|
||||||
@ -516,7 +503,6 @@ void RetData::print_data_on(outputStream* st, const char* extra) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // !PRODUCT
|
|
||||||
|
|
||||||
// ==================================================================
|
// ==================================================================
|
||||||
// BranchData
|
// BranchData
|
||||||
@ -534,7 +520,6 @@ void BranchData::post_initialize(BytecodeStream* stream, MethodData* mdo) {
|
|||||||
set_displacement(offset);
|
set_displacement(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void BranchData::print_data_on(outputStream* st, const char* extra) const {
|
void BranchData::print_data_on(outputStream* st, const char* extra) const {
|
||||||
print_shared(st, "BranchData", extra);
|
print_shared(st, "BranchData", extra);
|
||||||
st->print_cr("taken(%u) displacement(%d)",
|
st->print_cr("taken(%u) displacement(%d)",
|
||||||
@ -542,7 +527,6 @@ void BranchData::print_data_on(outputStream* st, const char* extra) const {
|
|||||||
tab(st);
|
tab(st);
|
||||||
st->print_cr("not taken(%u)", not_taken());
|
st->print_cr("not taken(%u)", not_taken());
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// ==================================================================
|
// ==================================================================
|
||||||
// MultiBranchData
|
// MultiBranchData
|
||||||
@ -608,7 +592,6 @@ void MultiBranchData::post_initialize(BytecodeStream* stream,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void MultiBranchData::print_data_on(outputStream* st, const char* extra) const {
|
void MultiBranchData::print_data_on(outputStream* st, const char* extra) const {
|
||||||
print_shared(st, "MultiBranchData", extra);
|
print_shared(st, "MultiBranchData", extra);
|
||||||
st->print_cr("default_count(%u) displacement(%d)",
|
st->print_cr("default_count(%u) displacement(%d)",
|
||||||
@ -620,9 +603,7 @@ void MultiBranchData::print_data_on(outputStream* st, const char* extra) const {
|
|||||||
count_at(i), displacement_at(i));
|
count_at(i), displacement_at(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void ArgInfoData::print_data_on(outputStream* st, const char* extra) const {
|
void ArgInfoData::print_data_on(outputStream* st, const char* extra) const {
|
||||||
print_shared(st, "ArgInfoData", extra);
|
print_shared(st, "ArgInfoData", extra);
|
||||||
int nargs = number_of_args();
|
int nargs = number_of_args();
|
||||||
@ -632,8 +613,6 @@ void ArgInfoData::print_data_on(outputStream* st, const char* extra) const {
|
|||||||
st->cr();
|
st->cr();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int ParametersTypeData::compute_cell_count(Method* m) {
|
int ParametersTypeData::compute_cell_count(Method* m) {
|
||||||
if (!MethodData::profile_parameters_for_method(m)) {
|
if (!MethodData::profile_parameters_for_method(m)) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -654,7 +633,6 @@ bool ParametersTypeData::profiling_enabled() {
|
|||||||
return MethodData::profile_parameters();
|
return MethodData::profile_parameters();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void ParametersTypeData::print_data_on(outputStream* st, const char* extra) const {
|
void ParametersTypeData::print_data_on(outputStream* st, const char* extra) const {
|
||||||
st->print("parameter types", extra);
|
st->print("parameter types", extra);
|
||||||
_parameters.print_data_on(st);
|
_parameters.print_data_on(st);
|
||||||
@ -666,7 +644,6 @@ void SpeculativeTrapData::print_data_on(outputStream* st, const char* extra) con
|
|||||||
method()->print_short_name(st);
|
method()->print_short_name(st);
|
||||||
st->cr();
|
st->cr();
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
// ==================================================================
|
// ==================================================================
|
||||||
// MethodData*
|
// MethodData*
|
||||||
@ -801,6 +778,8 @@ bool MethodData::is_speculative_trap_bytecode(Bytecodes::Code code) {
|
|||||||
case Bytecodes::_invokeinterface:
|
case Bytecodes::_invokeinterface:
|
||||||
case Bytecodes::_if_acmpeq:
|
case Bytecodes::_if_acmpeq:
|
||||||
case Bytecodes::_if_acmpne:
|
case Bytecodes::_if_acmpne:
|
||||||
|
case Bytecodes::_ifnull:
|
||||||
|
case Bytecodes::_ifnonnull:
|
||||||
case Bytecodes::_invokestatic:
|
case Bytecodes::_invokestatic:
|
||||||
#ifdef COMPILER2
|
#ifdef COMPILER2
|
||||||
return UseTypeSpeculation;
|
return UseTypeSpeculation;
|
||||||
@ -1357,8 +1336,6 @@ ArgInfoData *MethodData::arg_info() {
|
|||||||
|
|
||||||
// Printing
|
// Printing
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
|
|
||||||
void MethodData::print_on(outputStream* st) const {
|
void MethodData::print_on(outputStream* st) const {
|
||||||
assert(is_methodData(), "should be method data");
|
assert(is_methodData(), "should be method data");
|
||||||
st->print("method data for ");
|
st->print("method data for ");
|
||||||
@ -1367,15 +1344,12 @@ void MethodData::print_on(outputStream* st) const {
|
|||||||
print_data_on(st);
|
print_data_on(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif //PRODUCT
|
|
||||||
|
|
||||||
void MethodData::print_value_on(outputStream* st) const {
|
void MethodData::print_value_on(outputStream* st) const {
|
||||||
assert(is_methodData(), "should be method data");
|
assert(is_methodData(), "should be method data");
|
||||||
st->print("method data for ");
|
st->print("method data for ");
|
||||||
method()->print_value_on(st);
|
method()->print_value_on(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void MethodData::print_data_on(outputStream* st) const {
|
void MethodData::print_data_on(outputStream* st) const {
|
||||||
ResourceMark rm;
|
ResourceMark rm;
|
||||||
ProfileData* data = first_data();
|
ProfileData* data = first_data();
|
||||||
@ -1416,7 +1390,6 @@ void MethodData::print_data_on(outputStream* st) const {
|
|||||||
if (dp >= end) return;
|
if (dp >= end) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#if INCLUDE_SERVICES
|
#if INCLUDE_SERVICES
|
||||||
// Size Statistics
|
// Size Statistics
|
||||||
|
@ -280,12 +280,10 @@ class ProfileData : public ResourceObj {
|
|||||||
friend class ReturnTypeEntry;
|
friend class ReturnTypeEntry;
|
||||||
friend class TypeStackSlotEntries;
|
friend class TypeStackSlotEntries;
|
||||||
private:
|
private:
|
||||||
#ifndef PRODUCT
|
|
||||||
enum {
|
enum {
|
||||||
tab_width_one = 16,
|
tab_width_one = 16,
|
||||||
tab_width_two = 36
|
tab_width_two = 36
|
||||||
};
|
};
|
||||||
#endif // !PRODUCT
|
|
||||||
|
|
||||||
// This is a pointer to a section of profiling data.
|
// This is a pointer to a section of profiling data.
|
||||||
DataLayout* _data;
|
DataLayout* _data;
|
||||||
@ -521,10 +519,8 @@ public:
|
|||||||
|
|
||||||
void print_data_on(outputStream* st, const MethodData* md) const;
|
void print_data_on(outputStream* st, const MethodData* md) const;
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void print_shared(outputStream* st, const char* name, const char* extra) const;
|
void print_shared(outputStream* st, const char* name, const char* extra) const;
|
||||||
void tab(outputStream* st, bool first = false) const;
|
void tab(outputStream* st, bool first = false) const;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// BitData
|
// BitData
|
||||||
@ -583,9 +579,7 @@ public:
|
|||||||
}
|
}
|
||||||
#endif // CC_INTERP
|
#endif // CC_INTERP
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// CounterData
|
// CounterData
|
||||||
@ -646,9 +640,7 @@ public:
|
|||||||
}
|
}
|
||||||
#endif // CC_INTERP
|
#endif // CC_INTERP
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// JumpData
|
// JumpData
|
||||||
@ -733,9 +725,7 @@ public:
|
|||||||
// Specific initialization.
|
// Specific initialization.
|
||||||
void post_initialize(BytecodeStream* stream, MethodData* mdo);
|
void post_initialize(BytecodeStream* stream, MethodData* mdo);
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Entries in a ProfileData object to record types: it can either be
|
// Entries in a ProfileData object to record types: it can either be
|
||||||
@ -808,9 +798,7 @@ public:
|
|||||||
return with_status((intptr_t)k, in);
|
return with_status((intptr_t)k, in);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
static void print_klass(outputStream* st, intptr_t k);
|
static void print_klass(outputStream* st, intptr_t k);
|
||||||
#endif
|
|
||||||
|
|
||||||
// GC support
|
// GC support
|
||||||
static bool is_loader_alive(BoolObjectClosure* is_alive_cl, intptr_t p);
|
static bool is_loader_alive(BoolObjectClosure* is_alive_cl, intptr_t p);
|
||||||
@ -919,9 +907,7 @@ public:
|
|||||||
// GC support
|
// GC support
|
||||||
void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
|
void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void print_data_on(outputStream* st) const;
|
void print_data_on(outputStream* st) const;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Type entry used for return from a call. A single cell to record the
|
// Type entry used for return from a call. A single cell to record the
|
||||||
@ -964,9 +950,7 @@ public:
|
|||||||
// GC support
|
// GC support
|
||||||
void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
|
void clean_weak_klass_links(BoolObjectClosure* is_alive_closure);
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void print_data_on(outputStream* st) const;
|
void print_data_on(outputStream* st) const;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Entries to collect type information at a call: contains arguments
|
// Entries to collect type information at a call: contains arguments
|
||||||
@ -1144,9 +1128,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
|
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ReceiverTypeData
|
// ReceiverTypeData
|
||||||
@ -1288,10 +1270,8 @@ public:
|
|||||||
}
|
}
|
||||||
#endif // CC_INTERP
|
#endif // CC_INTERP
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void print_receiver_data_on(outputStream* st) const;
|
void print_receiver_data_on(outputStream* st) const;
|
||||||
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// VirtualCallData
|
// VirtualCallData
|
||||||
@ -1332,9 +1312,7 @@ public:
|
|||||||
}
|
}
|
||||||
#endif // CC_INTERP
|
#endif // CC_INTERP
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// VirtualCallTypeData
|
// VirtualCallTypeData
|
||||||
@ -1458,9 +1436,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
|
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// RetData
|
// RetData
|
||||||
@ -1561,9 +1537,7 @@ public:
|
|||||||
// Specific initialization.
|
// Specific initialization.
|
||||||
void post_initialize(BytecodeStream* stream, MethodData* mdo);
|
void post_initialize(BytecodeStream* stream, MethodData* mdo);
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// BranchData
|
// BranchData
|
||||||
@ -1639,9 +1613,7 @@ public:
|
|||||||
// Specific initialization.
|
// Specific initialization.
|
||||||
void post_initialize(BytecodeStream* stream, MethodData* mdo);
|
void post_initialize(BytecodeStream* stream, MethodData* mdo);
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ArrayData
|
// ArrayData
|
||||||
@ -1832,9 +1804,7 @@ public:
|
|||||||
// Specific initialization.
|
// Specific initialization.
|
||||||
void post_initialize(BytecodeStream* stream, MethodData* mdo);
|
void post_initialize(BytecodeStream* stream, MethodData* mdo);
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ArgInfoData : public ArrayData {
|
class ArgInfoData : public ArrayData {
|
||||||
@ -1859,9 +1829,7 @@ public:
|
|||||||
array_set_int_at(arg, val);
|
array_set_int_at(arg, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
void print_data_on(outputStream* st, const char* extra = NULL) const;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ParametersTypeData
|
// ParametersTypeData
|
||||||
@ -1920,9 +1888,7 @@ public:
|
|||||||
_parameters.clean_weak_klass_links(is_alive_closure);
|
_parameters.clean_weak_klass_links(is_alive_closure);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
|
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
|
||||||
#endif
|
|
||||||
|
|
||||||
static ByteSize stack_slot_offset(int i) {
|
static ByteSize stack_slot_offset(int i) {
|
||||||
return cell_offset(stack_slot_local_offset(i));
|
return cell_offset(stack_slot_local_offset(i));
|
||||||
@ -1976,9 +1942,7 @@ public:
|
|||||||
set_intptr_at(method_offset, (intptr_t)m);
|
set_intptr_at(method_offset, (intptr_t)m);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
|
virtual void print_data_on(outputStream* st, const char* extra = NULL) const;
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// MethodData*
|
// MethodData*
|
||||||
@ -2052,7 +2016,7 @@ public:
|
|||||||
|
|
||||||
// Whole-method sticky bits and flags
|
// Whole-method sticky bits and flags
|
||||||
enum {
|
enum {
|
||||||
_trap_hist_limit = 19, // decoupled from Deoptimization::Reason_LIMIT
|
_trap_hist_limit = 20, // decoupled from Deoptimization::Reason_LIMIT
|
||||||
_trap_hist_mask = max_jubyte,
|
_trap_hist_mask = max_jubyte,
|
||||||
_extra_data_count = 4 // extra DataLayout headers, for trap history
|
_extra_data_count = 4 // extra DataLayout headers, for trap history
|
||||||
}; // Public flag values
|
}; // Public flag values
|
||||||
@ -2457,15 +2421,11 @@ public:
|
|||||||
void set_size(int object_size_in_bytes) { _size = object_size_in_bytes; }
|
void set_size(int object_size_in_bytes) { _size = object_size_in_bytes; }
|
||||||
|
|
||||||
// Printing
|
// Printing
|
||||||
#ifndef PRODUCT
|
|
||||||
void print_on (outputStream* st) const;
|
void print_on (outputStream* st) const;
|
||||||
#endif
|
|
||||||
void print_value_on(outputStream* st) const;
|
void print_value_on(outputStream* st) const;
|
||||||
|
|
||||||
#ifndef PRODUCT
|
|
||||||
// printing support for method data
|
// printing support for method data
|
||||||
void print_data_on(outputStream* st) const;
|
void print_data_on(outputStream* st) const;
|
||||||
#endif
|
|
||||||
|
|
||||||
const char* internal_name() const { return "{method data}"; }
|
const char* internal_name() const { return "{method data}"; }
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
|
#include "opto/castnode.hpp"
|
||||||
#include "opto/cfgnode.hpp"
|
#include "opto/cfgnode.hpp"
|
||||||
#include "opto/connode.hpp"
|
#include "opto/connode.hpp"
|
||||||
#include "opto/machnode.hpp"
|
#include "opto/machnode.hpp"
|
||||||
|
@ -33,8 +33,8 @@
|
|||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
#include "opto/callGenerator.hpp"
|
#include "opto/callGenerator.hpp"
|
||||||
#include "opto/callnode.hpp"
|
#include "opto/callnode.hpp"
|
||||||
|
#include "opto/castnode.hpp"
|
||||||
#include "opto/cfgnode.hpp"
|
#include "opto/cfgnode.hpp"
|
||||||
#include "opto/connode.hpp"
|
|
||||||
#include "opto/parse.hpp"
|
#include "opto/parse.hpp"
|
||||||
#include "opto/rootnode.hpp"
|
#include "opto/rootnode.hpp"
|
||||||
#include "opto/runtime.hpp"
|
#include "opto/runtime.hpp"
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
#include "compiler/oopMap.hpp"
|
#include "compiler/oopMap.hpp"
|
||||||
#include "opto/callGenerator.hpp"
|
#include "opto/callGenerator.hpp"
|
||||||
#include "opto/callnode.hpp"
|
#include "opto/callnode.hpp"
|
||||||
|
#include "opto/castnode.hpp"
|
||||||
#include "opto/escape.hpp"
|
#include "opto/escape.hpp"
|
||||||
#include "opto/locknode.hpp"
|
#include "opto/locknode.hpp"
|
||||||
#include "opto/machnode.hpp"
|
#include "opto/machnode.hpp"
|
||||||
|
294
hotspot/src/share/vm/opto/castnode.cpp
Normal file
294
hotspot/src/share/vm/opto/castnode.cpp
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precompiled.hpp"
|
||||||
|
#include "opto/addnode.hpp"
|
||||||
|
#include "opto/castnode.hpp"
|
||||||
|
#include "opto/connode.hpp"
|
||||||
|
#include "opto/matcher.hpp"
|
||||||
|
#include "opto/phaseX.hpp"
|
||||||
|
#include "opto/subnode.hpp"
|
||||||
|
#include "opto/type.hpp"
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// If input is already higher or equal to cast type, then this is an identity.
|
||||||
|
Node *ConstraintCastNode::Identity( PhaseTransform *phase ) {
|
||||||
|
return phase->type(in(1))->higher_equal_speculative(_type) ? in(1) : this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
// Take 'join' of input and cast-up type
|
||||||
|
const Type *ConstraintCastNode::Value( PhaseTransform *phase ) const {
|
||||||
|
if( in(0) && phase->type(in(0)) == Type::TOP ) return Type::TOP;
|
||||||
|
const Type* ft = phase->type(in(1))->filter_speculative(_type);
|
||||||
|
|
||||||
|
#ifdef ASSERT
|
||||||
|
// Previous versions of this function had some special case logic,
|
||||||
|
// which is no longer necessary. Make sure of the required effects.
|
||||||
|
switch (Opcode()) {
|
||||||
|
case Op_CastII:
|
||||||
|
{
|
||||||
|
const Type* t1 = phase->type(in(1));
|
||||||
|
if( t1 == Type::TOP ) assert(ft == Type::TOP, "special case #1");
|
||||||
|
const Type* rt = t1->join_speculative(_type);
|
||||||
|
if (rt->empty()) assert(ft == Type::TOP, "special case #2");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Op_CastPP:
|
||||||
|
if (phase->type(in(1)) == TypePtr::NULL_PTR &&
|
||||||
|
_type->isa_ptr() && _type->is_ptr()->_ptr == TypePtr::NotNull)
|
||||||
|
assert(ft == Type::TOP, "special case #3");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif //ASSERT
|
||||||
|
|
||||||
|
return ft;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Ideal------------------------------------------
|
||||||
|
// Return a node which is more "ideal" than the current node. Strip out
|
||||||
|
// control copies
|
||||||
|
Node *ConstraintCastNode::Ideal(PhaseGVN *phase, bool can_reshape){
|
||||||
|
return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Ideal_DU_postCCP-------------------------------
|
||||||
|
// Throw away cast after constant propagation
|
||||||
|
Node *ConstraintCastNode::Ideal_DU_postCCP( PhaseCCP *ccp ) {
|
||||||
|
const Type *t = ccp->type(in(1));
|
||||||
|
ccp->hash_delete(this);
|
||||||
|
set_type(t); // Turn into ID function
|
||||||
|
ccp->hash_insert(this);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
|
||||||
|
//------------------------------Ideal_DU_postCCP-------------------------------
|
||||||
|
// If not converting int->oop, throw away cast after constant propagation
|
||||||
|
Node *CastPPNode::Ideal_DU_postCCP( PhaseCCP *ccp ) {
|
||||||
|
const Type *t = ccp->type(in(1));
|
||||||
|
if (!t->isa_oop_ptr() || ((in(1)->is_DecodeN()) && Matcher::gen_narrow_oop_implicit_null_checks())) {
|
||||||
|
return NULL; // do not transform raw pointers or narrow oops
|
||||||
|
}
|
||||||
|
return ConstraintCastNode::Ideal_DU_postCCP(ccp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Identity---------------------------------------
|
||||||
|
// If input is already higher or equal to cast type, then this is an identity.
|
||||||
|
Node *CheckCastPPNode::Identity( PhaseTransform *phase ) {
|
||||||
|
// Toned down to rescue meeting at a Phi 3 different oops all implementing
|
||||||
|
// the same interface. CompileTheWorld starting at 502, kd12rc1.zip.
|
||||||
|
return (phase->type(in(1)) == phase->type(this)) ? in(1) : this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
// Take 'join' of input and cast-up type, unless working with an Interface
|
||||||
|
const Type *CheckCastPPNode::Value( PhaseTransform *phase ) const {
|
||||||
|
if( in(0) && phase->type(in(0)) == Type::TOP ) return Type::TOP;
|
||||||
|
|
||||||
|
const Type *inn = phase->type(in(1));
|
||||||
|
if( inn == Type::TOP ) return Type::TOP; // No information yet
|
||||||
|
|
||||||
|
const TypePtr *in_type = inn->isa_ptr();
|
||||||
|
const TypePtr *my_type = _type->isa_ptr();
|
||||||
|
const Type *result = _type;
|
||||||
|
if( in_type != NULL && my_type != NULL ) {
|
||||||
|
TypePtr::PTR in_ptr = in_type->ptr();
|
||||||
|
if( in_ptr == TypePtr::Null ) {
|
||||||
|
result = in_type;
|
||||||
|
} else if( in_ptr == TypePtr::Constant ) {
|
||||||
|
// Casting a constant oop to an interface?
|
||||||
|
// (i.e., a String to a Comparable?)
|
||||||
|
// Then return the interface.
|
||||||
|
const TypeOopPtr *jptr = my_type->isa_oopptr();
|
||||||
|
assert( jptr, "" );
|
||||||
|
result = (jptr->klass()->is_interface() || !in_type->higher_equal(_type))
|
||||||
|
? my_type->cast_to_ptr_type( TypePtr::NotNull )
|
||||||
|
: in_type;
|
||||||
|
} else {
|
||||||
|
result = my_type->cast_to_ptr_type( my_type->join_ptr(in_ptr) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the code from TypePtr::xmeet() that prevents us from
|
||||||
|
// having 2 ways to represent the same type. We have to replicate it
|
||||||
|
// here because we don't go through meet/join.
|
||||||
|
if (result->remove_speculative() == result->speculative()) {
|
||||||
|
result = result->remove_speculative();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same as above: because we don't go through meet/join, remove the
|
||||||
|
// speculative type if we know we won't use it.
|
||||||
|
return result->cleanup_speculative();
|
||||||
|
|
||||||
|
// JOIN NOT DONE HERE BECAUSE OF INTERFACE ISSUES.
|
||||||
|
// FIX THIS (DO THE JOIN) WHEN UNION TYPES APPEAR!
|
||||||
|
|
||||||
|
//
|
||||||
|
// Remove this code after overnight run indicates no performance
|
||||||
|
// loss from not performing JOIN at CheckCastPPNode
|
||||||
|
//
|
||||||
|
// const TypeInstPtr *in_oop = in->isa_instptr();
|
||||||
|
// const TypeInstPtr *my_oop = _type->isa_instptr();
|
||||||
|
// // If either input is an 'interface', return destination type
|
||||||
|
// assert (in_oop == NULL || in_oop->klass() != NULL, "");
|
||||||
|
// assert (my_oop == NULL || my_oop->klass() != NULL, "");
|
||||||
|
// if( (in_oop && in_oop->klass()->is_interface())
|
||||||
|
// ||(my_oop && my_oop->klass()->is_interface()) ) {
|
||||||
|
// TypePtr::PTR in_ptr = in->isa_ptr() ? in->is_ptr()->_ptr : TypePtr::BotPTR;
|
||||||
|
// // Preserve cast away nullness for interfaces
|
||||||
|
// if( in_ptr == TypePtr::NotNull && my_oop && my_oop->_ptr == TypePtr::BotPTR ) {
|
||||||
|
// return my_oop->cast_to_ptr_type(TypePtr::NotNull);
|
||||||
|
// }
|
||||||
|
// return _type;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Neither the input nor the destination type is an interface,
|
||||||
|
//
|
||||||
|
// // history: JOIN used to cause weird corner case bugs
|
||||||
|
// // return (in == TypeOopPtr::NULL_PTR) ? in : _type;
|
||||||
|
// // JOIN picks up NotNull in common instance-of/check-cast idioms, both oops.
|
||||||
|
// // JOIN does not preserve NotNull in other cases, e.g. RawPtr vs InstPtr
|
||||||
|
// const Type *join = in->join(_type);
|
||||||
|
// // Check if join preserved NotNull'ness for pointers
|
||||||
|
// if( join->isa_ptr() && _type->isa_ptr() ) {
|
||||||
|
// TypePtr::PTR join_ptr = join->is_ptr()->_ptr;
|
||||||
|
// TypePtr::PTR type_ptr = _type->is_ptr()->_ptr;
|
||||||
|
// // If there isn't any NotNull'ness to preserve
|
||||||
|
// // OR if join preserved NotNull'ness then return it
|
||||||
|
// if( type_ptr == TypePtr::BotPTR || type_ptr == TypePtr::Null ||
|
||||||
|
// join_ptr == TypePtr::NotNull || join_ptr == TypePtr::Constant ) {
|
||||||
|
// return join;
|
||||||
|
// }
|
||||||
|
// // ELSE return same old type as before
|
||||||
|
// return _type;
|
||||||
|
// }
|
||||||
|
// // Not joining two pointers
|
||||||
|
// return join;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Ideal------------------------------------------
|
||||||
|
// Return a node which is more "ideal" than the current node. Strip out
|
||||||
|
// control copies
|
||||||
|
Node *CheckCastPPNode::Ideal(PhaseGVN *phase, bool can_reshape){
|
||||||
|
return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *CastX2PNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type* t = phase->type(in(1));
|
||||||
|
if (t == Type::TOP) return Type::TOP;
|
||||||
|
if (t->base() == Type_X && t->singleton()) {
|
||||||
|
uintptr_t bits = (uintptr_t) t->is_intptr_t()->get_con();
|
||||||
|
if (bits == 0) return TypePtr::NULL_PTR;
|
||||||
|
return TypeRawPtr::make((address) bits);
|
||||||
|
}
|
||||||
|
return CastX2PNode::bottom_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Idealize---------------------------------------
|
||||||
|
static inline bool fits_in_int(const Type* t, bool but_not_min_int = false) {
|
||||||
|
if (t == Type::TOP) return false;
|
||||||
|
const TypeX* tl = t->is_intptr_t();
|
||||||
|
jint lo = min_jint;
|
||||||
|
jint hi = max_jint;
|
||||||
|
if (but_not_min_int) ++lo; // caller wants to negate the value w/o overflow
|
||||||
|
return (tl->_lo >= lo) && (tl->_hi <= hi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline Node* addP_of_X2P(PhaseGVN *phase,
|
||||||
|
Node* base,
|
||||||
|
Node* dispX,
|
||||||
|
bool negate = false) {
|
||||||
|
if (negate) {
|
||||||
|
dispX = new (phase->C) SubXNode(phase->MakeConX(0), phase->transform(dispX));
|
||||||
|
}
|
||||||
|
return new (phase->C) AddPNode(phase->C->top(),
|
||||||
|
phase->transform(new (phase->C) CastX2PNode(base)),
|
||||||
|
phase->transform(dispX));
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *CastX2PNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
// convert CastX2P(AddX(x, y)) to AddP(CastX2P(x), y) if y fits in an int
|
||||||
|
int op = in(1)->Opcode();
|
||||||
|
Node* x;
|
||||||
|
Node* y;
|
||||||
|
switch (op) {
|
||||||
|
case Op_SubX:
|
||||||
|
x = in(1)->in(1);
|
||||||
|
// Avoid ideal transformations ping-pong between this and AddP for raw pointers.
|
||||||
|
if (phase->find_intptr_t_con(x, -1) == 0)
|
||||||
|
break;
|
||||||
|
y = in(1)->in(2);
|
||||||
|
if (fits_in_int(phase->type(y), true)) {
|
||||||
|
return addP_of_X2P(phase, x, y, true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Op_AddX:
|
||||||
|
x = in(1)->in(1);
|
||||||
|
y = in(1)->in(2);
|
||||||
|
if (fits_in_int(phase->type(y))) {
|
||||||
|
return addP_of_X2P(phase, x, y);
|
||||||
|
}
|
||||||
|
if (fits_in_int(phase->type(x))) {
|
||||||
|
return addP_of_X2P(phase, y, x);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Identity---------------------------------------
|
||||||
|
Node *CastX2PNode::Identity( PhaseTransform *phase ) {
|
||||||
|
if (in(1)->Opcode() == Op_CastP2X) return in(1)->in(1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *CastP2XNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type* t = phase->type(in(1));
|
||||||
|
if (t == Type::TOP) return Type::TOP;
|
||||||
|
if (t->base() == Type::RawPtr && t->singleton()) {
|
||||||
|
uintptr_t bits = (uintptr_t) t->is_rawptr()->get_con();
|
||||||
|
return TypeX::make(bits);
|
||||||
|
}
|
||||||
|
return CastP2XNode::bottom_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *CastP2XNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Identity---------------------------------------
|
||||||
|
Node *CastP2XNode::Identity( PhaseTransform *phase ) {
|
||||||
|
if (in(1)->Opcode() == Op_CastX2P) return in(1)->in(1);
|
||||||
|
return this;
|
||||||
|
}
|
119
hotspot/src/share/vm/opto/castnode.hpp
Normal file
119
hotspot/src/share/vm/opto/castnode.hpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHARE_VM_OPTO_CASTNODE_HPP
|
||||||
|
#define SHARE_VM_OPTO_CASTNODE_HPP
|
||||||
|
|
||||||
|
#include "opto/node.hpp"
|
||||||
|
#include "opto/opcodes.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------ConstraintCastNode-----------------------------
|
||||||
|
// cast to a different range
|
||||||
|
class ConstraintCastNode: public TypeNode {
|
||||||
|
public:
|
||||||
|
ConstraintCastNode (Node *n, const Type *t ): TypeNode(t,2) {
|
||||||
|
init_class_id(Class_ConstraintCast);
|
||||||
|
init_req(1, n);
|
||||||
|
}
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual uint ideal_reg() const = 0;
|
||||||
|
virtual Node *Ideal_DU_postCCP( PhaseCCP * );
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------CastIINode-------------------------------------
|
||||||
|
// cast integer to integer (different range)
|
||||||
|
class CastIINode: public ConstraintCastNode {
|
||||||
|
public:
|
||||||
|
CastIINode (Node *n, const Type *t ): ConstraintCastNode(n,t) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual uint ideal_reg() const { return Op_RegI; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------CastPPNode-------------------------------------
|
||||||
|
// cast pointer to pointer (different type)
|
||||||
|
class CastPPNode: public ConstraintCastNode {
|
||||||
|
public:
|
||||||
|
CastPPNode (Node *n, const Type *t ): ConstraintCastNode(n, t) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual uint ideal_reg() const { return Op_RegP; }
|
||||||
|
virtual Node *Ideal_DU_postCCP( PhaseCCP * );
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------CheckCastPPNode--------------------------------
|
||||||
|
// for _checkcast, cast pointer to pointer (different type), without JOIN,
|
||||||
|
class CheckCastPPNode: public TypeNode {
|
||||||
|
public:
|
||||||
|
CheckCastPPNode( Node *c, Node *n, const Type *t ) : TypeNode(t,2) {
|
||||||
|
init_class_id(Class_CheckCastPP);
|
||||||
|
init_req(0, c);
|
||||||
|
init_req(1, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual uint ideal_reg() const { return Op_RegP; }
|
||||||
|
// No longer remove CheckCast after CCP as it gives me a place to hang
|
||||||
|
// the proper address type - which is required to compute anti-deps.
|
||||||
|
//virtual Node *Ideal_DU_postCCP( PhaseCCP * );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------CastX2PNode-------------------------------------
|
||||||
|
// convert a machine-pointer-sized integer to a raw pointer
|
||||||
|
class CastX2PNode : public Node {
|
||||||
|
public:
|
||||||
|
CastX2PNode( Node *n ) : Node(NULL, n) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
virtual uint ideal_reg() const { return Op_RegP; }
|
||||||
|
virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------CastP2XNode-------------------------------------
|
||||||
|
// Used in both 32-bit and 64-bit land.
|
||||||
|
// Used for card-marks and unsafe pointer math.
|
||||||
|
class CastP2XNode : public Node {
|
||||||
|
public:
|
||||||
|
CastP2XNode( Node *ctrl, Node *n ) : Node(ctrl, n) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
virtual uint ideal_reg() const { return Op_RegX; }
|
||||||
|
virtual const Type *bottom_type() const { return TypeX_X; }
|
||||||
|
// Return false to keep node from moving away from an associated card mark.
|
||||||
|
virtual bool depends_only_on_test() const { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SHARE_VM_OPTO_CASTNODE_HPP
|
@ -29,8 +29,11 @@
|
|||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
#include "opto/cfgnode.hpp"
|
#include "opto/cfgnode.hpp"
|
||||||
#include "opto/connode.hpp"
|
#include "opto/connode.hpp"
|
||||||
|
#include "opto/convertnode.hpp"
|
||||||
#include "opto/loopnode.hpp"
|
#include "opto/loopnode.hpp"
|
||||||
#include "opto/machnode.hpp"
|
#include "opto/machnode.hpp"
|
||||||
|
#include "opto/movenode.hpp"
|
||||||
|
#include "opto/narrowptrnode.hpp"
|
||||||
#include "opto/mulnode.hpp"
|
#include "opto/mulnode.hpp"
|
||||||
#include "opto/phaseX.hpp"
|
#include "opto/phaseX.hpp"
|
||||||
#include "opto/regmask.hpp"
|
#include "opto/regmask.hpp"
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include "opto/indexSet.hpp"
|
#include "opto/indexSet.hpp"
|
||||||
#include "opto/machnode.hpp"
|
#include "opto/machnode.hpp"
|
||||||
#include "opto/memnode.hpp"
|
#include "opto/memnode.hpp"
|
||||||
|
#include "opto/movenode.hpp"
|
||||||
#include "opto/opcodes.hpp"
|
#include "opto/opcodes.hpp"
|
||||||
#include "opto/rootnode.hpp"
|
#include "opto/rootnode.hpp"
|
||||||
|
|
||||||
|
@ -25,17 +25,24 @@
|
|||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
#include "opto/callnode.hpp"
|
#include "opto/callnode.hpp"
|
||||||
|
#include "opto/castnode.hpp"
|
||||||
#include "opto/cfgnode.hpp"
|
#include "opto/cfgnode.hpp"
|
||||||
#include "opto/connode.hpp"
|
#include "opto/connode.hpp"
|
||||||
|
#include "opto/convertnode.hpp"
|
||||||
|
#include "opto/countbitsnode.hpp"
|
||||||
#include "opto/divnode.hpp"
|
#include "opto/divnode.hpp"
|
||||||
|
#include "opto/intrinsicnode.hpp"
|
||||||
#include "opto/locknode.hpp"
|
#include "opto/locknode.hpp"
|
||||||
#include "opto/loopnode.hpp"
|
#include "opto/loopnode.hpp"
|
||||||
#include "opto/machnode.hpp"
|
#include "opto/machnode.hpp"
|
||||||
#include "opto/memnode.hpp"
|
#include "opto/memnode.hpp"
|
||||||
#include "opto/mathexactnode.hpp"
|
#include "opto/mathexactnode.hpp"
|
||||||
|
#include "opto/movenode.hpp"
|
||||||
#include "opto/mulnode.hpp"
|
#include "opto/mulnode.hpp"
|
||||||
#include "opto/multnode.hpp"
|
#include "opto/multnode.hpp"
|
||||||
|
#include "opto/narrowptrnode.hpp"
|
||||||
#include "opto/node.hpp"
|
#include "opto/node.hpp"
|
||||||
|
#include "opto/opaquenode.hpp"
|
||||||
#include "opto/rootnode.hpp"
|
#include "opto/rootnode.hpp"
|
||||||
#include "opto/subnode.hpp"
|
#include "opto/subnode.hpp"
|
||||||
#include "opto/vectornode.hpp"
|
#include "opto/vectornode.hpp"
|
||||||
|
@ -51,6 +51,7 @@
|
|||||||
#include "opto/mathexactnode.hpp"
|
#include "opto/mathexactnode.hpp"
|
||||||
#include "opto/memnode.hpp"
|
#include "opto/memnode.hpp"
|
||||||
#include "opto/mulnode.hpp"
|
#include "opto/mulnode.hpp"
|
||||||
|
#include "opto/narrowptrnode.hpp"
|
||||||
#include "opto/node.hpp"
|
#include "opto/node.hpp"
|
||||||
#include "opto/opcodes.hpp"
|
#include "opto/opcodes.hpp"
|
||||||
#include "opto/output.hpp"
|
#include "opto/output.hpp"
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -139,420 +139,6 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------BinaryNode-------------------------------------
|
|
||||||
// Place holder for the 2 conditional inputs to a CMove. CMove needs 4
|
|
||||||
// inputs: the Bool (for the lt/gt/eq/ne bits), the flags (result of some
|
|
||||||
// compare), and the 2 values to select between. The Matcher requires a
|
|
||||||
// binary tree so we break it down like this:
|
|
||||||
// (CMove (Binary bol cmp) (Binary src1 src2))
|
|
||||||
class BinaryNode : public Node {
|
|
||||||
public:
|
|
||||||
BinaryNode( Node *n1, Node *n2 ) : Node(0,n1,n2) { }
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual uint ideal_reg() const { return 0; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------CMoveNode--------------------------------------
|
|
||||||
// Conditional move
|
|
||||||
class CMoveNode : public TypeNode {
|
|
||||||
public:
|
|
||||||
enum { Control, // When is it safe to do this cmove?
|
|
||||||
Condition, // Condition controlling the cmove
|
|
||||||
IfFalse, // Value if condition is false
|
|
||||||
IfTrue }; // Value if condition is true
|
|
||||||
CMoveNode( Node *bol, Node *left, Node *right, const Type *t ) : TypeNode(t,4)
|
|
||||||
{
|
|
||||||
init_class_id(Class_CMove);
|
|
||||||
// all inputs are nullified in Node::Node(int)
|
|
||||||
// init_req(Control,NULL);
|
|
||||||
init_req(Condition,bol);
|
|
||||||
init_req(IfFalse,left);
|
|
||||||
init_req(IfTrue,right);
|
|
||||||
}
|
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
static CMoveNode *make( Compile *C, Node *c, Node *bol, Node *left, Node *right, const Type *t );
|
|
||||||
// Helper function to spot cmove graph shapes
|
|
||||||
static Node *is_cmove_id( PhaseTransform *phase, Node *cmp, Node *t, Node *f, BoolNode *b );
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------CMoveDNode-------------------------------------
|
|
||||||
class CMoveDNode : public CMoveNode {
|
|
||||||
public:
|
|
||||||
CMoveDNode( Node *bol, Node *left, Node *right, const Type* t) : CMoveNode(bol,left,right,t){}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------CMoveFNode-------------------------------------
|
|
||||||
class CMoveFNode : public CMoveNode {
|
|
||||||
public:
|
|
||||||
CMoveFNode( Node *bol, Node *left, Node *right, const Type* t ) : CMoveNode(bol,left,right,t) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------CMoveINode-------------------------------------
|
|
||||||
class CMoveINode : public CMoveNode {
|
|
||||||
public:
|
|
||||||
CMoveINode( Node *bol, Node *left, Node *right, const TypeInt *ti ) : CMoveNode(bol,left,right,ti){}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------CMoveLNode-------------------------------------
|
|
||||||
class CMoveLNode : public CMoveNode {
|
|
||||||
public:
|
|
||||||
CMoveLNode(Node *bol, Node *left, Node *right, const TypeLong *tl ) : CMoveNode(bol,left,right,tl){}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------CMovePNode-------------------------------------
|
|
||||||
class CMovePNode : public CMoveNode {
|
|
||||||
public:
|
|
||||||
CMovePNode( Node *c, Node *bol, Node *left, Node *right, const TypePtr* t ) : CMoveNode(bol,left,right,t) { init_req(Control,c); }
|
|
||||||
virtual int Opcode() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------CMoveNNode-------------------------------------
|
|
||||||
class CMoveNNode : public CMoveNode {
|
|
||||||
public:
|
|
||||||
CMoveNNode( Node *c, Node *bol, Node *left, Node *right, const Type* t ) : CMoveNode(bol,left,right,t) { init_req(Control,c); }
|
|
||||||
virtual int Opcode() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------ConstraintCastNode-----------------------------
|
|
||||||
// cast to a different range
|
|
||||||
class ConstraintCastNode: public TypeNode {
|
|
||||||
public:
|
|
||||||
ConstraintCastNode (Node *n, const Type *t ): TypeNode(t,2) {
|
|
||||||
init_class_id(Class_ConstraintCast);
|
|
||||||
init_req(1, n);
|
|
||||||
}
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual uint ideal_reg() const = 0;
|
|
||||||
virtual Node *Ideal_DU_postCCP( PhaseCCP * );
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------CastIINode-------------------------------------
|
|
||||||
// cast integer to integer (different range)
|
|
||||||
class CastIINode: public ConstraintCastNode {
|
|
||||||
public:
|
|
||||||
CastIINode (Node *n, const Type *t ): ConstraintCastNode(n,t) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual uint ideal_reg() const { return Op_RegI; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------CastPPNode-------------------------------------
|
|
||||||
// cast pointer to pointer (different type)
|
|
||||||
class CastPPNode: public ConstraintCastNode {
|
|
||||||
public:
|
|
||||||
CastPPNode (Node *n, const Type *t ): ConstraintCastNode(n, t) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual uint ideal_reg() const { return Op_RegP; }
|
|
||||||
virtual Node *Ideal_DU_postCCP( PhaseCCP * );
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------CheckCastPPNode--------------------------------
|
|
||||||
// for _checkcast, cast pointer to pointer (different type), without JOIN,
|
|
||||||
class CheckCastPPNode: public TypeNode {
|
|
||||||
public:
|
|
||||||
CheckCastPPNode( Node *c, Node *n, const Type *t ) : TypeNode(t,2) {
|
|
||||||
init_class_id(Class_CheckCastPP);
|
|
||||||
init_req(0, c);
|
|
||||||
init_req(1, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual uint ideal_reg() const { return Op_RegP; }
|
|
||||||
// No longer remove CheckCast after CCP as it gives me a place to hang
|
|
||||||
// the proper address type - which is required to compute anti-deps.
|
|
||||||
//virtual Node *Ideal_DU_postCCP( PhaseCCP * );
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//------------------------------EncodeNarrowPtr--------------------------------
|
|
||||||
class EncodeNarrowPtrNode : public TypeNode {
|
|
||||||
protected:
|
|
||||||
EncodeNarrowPtrNode(Node* value, const Type* type):
|
|
||||||
TypeNode(type, 2) {
|
|
||||||
init_class_id(Class_EncodeNarrowPtr);
|
|
||||||
init_req(0, NULL);
|
|
||||||
init_req(1, value);
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
virtual uint ideal_reg() const { return Op_RegN; }
|
|
||||||
virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp );
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------EncodeP--------------------------------
|
|
||||||
// Encodes an oop pointers into its compressed form
|
|
||||||
// Takes an extra argument which is the real heap base as a long which
|
|
||||||
// may be useful for code generation in the backend.
|
|
||||||
class EncodePNode : public EncodeNarrowPtrNode {
|
|
||||||
public:
|
|
||||||
EncodePNode(Node* value, const Type* type):
|
|
||||||
EncodeNarrowPtrNode(value, type) {
|
|
||||||
init_class_id(Class_EncodeP);
|
|
||||||
}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------EncodePKlass--------------------------------
|
|
||||||
// Encodes a klass pointer into its compressed form
|
|
||||||
// Takes an extra argument which is the real heap base as a long which
|
|
||||||
// may be useful for code generation in the backend.
|
|
||||||
class EncodePKlassNode : public EncodeNarrowPtrNode {
|
|
||||||
public:
|
|
||||||
EncodePKlassNode(Node* value, const Type* type):
|
|
||||||
EncodeNarrowPtrNode(value, type) {
|
|
||||||
init_class_id(Class_EncodePKlass);
|
|
||||||
}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------DecodeNarrowPtr--------------------------------
|
|
||||||
class DecodeNarrowPtrNode : public TypeNode {
|
|
||||||
protected:
|
|
||||||
DecodeNarrowPtrNode(Node* value, const Type* type):
|
|
||||||
TypeNode(type, 2) {
|
|
||||||
init_class_id(Class_DecodeNarrowPtr);
|
|
||||||
init_req(0, NULL);
|
|
||||||
init_req(1, value);
|
|
||||||
}
|
|
||||||
public:
|
|
||||||
virtual uint ideal_reg() const { return Op_RegP; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------DecodeN--------------------------------
|
|
||||||
// Converts a narrow oop into a real oop ptr.
|
|
||||||
// Takes an extra argument which is the real heap base as a long which
|
|
||||||
// may be useful for code generation in the backend.
|
|
||||||
class DecodeNNode : public DecodeNarrowPtrNode {
|
|
||||||
public:
|
|
||||||
DecodeNNode(Node* value, const Type* type):
|
|
||||||
DecodeNarrowPtrNode(value, type) {
|
|
||||||
init_class_id(Class_DecodeN);
|
|
||||||
}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------DecodeNKlass--------------------------------
|
|
||||||
// Converts a narrow klass pointer into a real klass ptr.
|
|
||||||
// Takes an extra argument which is the real heap base as a long which
|
|
||||||
// may be useful for code generation in the backend.
|
|
||||||
class DecodeNKlassNode : public DecodeNarrowPtrNode {
|
|
||||||
public:
|
|
||||||
DecodeNKlassNode(Node* value, const Type* type):
|
|
||||||
DecodeNarrowPtrNode(value, type) {
|
|
||||||
init_class_id(Class_DecodeNKlass);
|
|
||||||
}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------Conv2BNode-------------------------------------
|
|
||||||
// Convert int/pointer to a Boolean. Map zero to zero, all else to 1.
|
|
||||||
class Conv2BNode : public Node {
|
|
||||||
public:
|
|
||||||
Conv2BNode( Node *i ) : Node(0,i) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return TypeInt::BOOL; }
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual uint ideal_reg() const { return Op_RegI; }
|
|
||||||
};
|
|
||||||
|
|
||||||
// The conversions operations are all Alpha sorted. Please keep it that way!
|
|
||||||
//------------------------------ConvD2FNode------------------------------------
|
|
||||||
// Convert double to float
|
|
||||||
class ConvD2FNode : public Node {
|
|
||||||
public:
|
|
||||||
ConvD2FNode( Node *in1 ) : Node(0,in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return Type::FLOAT; }
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
virtual uint ideal_reg() const { return Op_RegF; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------ConvD2INode------------------------------------
|
|
||||||
// Convert Double to Integer
|
|
||||||
class ConvD2INode : public Node {
|
|
||||||
public:
|
|
||||||
ConvD2INode( Node *in1 ) : Node(0,in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
|
||||||
virtual uint ideal_reg() const { return Op_RegI; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------ConvD2LNode------------------------------------
|
|
||||||
// Convert Double to Long
|
|
||||||
class ConvD2LNode : public Node {
|
|
||||||
public:
|
|
||||||
ConvD2LNode( Node *dbl ) : Node(0,dbl) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return TypeLong::LONG; }
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
|
||||||
virtual uint ideal_reg() const { return Op_RegL; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------ConvF2DNode------------------------------------
|
|
||||||
// Convert Float to a Double.
|
|
||||||
class ConvF2DNode : public Node {
|
|
||||||
public:
|
|
||||||
ConvF2DNode( Node *in1 ) : Node(0,in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return Type::DOUBLE; }
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual uint ideal_reg() const { return Op_RegD; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------ConvF2INode------------------------------------
|
|
||||||
// Convert float to integer
|
|
||||||
class ConvF2INode : public Node {
|
|
||||||
public:
|
|
||||||
ConvF2INode( Node *in1 ) : Node(0,in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
|
||||||
virtual uint ideal_reg() const { return Op_RegI; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------ConvF2LNode------------------------------------
|
|
||||||
// Convert float to long
|
|
||||||
class ConvF2LNode : public Node {
|
|
||||||
public:
|
|
||||||
ConvF2LNode( Node *in1 ) : Node(0,in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return TypeLong::LONG; }
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
|
||||||
virtual uint ideal_reg() const { return Op_RegL; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------ConvI2DNode------------------------------------
|
|
||||||
// Convert Integer to Double
|
|
||||||
class ConvI2DNode : public Node {
|
|
||||||
public:
|
|
||||||
ConvI2DNode( Node *in1 ) : Node(0,in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return Type::DOUBLE; }
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual uint ideal_reg() const { return Op_RegD; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------ConvI2FNode------------------------------------
|
|
||||||
// Convert Integer to Float
|
|
||||||
class ConvI2FNode : public Node {
|
|
||||||
public:
|
|
||||||
ConvI2FNode( Node *in1 ) : Node(0,in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return Type::FLOAT; }
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
virtual uint ideal_reg() const { return Op_RegF; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------ConvI2LNode------------------------------------
|
|
||||||
// Convert integer to long
|
|
||||||
class ConvI2LNode : public TypeNode {
|
|
||||||
public:
|
|
||||||
ConvI2LNode(Node *in1, const TypeLong* t = TypeLong::INT)
|
|
||||||
: TypeNode(t, 2)
|
|
||||||
{ init_req(1, in1); }
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
|
||||||
virtual uint ideal_reg() const { return Op_RegL; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------ConvL2DNode------------------------------------
|
|
||||||
// Convert Long to Double
|
|
||||||
class ConvL2DNode : public Node {
|
|
||||||
public:
|
|
||||||
ConvL2DNode( Node *in1 ) : Node(0,in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return Type::DOUBLE; }
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual uint ideal_reg() const { return Op_RegD; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------ConvL2FNode------------------------------------
|
|
||||||
// Convert Long to Float
|
|
||||||
class ConvL2FNode : public Node {
|
|
||||||
public:
|
|
||||||
ConvL2FNode( Node *in1 ) : Node(0,in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return Type::FLOAT; }
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual uint ideal_reg() const { return Op_RegF; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------ConvL2INode------------------------------------
|
|
||||||
// Convert long to integer
|
|
||||||
class ConvL2INode : public Node {
|
|
||||||
public:
|
|
||||||
ConvL2INode( Node *in1 ) : Node(0,in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
|
||||||
virtual uint ideal_reg() const { return Op_RegI; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------CastX2PNode-------------------------------------
|
|
||||||
// convert a machine-pointer-sized integer to a raw pointer
|
|
||||||
class CastX2PNode : public Node {
|
|
||||||
public:
|
|
||||||
CastX2PNode( Node *n ) : Node(NULL, n) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
virtual uint ideal_reg() const { return Op_RegP; }
|
|
||||||
virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------CastP2XNode-------------------------------------
|
|
||||||
// Used in both 32-bit and 64-bit land.
|
|
||||||
// Used for card-marks and unsafe pointer math.
|
|
||||||
class CastP2XNode : public Node {
|
|
||||||
public:
|
|
||||||
CastP2XNode( Node *ctrl, Node *n ) : Node(ctrl, n) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
virtual uint ideal_reg() const { return Op_RegX; }
|
|
||||||
virtual const Type *bottom_type() const { return TypeX_X; }
|
|
||||||
// Return false to keep node from moving away from an associated card mark.
|
|
||||||
virtual bool depends_only_on_test() const { return false; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------ThreadLocalNode--------------------------------
|
//------------------------------ThreadLocalNode--------------------------------
|
||||||
// Ideal Node which returns the base of ThreadLocalStorage.
|
// Ideal Node which returns the base of ThreadLocalStorage.
|
||||||
class ThreadLocalNode : public Node {
|
class ThreadLocalNode : public Node {
|
||||||
@ -563,206 +149,6 @@ public:
|
|||||||
virtual uint ideal_reg() const { return Op_RegP; }
|
virtual uint ideal_reg() const { return Op_RegP; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------LoadReturnPCNode-------------------------------
|
|
||||||
class LoadReturnPCNode: public Node {
|
|
||||||
public:
|
|
||||||
LoadReturnPCNode(Node *c) : Node(c) { }
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual uint ideal_reg() const { return Op_RegP; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------RoundFloatNode----------------------------------
|
|
||||||
class RoundFloatNode: public Node {
|
|
||||||
public:
|
|
||||||
RoundFloatNode(Node* c, Node *in1): Node(c, in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return Type::FLOAT; }
|
|
||||||
virtual uint ideal_reg() const { return Op_RegF; }
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//-----------------------------RoundDoubleNode---------------------------------
|
|
||||||
class RoundDoubleNode: public Node {
|
|
||||||
public:
|
|
||||||
RoundDoubleNode(Node* c, Node *in1): Node(c, in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return Type::DOUBLE; }
|
|
||||||
virtual uint ideal_reg() const { return Op_RegD; }
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
virtual const Type *Value( PhaseTransform *phase ) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------Opaque1Node------------------------------------
|
|
||||||
// A node to prevent unwanted optimizations. Allows constant folding.
|
|
||||||
// Stops value-numbering, Ideal calls or Identity functions.
|
|
||||||
class Opaque1Node : public Node {
|
|
||||||
virtual uint hash() const ; // { return NO_HASH; }
|
|
||||||
virtual uint cmp( const Node &n ) const;
|
|
||||||
public:
|
|
||||||
Opaque1Node( Compile* C, Node *n ) : Node(0,n) {
|
|
||||||
// Put it on the Macro nodes list to removed during macro nodes expansion.
|
|
||||||
init_flags(Flag_is_macro);
|
|
||||||
C->add_macro_node(this);
|
|
||||||
}
|
|
||||||
// Special version for the pre-loop to hold the original loop limit
|
|
||||||
// which is consumed by range check elimination.
|
|
||||||
Opaque1Node( Compile* C, Node *n, Node* orig_limit ) : Node(0,n,orig_limit) {
|
|
||||||
// Put it on the Macro nodes list to removed during macro nodes expansion.
|
|
||||||
init_flags(Flag_is_macro);
|
|
||||||
C->add_macro_node(this);
|
|
||||||
}
|
|
||||||
Node* original_loop_limit() { return req()==3 ? in(2) : NULL; }
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
|
||||||
virtual Node *Identity( PhaseTransform *phase );
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------Opaque2Node------------------------------------
|
|
||||||
// A node to prevent unwanted optimizations. Allows constant folding. Stops
|
|
||||||
// value-numbering, most Ideal calls or Identity functions. This Node is
|
|
||||||
// specifically designed to prevent the pre-increment value of a loop trip
|
|
||||||
// counter from being live out of the bottom of the loop (hence causing the
|
|
||||||
// pre- and post-increment values both being live and thus requiring an extra
|
|
||||||
// temp register and an extra move). If we "accidentally" optimize through
|
|
||||||
// this kind of a Node, we'll get slightly pessimal, but correct, code. Thus
|
|
||||||
// it's OK to be slightly sloppy on optimizations here.
|
|
||||||
class Opaque2Node : public Node {
|
|
||||||
virtual uint hash() const ; // { return NO_HASH; }
|
|
||||||
virtual uint cmp( const Node &n ) const;
|
|
||||||
public:
|
|
||||||
Opaque2Node( Compile* C, Node *n ) : Node(0,n) {
|
|
||||||
// Put it on the Macro nodes list to removed during macro nodes expansion.
|
|
||||||
init_flags(Flag_is_macro);
|
|
||||||
C->add_macro_node(this);
|
|
||||||
}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------Opaque3Node------------------------------------
|
|
||||||
// A node to prevent unwanted optimizations. Will be optimized only during
|
|
||||||
// macro nodes expansion.
|
|
||||||
class Opaque3Node : public Opaque2Node {
|
|
||||||
int _opt; // what optimization it was used for
|
|
||||||
public:
|
|
||||||
enum { RTM_OPT };
|
|
||||||
Opaque3Node(Compile* C, Node *n, int opt) : Opaque2Node(C, n), _opt(opt) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
bool rtm_opt() const { return (_opt == RTM_OPT); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//----------------------PartialSubtypeCheckNode--------------------------------
|
|
||||||
// The 2nd slow-half of a subtype check. Scan the subklass's 2ndary superklass
|
|
||||||
// array for an instance of the superklass. Set a hidden internal cache on a
|
|
||||||
// hit (cache is checked with exposed code in gen_subtype_check()). Return
|
|
||||||
// not zero for a miss or zero for a hit.
|
|
||||||
class PartialSubtypeCheckNode : public Node {
|
|
||||||
public:
|
|
||||||
PartialSubtypeCheckNode(Node* c, Node* sub, Node* super) : Node(c,sub,super) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM; }
|
|
||||||
virtual uint ideal_reg() const { return Op_RegP; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
class MoveI2FNode : public Node {
|
|
||||||
public:
|
|
||||||
MoveI2FNode( Node *value ) : Node(0,value) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return Type::FLOAT; }
|
|
||||||
virtual uint ideal_reg() const { return Op_RegF; }
|
|
||||||
virtual const Type* Value( PhaseTransform *phase ) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MoveL2DNode : public Node {
|
|
||||||
public:
|
|
||||||
MoveL2DNode( Node *value ) : Node(0,value) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return Type::DOUBLE; }
|
|
||||||
virtual uint ideal_reg() const { return Op_RegD; }
|
|
||||||
virtual const Type* Value( PhaseTransform *phase ) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MoveF2INode : public Node {
|
|
||||||
public:
|
|
||||||
MoveF2INode( Node *value ) : Node(0,value) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
|
||||||
virtual uint ideal_reg() const { return Op_RegI; }
|
|
||||||
virtual const Type* Value( PhaseTransform *phase ) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MoveD2LNode : public Node {
|
|
||||||
public:
|
|
||||||
MoveD2LNode( Node *value ) : Node(0,value) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type *bottom_type() const { return TypeLong::LONG; }
|
|
||||||
virtual uint ideal_reg() const { return Op_RegL; }
|
|
||||||
virtual const Type* Value( PhaseTransform *phase ) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------- CountBitsNode -----------------------------------------------------
|
|
||||||
class CountBitsNode : public Node {
|
|
||||||
public:
|
|
||||||
CountBitsNode(Node* in1) : Node(0, in1) {}
|
|
||||||
const Type* bottom_type() const { return TypeInt::INT; }
|
|
||||||
virtual uint ideal_reg() const { return Op_RegI; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------- CountLeadingZerosINode --------------------------------------------
|
|
||||||
// Count leading zeros (0-bit count starting from MSB) of an integer.
|
|
||||||
class CountLeadingZerosINode : public CountBitsNode {
|
|
||||||
public:
|
|
||||||
CountLeadingZerosINode(Node* in1) : CountBitsNode(in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type* Value(PhaseTransform* phase) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------- CountLeadingZerosLNode --------------------------------------------
|
|
||||||
// Count leading zeros (0-bit count starting from MSB) of a long.
|
|
||||||
class CountLeadingZerosLNode : public CountBitsNode {
|
|
||||||
public:
|
|
||||||
CountLeadingZerosLNode(Node* in1) : CountBitsNode(in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type* Value(PhaseTransform* phase) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------- CountTrailingZerosINode -------------------------------------------
|
|
||||||
// Count trailing zeros (0-bit count starting from LSB) of an integer.
|
|
||||||
class CountTrailingZerosINode : public CountBitsNode {
|
|
||||||
public:
|
|
||||||
CountTrailingZerosINode(Node* in1) : CountBitsNode(in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type* Value(PhaseTransform* phase) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------- CountTrailingZerosLNode -------------------------------------------
|
|
||||||
// Count trailing zeros (0-bit count starting from LSB) of a long.
|
|
||||||
class CountTrailingZerosLNode : public CountBitsNode {
|
|
||||||
public:
|
|
||||||
CountTrailingZerosLNode(Node* in1) : CountBitsNode(in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type* Value(PhaseTransform* phase) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------- PopCountINode -----------------------------------------------------
|
|
||||||
// Population count (bit count) of an integer.
|
|
||||||
class PopCountINode : public CountBitsNode {
|
|
||||||
public:
|
|
||||||
PopCountINode(Node* in1) : CountBitsNode(in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------- PopCountLNode -----------------------------------------------------
|
|
||||||
// Population count (bit count) of a long.
|
|
||||||
class PopCountLNode : public CountBitsNode {
|
|
||||||
public:
|
|
||||||
PopCountLNode(Node* in1) : CountBitsNode(in1) {}
|
|
||||||
virtual int Opcode() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // SHARE_VM_OPTO_CONNODE_HPP
|
#endif // SHARE_VM_OPTO_CONNODE_HPP
|
||||||
|
512
hotspot/src/share/vm/opto/convertnode.cpp
Normal file
512
hotspot/src/share/vm/opto/convertnode.cpp
Normal file
@ -0,0 +1,512 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precompiled.hpp"
|
||||||
|
#include "opto/addnode.hpp"
|
||||||
|
#include "opto/convertnode.hpp"
|
||||||
|
#include "opto/matcher.hpp"
|
||||||
|
#include "opto/phaseX.hpp"
|
||||||
|
#include "opto/subnode.hpp"
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Identity---------------------------------------
|
||||||
|
Node *Conv2BNode::Identity( PhaseTransform *phase ) {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return in(1);
|
||||||
|
if( t == TypeInt::ZERO ) return in(1);
|
||||||
|
if( t == TypeInt::ONE ) return in(1);
|
||||||
|
if( t == TypeInt::BOOL ) return in(1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *Conv2BNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
if( t == TypeInt::ZERO ) return TypeInt::ZERO;
|
||||||
|
if( t == TypePtr::NULL_PTR ) return TypeInt::ZERO;
|
||||||
|
const TypePtr *tp = t->isa_ptr();
|
||||||
|
if( tp != NULL ) {
|
||||||
|
if( tp->ptr() == TypePtr::AnyNull ) return Type::TOP;
|
||||||
|
if( tp->ptr() == TypePtr::Constant) return TypeInt::ONE;
|
||||||
|
if (tp->ptr() == TypePtr::NotNull) return TypeInt::ONE;
|
||||||
|
return TypeInt::BOOL;
|
||||||
|
}
|
||||||
|
if (t->base() != Type::Int) return TypeInt::BOOL;
|
||||||
|
const TypeInt *ti = t->is_int();
|
||||||
|
if( ti->_hi < 0 || ti->_lo > 0 ) return TypeInt::ONE;
|
||||||
|
return TypeInt::BOOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The conversions operations are all Alpha sorted. Please keep it that way!
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *ConvD2FNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
if( t == Type::DOUBLE ) return Type::FLOAT;
|
||||||
|
const TypeD *td = t->is_double_constant();
|
||||||
|
return TypeF::make( (float)td->getd() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Identity---------------------------------------
|
||||||
|
// Float's can be converted to doubles with no loss of bits. Hence
|
||||||
|
// converting a float to a double and back to a float is a NOP.
|
||||||
|
Node *ConvD2FNode::Identity(PhaseTransform *phase) {
|
||||||
|
return (in(1)->Opcode() == Op_ConvF2D) ? in(1)->in(1) : this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *ConvD2INode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
if( t == Type::DOUBLE ) return TypeInt::INT;
|
||||||
|
const TypeD *td = t->is_double_constant();
|
||||||
|
return TypeInt::make( SharedRuntime::d2i( td->getd() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Ideal------------------------------------------
|
||||||
|
// If converting to an int type, skip any rounding nodes
|
||||||
|
Node *ConvD2INode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
if( in(1)->Opcode() == Op_RoundDouble )
|
||||||
|
set_req(1,in(1)->in(1));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Identity---------------------------------------
|
||||||
|
// Int's can be converted to doubles with no loss of bits. Hence
|
||||||
|
// converting an integer to a double and back to an integer is a NOP.
|
||||||
|
Node *ConvD2INode::Identity(PhaseTransform *phase) {
|
||||||
|
return (in(1)->Opcode() == Op_ConvI2D) ? in(1)->in(1) : this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *ConvD2LNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
if( t == Type::DOUBLE ) return TypeLong::LONG;
|
||||||
|
const TypeD *td = t->is_double_constant();
|
||||||
|
return TypeLong::make( SharedRuntime::d2l( td->getd() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Identity---------------------------------------
|
||||||
|
Node *ConvD2LNode::Identity(PhaseTransform *phase) {
|
||||||
|
// Remove ConvD2L->ConvL2D->ConvD2L sequences.
|
||||||
|
if( in(1) ->Opcode() == Op_ConvL2D &&
|
||||||
|
in(1)->in(1)->Opcode() == Op_ConvD2L )
|
||||||
|
return in(1)->in(1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Ideal------------------------------------------
|
||||||
|
// If converting to an int type, skip any rounding nodes
|
||||||
|
Node *ConvD2LNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
if( in(1)->Opcode() == Op_RoundDouble )
|
||||||
|
set_req(1,in(1)->in(1));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *ConvF2DNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
if( t == Type::FLOAT ) return Type::DOUBLE;
|
||||||
|
const TypeF *tf = t->is_float_constant();
|
||||||
|
return TypeD::make( (double)tf->getf() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *ConvF2INode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
if( t == Type::FLOAT ) return TypeInt::INT;
|
||||||
|
const TypeF *tf = t->is_float_constant();
|
||||||
|
return TypeInt::make( SharedRuntime::f2i( tf->getf() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Identity---------------------------------------
|
||||||
|
Node *ConvF2INode::Identity(PhaseTransform *phase) {
|
||||||
|
// Remove ConvF2I->ConvI2F->ConvF2I sequences.
|
||||||
|
if( in(1) ->Opcode() == Op_ConvI2F &&
|
||||||
|
in(1)->in(1)->Opcode() == Op_ConvF2I )
|
||||||
|
return in(1)->in(1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Ideal------------------------------------------
|
||||||
|
// If converting to an int type, skip any rounding nodes
|
||||||
|
Node *ConvF2INode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
if( in(1)->Opcode() == Op_RoundFloat )
|
||||||
|
set_req(1,in(1)->in(1));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *ConvF2LNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
if( t == Type::FLOAT ) return TypeLong::LONG;
|
||||||
|
const TypeF *tf = t->is_float_constant();
|
||||||
|
return TypeLong::make( SharedRuntime::f2l( tf->getf() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Identity---------------------------------------
|
||||||
|
Node *ConvF2LNode::Identity(PhaseTransform *phase) {
|
||||||
|
// Remove ConvF2L->ConvL2F->ConvF2L sequences.
|
||||||
|
if( in(1) ->Opcode() == Op_ConvL2F &&
|
||||||
|
in(1)->in(1)->Opcode() == Op_ConvF2L )
|
||||||
|
return in(1)->in(1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Ideal------------------------------------------
|
||||||
|
// If converting to an int type, skip any rounding nodes
|
||||||
|
Node *ConvF2LNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
if( in(1)->Opcode() == Op_RoundFloat )
|
||||||
|
set_req(1,in(1)->in(1));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *ConvI2DNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
const TypeInt *ti = t->is_int();
|
||||||
|
if( ti->is_con() ) return TypeD::make( (double)ti->get_con() );
|
||||||
|
return bottom_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *ConvI2FNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
const TypeInt *ti = t->is_int();
|
||||||
|
if( ti->is_con() ) return TypeF::make( (float)ti->get_con() );
|
||||||
|
return bottom_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Identity---------------------------------------
|
||||||
|
Node *ConvI2FNode::Identity(PhaseTransform *phase) {
|
||||||
|
// Remove ConvI2F->ConvF2I->ConvI2F sequences.
|
||||||
|
if( in(1) ->Opcode() == Op_ConvF2I &&
|
||||||
|
in(1)->in(1)->Opcode() == Op_ConvI2F )
|
||||||
|
return in(1)->in(1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *ConvI2LNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
const TypeInt *ti = t->is_int();
|
||||||
|
const Type* tl = TypeLong::make(ti->_lo, ti->_hi, ti->_widen);
|
||||||
|
// Join my declared type against my incoming type.
|
||||||
|
tl = tl->filter(_type);
|
||||||
|
return tl;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _LP64
|
||||||
|
static inline bool long_ranges_overlap(jlong lo1, jlong hi1,
|
||||||
|
jlong lo2, jlong hi2) {
|
||||||
|
// Two ranges overlap iff one range's low point falls in the other range.
|
||||||
|
return (lo2 <= lo1 && lo1 <= hi2) || (lo1 <= lo2 && lo2 <= hi1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------------------------Ideal------------------------------------------
|
||||||
|
Node *ConvI2LNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
const TypeLong* this_type = this->type()->is_long();
|
||||||
|
Node* this_changed = NULL;
|
||||||
|
|
||||||
|
// If _major_progress, then more loop optimizations follow. Do NOT
|
||||||
|
// remove this node's type assertion until no more loop ops can happen.
|
||||||
|
// The progress bit is set in the major loop optimizations THEN comes the
|
||||||
|
// call to IterGVN and any chance of hitting this code. Cf. Opaque1Node.
|
||||||
|
if (can_reshape && !phase->C->major_progress()) {
|
||||||
|
const TypeInt* in_type = phase->type(in(1))->isa_int();
|
||||||
|
if (in_type != NULL && this_type != NULL &&
|
||||||
|
(in_type->_lo != this_type->_lo ||
|
||||||
|
in_type->_hi != this_type->_hi)) {
|
||||||
|
// Although this WORSENS the type, it increases GVN opportunities,
|
||||||
|
// because I2L nodes with the same input will common up, regardless
|
||||||
|
// of slightly differing type assertions. Such slight differences
|
||||||
|
// arise routinely as a result of loop unrolling, so this is a
|
||||||
|
// post-unrolling graph cleanup. Choose a type which depends only
|
||||||
|
// on my input. (Exception: Keep a range assertion of >=0 or <0.)
|
||||||
|
jlong lo1 = this_type->_lo;
|
||||||
|
jlong hi1 = this_type->_hi;
|
||||||
|
int w1 = this_type->_widen;
|
||||||
|
if (lo1 != (jint)lo1 ||
|
||||||
|
hi1 != (jint)hi1 ||
|
||||||
|
lo1 > hi1) {
|
||||||
|
// Overflow leads to wraparound, wraparound leads to range saturation.
|
||||||
|
lo1 = min_jint; hi1 = max_jint;
|
||||||
|
} else if (lo1 >= 0) {
|
||||||
|
// Keep a range assertion of >=0.
|
||||||
|
lo1 = 0; hi1 = max_jint;
|
||||||
|
} else if (hi1 < 0) {
|
||||||
|
// Keep a range assertion of <0.
|
||||||
|
lo1 = min_jint; hi1 = -1;
|
||||||
|
} else {
|
||||||
|
lo1 = min_jint; hi1 = max_jint;
|
||||||
|
}
|
||||||
|
const TypeLong* wtype = TypeLong::make(MAX2((jlong)in_type->_lo, lo1),
|
||||||
|
MIN2((jlong)in_type->_hi, hi1),
|
||||||
|
MAX2((int)in_type->_widen, w1));
|
||||||
|
if (wtype != type()) {
|
||||||
|
set_type(wtype);
|
||||||
|
// Note: this_type still has old type value, for the logic below.
|
||||||
|
this_changed = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _LP64
|
||||||
|
// Convert ConvI2L(AddI(x, y)) to AddL(ConvI2L(x), ConvI2L(y)) ,
|
||||||
|
// but only if x and y have subranges that cannot cause 32-bit overflow,
|
||||||
|
// under the assumption that x+y is in my own subrange this->type().
|
||||||
|
|
||||||
|
// This assumption is based on a constraint (i.e., type assertion)
|
||||||
|
// established in Parse::array_addressing or perhaps elsewhere.
|
||||||
|
// This constraint has been adjoined to the "natural" type of
|
||||||
|
// the incoming argument in(0). We know (because of runtime
|
||||||
|
// checks) - that the result value I2L(x+y) is in the joined range.
|
||||||
|
// Hence we can restrict the incoming terms (x, y) to values such
|
||||||
|
// that their sum also lands in that range.
|
||||||
|
|
||||||
|
// This optimization is useful only on 64-bit systems, where we hope
|
||||||
|
// the addition will end up subsumed in an addressing mode.
|
||||||
|
// It is necessary to do this when optimizing an unrolled array
|
||||||
|
// copy loop such as x[i++] = y[i++].
|
||||||
|
|
||||||
|
// On 32-bit systems, it's better to perform as much 32-bit math as
|
||||||
|
// possible before the I2L conversion, because 32-bit math is cheaper.
|
||||||
|
// There's no common reason to "leak" a constant offset through the I2L.
|
||||||
|
// Addressing arithmetic will not absorb it as part of a 64-bit AddL.
|
||||||
|
|
||||||
|
Node* z = in(1);
|
||||||
|
int op = z->Opcode();
|
||||||
|
if (op == Op_AddI || op == Op_SubI) {
|
||||||
|
Node* x = z->in(1);
|
||||||
|
Node* y = z->in(2);
|
||||||
|
assert (x != z && y != z, "dead loop in ConvI2LNode::Ideal");
|
||||||
|
if (phase->type(x) == Type::TOP) return this_changed;
|
||||||
|
if (phase->type(y) == Type::TOP) return this_changed;
|
||||||
|
const TypeInt* tx = phase->type(x)->is_int();
|
||||||
|
const TypeInt* ty = phase->type(y)->is_int();
|
||||||
|
const TypeLong* tz = this_type;
|
||||||
|
jlong xlo = tx->_lo;
|
||||||
|
jlong xhi = tx->_hi;
|
||||||
|
jlong ylo = ty->_lo;
|
||||||
|
jlong yhi = ty->_hi;
|
||||||
|
jlong zlo = tz->_lo;
|
||||||
|
jlong zhi = tz->_hi;
|
||||||
|
jlong vbit = CONST64(1) << BitsPerInt;
|
||||||
|
int widen = MAX2(tx->_widen, ty->_widen);
|
||||||
|
if (op == Op_SubI) {
|
||||||
|
jlong ylo0 = ylo;
|
||||||
|
ylo = -yhi;
|
||||||
|
yhi = -ylo0;
|
||||||
|
}
|
||||||
|
// See if x+y can cause positive overflow into z+2**32
|
||||||
|
if (long_ranges_overlap(xlo+ylo, xhi+yhi, zlo+vbit, zhi+vbit)) {
|
||||||
|
return this_changed;
|
||||||
|
}
|
||||||
|
// See if x+y can cause negative overflow into z-2**32
|
||||||
|
if (long_ranges_overlap(xlo+ylo, xhi+yhi, zlo-vbit, zhi-vbit)) {
|
||||||
|
return this_changed;
|
||||||
|
}
|
||||||
|
// Now it's always safe to assume x+y does not overflow.
|
||||||
|
// This is true even if some pairs x,y might cause overflow, as long
|
||||||
|
// as that overflow value cannot fall into [zlo,zhi].
|
||||||
|
|
||||||
|
// Confident that the arithmetic is "as if infinite precision",
|
||||||
|
// we can now use z's range to put constraints on those of x and y.
|
||||||
|
// The "natural" range of x [xlo,xhi] can perhaps be narrowed to a
|
||||||
|
// more "restricted" range by intersecting [xlo,xhi] with the
|
||||||
|
// range obtained by subtracting y's range from the asserted range
|
||||||
|
// of the I2L conversion. Here's the interval arithmetic algebra:
|
||||||
|
// x == z-y == [zlo,zhi]-[ylo,yhi] == [zlo,zhi]+[-yhi,-ylo]
|
||||||
|
// => x in [zlo-yhi, zhi-ylo]
|
||||||
|
// => x in [zlo-yhi, zhi-ylo] INTERSECT [xlo,xhi]
|
||||||
|
// => x in [xlo MAX zlo-yhi, xhi MIN zhi-ylo]
|
||||||
|
jlong rxlo = MAX2(xlo, zlo - yhi);
|
||||||
|
jlong rxhi = MIN2(xhi, zhi - ylo);
|
||||||
|
// And similarly, x changing place with y:
|
||||||
|
jlong rylo = MAX2(ylo, zlo - xhi);
|
||||||
|
jlong ryhi = MIN2(yhi, zhi - xlo);
|
||||||
|
if (rxlo > rxhi || rylo > ryhi) {
|
||||||
|
return this_changed; // x or y is dying; don't mess w/ it
|
||||||
|
}
|
||||||
|
if (op == Op_SubI) {
|
||||||
|
jlong rylo0 = rylo;
|
||||||
|
rylo = -ryhi;
|
||||||
|
ryhi = -rylo0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* cx = phase->transform( new (phase->C) ConvI2LNode(x, TypeLong::make(rxlo, rxhi, widen)) );
|
||||||
|
Node* cy = phase->transform( new (phase->C) ConvI2LNode(y, TypeLong::make(rylo, ryhi, widen)) );
|
||||||
|
switch (op) {
|
||||||
|
case Op_AddI: return new (phase->C) AddLNode(cx, cy);
|
||||||
|
case Op_SubI: return new (phase->C) SubLNode(cx, cy);
|
||||||
|
default: ShouldNotReachHere();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif //_LP64
|
||||||
|
|
||||||
|
return this_changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *ConvL2DNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
const TypeLong *tl = t->is_long();
|
||||||
|
if( tl->is_con() ) return TypeD::make( (double)tl->get_con() );
|
||||||
|
return bottom_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *ConvL2FNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
const TypeLong *tl = t->is_long();
|
||||||
|
if( tl->is_con() ) return TypeF::make( (float)tl->get_con() );
|
||||||
|
return bottom_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//----------------------------Identity-----------------------------------------
|
||||||
|
Node *ConvL2INode::Identity( PhaseTransform *phase ) {
|
||||||
|
// Convert L2I(I2L(x)) => x
|
||||||
|
if (in(1)->Opcode() == Op_ConvI2L) return in(1)->in(1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *ConvL2INode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
const TypeLong *tl = t->is_long();
|
||||||
|
if (tl->is_con())
|
||||||
|
// Easy case.
|
||||||
|
return TypeInt::make((jint)tl->get_con());
|
||||||
|
return bottom_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Ideal------------------------------------------
|
||||||
|
// Return a node which is more "ideal" than the current node.
|
||||||
|
// Blow off prior masking to int
|
||||||
|
Node *ConvL2INode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
Node *andl = in(1);
|
||||||
|
uint andl_op = andl->Opcode();
|
||||||
|
if( andl_op == Op_AndL ) {
|
||||||
|
// Blow off prior masking to int
|
||||||
|
if( phase->type(andl->in(2)) == TypeLong::make( 0xFFFFFFFF ) ) {
|
||||||
|
set_req(1,andl->in(1));
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swap with a prior add: convL2I(addL(x,y)) ==> addI(convL2I(x),convL2I(y))
|
||||||
|
// This replaces an 'AddL' with an 'AddI'.
|
||||||
|
if( andl_op == Op_AddL ) {
|
||||||
|
// Don't do this for nodes which have more than one user since
|
||||||
|
// we'll end up computing the long add anyway.
|
||||||
|
if (andl->outcnt() > 1) return NULL;
|
||||||
|
|
||||||
|
Node* x = andl->in(1);
|
||||||
|
Node* y = andl->in(2);
|
||||||
|
assert( x != andl && y != andl, "dead loop in ConvL2INode::Ideal" );
|
||||||
|
if (phase->type(x) == Type::TOP) return NULL;
|
||||||
|
if (phase->type(y) == Type::TOP) return NULL;
|
||||||
|
Node *add1 = phase->transform(new (phase->C) ConvL2INode(x));
|
||||||
|
Node *add2 = phase->transform(new (phase->C) ConvL2INode(y));
|
||||||
|
return new (phase->C) AddINode(add1,add2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disable optimization: LoadL->ConvL2I ==> LoadI.
|
||||||
|
// It causes problems (sizes of Load and Store nodes do not match)
|
||||||
|
// in objects initialization code and Escape Analysis.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Identity---------------------------------------
|
||||||
|
// Remove redundant roundings
|
||||||
|
Node *RoundFloatNode::Identity( PhaseTransform *phase ) {
|
||||||
|
assert(Matcher::strict_fp_requires_explicit_rounding, "should only generate for Intel");
|
||||||
|
// Do not round constants
|
||||||
|
if (phase->type(in(1))->base() == Type::FloatCon) return in(1);
|
||||||
|
int op = in(1)->Opcode();
|
||||||
|
// Redundant rounding
|
||||||
|
if( op == Op_RoundFloat ) return in(1);
|
||||||
|
// Already rounded
|
||||||
|
if( op == Op_Parm ) return in(1);
|
||||||
|
if( op == Op_LoadF ) return in(1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *RoundFloatNode::Value( PhaseTransform *phase ) const {
|
||||||
|
return phase->type( in(1) );
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Identity---------------------------------------
|
||||||
|
// Remove redundant roundings. Incoming arguments are already rounded.
|
||||||
|
Node *RoundDoubleNode::Identity( PhaseTransform *phase ) {
|
||||||
|
assert(Matcher::strict_fp_requires_explicit_rounding, "should only generate for Intel");
|
||||||
|
// Do not round constants
|
||||||
|
if (phase->type(in(1))->base() == Type::DoubleCon) return in(1);
|
||||||
|
int op = in(1)->Opcode();
|
||||||
|
// Redundant rounding
|
||||||
|
if( op == Op_RoundDouble ) return in(1);
|
||||||
|
// Already rounded
|
||||||
|
if( op == Op_Parm ) return in(1);
|
||||||
|
if( op == Op_LoadD ) return in(1);
|
||||||
|
if( op == Op_ConvF2D ) return in(1);
|
||||||
|
if( op == Op_ConvI2D ) return in(1);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *RoundDoubleNode::Value( PhaseTransform *phase ) const {
|
||||||
|
return phase->type( in(1) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
215
hotspot/src/share/vm/opto/convertnode.hpp
Normal file
215
hotspot/src/share/vm/opto/convertnode.hpp
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHARE_VM_OPTO_CONVERTNODE_HPP
|
||||||
|
#define SHARE_VM_OPTO_CONVERTNODE_HPP
|
||||||
|
|
||||||
|
#include "opto/node.hpp"
|
||||||
|
#include "opto/opcodes.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------Conv2BNode-------------------------------------
|
||||||
|
// Convert int/pointer to a Boolean. Map zero to zero, all else to 1.
|
||||||
|
class Conv2BNode : public Node {
|
||||||
|
public:
|
||||||
|
Conv2BNode( Node *i ) : Node(0,i) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return TypeInt::BOOL; }
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual uint ideal_reg() const { return Op_RegI; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// The conversions operations are all Alpha sorted. Please keep it that way!
|
||||||
|
//------------------------------ConvD2FNode------------------------------------
|
||||||
|
// Convert double to float
|
||||||
|
class ConvD2FNode : public Node {
|
||||||
|
public:
|
||||||
|
ConvD2FNode( Node *in1 ) : Node(0,in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return Type::FLOAT; }
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
virtual uint ideal_reg() const { return Op_RegF; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------ConvD2INode------------------------------------
|
||||||
|
// Convert Double to Integer
|
||||||
|
class ConvD2INode : public Node {
|
||||||
|
public:
|
||||||
|
ConvD2INode( Node *in1 ) : Node(0,in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual uint ideal_reg() const { return Op_RegI; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------ConvD2LNode------------------------------------
|
||||||
|
// Convert Double to Long
|
||||||
|
class ConvD2LNode : public Node {
|
||||||
|
public:
|
||||||
|
ConvD2LNode( Node *dbl ) : Node(0,dbl) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return TypeLong::LONG; }
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual uint ideal_reg() const { return Op_RegL; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------ConvF2DNode------------------------------------
|
||||||
|
// Convert Float to a Double.
|
||||||
|
class ConvF2DNode : public Node {
|
||||||
|
public:
|
||||||
|
ConvF2DNode( Node *in1 ) : Node(0,in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return Type::DOUBLE; }
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual uint ideal_reg() const { return Op_RegD; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------ConvF2INode------------------------------------
|
||||||
|
// Convert float to integer
|
||||||
|
class ConvF2INode : public Node {
|
||||||
|
public:
|
||||||
|
ConvF2INode( Node *in1 ) : Node(0,in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual uint ideal_reg() const { return Op_RegI; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------ConvF2LNode------------------------------------
|
||||||
|
// Convert float to long
|
||||||
|
class ConvF2LNode : public Node {
|
||||||
|
public:
|
||||||
|
ConvF2LNode( Node *in1 ) : Node(0,in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return TypeLong::LONG; }
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual uint ideal_reg() const { return Op_RegL; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------ConvI2DNode------------------------------------
|
||||||
|
// Convert Integer to Double
|
||||||
|
class ConvI2DNode : public Node {
|
||||||
|
public:
|
||||||
|
ConvI2DNode( Node *in1 ) : Node(0,in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return Type::DOUBLE; }
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual uint ideal_reg() const { return Op_RegD; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------ConvI2FNode------------------------------------
|
||||||
|
// Convert Integer to Float
|
||||||
|
class ConvI2FNode : public Node {
|
||||||
|
public:
|
||||||
|
ConvI2FNode( Node *in1 ) : Node(0,in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return Type::FLOAT; }
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
virtual uint ideal_reg() const { return Op_RegF; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------ConvI2LNode------------------------------------
|
||||||
|
// Convert integer to long
|
||||||
|
class ConvI2LNode : public TypeNode {
|
||||||
|
public:
|
||||||
|
ConvI2LNode(Node *in1, const TypeLong* t = TypeLong::INT)
|
||||||
|
: TypeNode(t, 2)
|
||||||
|
{ init_req(1, in1); }
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual uint ideal_reg() const { return Op_RegL; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------ConvL2DNode------------------------------------
|
||||||
|
// Convert Long to Double
|
||||||
|
class ConvL2DNode : public Node {
|
||||||
|
public:
|
||||||
|
ConvL2DNode( Node *in1 ) : Node(0,in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return Type::DOUBLE; }
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual uint ideal_reg() const { return Op_RegD; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------ConvL2FNode------------------------------------
|
||||||
|
// Convert Long to Float
|
||||||
|
class ConvL2FNode : public Node {
|
||||||
|
public:
|
||||||
|
ConvL2FNode( Node *in1 ) : Node(0,in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return Type::FLOAT; }
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual uint ideal_reg() const { return Op_RegF; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------ConvL2INode------------------------------------
|
||||||
|
// Convert long to integer
|
||||||
|
class ConvL2INode : public Node {
|
||||||
|
public:
|
||||||
|
ConvL2INode( Node *in1 ) : Node(0,in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual uint ideal_reg() const { return Op_RegI; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//-----------------------------RoundFloatNode----------------------------------
|
||||||
|
class RoundFloatNode: public Node {
|
||||||
|
public:
|
||||||
|
RoundFloatNode(Node* c, Node *in1): Node(c, in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return Type::FLOAT; }
|
||||||
|
virtual uint ideal_reg() const { return Op_RegF; }
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------RoundDoubleNode---------------------------------
|
||||||
|
class RoundDoubleNode: public Node {
|
||||||
|
public:
|
||||||
|
RoundDoubleNode(Node* c, Node *in1): Node(c, in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return Type::DOUBLE; }
|
||||||
|
virtual uint ideal_reg() const { return Op_RegD; }
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SHARE_VM_OPTO_CONVERTNODE_HPP
|
119
hotspot/src/share/vm/opto/countbitsnode.cpp
Normal file
119
hotspot/src/share/vm/opto/countbitsnode.cpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precompiled.hpp"
|
||||||
|
#include "opto/countbitsnode.hpp"
|
||||||
|
#include "opto/opcodes.hpp"
|
||||||
|
#include "opto/phaseX.hpp"
|
||||||
|
#include "opto/type.hpp"
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type* CountLeadingZerosINode::Value(PhaseTransform* phase) const {
|
||||||
|
const Type* t = phase->type(in(1));
|
||||||
|
if (t == Type::TOP) return Type::TOP;
|
||||||
|
const TypeInt* ti = t->isa_int();
|
||||||
|
if (ti && ti->is_con()) {
|
||||||
|
jint i = ti->get_con();
|
||||||
|
// HD, Figure 5-6
|
||||||
|
if (i == 0)
|
||||||
|
return TypeInt::make(BitsPerInt);
|
||||||
|
int n = 1;
|
||||||
|
unsigned int x = i;
|
||||||
|
if (x >> 16 == 0) { n += 16; x <<= 16; }
|
||||||
|
if (x >> 24 == 0) { n += 8; x <<= 8; }
|
||||||
|
if (x >> 28 == 0) { n += 4; x <<= 4; }
|
||||||
|
if (x >> 30 == 0) { n += 2; x <<= 2; }
|
||||||
|
n -= x >> 31;
|
||||||
|
return TypeInt::make(n);
|
||||||
|
}
|
||||||
|
return TypeInt::INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type* CountLeadingZerosLNode::Value(PhaseTransform* phase) const {
|
||||||
|
const Type* t = phase->type(in(1));
|
||||||
|
if (t == Type::TOP) return Type::TOP;
|
||||||
|
const TypeLong* tl = t->isa_long();
|
||||||
|
if (tl && tl->is_con()) {
|
||||||
|
jlong l = tl->get_con();
|
||||||
|
// HD, Figure 5-6
|
||||||
|
if (l == 0)
|
||||||
|
return TypeInt::make(BitsPerLong);
|
||||||
|
int n = 1;
|
||||||
|
unsigned int x = (((julong) l) >> 32);
|
||||||
|
if (x == 0) { n += 32; x = (int) l; }
|
||||||
|
if (x >> 16 == 0) { n += 16; x <<= 16; }
|
||||||
|
if (x >> 24 == 0) { n += 8; x <<= 8; }
|
||||||
|
if (x >> 28 == 0) { n += 4; x <<= 4; }
|
||||||
|
if (x >> 30 == 0) { n += 2; x <<= 2; }
|
||||||
|
n -= x >> 31;
|
||||||
|
return TypeInt::make(n);
|
||||||
|
}
|
||||||
|
return TypeInt::INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type* CountTrailingZerosINode::Value(PhaseTransform* phase) const {
|
||||||
|
const Type* t = phase->type(in(1));
|
||||||
|
if (t == Type::TOP) return Type::TOP;
|
||||||
|
const TypeInt* ti = t->isa_int();
|
||||||
|
if (ti && ti->is_con()) {
|
||||||
|
jint i = ti->get_con();
|
||||||
|
// HD, Figure 5-14
|
||||||
|
int y;
|
||||||
|
if (i == 0)
|
||||||
|
return TypeInt::make(BitsPerInt);
|
||||||
|
int n = 31;
|
||||||
|
y = i << 16; if (y != 0) { n = n - 16; i = y; }
|
||||||
|
y = i << 8; if (y != 0) { n = n - 8; i = y; }
|
||||||
|
y = i << 4; if (y != 0) { n = n - 4; i = y; }
|
||||||
|
y = i << 2; if (y != 0) { n = n - 2; i = y; }
|
||||||
|
y = i << 1; if (y != 0) { n = n - 1; }
|
||||||
|
return TypeInt::make(n);
|
||||||
|
}
|
||||||
|
return TypeInt::INT;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type* CountTrailingZerosLNode::Value(PhaseTransform* phase) const {
|
||||||
|
const Type* t = phase->type(in(1));
|
||||||
|
if (t == Type::TOP) return Type::TOP;
|
||||||
|
const TypeLong* tl = t->isa_long();
|
||||||
|
if (tl && tl->is_con()) {
|
||||||
|
jlong l = tl->get_con();
|
||||||
|
// HD, Figure 5-14
|
||||||
|
int x, y;
|
||||||
|
if (l == 0)
|
||||||
|
return TypeInt::make(BitsPerLong);
|
||||||
|
int n = 63;
|
||||||
|
y = (int) l; if (y != 0) { n = n - 32; x = y; } else x = (((julong) l) >> 32);
|
||||||
|
y = x << 16; if (y != 0) { n = n - 16; x = y; }
|
||||||
|
y = x << 8; if (y != 0) { n = n - 8; x = y; }
|
||||||
|
y = x << 4; if (y != 0) { n = n - 4; x = y; }
|
||||||
|
y = x << 2; if (y != 0) { n = n - 2; x = y; }
|
||||||
|
y = x << 1; if (y != 0) { n = n - 1; }
|
||||||
|
return TypeInt::make(n);
|
||||||
|
}
|
||||||
|
return TypeInt::INT;
|
||||||
|
}
|
94
hotspot/src/share/vm/opto/countbitsnode.hpp
Normal file
94
hotspot/src/share/vm/opto/countbitsnode.hpp
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHARE_VM_OPTO_COUNTBITSNODE_HPP
|
||||||
|
#define SHARE_VM_OPTO_COUNTBITSNODE_HPP
|
||||||
|
|
||||||
|
#include "opto/node.hpp"
|
||||||
|
#include "opto/opcodes.hpp"
|
||||||
|
|
||||||
|
class PhaseTransform;
|
||||||
|
|
||||||
|
//---------- CountBitsNode -----------------------------------------------------
|
||||||
|
class CountBitsNode : public Node {
|
||||||
|
public:
|
||||||
|
CountBitsNode(Node* in1) : Node(0, in1) {}
|
||||||
|
const Type* bottom_type() const { return TypeInt::INT; }
|
||||||
|
virtual uint ideal_reg() const { return Op_RegI; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------- CountLeadingZerosINode --------------------------------------------
|
||||||
|
// Count leading zeros (0-bit count starting from MSB) of an integer.
|
||||||
|
class CountLeadingZerosINode : public CountBitsNode {
|
||||||
|
public:
|
||||||
|
CountLeadingZerosINode(Node* in1) : CountBitsNode(in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type* Value(PhaseTransform* phase) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------- CountLeadingZerosLNode --------------------------------------------
|
||||||
|
// Count leading zeros (0-bit count starting from MSB) of a long.
|
||||||
|
class CountLeadingZerosLNode : public CountBitsNode {
|
||||||
|
public:
|
||||||
|
CountLeadingZerosLNode(Node* in1) : CountBitsNode(in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type* Value(PhaseTransform* phase) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------- CountTrailingZerosINode -------------------------------------------
|
||||||
|
// Count trailing zeros (0-bit count starting from LSB) of an integer.
|
||||||
|
class CountTrailingZerosINode : public CountBitsNode {
|
||||||
|
public:
|
||||||
|
CountTrailingZerosINode(Node* in1) : CountBitsNode(in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type* Value(PhaseTransform* phase) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------- CountTrailingZerosLNode -------------------------------------------
|
||||||
|
// Count trailing zeros (0-bit count starting from LSB) of a long.
|
||||||
|
class CountTrailingZerosLNode : public CountBitsNode {
|
||||||
|
public:
|
||||||
|
CountTrailingZerosLNode(Node* in1) : CountBitsNode(in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type* Value(PhaseTransform* phase) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------- PopCountINode -----------------------------------------------------
|
||||||
|
// Population count (bit count) of an integer.
|
||||||
|
class PopCountINode : public CountBitsNode {
|
||||||
|
public:
|
||||||
|
PopCountINode(Node* in1) : CountBitsNode(in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------- PopCountLNode -----------------------------------------------------
|
||||||
|
// Population count (bit count) of a long.
|
||||||
|
class PopCountLNode : public CountBitsNode {
|
||||||
|
public:
|
||||||
|
PopCountLNode(Node* in1) : CountBitsNode(in1) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SHARE_VM_OPTO_COUNTBITSNODE_HPP
|
@ -26,8 +26,10 @@
|
|||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
#include "opto/connode.hpp"
|
#include "opto/connode.hpp"
|
||||||
|
#include "opto/convertnode.hpp"
|
||||||
#include "opto/divnode.hpp"
|
#include "opto/divnode.hpp"
|
||||||
#include "opto/machnode.hpp"
|
#include "opto/machnode.hpp"
|
||||||
|
#include "opto/movenode.hpp"
|
||||||
#include "opto/matcher.hpp"
|
#include "opto/matcher.hpp"
|
||||||
#include "opto/mulnode.hpp"
|
#include "opto/mulnode.hpp"
|
||||||
#include "opto/phaseX.hpp"
|
#include "opto/phaseX.hpp"
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "interpreter/linkResolver.hpp"
|
#include "interpreter/linkResolver.hpp"
|
||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
#include "opto/callGenerator.hpp"
|
#include "opto/callGenerator.hpp"
|
||||||
|
#include "opto/castnode.hpp"
|
||||||
#include "opto/cfgnode.hpp"
|
#include "opto/cfgnode.hpp"
|
||||||
#include "opto/mulnode.hpp"
|
#include "opto/mulnode.hpp"
|
||||||
#include "opto/parse.hpp"
|
#include "opto/parse.hpp"
|
||||||
@ -249,8 +250,7 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
|
|||||||
}
|
}
|
||||||
CallGenerator* miss_cg;
|
CallGenerator* miss_cg;
|
||||||
Deoptimization::DeoptReason reason = morphism == 2 ?
|
Deoptimization::DeoptReason reason = morphism == 2 ?
|
||||||
Deoptimization::Reason_bimorphic :
|
Deoptimization::Reason_bimorphic : Deoptimization::reason_class_check(speculative_receiver_type != NULL);
|
||||||
(speculative_receiver_type == NULL ? Deoptimization::Reason_class_check : Deoptimization::Reason_speculate_class_check);
|
|
||||||
if ((morphism == 1 || (morphism == 2 && next_hit_cg != NULL)) &&
|
if ((morphism == 1 || (morphism == 2 && next_hit_cg != NULL)) &&
|
||||||
!too_many_traps(jvms->method(), jvms->bci(), reason)
|
!too_many_traps(jvms->method(), jvms->bci(), reason)
|
||||||
) {
|
) {
|
||||||
@ -631,13 +631,7 @@ void Parse::do_call() {
|
|||||||
}
|
}
|
||||||
BasicType ct = ctype->basic_type();
|
BasicType ct = ctype->basic_type();
|
||||||
if (ct == T_OBJECT || ct == T_ARRAY) {
|
if (ct == T_OBJECT || ct == T_ARRAY) {
|
||||||
ciKlass* better_type = method()->return_profiled_type(bci());
|
record_profiled_return_for_speculation();
|
||||||
if (UseTypeSpeculation && better_type != NULL) {
|
|
||||||
// If profiling reports a single type for the return value,
|
|
||||||
// feed it to the type system so it can propagate it as a
|
|
||||||
// speculative type
|
|
||||||
record_profile_for_speculation(stack(sp()-1), better_type);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "opto/compile.hpp"
|
#include "opto/compile.hpp"
|
||||||
#include "opto/escape.hpp"
|
#include "opto/escape.hpp"
|
||||||
#include "opto/phaseX.hpp"
|
#include "opto/phaseX.hpp"
|
||||||
|
#include "opto/movenode.hpp"
|
||||||
#include "opto/rootnode.hpp"
|
#include "opto/rootnode.hpp"
|
||||||
|
|
||||||
ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) :
|
ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) :
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
#include "opto/callnode.hpp"
|
#include "opto/callnode.hpp"
|
||||||
#include "opto/cfgnode.hpp"
|
#include "opto/cfgnode.hpp"
|
||||||
#include "opto/compile.hpp"
|
#include "opto/compile.hpp"
|
||||||
#include "opto/connode.hpp"
|
#include "opto/convertnode.hpp"
|
||||||
#include "opto/locknode.hpp"
|
#include "opto/locknode.hpp"
|
||||||
#include "opto/memnode.hpp"
|
#include "opto/memnode.hpp"
|
||||||
#include "opto/mulnode.hpp"
|
#include "opto/mulnode.hpp"
|
||||||
|
@ -30,10 +30,14 @@
|
|||||||
#include "memory/barrierSet.hpp"
|
#include "memory/barrierSet.hpp"
|
||||||
#include "memory/cardTableModRefBS.hpp"
|
#include "memory/cardTableModRefBS.hpp"
|
||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
|
#include "opto/castnode.hpp"
|
||||||
|
#include "opto/convertnode.hpp"
|
||||||
#include "opto/graphKit.hpp"
|
#include "opto/graphKit.hpp"
|
||||||
#include "opto/idealKit.hpp"
|
#include "opto/idealKit.hpp"
|
||||||
|
#include "opto/intrinsicnode.hpp"
|
||||||
#include "opto/locknode.hpp"
|
#include "opto/locknode.hpp"
|
||||||
#include "opto/machnode.hpp"
|
#include "opto/machnode.hpp"
|
||||||
|
#include "opto/opaquenode.hpp"
|
||||||
#include "opto/parse.hpp"
|
#include "opto/parse.hpp"
|
||||||
#include "opto/rootnode.hpp"
|
#include "opto/rootnode.hpp"
|
||||||
#include "opto/runtime.hpp"
|
#include "opto/runtime.hpp"
|
||||||
@ -612,10 +616,10 @@ void GraphKit::builtin_throw(Deoptimization::DeoptReason reason, Node* arg) {
|
|||||||
// Usual case: Bail to interpreter.
|
// Usual case: Bail to interpreter.
|
||||||
// Reserve the right to recompile if we haven't seen anything yet.
|
// Reserve the right to recompile if we haven't seen anything yet.
|
||||||
|
|
||||||
assert(!Deoptimization::reason_is_speculate(reason), "unsupported");
|
ciMethod* m = Deoptimization::reason_is_speculate(reason) ? C->method() : NULL;
|
||||||
Deoptimization::DeoptAction action = Deoptimization::Action_maybe_recompile;
|
Deoptimization::DeoptAction action = Deoptimization::Action_maybe_recompile;
|
||||||
if (treat_throw_as_hot
|
if (treat_throw_as_hot
|
||||||
&& (method()->method_data()->trap_recompiled_at(bci(), NULL)
|
&& (method()->method_data()->trap_recompiled_at(bci(), m)
|
||||||
|| C->too_many_traps(reason))) {
|
|| C->too_many_traps(reason))) {
|
||||||
// We cannot afford to take more traps here. Suffer in the interpreter.
|
// We cannot afford to take more traps here. Suffer in the interpreter.
|
||||||
if (C->log() != NULL)
|
if (C->log() != NULL)
|
||||||
@ -1181,7 +1185,8 @@ extern int explicit_null_checks_inserted,
|
|||||||
Node* GraphKit::null_check_common(Node* value, BasicType type,
|
Node* GraphKit::null_check_common(Node* value, BasicType type,
|
||||||
// optional arguments for variations:
|
// optional arguments for variations:
|
||||||
bool assert_null,
|
bool assert_null,
|
||||||
Node* *null_control) {
|
Node* *null_control,
|
||||||
|
bool speculative) {
|
||||||
assert(!assert_null || null_control == NULL, "not both at once");
|
assert(!assert_null || null_control == NULL, "not both at once");
|
||||||
if (stopped()) return top();
|
if (stopped()) return top();
|
||||||
if (!GenerateCompilerNullChecks && !assert_null && null_control == NULL) {
|
if (!GenerateCompilerNullChecks && !assert_null && null_control == NULL) {
|
||||||
@ -1291,13 +1296,13 @@ Node* GraphKit::null_check_common(Node* value, BasicType type,
|
|||||||
// Branch to failure if null
|
// Branch to failure if null
|
||||||
float ok_prob = PROB_MAX; // a priori estimate: nulls never happen
|
float ok_prob = PROB_MAX; // a priori estimate: nulls never happen
|
||||||
Deoptimization::DeoptReason reason;
|
Deoptimization::DeoptReason reason;
|
||||||
if (assert_null)
|
if (assert_null) {
|
||||||
reason = Deoptimization::Reason_null_assert;
|
reason = Deoptimization::Reason_null_assert;
|
||||||
else if (type == T_OBJECT)
|
} else if (type == T_OBJECT) {
|
||||||
reason = Deoptimization::Reason_null_check;
|
reason = Deoptimization::reason_null_check(speculative);
|
||||||
else
|
} else {
|
||||||
reason = Deoptimization::Reason_div0_check;
|
reason = Deoptimization::Reason_div0_check;
|
||||||
|
}
|
||||||
// %%% Since Reason_unhandled is not recorded on a per-bytecode basis,
|
// %%% Since Reason_unhandled is not recorded on a per-bytecode basis,
|
||||||
// ciMethodData::has_trap_at will return a conservative -1 if any
|
// ciMethodData::has_trap_at will return a conservative -1 if any
|
||||||
// must-be-null assertion has failed. This could cause performance
|
// must-be-null assertion has failed. This could cause performance
|
||||||
@ -2120,21 +2125,36 @@ void GraphKit::round_double_arguments(ciMethod* dest_method) {
|
|||||||
*
|
*
|
||||||
* @param n node that the type applies to
|
* @param n node that the type applies to
|
||||||
* @param exact_kls type from profiling
|
* @param exact_kls type from profiling
|
||||||
|
* @param maybe_null did profiling see null?
|
||||||
*
|
*
|
||||||
* @return node with improved type
|
* @return node with improved type
|
||||||
*/
|
*/
|
||||||
Node* GraphKit::record_profile_for_speculation(Node* n, ciKlass* exact_kls) {
|
Node* GraphKit::record_profile_for_speculation(Node* n, ciKlass* exact_kls, bool maybe_null) {
|
||||||
const Type* current_type = _gvn.type(n);
|
const Type* current_type = _gvn.type(n);
|
||||||
assert(UseTypeSpeculation, "type speculation must be on");
|
assert(UseTypeSpeculation, "type speculation must be on");
|
||||||
|
|
||||||
const TypeOopPtr* speculative = current_type->speculative();
|
const TypePtr* speculative = current_type->speculative();
|
||||||
|
|
||||||
|
// Should the klass from the profile be recorded in the speculative type?
|
||||||
if (current_type->would_improve_type(exact_kls, jvms()->depth())) {
|
if (current_type->would_improve_type(exact_kls, jvms()->depth())) {
|
||||||
const TypeKlassPtr* tklass = TypeKlassPtr::make(exact_kls);
|
const TypeKlassPtr* tklass = TypeKlassPtr::make(exact_kls);
|
||||||
const TypeOopPtr* xtype = tklass->as_instance_type();
|
const TypeOopPtr* xtype = tklass->as_instance_type();
|
||||||
assert(xtype->klass_is_exact(), "Should be exact");
|
assert(xtype->klass_is_exact(), "Should be exact");
|
||||||
|
// Any reason to believe n is not null (from this profiling or a previous one)?
|
||||||
|
const TypePtr* ptr = (maybe_null && current_type->speculative_maybe_null()) ? TypePtr::BOTTOM : TypePtr::NOTNULL;
|
||||||
// record the new speculative type's depth
|
// record the new speculative type's depth
|
||||||
speculative = xtype->with_inline_depth(jvms()->depth());
|
speculative = xtype->cast_to_ptr_type(ptr->ptr())->is_ptr();
|
||||||
|
speculative = speculative->with_inline_depth(jvms()->depth());
|
||||||
|
} else if (current_type->would_improve_ptr(maybe_null)) {
|
||||||
|
// Profiling report that null was never seen so we can change the
|
||||||
|
// speculative type to non null ptr.
|
||||||
|
assert(!maybe_null, "nothing to improve");
|
||||||
|
if (speculative == NULL) {
|
||||||
|
speculative = TypePtr::NOTNULL;
|
||||||
|
} else {
|
||||||
|
const TypePtr* ptr = TypePtr::NOTNULL;
|
||||||
|
speculative = speculative->cast_to_ptr_type(ptr->ptr())->is_ptr();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (speculative != current_type->speculative()) {
|
if (speculative != current_type->speculative()) {
|
||||||
@ -2167,7 +2187,15 @@ Node* GraphKit::record_profiled_receiver_for_speculation(Node* n) {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
ciKlass* exact_kls = profile_has_unique_klass();
|
ciKlass* exact_kls = profile_has_unique_klass();
|
||||||
return record_profile_for_speculation(n, exact_kls);
|
bool maybe_null = true;
|
||||||
|
if (java_bc() == Bytecodes::_checkcast ||
|
||||||
|
java_bc() == Bytecodes::_instanceof ||
|
||||||
|
java_bc() == Bytecodes::_aastore) {
|
||||||
|
ciProfileData* data = method()->method_data()->bci_to_data(bci());
|
||||||
|
bool maybe_null = data == NULL ? true : data->as_BitData()->null_seen();
|
||||||
|
}
|
||||||
|
return record_profile_for_speculation(n, exact_kls, maybe_null);
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2187,9 +2215,10 @@ void GraphKit::record_profiled_arguments_for_speculation(ciMethod* dest_method,
|
|||||||
for (int j = skip, i = 0; j < nargs && i < TypeProfileArgsLimit; j++) {
|
for (int j = skip, i = 0; j < nargs && i < TypeProfileArgsLimit; j++) {
|
||||||
const Type *targ = tf->_domain->field_at(j + TypeFunc::Parms);
|
const Type *targ = tf->_domain->field_at(j + TypeFunc::Parms);
|
||||||
if (targ->basic_type() == T_OBJECT || targ->basic_type() == T_ARRAY) {
|
if (targ->basic_type() == T_OBJECT || targ->basic_type() == T_ARRAY) {
|
||||||
ciKlass* better_type = method()->argument_profiled_type(bci(), i);
|
bool maybe_null = true;
|
||||||
if (better_type != NULL) {
|
ciKlass* better_type = NULL;
|
||||||
record_profile_for_speculation(argument(j), better_type);
|
if (method()->argument_profiled_type(bci(), i, better_type, maybe_null)) {
|
||||||
|
record_profile_for_speculation(argument(j), better_type, maybe_null);
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
@ -2206,15 +2235,34 @@ void GraphKit::record_profiled_parameters_for_speculation() {
|
|||||||
}
|
}
|
||||||
for (int i = 0, j = 0; i < method()->arg_size() ; i++) {
|
for (int i = 0, j = 0; i < method()->arg_size() ; i++) {
|
||||||
if (_gvn.type(local(i))->isa_oopptr()) {
|
if (_gvn.type(local(i))->isa_oopptr()) {
|
||||||
ciKlass* better_type = method()->parameter_profiled_type(j);
|
bool maybe_null = true;
|
||||||
if (better_type != NULL) {
|
ciKlass* better_type = NULL;
|
||||||
record_profile_for_speculation(local(i), better_type);
|
if (method()->parameter_profiled_type(j, better_type, maybe_null)) {
|
||||||
|
record_profile_for_speculation(local(i), better_type, maybe_null);
|
||||||
}
|
}
|
||||||
j++;
|
j++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Record profiling data from return value profiling at an invoke with
|
||||||
|
* the type system so that it can propagate it (speculation)
|
||||||
|
*/
|
||||||
|
void GraphKit::record_profiled_return_for_speculation() {
|
||||||
|
if (!UseTypeSpeculation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool maybe_null = true;
|
||||||
|
ciKlass* better_type = NULL;
|
||||||
|
if (method()->return_profiled_type(bci(), better_type, maybe_null)) {
|
||||||
|
// If profiling reports a single type for the return value,
|
||||||
|
// feed it to the type system so it can propagate it as a
|
||||||
|
// speculative type
|
||||||
|
record_profile_for_speculation(stack(sp()-1), better_type, maybe_null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void GraphKit::round_double_result(ciMethod* dest_method) {
|
void GraphKit::round_double_result(ciMethod* dest_method) {
|
||||||
// A non-strict method may return a double value which has an extended
|
// A non-strict method may return a double value which has an extended
|
||||||
// exponent, but this must not be visible in a caller which is 'strict'
|
// exponent, but this must not be visible in a caller which is 'strict'
|
||||||
@ -2294,10 +2342,12 @@ Node* GraphKit::dstore_rounding(Node* n) {
|
|||||||
// Null check oop. Set null-path control into Region in slot 3.
|
// Null check oop. Set null-path control into Region in slot 3.
|
||||||
// Make a cast-not-nullness use the other not-null control. Return cast.
|
// Make a cast-not-nullness use the other not-null control. Return cast.
|
||||||
Node* GraphKit::null_check_oop(Node* value, Node* *null_control,
|
Node* GraphKit::null_check_oop(Node* value, Node* *null_control,
|
||||||
bool never_see_null, bool safe_for_replace) {
|
bool never_see_null,
|
||||||
|
bool safe_for_replace,
|
||||||
|
bool speculative) {
|
||||||
// Initial NULL check taken path
|
// Initial NULL check taken path
|
||||||
(*null_control) = top();
|
(*null_control) = top();
|
||||||
Node* cast = null_check_common(value, T_OBJECT, false, null_control);
|
Node* cast = null_check_common(value, T_OBJECT, false, null_control, speculative);
|
||||||
|
|
||||||
// Generate uncommon_trap:
|
// Generate uncommon_trap:
|
||||||
if (never_see_null && (*null_control) != top()) {
|
if (never_see_null && (*null_control) != top()) {
|
||||||
@ -2308,7 +2358,8 @@ Node* GraphKit::null_check_oop(Node* value, Node* *null_control,
|
|||||||
PreserveJVMState pjvms(this);
|
PreserveJVMState pjvms(this);
|
||||||
set_control(*null_control);
|
set_control(*null_control);
|
||||||
replace_in_map(value, null());
|
replace_in_map(value, null());
|
||||||
uncommon_trap(Deoptimization::Reason_null_check,
|
Deoptimization::DeoptReason reason = Deoptimization::reason_null_check(speculative);
|
||||||
|
uncommon_trap(reason,
|
||||||
Deoptimization::Action_make_not_entrant);
|
Deoptimization::Action_make_not_entrant);
|
||||||
(*null_control) = top(); // NULL path is dead
|
(*null_control) = top(); // NULL path is dead
|
||||||
}
|
}
|
||||||
@ -2732,11 +2783,16 @@ Node* GraphKit::type_check_receiver(Node* receiver, ciKlass* klass,
|
|||||||
// recompile; the offending check will be recompiled to handle NULLs.
|
// recompile; the offending check will be recompiled to handle NULLs.
|
||||||
// If we see several offending BCIs, then all checks in the
|
// If we see several offending BCIs, then all checks in the
|
||||||
// method will be recompiled.
|
// method will be recompiled.
|
||||||
bool GraphKit::seems_never_null(Node* obj, ciProfileData* data) {
|
bool GraphKit::seems_never_null(Node* obj, ciProfileData* data, bool& speculating) {
|
||||||
|
speculating = !_gvn.type(obj)->speculative_maybe_null();
|
||||||
|
Deoptimization::DeoptReason reason = Deoptimization::reason_null_check(speculating);
|
||||||
if (UncommonNullCast // Cutout for this technique
|
if (UncommonNullCast // Cutout for this technique
|
||||||
&& obj != null() // And not the -Xcomp stupid case?
|
&& obj != null() // And not the -Xcomp stupid case?
|
||||||
&& !too_many_traps(Deoptimization::Reason_null_check)
|
&& !too_many_traps(reason)
|
||||||
) {
|
) {
|
||||||
|
if (speculating) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (data == NULL)
|
if (data == NULL)
|
||||||
// Edge case: no mature data. Be optimistic here.
|
// Edge case: no mature data. Be optimistic here.
|
||||||
return true;
|
return true;
|
||||||
@ -2746,6 +2802,7 @@ bool GraphKit::seems_never_null(Node* obj, ciProfileData* data) {
|
|||||||
java_bc() == Bytecodes::_aastore, "MDO must collect null_seen bit here");
|
java_bc() == Bytecodes::_aastore, "MDO must collect null_seen bit here");
|
||||||
return !data->as_BitData()->null_seen();
|
return !data->as_BitData()->null_seen();
|
||||||
}
|
}
|
||||||
|
speculating = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2758,7 +2815,7 @@ Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj,
|
|||||||
bool safe_for_replace) {
|
bool safe_for_replace) {
|
||||||
if (!UseTypeProfile || !TypeProfileCasts) return NULL;
|
if (!UseTypeProfile || !TypeProfileCasts) return NULL;
|
||||||
|
|
||||||
Deoptimization::DeoptReason reason = spec_klass == NULL ? Deoptimization::Reason_class_check : Deoptimization::Reason_speculate_class_check;
|
Deoptimization::DeoptReason reason = Deoptimization::reason_class_check(spec_klass != NULL);
|
||||||
|
|
||||||
// Make sure we haven't already deoptimized from this tactic.
|
// Make sure we haven't already deoptimized from this tactic.
|
||||||
if (too_many_traps(reason))
|
if (too_many_traps(reason))
|
||||||
@ -2811,7 +2868,7 @@ Node* GraphKit::maybe_cast_profiled_obj(Node* obj,
|
|||||||
// type == NULL if profiling tells us this object is always null
|
// type == NULL if profiling tells us this object is always null
|
||||||
if (type != NULL) {
|
if (type != NULL) {
|
||||||
Deoptimization::DeoptReason class_reason = Deoptimization::Reason_speculate_class_check;
|
Deoptimization::DeoptReason class_reason = Deoptimization::Reason_speculate_class_check;
|
||||||
Deoptimization::DeoptReason null_reason = Deoptimization::Reason_null_check;
|
Deoptimization::DeoptReason null_reason = Deoptimization::Reason_speculate_null_check;
|
||||||
if (!too_many_traps(null_reason) &&
|
if (!too_many_traps(null_reason) &&
|
||||||
!too_many_traps(class_reason)) {
|
!too_many_traps(class_reason)) {
|
||||||
Node* not_null_obj = NULL;
|
Node* not_null_obj = NULL;
|
||||||
@ -2819,7 +2876,7 @@ Node* GraphKit::maybe_cast_profiled_obj(Node* obj,
|
|||||||
// there's no need for a null check
|
// there's no need for a null check
|
||||||
if (!not_null) {
|
if (!not_null) {
|
||||||
Node* null_ctl = top();
|
Node* null_ctl = top();
|
||||||
not_null_obj = null_check_oop(obj, &null_ctl, true, true);
|
not_null_obj = null_check_oop(obj, &null_ctl, true, true, true);
|
||||||
assert(null_ctl->is_top(), "no null control here");
|
assert(null_ctl->is_top(), "no null control here");
|
||||||
} else {
|
} else {
|
||||||
not_null_obj = obj;
|
not_null_obj = obj;
|
||||||
@ -2867,12 +2924,13 @@ Node* GraphKit::gen_instanceof(Node* obj, Node* superklass, bool safe_for_replac
|
|||||||
if (java_bc() == Bytecodes::_instanceof) { // Only for the bytecode
|
if (java_bc() == Bytecodes::_instanceof) { // Only for the bytecode
|
||||||
data = method()->method_data()->bci_to_data(bci());
|
data = method()->method_data()->bci_to_data(bci());
|
||||||
}
|
}
|
||||||
|
bool speculative_not_null = false;
|
||||||
bool never_see_null = (ProfileDynamicTypes // aggressive use of profile
|
bool never_see_null = (ProfileDynamicTypes // aggressive use of profile
|
||||||
&& seems_never_null(obj, data));
|
&& seems_never_null(obj, data, speculative_not_null));
|
||||||
|
|
||||||
// Null check; get casted pointer; set region slot 3
|
// Null check; get casted pointer; set region slot 3
|
||||||
Node* null_ctl = top();
|
Node* null_ctl = top();
|
||||||
Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace);
|
Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace, speculative_not_null);
|
||||||
|
|
||||||
// If not_null_obj is dead, only null-path is taken
|
// If not_null_obj is dead, only null-path is taken
|
||||||
if (stopped()) { // Doing instance-of on a NULL?
|
if (stopped()) { // Doing instance-of on a NULL?
|
||||||
@ -2995,12 +3053,13 @@ Node* GraphKit::gen_checkcast(Node *obj, Node* superklass,
|
|||||||
C->set_has_split_ifs(true); // Has chance for split-if optimization
|
C->set_has_split_ifs(true); // Has chance for split-if optimization
|
||||||
|
|
||||||
// Use null-cast information if it is available
|
// Use null-cast information if it is available
|
||||||
|
bool speculative_not_null = false;
|
||||||
bool never_see_null = ((failure_control == NULL) // regular case only
|
bool never_see_null = ((failure_control == NULL) // regular case only
|
||||||
&& seems_never_null(obj, data));
|
&& seems_never_null(obj, data, speculative_not_null));
|
||||||
|
|
||||||
// Null check; get casted pointer; set region slot 3
|
// Null check; get casted pointer; set region slot 3
|
||||||
Node* null_ctl = top();
|
Node* null_ctl = top();
|
||||||
Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace);
|
Node* not_null_obj = null_check_oop(obj, &null_ctl, never_see_null, safe_for_replace, speculative_not_null);
|
||||||
|
|
||||||
// If not_null_obj is dead, only null-path is taken
|
// If not_null_obj is dead, only null-path is taken
|
||||||
if (stopped()) { // Doing instance-of on a NULL?
|
if (stopped()) { // Doing instance-of on a NULL?
|
||||||
|
@ -351,9 +351,11 @@ class GraphKit : public Phase {
|
|||||||
// Return the value cast to not-null.
|
// Return the value cast to not-null.
|
||||||
// Be clever about equivalent dominating null checks.
|
// Be clever about equivalent dominating null checks.
|
||||||
Node* null_check_common(Node* value, BasicType type,
|
Node* null_check_common(Node* value, BasicType type,
|
||||||
bool assert_null = false, Node* *null_control = NULL);
|
bool assert_null = false,
|
||||||
|
Node* *null_control = NULL,
|
||||||
|
bool speculative = false);
|
||||||
Node* null_check(Node* value, BasicType type = T_OBJECT) {
|
Node* null_check(Node* value, BasicType type = T_OBJECT) {
|
||||||
return null_check_common(value, type);
|
return null_check_common(value, type, false, NULL, !_gvn.type(value)->speculative_maybe_null());
|
||||||
}
|
}
|
||||||
Node* null_check_receiver() {
|
Node* null_check_receiver() {
|
||||||
assert(argument(0)->bottom_type()->isa_ptr(), "must be");
|
assert(argument(0)->bottom_type()->isa_ptr(), "must be");
|
||||||
@ -382,10 +384,12 @@ class GraphKit : public Phase {
|
|||||||
// If safe_for_replace, then we can replace the value with the cast
|
// If safe_for_replace, then we can replace the value with the cast
|
||||||
// in the parsing map (the cast is guaranteed to dominate the map)
|
// in the parsing map (the cast is guaranteed to dominate the map)
|
||||||
Node* null_check_oop(Node* value, Node* *null_control,
|
Node* null_check_oop(Node* value, Node* *null_control,
|
||||||
bool never_see_null = false, bool safe_for_replace = false);
|
bool never_see_null = false,
|
||||||
|
bool safe_for_replace = false,
|
||||||
|
bool speculative = false);
|
||||||
|
|
||||||
// Check the null_seen bit.
|
// Check the null_seen bit.
|
||||||
bool seems_never_null(Node* obj, ciProfileData* data);
|
bool seems_never_null(Node* obj, ciProfileData* data, bool& speculating);
|
||||||
|
|
||||||
// Check for unique class for receiver at call
|
// Check for unique class for receiver at call
|
||||||
ciKlass* profile_has_unique_klass() {
|
ciKlass* profile_has_unique_klass() {
|
||||||
@ -399,10 +403,11 @@ class GraphKit : public Phase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// record type from profiling with the type system
|
// record type from profiling with the type system
|
||||||
Node* record_profile_for_speculation(Node* n, ciKlass* exact_kls);
|
Node* record_profile_for_speculation(Node* n, ciKlass* exact_kls, bool maybe_null);
|
||||||
Node* record_profiled_receiver_for_speculation(Node* n);
|
|
||||||
void record_profiled_arguments_for_speculation(ciMethod* dest_method, Bytecodes::Code bc);
|
void record_profiled_arguments_for_speculation(ciMethod* dest_method, Bytecodes::Code bc);
|
||||||
void record_profiled_parameters_for_speculation();
|
void record_profiled_parameters_for_speculation();
|
||||||
|
void record_profiled_return_for_speculation();
|
||||||
|
Node* record_profiled_receiver_for_speculation(Node* n);
|
||||||
|
|
||||||
// Use the type profile to narrow an object type.
|
// Use the type profile to narrow an object type.
|
||||||
Node* maybe_cast_profiled_receiver(Node* not_null_obj,
|
Node* maybe_cast_profiled_receiver(Node* not_null_obj,
|
||||||
|
@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
#include "opto/cfgnode.hpp"
|
#include "opto/cfgnode.hpp"
|
||||||
|
#include "opto/castnode.hpp"
|
||||||
#include "opto/connode.hpp"
|
#include "opto/connode.hpp"
|
||||||
#include "opto/divnode.hpp"
|
#include "opto/divnode.hpp"
|
||||||
#include "opto/graphKit.hpp"
|
#include "opto/graphKit.hpp"
|
||||||
|
@ -31,7 +31,6 @@
|
|||||||
#include "opto/cfgnode.hpp"
|
#include "opto/cfgnode.hpp"
|
||||||
#include "opto/chaitin.hpp"
|
#include "opto/chaitin.hpp"
|
||||||
#include "opto/coalesce.hpp"
|
#include "opto/coalesce.hpp"
|
||||||
#include "opto/connode.hpp"
|
|
||||||
#include "opto/indexSet.hpp"
|
#include "opto/indexSet.hpp"
|
||||||
#include "opto/machnode.hpp"
|
#include "opto/machnode.hpp"
|
||||||
#include "opto/memnode.hpp"
|
#include "opto/memnode.hpp"
|
||||||
|
82
hotspot/src/share/vm/opto/intrinsicnode.cpp
Normal file
82
hotspot/src/share/vm/opto/intrinsicnode.cpp
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precompiled.hpp"
|
||||||
|
#include "opto/intrinsicnode.hpp"
|
||||||
|
#include "opto/memnode.hpp"
|
||||||
|
#include "opto/phaseX.hpp"
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// Do not match memory edge.
|
||||||
|
uint StrIntrinsicNode::match_edge(uint idx) const {
|
||||||
|
return idx == 2 || idx == 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Ideal------------------------------------------
|
||||||
|
// Return a node which is more "ideal" than the current node. Strip out
|
||||||
|
// control copies
|
||||||
|
Node *StrIntrinsicNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
if (remove_dead_region(phase, can_reshape)) return this;
|
||||||
|
// Don't bother trying to transform a dead node
|
||||||
|
if (in(0) && in(0)->is_top()) return NULL;
|
||||||
|
|
||||||
|
if (can_reshape) {
|
||||||
|
Node* mem = phase->transform(in(MemNode::Memory));
|
||||||
|
// If transformed to a MergeMem, get the desired slice
|
||||||
|
uint alias_idx = phase->C->get_alias_index(adr_type());
|
||||||
|
mem = mem->is_MergeMem() ? mem->as_MergeMem()->memory_at(alias_idx) : mem;
|
||||||
|
if (mem != in(MemNode::Memory)) {
|
||||||
|
set_req(MemNode::Memory, mem);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *StrIntrinsicNode::Value( PhaseTransform *phase ) const {
|
||||||
|
if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP;
|
||||||
|
return bottom_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------match_edge-------------------------------------
|
||||||
|
// Do not match memory edge
|
||||||
|
uint EncodeISOArrayNode::match_edge(uint idx) const {
|
||||||
|
return idx == 2 || idx == 3; // EncodeISOArray src (Binary dst len)
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Ideal------------------------------------------
|
||||||
|
// Return a node which is more "ideal" than the current node. Strip out
|
||||||
|
// control copies
|
||||||
|
Node *EncodeISOArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
return remove_dead_region(phase, can_reshape) ? this : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *EncodeISOArrayNode::Value(PhaseTransform *phase) const {
|
||||||
|
if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP;
|
||||||
|
return bottom_type();
|
||||||
|
}
|
||||||
|
|
127
hotspot/src/share/vm/opto/intrinsicnode.hpp
Normal file
127
hotspot/src/share/vm/opto/intrinsicnode.hpp
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHARE_VM_OPTO_INTRINSICNODE_HPP
|
||||||
|
#define SHARE_VM_OPTO_INTRINSICNODE_HPP
|
||||||
|
|
||||||
|
#include "opto/node.hpp"
|
||||||
|
#include "opto/opcodes.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------PartialSubtypeCheckNode--------------------------------
|
||||||
|
// The 2nd slow-half of a subtype check. Scan the subklass's 2ndary superklass
|
||||||
|
// array for an instance of the superklass. Set a hidden internal cache on a
|
||||||
|
// hit (cache is checked with exposed code in gen_subtype_check()). Return
|
||||||
|
// not zero for a miss or zero for a hit.
|
||||||
|
class PartialSubtypeCheckNode : public Node {
|
||||||
|
public:
|
||||||
|
PartialSubtypeCheckNode(Node* c, Node* sub, Node* super) : Node(c,sub,super) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return TypeRawPtr::BOTTOM; }
|
||||||
|
virtual uint ideal_reg() const { return Op_RegP; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------StrIntrinsic-------------------------------
|
||||||
|
// Base class for Ideal nodes used in String instrinsic code.
|
||||||
|
class StrIntrinsicNode: public Node {
|
||||||
|
public:
|
||||||
|
StrIntrinsicNode(Node* control, Node* char_array_mem,
|
||||||
|
Node* s1, Node* c1, Node* s2, Node* c2):
|
||||||
|
Node(control, char_array_mem, s1, c1, s2, c2) {
|
||||||
|
}
|
||||||
|
|
||||||
|
StrIntrinsicNode(Node* control, Node* char_array_mem,
|
||||||
|
Node* s1, Node* s2, Node* c):
|
||||||
|
Node(control, char_array_mem, s1, s2, c) {
|
||||||
|
}
|
||||||
|
|
||||||
|
StrIntrinsicNode(Node* control, Node* char_array_mem,
|
||||||
|
Node* s1, Node* s2):
|
||||||
|
Node(control, char_array_mem, s1, s2) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool depends_only_on_test() const { return false; }
|
||||||
|
virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; }
|
||||||
|
virtual uint match_edge(uint idx) const;
|
||||||
|
virtual uint ideal_reg() const { return Op_RegI; }
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual const Type *Value(PhaseTransform *phase) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------StrComp-------------------------------------
|
||||||
|
class StrCompNode: public StrIntrinsicNode {
|
||||||
|
public:
|
||||||
|
StrCompNode(Node* control, Node* char_array_mem,
|
||||||
|
Node* s1, Node* c1, Node* s2, Node* c2):
|
||||||
|
StrIntrinsicNode(control, char_array_mem, s1, c1, s2, c2) {};
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type* bottom_type() const { return TypeInt::INT; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------StrEquals-------------------------------------
|
||||||
|
class StrEqualsNode: public StrIntrinsicNode {
|
||||||
|
public:
|
||||||
|
StrEqualsNode(Node* control, Node* char_array_mem,
|
||||||
|
Node* s1, Node* s2, Node* c):
|
||||||
|
StrIntrinsicNode(control, char_array_mem, s1, s2, c) {};
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type* bottom_type() const { return TypeInt::BOOL; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------StrIndexOf-------------------------------------
|
||||||
|
class StrIndexOfNode: public StrIntrinsicNode {
|
||||||
|
public:
|
||||||
|
StrIndexOfNode(Node* control, Node* char_array_mem,
|
||||||
|
Node* s1, Node* c1, Node* s2, Node* c2):
|
||||||
|
StrIntrinsicNode(control, char_array_mem, s1, c1, s2, c2) {};
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type* bottom_type() const { return TypeInt::INT; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------AryEq---------------------------------------
|
||||||
|
class AryEqNode: public StrIntrinsicNode {
|
||||||
|
public:
|
||||||
|
AryEqNode(Node* control, Node* char_array_mem, Node* s1, Node* s2):
|
||||||
|
StrIntrinsicNode(control, char_array_mem, s1, s2) {};
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type* bottom_type() const { return TypeInt::BOOL; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------EncodeISOArray--------------------------------
|
||||||
|
// encode char[] to byte[] in ISO_8859_1
|
||||||
|
class EncodeISOArrayNode: public Node {
|
||||||
|
public:
|
||||||
|
EncodeISOArrayNode(Node *control, Node* arymem, Node* s1, Node* s2, Node* c): Node(control, arymem, s1, s2, c) {};
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual bool depends_only_on_test() const { return false; }
|
||||||
|
virtual const Type* bottom_type() const { return TypeInt::INT; }
|
||||||
|
virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; }
|
||||||
|
virtual uint match_edge(uint idx) const;
|
||||||
|
virtual uint ideal_reg() const { return Op_RegI; }
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual const Type *Value(PhaseTransform *phase) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SHARE_VM_OPTO_INTRINSICNODE_HPP
|
@ -30,10 +30,16 @@
|
|||||||
#include "oops/objArrayKlass.hpp"
|
#include "oops/objArrayKlass.hpp"
|
||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
#include "opto/callGenerator.hpp"
|
#include "opto/callGenerator.hpp"
|
||||||
|
#include "opto/castnode.hpp"
|
||||||
#include "opto/cfgnode.hpp"
|
#include "opto/cfgnode.hpp"
|
||||||
|
#include "opto/convertnode.hpp"
|
||||||
|
#include "opto/countbitsnode.hpp"
|
||||||
|
#include "opto/intrinsicnode.hpp"
|
||||||
#include "opto/idealKit.hpp"
|
#include "opto/idealKit.hpp"
|
||||||
#include "opto/mathexactnode.hpp"
|
#include "opto/mathexactnode.hpp"
|
||||||
|
#include "opto/movenode.hpp"
|
||||||
#include "opto/mulnode.hpp"
|
#include "opto/mulnode.hpp"
|
||||||
|
#include "opto/narrowptrnode.hpp"
|
||||||
#include "opto/parse.hpp"
|
#include "opto/parse.hpp"
|
||||||
#include "opto/runtime.hpp"
|
#include "opto/runtime.hpp"
|
||||||
#include "opto/subnode.hpp"
|
#include "opto/subnode.hpp"
|
||||||
@ -4658,7 +4664,7 @@ bool LibraryCallKit::inline_arraycopy() {
|
|||||||
|
|
||||||
ciKlass* src_k = NULL;
|
ciKlass* src_k = NULL;
|
||||||
if (!has_src) {
|
if (!has_src) {
|
||||||
src_k = src_type->speculative_type();
|
src_k = src_type->speculative_type_not_null();
|
||||||
if (src_k != NULL && src_k->is_array_klass()) {
|
if (src_k != NULL && src_k->is_array_klass()) {
|
||||||
could_have_src = true;
|
could_have_src = true;
|
||||||
}
|
}
|
||||||
@ -4666,7 +4672,7 @@ bool LibraryCallKit::inline_arraycopy() {
|
|||||||
|
|
||||||
ciKlass* dest_k = NULL;
|
ciKlass* dest_k = NULL;
|
||||||
if (!has_dest) {
|
if (!has_dest) {
|
||||||
dest_k = dest_type->speculative_type();
|
dest_k = dest_type->speculative_type_not_null();
|
||||||
if (dest_k != NULL && dest_k->is_array_klass()) {
|
if (dest_k != NULL && dest_k->is_array_klass()) {
|
||||||
could_have_dest = true;
|
could_have_dest = true;
|
||||||
}
|
}
|
||||||
@ -4738,13 +4744,13 @@ bool LibraryCallKit::inline_arraycopy() {
|
|||||||
ciKlass* src_k = top_src->klass();
|
ciKlass* src_k = top_src->klass();
|
||||||
ciKlass* dest_k = top_dest->klass();
|
ciKlass* dest_k = top_dest->klass();
|
||||||
if (!src_spec) {
|
if (!src_spec) {
|
||||||
src_k = src_type->speculative_type();
|
src_k = src_type->speculative_type_not_null();
|
||||||
if (src_k != NULL && src_k->is_array_klass()) {
|
if (src_k != NULL && src_k->is_array_klass()) {
|
||||||
could_have_src = true;
|
could_have_src = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!dest_spec) {
|
if (!dest_spec) {
|
||||||
dest_k = dest_type->speculative_type();
|
dest_k = dest_type->speculative_type_not_null();
|
||||||
if (dest_k != NULL && dest_k->is_array_klass()) {
|
if (dest_k != NULL && dest_k->is_array_klass()) {
|
||||||
could_have_dest = true;
|
could_have_dest = true;
|
||||||
}
|
}
|
||||||
|
@ -27,8 +27,10 @@
|
|||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
#include "opto/callnode.hpp"
|
#include "opto/callnode.hpp"
|
||||||
#include "opto/connode.hpp"
|
#include "opto/connode.hpp"
|
||||||
|
#include "opto/convertnode.hpp"
|
||||||
#include "opto/loopnode.hpp"
|
#include "opto/loopnode.hpp"
|
||||||
#include "opto/mulnode.hpp"
|
#include "opto/mulnode.hpp"
|
||||||
|
#include "opto/opaquenode.hpp"
|
||||||
#include "opto/rootnode.hpp"
|
#include "opto/rootnode.hpp"
|
||||||
#include "opto/subnode.hpp"
|
#include "opto/subnode.hpp"
|
||||||
|
|
||||||
|
@ -28,9 +28,12 @@
|
|||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
#include "opto/callnode.hpp"
|
#include "opto/callnode.hpp"
|
||||||
#include "opto/connode.hpp"
|
#include "opto/connode.hpp"
|
||||||
|
#include "opto/convertnode.hpp"
|
||||||
#include "opto/divnode.hpp"
|
#include "opto/divnode.hpp"
|
||||||
#include "opto/loopnode.hpp"
|
#include "opto/loopnode.hpp"
|
||||||
#include "opto/mulnode.hpp"
|
#include "opto/mulnode.hpp"
|
||||||
|
#include "opto/movenode.hpp"
|
||||||
|
#include "opto/opaquenode.hpp"
|
||||||
#include "opto/rootnode.hpp"
|
#include "opto/rootnode.hpp"
|
||||||
#include "opto/runtime.hpp"
|
#include "opto/runtime.hpp"
|
||||||
#include "opto/subnode.hpp"
|
#include "opto/subnode.hpp"
|
||||||
|
@ -25,7 +25,9 @@
|
|||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "opto/connode.hpp"
|
#include "opto/connode.hpp"
|
||||||
|
#include "opto/convertnode.hpp"
|
||||||
#include "opto/loopnode.hpp"
|
#include "opto/loopnode.hpp"
|
||||||
|
#include "opto/opaquenode.hpp"
|
||||||
#include "opto/rootnode.hpp"
|
#include "opto/rootnode.hpp"
|
||||||
|
|
||||||
//================= Loop Unswitching =====================
|
//================= Loop Unswitching =====================
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
#include "opto/callnode.hpp"
|
#include "opto/callnode.hpp"
|
||||||
#include "opto/connode.hpp"
|
#include "opto/connode.hpp"
|
||||||
|
#include "opto/convertnode.hpp"
|
||||||
#include "opto/divnode.hpp"
|
#include "opto/divnode.hpp"
|
||||||
#include "opto/idealGraphPrinter.hpp"
|
#include "opto/idealGraphPrinter.hpp"
|
||||||
#include "opto/loopnode.hpp"
|
#include "opto/loopnode.hpp"
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
#include "opto/loopnode.hpp"
|
#include "opto/loopnode.hpp"
|
||||||
#include "opto/matcher.hpp"
|
#include "opto/matcher.hpp"
|
||||||
#include "opto/mulnode.hpp"
|
#include "opto/mulnode.hpp"
|
||||||
|
#include "opto/movenode.hpp"
|
||||||
|
#include "opto/opaquenode.hpp"
|
||||||
#include "opto/rootnode.hpp"
|
#include "opto/rootnode.hpp"
|
||||||
#include "opto/subnode.hpp"
|
#include "opto/subnode.hpp"
|
||||||
|
|
||||||
|
@ -27,14 +27,17 @@
|
|||||||
#include "libadt/vectset.hpp"
|
#include "libadt/vectset.hpp"
|
||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
#include "opto/callnode.hpp"
|
#include "opto/callnode.hpp"
|
||||||
|
#include "opto/castnode.hpp"
|
||||||
#include "opto/cfgnode.hpp"
|
#include "opto/cfgnode.hpp"
|
||||||
#include "opto/compile.hpp"
|
#include "opto/compile.hpp"
|
||||||
#include "opto/connode.hpp"
|
#include "opto/convertnode.hpp"
|
||||||
#include "opto/locknode.hpp"
|
#include "opto/locknode.hpp"
|
||||||
#include "opto/loopnode.hpp"
|
#include "opto/loopnode.hpp"
|
||||||
#include "opto/macro.hpp"
|
#include "opto/macro.hpp"
|
||||||
#include "opto/memnode.hpp"
|
#include "opto/memnode.hpp"
|
||||||
|
#include "opto/narrowptrnode.hpp"
|
||||||
#include "opto/node.hpp"
|
#include "opto/node.hpp"
|
||||||
|
#include "opto/opaquenode.hpp"
|
||||||
#include "opto/phaseX.hpp"
|
#include "opto/phaseX.hpp"
|
||||||
#include "opto/rootnode.hpp"
|
#include "opto/rootnode.hpp"
|
||||||
#include "opto/runtime.hpp"
|
#include "opto/runtime.hpp"
|
||||||
|
@ -26,10 +26,10 @@
|
|||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
#include "opto/callnode.hpp"
|
#include "opto/callnode.hpp"
|
||||||
#include "opto/connode.hpp"
|
|
||||||
#include "opto/idealGraphPrinter.hpp"
|
#include "opto/idealGraphPrinter.hpp"
|
||||||
#include "opto/matcher.hpp"
|
#include "opto/matcher.hpp"
|
||||||
#include "opto/memnode.hpp"
|
#include "opto/memnode.hpp"
|
||||||
|
#include "opto/movenode.hpp"
|
||||||
#include "opto/opcodes.hpp"
|
#include "opto/opcodes.hpp"
|
||||||
#include "opto/regmask.hpp"
|
#include "opto/regmask.hpp"
|
||||||
#include "opto/rootnode.hpp"
|
#include "opto/rootnode.hpp"
|
||||||
|
@ -31,11 +31,13 @@
|
|||||||
#include "opto/cfgnode.hpp"
|
#include "opto/cfgnode.hpp"
|
||||||
#include "opto/compile.hpp"
|
#include "opto/compile.hpp"
|
||||||
#include "opto/connode.hpp"
|
#include "opto/connode.hpp"
|
||||||
|
#include "opto/convertnode.hpp"
|
||||||
#include "opto/loopnode.hpp"
|
#include "opto/loopnode.hpp"
|
||||||
#include "opto/machnode.hpp"
|
#include "opto/machnode.hpp"
|
||||||
#include "opto/matcher.hpp"
|
#include "opto/matcher.hpp"
|
||||||
#include "opto/memnode.hpp"
|
#include "opto/memnode.hpp"
|
||||||
#include "opto/mulnode.hpp"
|
#include "opto/mulnode.hpp"
|
||||||
|
#include "opto/narrowptrnode.hpp"
|
||||||
#include "opto/phaseX.hpp"
|
#include "opto/phaseX.hpp"
|
||||||
#include "opto/regmask.hpp"
|
#include "opto/regmask.hpp"
|
||||||
|
|
||||||
@ -2903,59 +2905,6 @@ Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest,
|
|||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
// Do not match memory edge.
|
|
||||||
uint StrIntrinsicNode::match_edge(uint idx) const {
|
|
||||||
return idx == 2 || idx == 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------Ideal------------------------------------------
|
|
||||||
// Return a node which is more "ideal" than the current node. Strip out
|
|
||||||
// control copies
|
|
||||||
Node *StrIntrinsicNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|
||||||
if (remove_dead_region(phase, can_reshape)) return this;
|
|
||||||
// Don't bother trying to transform a dead node
|
|
||||||
if (in(0) && in(0)->is_top()) return NULL;
|
|
||||||
|
|
||||||
if (can_reshape) {
|
|
||||||
Node* mem = phase->transform(in(MemNode::Memory));
|
|
||||||
// If transformed to a MergeMem, get the desired slice
|
|
||||||
uint alias_idx = phase->C->get_alias_index(adr_type());
|
|
||||||
mem = mem->is_MergeMem() ? mem->as_MergeMem()->memory_at(alias_idx) : mem;
|
|
||||||
if (mem != in(MemNode::Memory)) {
|
|
||||||
set_req(MemNode::Memory, mem);
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------Value------------------------------------------
|
|
||||||
const Type *StrIntrinsicNode::Value( PhaseTransform *phase ) const {
|
|
||||||
if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP;
|
|
||||||
return bottom_type();
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
//------------------------------match_edge-------------------------------------
|
|
||||||
// Do not match memory edge
|
|
||||||
uint EncodeISOArrayNode::match_edge(uint idx) const {
|
|
||||||
return idx == 2 || idx == 3; // EncodeISOArray src (Binary dst len)
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------Ideal------------------------------------------
|
|
||||||
// Return a node which is more "ideal" than the current node. Strip out
|
|
||||||
// control copies
|
|
||||||
Node *EncodeISOArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|
||||||
return remove_dead_region(phase, can_reshape) ? this : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------Value------------------------------------------
|
|
||||||
const Type *EncodeISOArrayNode::Value(PhaseTransform *phase) const {
|
|
||||||
if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP;
|
|
||||||
return bottom_type();
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
MemBarNode::MemBarNode(Compile* C, int alias_idx, Node* precedent)
|
MemBarNode::MemBarNode(Compile* C, int alias_idx, Node* precedent)
|
||||||
: MultiNode(TypeFunc::Parms + (precedent == NULL? 0: 1)),
|
: MultiNode(TypeFunc::Parms + (precedent == NULL? 0: 1)),
|
||||||
|
@ -866,88 +866,6 @@ public:
|
|||||||
static bool step_through(Node** np, uint instance_id, PhaseTransform* phase);
|
static bool step_through(Node** np, uint instance_id, PhaseTransform* phase);
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------StrIntrinsic-------------------------------
|
|
||||||
// Base class for Ideal nodes used in String instrinsic code.
|
|
||||||
class StrIntrinsicNode: public Node {
|
|
||||||
public:
|
|
||||||
StrIntrinsicNode(Node* control, Node* char_array_mem,
|
|
||||||
Node* s1, Node* c1, Node* s2, Node* c2):
|
|
||||||
Node(control, char_array_mem, s1, c1, s2, c2) {
|
|
||||||
}
|
|
||||||
|
|
||||||
StrIntrinsicNode(Node* control, Node* char_array_mem,
|
|
||||||
Node* s1, Node* s2, Node* c):
|
|
||||||
Node(control, char_array_mem, s1, s2, c) {
|
|
||||||
}
|
|
||||||
|
|
||||||
StrIntrinsicNode(Node* control, Node* char_array_mem,
|
|
||||||
Node* s1, Node* s2):
|
|
||||||
Node(control, char_array_mem, s1, s2) {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool depends_only_on_test() const { return false; }
|
|
||||||
virtual const TypePtr* adr_type() const { return TypeAryPtr::CHARS; }
|
|
||||||
virtual uint match_edge(uint idx) const;
|
|
||||||
virtual uint ideal_reg() const { return Op_RegI; }
|
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
|
||||||
virtual const Type *Value(PhaseTransform *phase) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------StrComp-------------------------------------
|
|
||||||
class StrCompNode: public StrIntrinsicNode {
|
|
||||||
public:
|
|
||||||
StrCompNode(Node* control, Node* char_array_mem,
|
|
||||||
Node* s1, Node* c1, Node* s2, Node* c2):
|
|
||||||
StrIntrinsicNode(control, char_array_mem, s1, c1, s2, c2) {};
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type* bottom_type() const { return TypeInt::INT; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------StrEquals-------------------------------------
|
|
||||||
class StrEqualsNode: public StrIntrinsicNode {
|
|
||||||
public:
|
|
||||||
StrEqualsNode(Node* control, Node* char_array_mem,
|
|
||||||
Node* s1, Node* s2, Node* c):
|
|
||||||
StrIntrinsicNode(control, char_array_mem, s1, s2, c) {};
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type* bottom_type() const { return TypeInt::BOOL; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------StrIndexOf-------------------------------------
|
|
||||||
class StrIndexOfNode: public StrIntrinsicNode {
|
|
||||||
public:
|
|
||||||
StrIndexOfNode(Node* control, Node* char_array_mem,
|
|
||||||
Node* s1, Node* c1, Node* s2, Node* c2):
|
|
||||||
StrIntrinsicNode(control, char_array_mem, s1, c1, s2, c2) {};
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type* bottom_type() const { return TypeInt::INT; }
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------AryEq---------------------------------------
|
|
||||||
class AryEqNode: public StrIntrinsicNode {
|
|
||||||
public:
|
|
||||||
AryEqNode(Node* control, Node* char_array_mem, Node* s1, Node* s2):
|
|
||||||
StrIntrinsicNode(control, char_array_mem, s1, s2) {};
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual const Type* bottom_type() const { return TypeInt::BOOL; }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
//------------------------------EncodeISOArray--------------------------------
|
|
||||||
// encode char[] to byte[] in ISO_8859_1
|
|
||||||
class EncodeISOArrayNode: public Node {
|
|
||||||
public:
|
|
||||||
EncodeISOArrayNode(Node *control, Node* arymem, Node* s1, Node* s2, Node* c): Node(control, arymem, s1, s2, c) {};
|
|
||||||
virtual int Opcode() const;
|
|
||||||
virtual bool depends_only_on_test() const { return false; }
|
|
||||||
virtual const Type* bottom_type() const { return TypeInt::INT; }
|
|
||||||
virtual const TypePtr* adr_type() const { return TypePtr::BOTTOM; }
|
|
||||||
virtual uint match_edge(uint idx) const;
|
|
||||||
virtual uint ideal_reg() const { return Op_RegI; }
|
|
||||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
|
||||||
virtual const Type *Value(PhaseTransform *phase) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
//------------------------------MemBar-----------------------------------------
|
//------------------------------MemBar-----------------------------------------
|
||||||
// There are different flavors of Memory Barriers to match the Java Memory
|
// There are different flavors of Memory Barriers to match the Java Memory
|
||||||
// Model. Monitor-enter and volatile-load act as Aquires: no following ref
|
// Model. Monitor-enter and volatile-load act as Aquires: no following ref
|
||||||
|
398
hotspot/src/share/vm/opto/movenode.cpp
Normal file
398
hotspot/src/share/vm/opto/movenode.cpp
Normal file
@ -0,0 +1,398 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precompiled.hpp"
|
||||||
|
#include "opto/addnode.hpp"
|
||||||
|
#include "opto/connode.hpp"
|
||||||
|
#include "opto/convertnode.hpp"
|
||||||
|
#include "opto/movenode.hpp"
|
||||||
|
#include "opto/phaseX.hpp"
|
||||||
|
#include "opto/subnode.hpp"
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
/*
|
||||||
|
The major change is for CMoveP and StrComp. They have related but slightly
|
||||||
|
different problems. They both take in TWO oops which are both null-checked
|
||||||
|
independently before the using Node. After CCP removes the CastPP's they need
|
||||||
|
to pick up the guarding test edge - in this case TWO control edges. I tried
|
||||||
|
various solutions, all have problems:
|
||||||
|
|
||||||
|
(1) Do nothing. This leads to a bug where we hoist a Load from a CMoveP or a
|
||||||
|
StrComp above a guarding null check. I've seen both cases in normal -Xcomp
|
||||||
|
testing.
|
||||||
|
|
||||||
|
(2) Plug the control edge from 1 of the 2 oops in. Apparent problem here is
|
||||||
|
to figure out which test post-dominates. The real problem is that it doesn't
|
||||||
|
matter which one you pick. After you pick up, the dominating-test elider in
|
||||||
|
IGVN can remove the test and allow you to hoist up to the dominating test on
|
||||||
|
the chosen oop bypassing the test on the not-chosen oop. Seen in testing.
|
||||||
|
Oops.
|
||||||
|
|
||||||
|
(3) Leave the CastPP's in. This makes the graph more accurate in some sense;
|
||||||
|
we get to keep around the knowledge that an oop is not-null after some test.
|
||||||
|
Alas, the CastPP's interfere with GVN (some values are the regular oop, some
|
||||||
|
are the CastPP of the oop, all merge at Phi's which cannot collapse, etc).
|
||||||
|
This cost us 10% on SpecJVM, even when I removed some of the more trivial
|
||||||
|
cases in the optimizer. Removing more useless Phi's started allowing Loads to
|
||||||
|
illegally float above null checks. I gave up on this approach.
|
||||||
|
|
||||||
|
(4) Add BOTH control edges to both tests. Alas, too much code knows that
|
||||||
|
control edges are in slot-zero ONLY. Many quick asserts fail; no way to do
|
||||||
|
this one. Note that I really want to allow the CMoveP to float and add both
|
||||||
|
control edges to the dependent Load op - meaning I can select early but I
|
||||||
|
cannot Load until I pass both tests.
|
||||||
|
|
||||||
|
(5) Do not hoist CMoveP and StrComp. To this end I added the v-call
|
||||||
|
depends_only_on_test(). No obvious performance loss on Spec, but we are
|
||||||
|
clearly conservative on CMoveP (also so on StrComp but that's unlikely to
|
||||||
|
matter ever).
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
//------------------------------Ideal------------------------------------------
|
||||||
|
// Return a node which is more "ideal" than the current node.
|
||||||
|
// Move constants to the right.
|
||||||
|
Node *CMoveNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
if( in(0) && remove_dead_region(phase, can_reshape) ) return this;
|
||||||
|
// Don't bother trying to transform a dead node
|
||||||
|
if( in(0) && in(0)->is_top() ) return NULL;
|
||||||
|
assert( !phase->eqv(in(Condition), this) &&
|
||||||
|
!phase->eqv(in(IfFalse), this) &&
|
||||||
|
!phase->eqv(in(IfTrue), this), "dead loop in CMoveNode::Ideal" );
|
||||||
|
if( phase->type(in(Condition)) == Type::TOP )
|
||||||
|
return NULL; // return NULL when Condition is dead
|
||||||
|
|
||||||
|
if( in(IfFalse)->is_Con() && !in(IfTrue)->is_Con() ) {
|
||||||
|
if( in(Condition)->is_Bool() ) {
|
||||||
|
BoolNode* b = in(Condition)->as_Bool();
|
||||||
|
BoolNode* b2 = b->negate(phase);
|
||||||
|
return make( phase->C, in(Control), phase->transform(b2), in(IfTrue), in(IfFalse), _type );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------is_cmove_id------------------------------------
|
||||||
|
// Helper function to check for CMOVE identity. Shared with PhiNode::Identity
|
||||||
|
Node *CMoveNode::is_cmove_id( PhaseTransform *phase, Node *cmp, Node *t, Node *f, BoolNode *b ) {
|
||||||
|
// Check for Cmp'ing and CMove'ing same values
|
||||||
|
if( (phase->eqv(cmp->in(1),f) &&
|
||||||
|
phase->eqv(cmp->in(2),t)) ||
|
||||||
|
// Swapped Cmp is OK
|
||||||
|
(phase->eqv(cmp->in(2),f) &&
|
||||||
|
phase->eqv(cmp->in(1),t)) ) {
|
||||||
|
// Give up this identity check for floating points because it may choose incorrect
|
||||||
|
// value around 0.0 and -0.0
|
||||||
|
if ( cmp->Opcode()==Op_CmpF || cmp->Opcode()==Op_CmpD )
|
||||||
|
return NULL;
|
||||||
|
// Check for "(t==f)?t:f;" and replace with "f"
|
||||||
|
if( b->_test._test == BoolTest::eq )
|
||||||
|
return f;
|
||||||
|
// Allow the inverted case as well
|
||||||
|
// Check for "(t!=f)?t:f;" and replace with "t"
|
||||||
|
if( b->_test._test == BoolTest::ne )
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Identity---------------------------------------
|
||||||
|
// Conditional-move is an identity if both inputs are the same, or the test
|
||||||
|
// true or false.
|
||||||
|
Node *CMoveNode::Identity( PhaseTransform *phase ) {
|
||||||
|
if( phase->eqv(in(IfFalse),in(IfTrue)) ) // C-moving identical inputs?
|
||||||
|
return in(IfFalse); // Then it doesn't matter
|
||||||
|
if( phase->type(in(Condition)) == TypeInt::ZERO )
|
||||||
|
return in(IfFalse); // Always pick left(false) input
|
||||||
|
if( phase->type(in(Condition)) == TypeInt::ONE )
|
||||||
|
return in(IfTrue); // Always pick right(true) input
|
||||||
|
|
||||||
|
// Check for CMove'ing a constant after comparing against the constant.
|
||||||
|
// Happens all the time now, since if we compare equality vs a constant in
|
||||||
|
// the parser, we "know" the variable is constant on one path and we force
|
||||||
|
// it. Thus code like "if( x==0 ) {/*EMPTY*/}" ends up inserting a
|
||||||
|
// conditional move: "x = (x==0)?0:x;". Yucko. This fix is slightly more
|
||||||
|
// general in that we don't need constants.
|
||||||
|
if( in(Condition)->is_Bool() ) {
|
||||||
|
BoolNode *b = in(Condition)->as_Bool();
|
||||||
|
Node *cmp = b->in(1);
|
||||||
|
if( cmp->is_Cmp() ) {
|
||||||
|
Node *id = is_cmove_id( phase, cmp, in(IfTrue), in(IfFalse), b );
|
||||||
|
if( id ) return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
// Result is the meet of inputs
|
||||||
|
const Type *CMoveNode::Value( PhaseTransform *phase ) const {
|
||||||
|
if( phase->type(in(Condition)) == Type::TOP )
|
||||||
|
return Type::TOP;
|
||||||
|
return phase->type(in(IfFalse))->meet_speculative(phase->type(in(IfTrue)));
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------make-------------------------------------------
|
||||||
|
// Make a correctly-flavored CMove. Since _type is directly determined
|
||||||
|
// from the inputs we do not need to specify it here.
|
||||||
|
CMoveNode *CMoveNode::make( Compile *C, Node *c, Node *bol, Node *left, Node *right, const Type *t ) {
|
||||||
|
switch( t->basic_type() ) {
|
||||||
|
case T_INT: return new (C) CMoveINode( bol, left, right, t->is_int() );
|
||||||
|
case T_FLOAT: return new (C) CMoveFNode( bol, left, right, t );
|
||||||
|
case T_DOUBLE: return new (C) CMoveDNode( bol, left, right, t );
|
||||||
|
case T_LONG: return new (C) CMoveLNode( bol, left, right, t->is_long() );
|
||||||
|
case T_OBJECT: return new (C) CMovePNode( c, bol, left, right, t->is_oopptr() );
|
||||||
|
case T_ADDRESS: return new (C) CMovePNode( c, bol, left, right, t->is_ptr() );
|
||||||
|
case T_NARROWOOP: return new (C) CMoveNNode( c, bol, left, right, t );
|
||||||
|
default:
|
||||||
|
ShouldNotReachHere();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Ideal------------------------------------------
|
||||||
|
// Return a node which is more "ideal" than the current node.
|
||||||
|
// Check for conversions to boolean
|
||||||
|
Node *CMoveINode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
// Try generic ideal's first
|
||||||
|
Node *x = CMoveNode::Ideal(phase, can_reshape);
|
||||||
|
if( x ) return x;
|
||||||
|
|
||||||
|
// If zero is on the left (false-case, no-move-case) it must mean another
|
||||||
|
// constant is on the right (otherwise the shared CMove::Ideal code would
|
||||||
|
// have moved the constant to the right). This situation is bad for Intel
|
||||||
|
// and a don't-care for Sparc. It's bad for Intel because the zero has to
|
||||||
|
// be manifested in a register with a XOR which kills flags, which are live
|
||||||
|
// on input to the CMoveI, leading to a situation which causes excessive
|
||||||
|
// spilling on Intel. For Sparc, if the zero in on the left the Sparc will
|
||||||
|
// zero a register via G0 and conditionally-move the other constant. If the
|
||||||
|
// zero is on the right, the Sparc will load the first constant with a
|
||||||
|
// 13-bit set-lo and conditionally move G0. See bug 4677505.
|
||||||
|
if( phase->type(in(IfFalse)) == TypeInt::ZERO && !(phase->type(in(IfTrue)) == TypeInt::ZERO) ) {
|
||||||
|
if( in(Condition)->is_Bool() ) {
|
||||||
|
BoolNode* b = in(Condition)->as_Bool();
|
||||||
|
BoolNode* b2 = b->negate(phase);
|
||||||
|
return make( phase->C, in(Control), phase->transform(b2), in(IfTrue), in(IfFalse), _type );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now check for booleans
|
||||||
|
int flip = 0;
|
||||||
|
|
||||||
|
// Check for picking from zero/one
|
||||||
|
if( phase->type(in(IfFalse)) == TypeInt::ZERO && phase->type(in(IfTrue)) == TypeInt::ONE ) {
|
||||||
|
flip = 1 - flip;
|
||||||
|
} else if( phase->type(in(IfFalse)) == TypeInt::ONE && phase->type(in(IfTrue)) == TypeInt::ZERO ) {
|
||||||
|
} else return NULL;
|
||||||
|
|
||||||
|
// Check for eq/ne test
|
||||||
|
if( !in(1)->is_Bool() ) return NULL;
|
||||||
|
BoolNode *bol = in(1)->as_Bool();
|
||||||
|
if( bol->_test._test == BoolTest::eq ) {
|
||||||
|
} else if( bol->_test._test == BoolTest::ne ) {
|
||||||
|
flip = 1-flip;
|
||||||
|
} else return NULL;
|
||||||
|
|
||||||
|
// Check for vs 0 or 1
|
||||||
|
if( !bol->in(1)->is_Cmp() ) return NULL;
|
||||||
|
const CmpNode *cmp = bol->in(1)->as_Cmp();
|
||||||
|
if( phase->type(cmp->in(2)) == TypeInt::ZERO ) {
|
||||||
|
} else if( phase->type(cmp->in(2)) == TypeInt::ONE ) {
|
||||||
|
// Allow cmp-vs-1 if the other input is bounded by 0-1
|
||||||
|
if( phase->type(cmp->in(1)) != TypeInt::BOOL )
|
||||||
|
return NULL;
|
||||||
|
flip = 1 - flip;
|
||||||
|
} else return NULL;
|
||||||
|
|
||||||
|
// Convert to a bool (flipped)
|
||||||
|
// Build int->bool conversion
|
||||||
|
#ifndef PRODUCT
|
||||||
|
if( PrintOpto ) tty->print_cr("CMOV to I2B");
|
||||||
|
#endif
|
||||||
|
Node *n = new (phase->C) Conv2BNode( cmp->in(1) );
|
||||||
|
if( flip )
|
||||||
|
n = new (phase->C) XorINode( phase->transform(n), phase->intcon(1) );
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Ideal------------------------------------------
|
||||||
|
// Return a node which is more "ideal" than the current node.
|
||||||
|
// Check for absolute value
|
||||||
|
Node *CMoveFNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
// Try generic ideal's first
|
||||||
|
Node *x = CMoveNode::Ideal(phase, can_reshape);
|
||||||
|
if( x ) return x;
|
||||||
|
|
||||||
|
int cmp_zero_idx = 0; // Index of compare input where to look for zero
|
||||||
|
int phi_x_idx = 0; // Index of phi input where to find naked x
|
||||||
|
|
||||||
|
// Find the Bool
|
||||||
|
if( !in(1)->is_Bool() ) return NULL;
|
||||||
|
BoolNode *bol = in(1)->as_Bool();
|
||||||
|
// Check bool sense
|
||||||
|
switch( bol->_test._test ) {
|
||||||
|
case BoolTest::lt: cmp_zero_idx = 1; phi_x_idx = IfTrue; break;
|
||||||
|
case BoolTest::le: cmp_zero_idx = 2; phi_x_idx = IfFalse; break;
|
||||||
|
case BoolTest::gt: cmp_zero_idx = 2; phi_x_idx = IfTrue; break;
|
||||||
|
case BoolTest::ge: cmp_zero_idx = 1; phi_x_idx = IfFalse; break;
|
||||||
|
default: return NULL; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find zero input of CmpF; the other input is being abs'd
|
||||||
|
Node *cmpf = bol->in(1);
|
||||||
|
if( cmpf->Opcode() != Op_CmpF ) return NULL;
|
||||||
|
Node *X = NULL;
|
||||||
|
bool flip = false;
|
||||||
|
if( phase->type(cmpf->in(cmp_zero_idx)) == TypeF::ZERO ) {
|
||||||
|
X = cmpf->in(3 - cmp_zero_idx);
|
||||||
|
} else if (phase->type(cmpf->in(3 - cmp_zero_idx)) == TypeF::ZERO) {
|
||||||
|
// The test is inverted, we should invert the result...
|
||||||
|
X = cmpf->in(cmp_zero_idx);
|
||||||
|
flip = true;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If X is found on the appropriate phi input, find the subtract on the other
|
||||||
|
if( X != in(phi_x_idx) ) return NULL;
|
||||||
|
int phi_sub_idx = phi_x_idx == IfTrue ? IfFalse : IfTrue;
|
||||||
|
Node *sub = in(phi_sub_idx);
|
||||||
|
|
||||||
|
// Allow only SubF(0,X) and fail out for all others; NegF is not OK
|
||||||
|
if( sub->Opcode() != Op_SubF ||
|
||||||
|
sub->in(2) != X ||
|
||||||
|
phase->type(sub->in(1)) != TypeF::ZERO ) return NULL;
|
||||||
|
|
||||||
|
Node *abs = new (phase->C) AbsFNode( X );
|
||||||
|
if( flip )
|
||||||
|
abs = new (phase->C) SubFNode(sub->in(1), phase->transform(abs));
|
||||||
|
|
||||||
|
return abs;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
//------------------------------Ideal------------------------------------------
|
||||||
|
// Return a node which is more "ideal" than the current node.
|
||||||
|
// Check for absolute value
|
||||||
|
Node *CMoveDNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||||
|
// Try generic ideal's first
|
||||||
|
Node *x = CMoveNode::Ideal(phase, can_reshape);
|
||||||
|
if( x ) return x;
|
||||||
|
|
||||||
|
int cmp_zero_idx = 0; // Index of compare input where to look for zero
|
||||||
|
int phi_x_idx = 0; // Index of phi input where to find naked x
|
||||||
|
|
||||||
|
// Find the Bool
|
||||||
|
if( !in(1)->is_Bool() ) return NULL;
|
||||||
|
BoolNode *bol = in(1)->as_Bool();
|
||||||
|
// Check bool sense
|
||||||
|
switch( bol->_test._test ) {
|
||||||
|
case BoolTest::lt: cmp_zero_idx = 1; phi_x_idx = IfTrue; break;
|
||||||
|
case BoolTest::le: cmp_zero_idx = 2; phi_x_idx = IfFalse; break;
|
||||||
|
case BoolTest::gt: cmp_zero_idx = 2; phi_x_idx = IfTrue; break;
|
||||||
|
case BoolTest::ge: cmp_zero_idx = 1; phi_x_idx = IfFalse; break;
|
||||||
|
default: return NULL; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find zero input of CmpD; the other input is being abs'd
|
||||||
|
Node *cmpd = bol->in(1);
|
||||||
|
if( cmpd->Opcode() != Op_CmpD ) return NULL;
|
||||||
|
Node *X = NULL;
|
||||||
|
bool flip = false;
|
||||||
|
if( phase->type(cmpd->in(cmp_zero_idx)) == TypeD::ZERO ) {
|
||||||
|
X = cmpd->in(3 - cmp_zero_idx);
|
||||||
|
} else if (phase->type(cmpd->in(3 - cmp_zero_idx)) == TypeD::ZERO) {
|
||||||
|
// The test is inverted, we should invert the result...
|
||||||
|
X = cmpd->in(cmp_zero_idx);
|
||||||
|
flip = true;
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If X is found on the appropriate phi input, find the subtract on the other
|
||||||
|
if( X != in(phi_x_idx) ) return NULL;
|
||||||
|
int phi_sub_idx = phi_x_idx == IfTrue ? IfFalse : IfTrue;
|
||||||
|
Node *sub = in(phi_sub_idx);
|
||||||
|
|
||||||
|
// Allow only SubD(0,X) and fail out for all others; NegD is not OK
|
||||||
|
if( sub->Opcode() != Op_SubD ||
|
||||||
|
sub->in(2) != X ||
|
||||||
|
phase->type(sub->in(1)) != TypeD::ZERO ) return NULL;
|
||||||
|
|
||||||
|
Node *abs = new (phase->C) AbsDNode( X );
|
||||||
|
if( flip )
|
||||||
|
abs = new (phase->C) SubDNode(sub->in(1), phase->transform(abs));
|
||||||
|
|
||||||
|
return abs;
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *MoveL2DNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
const TypeLong *tl = t->is_long();
|
||||||
|
if( !tl->is_con() ) return bottom_type();
|
||||||
|
JavaValue v;
|
||||||
|
v.set_jlong(tl->get_con());
|
||||||
|
return TypeD::make( v.get_jdouble() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *MoveI2FNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
const TypeInt *ti = t->is_int();
|
||||||
|
if( !ti->is_con() ) return bottom_type();
|
||||||
|
JavaValue v;
|
||||||
|
v.set_jint(ti->get_con());
|
||||||
|
return TypeF::make( v.get_jfloat() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *MoveF2INode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
if( t == Type::FLOAT ) return TypeInt::INT;
|
||||||
|
const TypeF *tf = t->is_float_constant();
|
||||||
|
JavaValue v;
|
||||||
|
v.set_jfloat(tf->getf());
|
||||||
|
return TypeInt::make( v.get_jint() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Value------------------------------------------
|
||||||
|
const Type *MoveD2LNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return Type::TOP;
|
||||||
|
if( t == Type::DOUBLE ) return TypeLong::LONG;
|
||||||
|
const TypeD *td = t->is_double_constant();
|
||||||
|
JavaValue v;
|
||||||
|
v.set_jdouble(td->getd());
|
||||||
|
return TypeLong::make( v.get_jlong() );
|
||||||
|
}
|
||||||
|
|
152
hotspot/src/share/vm/opto/movenode.hpp
Normal file
152
hotspot/src/share/vm/opto/movenode.hpp
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHARE_VM_OPTO_MOVENODE_HPP
|
||||||
|
#define SHARE_VM_OPTO_MOVENODE_HPP
|
||||||
|
|
||||||
|
#include "opto/node.hpp"
|
||||||
|
|
||||||
|
//------------------------------CMoveNode--------------------------------------
|
||||||
|
// Conditional move
|
||||||
|
class CMoveNode : public TypeNode {
|
||||||
|
public:
|
||||||
|
enum { Control, // When is it safe to do this cmove?
|
||||||
|
Condition, // Condition controlling the cmove
|
||||||
|
IfFalse, // Value if condition is false
|
||||||
|
IfTrue }; // Value if condition is true
|
||||||
|
CMoveNode( Node *bol, Node *left, Node *right, const Type *t ) : TypeNode(t,4)
|
||||||
|
{
|
||||||
|
init_class_id(Class_CMove);
|
||||||
|
// all inputs are nullified in Node::Node(int)
|
||||||
|
// init_req(Control,NULL);
|
||||||
|
init_req(Condition,bol);
|
||||||
|
init_req(IfFalse,left);
|
||||||
|
init_req(IfTrue,right);
|
||||||
|
}
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
static CMoveNode *make( Compile *C, Node *c, Node *bol, Node *left, Node *right, const Type *t );
|
||||||
|
// Helper function to spot cmove graph shapes
|
||||||
|
static Node *is_cmove_id( PhaseTransform *phase, Node *cmp, Node *t, Node *f, BoolNode *b );
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------CMoveDNode-------------------------------------
|
||||||
|
class CMoveDNode : public CMoveNode {
|
||||||
|
public:
|
||||||
|
CMoveDNode( Node *bol, Node *left, Node *right, const Type* t) : CMoveNode(bol,left,right,t){}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------CMoveFNode-------------------------------------
|
||||||
|
class CMoveFNode : public CMoveNode {
|
||||||
|
public:
|
||||||
|
CMoveFNode( Node *bol, Node *left, Node *right, const Type* t ) : CMoveNode(bol,left,right,t) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------CMoveINode-------------------------------------
|
||||||
|
class CMoveINode : public CMoveNode {
|
||||||
|
public:
|
||||||
|
CMoveINode( Node *bol, Node *left, Node *right, const TypeInt *ti ) : CMoveNode(bol,left,right,ti){}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------CMoveLNode-------------------------------------
|
||||||
|
class CMoveLNode : public CMoveNode {
|
||||||
|
public:
|
||||||
|
CMoveLNode(Node *bol, Node *left, Node *right, const TypeLong *tl ) : CMoveNode(bol,left,right,tl){}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------CMovePNode-------------------------------------
|
||||||
|
class CMovePNode : public CMoveNode {
|
||||||
|
public:
|
||||||
|
CMovePNode( Node *c, Node *bol, Node *left, Node *right, const TypePtr* t ) : CMoveNode(bol,left,right,t) { init_req(Control,c); }
|
||||||
|
virtual int Opcode() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------CMoveNNode-------------------------------------
|
||||||
|
class CMoveNNode : public CMoveNode {
|
||||||
|
public:
|
||||||
|
CMoveNNode( Node *c, Node *bol, Node *left, Node *right, const Type* t ) : CMoveNode(bol,left,right,t) { init_req(Control,c); }
|
||||||
|
virtual int Opcode() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
class MoveI2FNode : public Node {
|
||||||
|
public:
|
||||||
|
MoveI2FNode( Node *value ) : Node(0,value) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return Type::FLOAT; }
|
||||||
|
virtual uint ideal_reg() const { return Op_RegF; }
|
||||||
|
virtual const Type* Value( PhaseTransform *phase ) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MoveL2DNode : public Node {
|
||||||
|
public:
|
||||||
|
MoveL2DNode( Node *value ) : Node(0,value) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return Type::DOUBLE; }
|
||||||
|
virtual uint ideal_reg() const { return Op_RegD; }
|
||||||
|
virtual const Type* Value( PhaseTransform *phase ) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MoveF2INode : public Node {
|
||||||
|
public:
|
||||||
|
MoveF2INode( Node *value ) : Node(0,value) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
||||||
|
virtual uint ideal_reg() const { return Op_RegI; }
|
||||||
|
virtual const Type* Value( PhaseTransform *phase ) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MoveD2LNode : public Node {
|
||||||
|
public:
|
||||||
|
MoveD2LNode( Node *value ) : Node(0,value) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return TypeLong::LONG; }
|
||||||
|
virtual uint ideal_reg() const { return Op_RegL; }
|
||||||
|
virtual const Type* Value( PhaseTransform *phase ) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------BinaryNode-------------------------------------
|
||||||
|
// Place holder for the 2 conditional inputs to a CMove. CMove needs 4
|
||||||
|
// inputs: the Bool (for the lt/gt/eq/ne bits), the flags (result of some
|
||||||
|
// compare), and the 2 values to select between. The Matcher requires a
|
||||||
|
// binary tree so we break it down like this:
|
||||||
|
// (CMove (Binary bol cmp) (Binary src1 src2))
|
||||||
|
class BinaryNode : public Node {
|
||||||
|
public:
|
||||||
|
BinaryNode( Node *n1, Node *n2 ) : Node(0,n1,n2) { }
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual uint ideal_reg() const { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // SHARE_VM_OPTO_MOVENODE_HPP
|
||||||
|
|
@ -26,6 +26,7 @@
|
|||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
#include "opto/connode.hpp"
|
#include "opto/connode.hpp"
|
||||||
|
#include "opto/convertnode.hpp"
|
||||||
#include "opto/memnode.hpp"
|
#include "opto/memnode.hpp"
|
||||||
#include "opto/mulnode.hpp"
|
#include "opto/mulnode.hpp"
|
||||||
#include "opto/phaseX.hpp"
|
#include "opto/phaseX.hpp"
|
||||||
|
113
hotspot/src/share/vm/opto/narrowptrnode.cpp
Normal file
113
hotspot/src/share/vm/opto/narrowptrnode.cpp
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precompiled.hpp"
|
||||||
|
#include "opto/narrowptrnode.hpp"
|
||||||
|
#include "opto/phaseX.hpp"
|
||||||
|
|
||||||
|
Node* DecodeNNode::Identity(PhaseTransform* phase) {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return in(1);
|
||||||
|
|
||||||
|
if (in(1)->is_EncodeP()) {
|
||||||
|
// (DecodeN (EncodeP p)) -> p
|
||||||
|
return in(1)->in(1);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type *DecodeNNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if (t == Type::TOP) return Type::TOP;
|
||||||
|
if (t == TypeNarrowOop::NULL_PTR) return TypePtr::NULL_PTR;
|
||||||
|
|
||||||
|
assert(t->isa_narrowoop(), "only narrowoop here");
|
||||||
|
return t->make_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* EncodePNode::Identity(PhaseTransform* phase) {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return in(1);
|
||||||
|
|
||||||
|
if (in(1)->is_DecodeN()) {
|
||||||
|
// (EncodeP (DecodeN p)) -> p
|
||||||
|
return in(1)->in(1);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type *EncodePNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if (t == Type::TOP) return Type::TOP;
|
||||||
|
if (t == TypePtr::NULL_PTR) return TypeNarrowOop::NULL_PTR;
|
||||||
|
|
||||||
|
assert(t->isa_oop_ptr(), "only oopptr here");
|
||||||
|
return t->make_narrowoop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Node *EncodeNarrowPtrNode::Ideal_DU_postCCP( PhaseCCP *ccp ) {
|
||||||
|
return MemNode::Ideal_common_DU_postCCP(ccp, this, in(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* DecodeNKlassNode::Identity(PhaseTransform* phase) {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return in(1);
|
||||||
|
|
||||||
|
if (in(1)->is_EncodePKlass()) {
|
||||||
|
// (DecodeNKlass (EncodePKlass p)) -> p
|
||||||
|
return in(1)->in(1);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type *DecodeNKlassNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if (t == Type::TOP) return Type::TOP;
|
||||||
|
assert(t != TypeNarrowKlass::NULL_PTR, "null klass?");
|
||||||
|
|
||||||
|
assert(t->isa_narrowklass(), "only narrow klass ptr here");
|
||||||
|
return t->make_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* EncodePKlassNode::Identity(PhaseTransform* phase) {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if( t == Type::TOP ) return in(1);
|
||||||
|
|
||||||
|
if (in(1)->is_DecodeNKlass()) {
|
||||||
|
// (EncodePKlass (DecodeNKlass p)) -> p
|
||||||
|
return in(1)->in(1);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type *EncodePKlassNode::Value( PhaseTransform *phase ) const {
|
||||||
|
const Type *t = phase->type( in(1) );
|
||||||
|
if (t == Type::TOP) return Type::TOP;
|
||||||
|
assert (t != TypePtr::NULL_PTR, "null klass?");
|
||||||
|
|
||||||
|
assert(UseCompressedClassPointers && t->isa_klassptr(), "only klass ptr here");
|
||||||
|
return t->make_narrowklass();
|
||||||
|
}
|
||||||
|
|
119
hotspot/src/share/vm/opto/narrowptrnode.hpp
Normal file
119
hotspot/src/share/vm/opto/narrowptrnode.hpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHARE_VM_OPTO_NARROWPTRNODE_HPP
|
||||||
|
#define SHARE_VM_OPTO_NARROWPTRNODE_HPP
|
||||||
|
|
||||||
|
#include "opto/node.hpp"
|
||||||
|
#include "opto/opcodes.hpp"
|
||||||
|
|
||||||
|
//------------------------------EncodeNarrowPtr--------------------------------
|
||||||
|
class EncodeNarrowPtrNode : public TypeNode {
|
||||||
|
protected:
|
||||||
|
EncodeNarrowPtrNode(Node* value, const Type* type):
|
||||||
|
TypeNode(type, 2) {
|
||||||
|
init_class_id(Class_EncodeNarrowPtr);
|
||||||
|
init_req(0, NULL);
|
||||||
|
init_req(1, value);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
virtual uint ideal_reg() const { return Op_RegN; }
|
||||||
|
virtual Node *Ideal_DU_postCCP( PhaseCCP *ccp );
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------EncodeP--------------------------------
|
||||||
|
// Encodes an oop pointers into its compressed form
|
||||||
|
// Takes an extra argument which is the real heap base as a long which
|
||||||
|
// may be useful for code generation in the backend.
|
||||||
|
class EncodePNode : public EncodeNarrowPtrNode {
|
||||||
|
public:
|
||||||
|
EncodePNode(Node* value, const Type* type):
|
||||||
|
EncodeNarrowPtrNode(value, type) {
|
||||||
|
init_class_id(Class_EncodeP);
|
||||||
|
}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------EncodePKlass--------------------------------
|
||||||
|
// Encodes a klass pointer into its compressed form
|
||||||
|
// Takes an extra argument which is the real heap base as a long which
|
||||||
|
// may be useful for code generation in the backend.
|
||||||
|
class EncodePKlassNode : public EncodeNarrowPtrNode {
|
||||||
|
public:
|
||||||
|
EncodePKlassNode(Node* value, const Type* type):
|
||||||
|
EncodeNarrowPtrNode(value, type) {
|
||||||
|
init_class_id(Class_EncodePKlass);
|
||||||
|
}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------DecodeNarrowPtr--------------------------------
|
||||||
|
class DecodeNarrowPtrNode : public TypeNode {
|
||||||
|
protected:
|
||||||
|
DecodeNarrowPtrNode(Node* value, const Type* type):
|
||||||
|
TypeNode(type, 2) {
|
||||||
|
init_class_id(Class_DecodeNarrowPtr);
|
||||||
|
init_req(0, NULL);
|
||||||
|
init_req(1, value);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
virtual uint ideal_reg() const { return Op_RegP; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------DecodeN--------------------------------
|
||||||
|
// Converts a narrow oop into a real oop ptr.
|
||||||
|
// Takes an extra argument which is the real heap base as a long which
|
||||||
|
// may be useful for code generation in the backend.
|
||||||
|
class DecodeNNode : public DecodeNarrowPtrNode {
|
||||||
|
public:
|
||||||
|
DecodeNNode(Node* value, const Type* type):
|
||||||
|
DecodeNarrowPtrNode(value, type) {
|
||||||
|
init_class_id(Class_DecodeN);
|
||||||
|
}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------DecodeNKlass--------------------------------
|
||||||
|
// Converts a narrow klass pointer into a real klass ptr.
|
||||||
|
// Takes an extra argument which is the real heap base as a long which
|
||||||
|
// may be useful for code generation in the backend.
|
||||||
|
class DecodeNKlassNode : public DecodeNarrowPtrNode {
|
||||||
|
public:
|
||||||
|
DecodeNKlassNode(Node* value, const Type* type):
|
||||||
|
DecodeNarrowPtrNode(value, type) {
|
||||||
|
init_class_id(Class_DecodeNKlass);
|
||||||
|
}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *Value( PhaseTransform *phase ) const;
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SHARE_VM_OPTO_NARROWPTRNODE_HPP
|
||||||
|
|
63
hotspot/src/share/vm/opto/opaquenode.cpp
Normal file
63
hotspot/src/share/vm/opto/opaquenode.cpp
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precompiled.hpp"
|
||||||
|
#include "opto/opaquenode.hpp"
|
||||||
|
#include "opto/phaseX.hpp"
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// Do not allow value-numbering
|
||||||
|
uint Opaque1Node::hash() const { return NO_HASH; }
|
||||||
|
uint Opaque1Node::cmp( const Node &n ) const {
|
||||||
|
return (&n == this); // Always fail except on self
|
||||||
|
}
|
||||||
|
|
||||||
|
//------------------------------Identity---------------------------------------
|
||||||
|
// If _major_progress, then more loop optimizations follow. Do NOT remove
|
||||||
|
// the opaque Node until no more loop ops can happen. Note the timing of
|
||||||
|
// _major_progress; it's set in the major loop optimizations THEN comes the
|
||||||
|
// call to IterGVN and any chance of hitting this code. Hence there's no
|
||||||
|
// phase-ordering problem with stripping Opaque1 in IGVN followed by some
|
||||||
|
// more loop optimizations that require it.
|
||||||
|
Node *Opaque1Node::Identity( PhaseTransform *phase ) {
|
||||||
|
return phase->C->major_progress() ? this : in(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// A node to prevent unwanted optimizations. Allows constant folding. Stops
|
||||||
|
// value-numbering, most Ideal calls or Identity functions. This Node is
|
||||||
|
// specifically designed to prevent the pre-increment value of a loop trip
|
||||||
|
// counter from being live out of the bottom of the loop (hence causing the
|
||||||
|
// pre- and post-increment values both being live and thus requiring an extra
|
||||||
|
// temp register and an extra move). If we "accidentally" optimize through
|
||||||
|
// this kind of a Node, we'll get slightly pessimal, but correct, code. Thus
|
||||||
|
// it's OK to be slightly sloppy on optimizations here.
|
||||||
|
|
||||||
|
// Do not allow value-numbering
|
||||||
|
uint Opaque2Node::hash() const { return NO_HASH; }
|
||||||
|
uint Opaque2Node::cmp( const Node &n ) const {
|
||||||
|
return (&n == this); // Always fail except on self
|
||||||
|
}
|
||||||
|
|
||||||
|
|
91
hotspot/src/share/vm/opto/opaquenode.hpp
Normal file
91
hotspot/src/share/vm/opto/opaquenode.hpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHARE_VM_OPTO_OPAQUENODE_HPP
|
||||||
|
#define SHARE_VM_OPTO_OPAQUENODE_HPP
|
||||||
|
|
||||||
|
#include "opto/node.hpp"
|
||||||
|
#include "opto/opcodes.hpp"
|
||||||
|
|
||||||
|
//------------------------------Opaque1Node------------------------------------
|
||||||
|
// A node to prevent unwanted optimizations. Allows constant folding.
|
||||||
|
// Stops value-numbering, Ideal calls or Identity functions.
|
||||||
|
class Opaque1Node : public Node {
|
||||||
|
virtual uint hash() const ; // { return NO_HASH; }
|
||||||
|
virtual uint cmp( const Node &n ) const;
|
||||||
|
public:
|
||||||
|
Opaque1Node( Compile* C, Node *n ) : Node(0,n) {
|
||||||
|
// Put it on the Macro nodes list to removed during macro nodes expansion.
|
||||||
|
init_flags(Flag_is_macro);
|
||||||
|
C->add_macro_node(this);
|
||||||
|
}
|
||||||
|
// Special version for the pre-loop to hold the original loop limit
|
||||||
|
// which is consumed by range check elimination.
|
||||||
|
Opaque1Node( Compile* C, Node *n, Node* orig_limit ) : Node(0,n,orig_limit) {
|
||||||
|
// Put it on the Macro nodes list to removed during macro nodes expansion.
|
||||||
|
init_flags(Flag_is_macro);
|
||||||
|
C->add_macro_node(this);
|
||||||
|
}
|
||||||
|
Node* original_loop_limit() { return req()==3 ? in(2) : NULL; }
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
||||||
|
virtual Node *Identity( PhaseTransform *phase );
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------Opaque2Node------------------------------------
|
||||||
|
// A node to prevent unwanted optimizations. Allows constant folding. Stops
|
||||||
|
// value-numbering, most Ideal calls or Identity functions. This Node is
|
||||||
|
// specifically designed to prevent the pre-increment value of a loop trip
|
||||||
|
// counter from being live out of the bottom of the loop (hence causing the
|
||||||
|
// pre- and post-increment values both being live and thus requiring an extra
|
||||||
|
// temp register and an extra move). If we "accidentally" optimize through
|
||||||
|
// this kind of a Node, we'll get slightly pessimal, but correct, code. Thus
|
||||||
|
// it's OK to be slightly sloppy on optimizations here.
|
||||||
|
class Opaque2Node : public Node {
|
||||||
|
virtual uint hash() const ; // { return NO_HASH; }
|
||||||
|
virtual uint cmp( const Node &n ) const;
|
||||||
|
public:
|
||||||
|
Opaque2Node( Compile* C, Node *n ) : Node(0,n) {
|
||||||
|
// Put it on the Macro nodes list to removed during macro nodes expansion.
|
||||||
|
init_flags(Flag_is_macro);
|
||||||
|
C->add_macro_node(this);
|
||||||
|
}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
virtual const Type *bottom_type() const { return TypeInt::INT; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//------------------------------Opaque3Node------------------------------------
|
||||||
|
// A node to prevent unwanted optimizations. Will be optimized only during
|
||||||
|
// macro nodes expansion.
|
||||||
|
class Opaque3Node : public Opaque2Node {
|
||||||
|
int _opt; // what optimization it was used for
|
||||||
|
public:
|
||||||
|
enum { RTM_OPT };
|
||||||
|
Opaque3Node(Compile* C, Node *n, int opt) : Opaque2Node(C, n), _opt(opt) {}
|
||||||
|
virtual int Opcode() const;
|
||||||
|
bool rtm_opt() const { return (_opt == RTM_OPT); }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SHARE_VM_OPTO_OPAQUENODE_HPP
|
||||||
|
|
@ -27,9 +27,11 @@
|
|||||||
#include "interpreter/linkResolver.hpp"
|
#include "interpreter/linkResolver.hpp"
|
||||||
#include "oops/method.hpp"
|
#include "oops/method.hpp"
|
||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
|
#include "opto/castnode.hpp"
|
||||||
#include "opto/idealGraphPrinter.hpp"
|
#include "opto/idealGraphPrinter.hpp"
|
||||||
#include "opto/locknode.hpp"
|
#include "opto/locknode.hpp"
|
||||||
#include "opto/memnode.hpp"
|
#include "opto/memnode.hpp"
|
||||||
|
#include "opto/opaquenode.hpp"
|
||||||
#include "opto/parse.hpp"
|
#include "opto/parse.hpp"
|
||||||
#include "opto/rootnode.hpp"
|
#include "opto/rootnode.hpp"
|
||||||
#include "opto/runtime.hpp"
|
#include "opto/runtime.hpp"
|
||||||
|
@ -30,6 +30,8 @@
|
|||||||
#include "interpreter/linkResolver.hpp"
|
#include "interpreter/linkResolver.hpp"
|
||||||
#include "memory/universe.inline.hpp"
|
#include "memory/universe.inline.hpp"
|
||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
|
#include "opto/castnode.hpp"
|
||||||
|
#include "opto/convertnode.hpp"
|
||||||
#include "opto/divnode.hpp"
|
#include "opto/divnode.hpp"
|
||||||
#include "opto/idealGraphPrinter.hpp"
|
#include "opto/idealGraphPrinter.hpp"
|
||||||
#include "opto/matcher.hpp"
|
#include "opto/matcher.hpp"
|
||||||
@ -1288,7 +1290,7 @@ void Parse::sharpen_type_after_if(BoolTest::mask btest,
|
|||||||
(jvms->is_loc(obj_in_map) || jvms->is_stk(obj_in_map))) {
|
(jvms->is_loc(obj_in_map) || jvms->is_stk(obj_in_map))) {
|
||||||
TypeNode* ccast = new (C) CheckCastPPNode(control(), obj, tboth);
|
TypeNode* ccast = new (C) CheckCastPPNode(control(), obj, tboth);
|
||||||
const Type* tcc = ccast->as_Type()->type();
|
const Type* tcc = ccast->as_Type()->type();
|
||||||
assert(tcc != obj_type && tcc->higher_equal_speculative(obj_type), "must improve");
|
assert(tcc != obj_type && tcc->higher_equal(obj_type), "must improve");
|
||||||
// Delay transform() call to allow recovery of pre-cast value
|
// Delay transform() call to allow recovery of pre-cast value
|
||||||
// at the control merge.
|
// at the control merge.
|
||||||
_gvn.set_type_bottom(ccast);
|
_gvn.set_type_bottom(ccast);
|
||||||
@ -1352,7 +1354,7 @@ void Parse::sharpen_type_after_if(BoolTest::mask btest,
|
|||||||
|
|
||||||
if (ccast != NULL) {
|
if (ccast != NULL) {
|
||||||
const Type* tcc = ccast->as_Type()->type();
|
const Type* tcc = ccast->as_Type()->type();
|
||||||
assert(tcc != tval && tcc->higher_equal_speculative(tval), "must improve");
|
assert(tcc != tval && tcc->higher_equal(tval), "must improve");
|
||||||
// Delay transform() call to allow recovery of pre-cast value
|
// Delay transform() call to allow recovery of pre-cast value
|
||||||
// at the control merge.
|
// at the control merge.
|
||||||
ccast->set_req(0, control());
|
ccast->set_req(0, control());
|
||||||
@ -1393,7 +1395,7 @@ Node* Parse::optimize_cmp_with_klass(Node* c) {
|
|||||||
Node* addp = load_klass->in(2);
|
Node* addp = load_klass->in(2);
|
||||||
Node* obj = addp->in(AddPNode::Address);
|
Node* obj = addp->in(AddPNode::Address);
|
||||||
const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr();
|
const TypeOopPtr* obj_type = _gvn.type(obj)->is_oopptr();
|
||||||
if (obj_type->speculative_type() != NULL) {
|
if (obj_type->speculative_type_not_null() != NULL) {
|
||||||
ciKlass* k = obj_type->speculative_type();
|
ciKlass* k = obj_type->speculative_type();
|
||||||
inc_sp(2);
|
inc_sp(2);
|
||||||
obj = maybe_cast_profiled_obj(obj, k);
|
obj = maybe_cast_profiled_obj(obj, k);
|
||||||
@ -2277,6 +2279,14 @@ void Parse::do_one_bytecode() {
|
|||||||
maybe_add_safepoint(iter().get_dest());
|
maybe_add_safepoint(iter().get_dest());
|
||||||
a = null();
|
a = null();
|
||||||
b = pop();
|
b = pop();
|
||||||
|
if (!_gvn.type(b)->speculative_maybe_null() &&
|
||||||
|
!too_many_traps(Deoptimization::Reason_speculate_null_check)) {
|
||||||
|
inc_sp(1);
|
||||||
|
Node* null_ctl = top();
|
||||||
|
b = null_check_oop(b, &null_ctl, true, true, true);
|
||||||
|
assert(null_ctl->is_top(), "no null control here");
|
||||||
|
dec_sp(1);
|
||||||
|
}
|
||||||
c = _gvn.transform( new (C) CmpPNode(b, a) );
|
c = _gvn.transform( new (C) CmpPNode(b, a) );
|
||||||
do_ifnull(btest, c);
|
do_ifnull(btest, c);
|
||||||
break;
|
break;
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "memory/universe.inline.hpp"
|
#include "memory/universe.inline.hpp"
|
||||||
#include "oops/objArrayKlass.hpp"
|
#include "oops/objArrayKlass.hpp"
|
||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
|
#include "opto/castnode.hpp"
|
||||||
#include "opto/memnode.hpp"
|
#include "opto/memnode.hpp"
|
||||||
#include "opto/parse.hpp"
|
#include "opto/parse.hpp"
|
||||||
#include "opto/rootnode.hpp"
|
#include "opto/rootnode.hpp"
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
#include "opto/block.hpp"
|
#include "opto/block.hpp"
|
||||||
#include "opto/callnode.hpp"
|
#include "opto/callnode.hpp"
|
||||||
#include "opto/cfgnode.hpp"
|
#include "opto/cfgnode.hpp"
|
||||||
#include "opto/connode.hpp"
|
|
||||||
#include "opto/idealGraphPrinter.hpp"
|
#include "opto/idealGraphPrinter.hpp"
|
||||||
#include "opto/loopnode.hpp"
|
#include "opto/loopnode.hpp"
|
||||||
#include "opto/machnode.hpp"
|
#include "opto/machnode.hpp"
|
||||||
@ -330,7 +329,7 @@ void NodeHash::check_no_speculative_types() {
|
|||||||
Node *sentinel_node = sentinel();
|
Node *sentinel_node = sentinel();
|
||||||
for (uint i = 0; i < max; ++i) {
|
for (uint i = 0; i < max; ++i) {
|
||||||
Node *n = at(i);
|
Node *n = at(i);
|
||||||
if(n != NULL && n != sentinel_node && n->is_Type()) {
|
if(n != NULL && n != sentinel_node && n->is_Type() && n->outcnt() > 0) {
|
||||||
TypeNode* tn = n->as_Type();
|
TypeNode* tn = n->as_Type();
|
||||||
const Type* t = tn->type();
|
const Type* t = tn->type();
|
||||||
const Type* t_no_spec = t->remove_speculative();
|
const Type* t_no_spec = t->remove_speculative();
|
||||||
|
@ -48,7 +48,6 @@
|
|||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
#include "opto/callnode.hpp"
|
#include "opto/callnode.hpp"
|
||||||
#include "opto/cfgnode.hpp"
|
#include "opto/cfgnode.hpp"
|
||||||
#include "opto/connode.hpp"
|
|
||||||
#include "opto/graphKit.hpp"
|
#include "opto/graphKit.hpp"
|
||||||
#include "opto/machnode.hpp"
|
#include "opto/machnode.hpp"
|
||||||
#include "opto/matcher.hpp"
|
#include "opto/matcher.hpp"
|
||||||
|
@ -25,8 +25,8 @@
|
|||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "opto/callnode.hpp"
|
#include "opto/callnode.hpp"
|
||||||
#include "opto/connode.hpp"
|
|
||||||
#include "opto/loopnode.hpp"
|
#include "opto/loopnode.hpp"
|
||||||
|
#include "opto/movenode.hpp"
|
||||||
|
|
||||||
|
|
||||||
//------------------------------split_thru_region------------------------------
|
//------------------------------split_thru_region------------------------------
|
||||||
|
@ -28,9 +28,9 @@
|
|||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
#include "opto/callnode.hpp"
|
#include "opto/callnode.hpp"
|
||||||
#include "opto/cfgnode.hpp"
|
#include "opto/cfgnode.hpp"
|
||||||
#include "opto/connode.hpp"
|
|
||||||
#include "opto/loopnode.hpp"
|
#include "opto/loopnode.hpp"
|
||||||
#include "opto/matcher.hpp"
|
#include "opto/matcher.hpp"
|
||||||
|
#include "opto/movenode.hpp"
|
||||||
#include "opto/mulnode.hpp"
|
#include "opto/mulnode.hpp"
|
||||||
#include "opto/opcodes.hpp"
|
#include "opto/opcodes.hpp"
|
||||||
#include "opto/phaseX.hpp"
|
#include "opto/phaseX.hpp"
|
||||||
|
@ -27,11 +27,14 @@
|
|||||||
#include "memory/allocation.inline.hpp"
|
#include "memory/allocation.inline.hpp"
|
||||||
#include "opto/addnode.hpp"
|
#include "opto/addnode.hpp"
|
||||||
#include "opto/callnode.hpp"
|
#include "opto/callnode.hpp"
|
||||||
|
#include "opto/castnode.hpp"
|
||||||
|
#include "opto/convertnode.hpp"
|
||||||
#include "opto/divnode.hpp"
|
#include "opto/divnode.hpp"
|
||||||
#include "opto/matcher.hpp"
|
#include "opto/matcher.hpp"
|
||||||
#include "opto/memnode.hpp"
|
#include "opto/memnode.hpp"
|
||||||
#include "opto/mulnode.hpp"
|
#include "opto/mulnode.hpp"
|
||||||
#include "opto/opcodes.hpp"
|
#include "opto/opcodes.hpp"
|
||||||
|
#include "opto/opaquenode.hpp"
|
||||||
#include "opto/superword.hpp"
|
#include "opto/superword.hpp"
|
||||||
#include "opto/vectornode.hpp"
|
#include "opto/vectornode.hpp"
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#ifndef SHARE_VM_OPTO_SUPERWORD_HPP
|
#ifndef SHARE_VM_OPTO_SUPERWORD_HPP
|
||||||
#define SHARE_VM_OPTO_SUPERWORD_HPP
|
#define SHARE_VM_OPTO_SUPERWORD_HPP
|
||||||
|
|
||||||
#include "opto/connode.hpp"
|
|
||||||
#include "opto/loopnode.hpp"
|
#include "opto/loopnode.hpp"
|
||||||
#include "opto/node.hpp"
|
#include "opto/node.hpp"
|
||||||
#include "opto/phaseX.hpp"
|
#include "opto/phaseX.hpp"
|
||||||
|
@ -372,7 +372,7 @@ void Type::Initialize_shared(Compile* current) {
|
|||||||
false, 0, oopDesc::mark_offset_in_bytes());
|
false, 0, oopDesc::mark_offset_in_bytes());
|
||||||
TypeInstPtr::KLASS = TypeInstPtr::make(TypePtr::BotPTR, current->env()->Object_klass(),
|
TypeInstPtr::KLASS = TypeInstPtr::make(TypePtr::BotPTR, current->env()->Object_klass(),
|
||||||
false, 0, oopDesc::klass_offset_in_bytes());
|
false, 0, oopDesc::klass_offset_in_bytes());
|
||||||
TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot, TypeOopPtr::InstanceBot, NULL);
|
TypeOopPtr::BOTTOM = TypeOopPtr::make(TypePtr::BotPTR, OffsetBot, TypeOopPtr::InstanceBot);
|
||||||
|
|
||||||
TypeMetadataPtr::BOTTOM = TypeMetadataPtr::make(TypePtr::BotPTR, NULL, OffsetBot);
|
TypeMetadataPtr::BOTTOM = TypeMetadataPtr::make(TypePtr::BotPTR, NULL, OffsetBot);
|
||||||
|
|
||||||
@ -620,8 +620,8 @@ bool Type::interface_vs_oop(const Type *t) const {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Now check the speculative parts as well
|
// Now check the speculative parts as well
|
||||||
const TypeOopPtr* this_spec = isa_oopptr() != NULL ? isa_oopptr()->speculative() : NULL;
|
const TypePtr* this_spec = isa_ptr() != NULL ? is_ptr()->speculative() : NULL;
|
||||||
const TypeOopPtr* t_spec = t->isa_oopptr() != NULL ? t->isa_oopptr()->speculative() : NULL;
|
const TypePtr* t_spec = t->isa_ptr() != NULL ? t->is_ptr()->speculative() : NULL;
|
||||||
if (this_spec != NULL && t_spec != NULL) {
|
if (this_spec != NULL && t_spec != NULL) {
|
||||||
if (this_spec->interface_vs_oop_helper(t_spec)) {
|
if (this_spec->interface_vs_oop_helper(t_spec)) {
|
||||||
return true;
|
return true;
|
||||||
@ -1975,6 +1975,25 @@ const Type* TypeAry::remove_speculative() const {
|
|||||||
return make(_elem->remove_speculative(), _size, _stable);
|
return make(_elem->remove_speculative(), _size, _stable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return same type with cleaned up speculative part of element
|
||||||
|
*/
|
||||||
|
const Type* TypeAry::cleanup_speculative() const {
|
||||||
|
return make(_elem->cleanup_speculative(), _size, _stable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return same type but with a different inline depth (used for speculation)
|
||||||
|
*
|
||||||
|
* @param depth depth to meet with
|
||||||
|
*/
|
||||||
|
const TypePtr* TypePtr::with_inline_depth(int depth) const {
|
||||||
|
if (!UseInlineDepthForSpeculativeTypes) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
return make(AnyPtr, _ptr, _offset, _speculative, depth);
|
||||||
|
}
|
||||||
|
|
||||||
//----------------------interface_vs_oop---------------------------------------
|
//----------------------interface_vs_oop---------------------------------------
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
bool TypeAry::interface_vs_oop(const Type *t) const {
|
bool TypeAry::interface_vs_oop(const Type *t) const {
|
||||||
@ -2179,15 +2198,15 @@ const TypePtr::PTR TypePtr::ptr_meet[TypePtr::lastPTR][TypePtr::lastPTR] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------make-------------------------------------------
|
//------------------------------make-------------------------------------------
|
||||||
const TypePtr *TypePtr::make( TYPES t, enum PTR ptr, int offset ) {
|
const TypePtr *TypePtr::make(TYPES t, enum PTR ptr, int offset, const TypePtr* speculative, int inline_depth) {
|
||||||
return (TypePtr*)(new TypePtr(t,ptr,offset))->hashcons();
|
return (TypePtr*)(new TypePtr(t,ptr,offset, speculative, inline_depth))->hashcons();
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------cast_to_ptr_type-------------------------------
|
//------------------------------cast_to_ptr_type-------------------------------
|
||||||
const Type *TypePtr::cast_to_ptr_type(PTR ptr) const {
|
const Type *TypePtr::cast_to_ptr_type(PTR ptr) const {
|
||||||
assert(_base == AnyPtr, "subclass must override cast_to_ptr_type");
|
assert(_base == AnyPtr, "subclass must override cast_to_ptr_type");
|
||||||
if( ptr == _ptr ) return this;
|
if( ptr == _ptr ) return this;
|
||||||
return make(_base, ptr, _offset);
|
return make(_base, ptr, _offset, _speculative, _inline_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------get_con----------------------------------------
|
//------------------------------get_con----------------------------------------
|
||||||
@ -2199,6 +2218,28 @@ intptr_t TypePtr::get_con() const {
|
|||||||
//------------------------------meet-------------------------------------------
|
//------------------------------meet-------------------------------------------
|
||||||
// Compute the MEET of two types. It returns a new Type object.
|
// Compute the MEET of two types. It returns a new Type object.
|
||||||
const Type *TypePtr::xmeet(const Type *t) const {
|
const Type *TypePtr::xmeet(const Type *t) const {
|
||||||
|
const Type* res = xmeet_helper(t);
|
||||||
|
if (res->isa_ptr() == NULL) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TypePtr* res_ptr = res->is_ptr();
|
||||||
|
if (res_ptr->speculative() != NULL) {
|
||||||
|
// type->speculative() == NULL means that speculation is no better
|
||||||
|
// than type, i.e. type->speculative() == type. So there are 2
|
||||||
|
// ways to represent the fact that we have no useful speculative
|
||||||
|
// data and we should use a single one to be able to test for
|
||||||
|
// equality between types. Check whether type->speculative() ==
|
||||||
|
// type and set speculative to NULL if it is the case.
|
||||||
|
if (res_ptr->remove_speculative() == res_ptr->speculative()) {
|
||||||
|
return res_ptr->remove_speculative();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type *TypePtr::xmeet_helper(const Type *t) const {
|
||||||
// Perform a fast test for common case; meeting the same types together.
|
// Perform a fast test for common case; meeting the same types together.
|
||||||
if( this == t ) return this; // Meeting same type-rep?
|
if( this == t ) return this; // Meeting same type-rep?
|
||||||
|
|
||||||
@ -2221,7 +2262,9 @@ const Type *TypePtr::xmeet( const Type *t ) const {
|
|||||||
|
|
||||||
case AnyPtr: { // Meeting to AnyPtrs
|
case AnyPtr: { // Meeting to AnyPtrs
|
||||||
const TypePtr *tp = t->is_ptr();
|
const TypePtr *tp = t->is_ptr();
|
||||||
return make( AnyPtr, meet_ptr(tp->ptr()), meet_offset(tp->offset()) );
|
const TypePtr* speculative = xmeet_speculative(tp);
|
||||||
|
int depth = meet_inline_depth(tp->inline_depth());
|
||||||
|
return make(AnyPtr, meet_ptr(tp->ptr()), meet_offset(tp->offset()), speculative, depth);
|
||||||
}
|
}
|
||||||
case RawPtr: // For these, flip the call around to cut down
|
case RawPtr: // For these, flip the call around to cut down
|
||||||
case OopPtr:
|
case OopPtr:
|
||||||
@ -2260,7 +2303,7 @@ const TypePtr::PTR TypePtr::ptr_dual[TypePtr::lastPTR] = {
|
|||||||
BotPTR, NotNull, Constant, Null, AnyNull, TopPTR
|
BotPTR, NotNull, Constant, Null, AnyNull, TopPTR
|
||||||
};
|
};
|
||||||
const Type *TypePtr::xdual() const {
|
const Type *TypePtr::xdual() const {
|
||||||
return new TypePtr( AnyPtr, dual_ptr(), dual_offset() );
|
return new TypePtr(AnyPtr, dual_ptr(), dual_offset(), dual_speculative(), dual_inline_depth());
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------xadd_offset------------------------------------
|
//------------------------------xadd_offset------------------------------------
|
||||||
@ -2281,20 +2324,245 @@ int TypePtr::xadd_offset( intptr_t offset ) const {
|
|||||||
|
|
||||||
//------------------------------add_offset-------------------------------------
|
//------------------------------add_offset-------------------------------------
|
||||||
const TypePtr *TypePtr::add_offset( intptr_t offset ) const {
|
const TypePtr *TypePtr::add_offset( intptr_t offset ) const {
|
||||||
return make( AnyPtr, _ptr, xadd_offset(offset) );
|
return make(AnyPtr, _ptr, xadd_offset(offset), _speculative, _inline_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------eq---------------------------------------------
|
//------------------------------eq---------------------------------------------
|
||||||
// Structural equality check for Type representations
|
// Structural equality check for Type representations
|
||||||
bool TypePtr::eq( const Type *t ) const {
|
bool TypePtr::eq( const Type *t ) const {
|
||||||
const TypePtr *a = (const TypePtr*)t;
|
const TypePtr *a = (const TypePtr*)t;
|
||||||
return _ptr == a->ptr() && _offset == a->offset();
|
return _ptr == a->ptr() && _offset == a->offset() && eq_speculative(a) && _inline_depth == a->_inline_depth;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------hash-------------------------------------------
|
//------------------------------hash-------------------------------------------
|
||||||
// Type-specific hashing function.
|
// Type-specific hashing function.
|
||||||
int TypePtr::hash(void) const {
|
int TypePtr::hash(void) const {
|
||||||
return _ptr + _offset;
|
return _ptr + _offset + hash_speculative() + _inline_depth;
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return same type without a speculative part
|
||||||
|
*/
|
||||||
|
const Type* TypePtr::remove_speculative() const {
|
||||||
|
if (_speculative == NULL) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth");
|
||||||
|
return make(AnyPtr, _ptr, _offset, NULL, _inline_depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return same type but drop speculative part if we know we won't use
|
||||||
|
* it
|
||||||
|
*/
|
||||||
|
const Type* TypePtr::cleanup_speculative() const {
|
||||||
|
if (speculative() == NULL) {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
const Type* no_spec = remove_speculative();
|
||||||
|
// If this is NULL_PTR then we don't need the speculative type
|
||||||
|
// (with_inline_depth in case the current type inline depth is
|
||||||
|
// InlineDepthTop)
|
||||||
|
if (no_spec == NULL_PTR->with_inline_depth(inline_depth())) {
|
||||||
|
return no_spec;
|
||||||
|
}
|
||||||
|
if (above_centerline(speculative()->ptr())) {
|
||||||
|
return no_spec;
|
||||||
|
}
|
||||||
|
const TypeOopPtr* spec_oopptr = speculative()->isa_oopptr();
|
||||||
|
// If the speculative may be null and is an inexact klass then it
|
||||||
|
// doesn't help
|
||||||
|
if (speculative()->maybe_null() && (spec_oopptr == NULL || !spec_oopptr->klass_is_exact())) {
|
||||||
|
return no_spec;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dual of the speculative part of the type
|
||||||
|
*/
|
||||||
|
const TypePtr* TypePtr::dual_speculative() const {
|
||||||
|
if (_speculative == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return _speculative->dual()->is_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* meet of the speculative parts of 2 types
|
||||||
|
*
|
||||||
|
* @param other type to meet with
|
||||||
|
*/
|
||||||
|
const TypePtr* TypePtr::xmeet_speculative(const TypePtr* other) const {
|
||||||
|
bool this_has_spec = (_speculative != NULL);
|
||||||
|
bool other_has_spec = (other->speculative() != NULL);
|
||||||
|
|
||||||
|
if (!this_has_spec && !other_has_spec) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we are at a point where control flow meets and one branch has
|
||||||
|
// a speculative type and the other has not, we meet the speculative
|
||||||
|
// type of one branch with the actual type of the other. If the
|
||||||
|
// actual type is exact and the speculative is as well, then the
|
||||||
|
// result is a speculative type which is exact and we can continue
|
||||||
|
// speculation further.
|
||||||
|
const TypePtr* this_spec = _speculative;
|
||||||
|
const TypePtr* other_spec = other->speculative();
|
||||||
|
|
||||||
|
if (!this_has_spec) {
|
||||||
|
this_spec = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!other_has_spec) {
|
||||||
|
other_spec = other;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this_spec->meet(other_spec)->is_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dual of the inline depth for this type (used for speculation)
|
||||||
|
*/
|
||||||
|
int TypePtr::dual_inline_depth() const {
|
||||||
|
return -inline_depth();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* meet of 2 inline depths (used for speculation)
|
||||||
|
*
|
||||||
|
* @param depth depth to meet with
|
||||||
|
*/
|
||||||
|
int TypePtr::meet_inline_depth(int depth) const {
|
||||||
|
return MAX2(inline_depth(), depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Are the speculative parts of 2 types equal?
|
||||||
|
*
|
||||||
|
* @param other type to compare this one to
|
||||||
|
*/
|
||||||
|
bool TypePtr::eq_speculative(const TypePtr* other) const {
|
||||||
|
if (_speculative == NULL || other->speculative() == NULL) {
|
||||||
|
return _speculative == other->speculative();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_speculative->base() != other->speculative()->base()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _speculative->eq(other->speculative());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash of the speculative part of the type
|
||||||
|
*/
|
||||||
|
int TypePtr::hash_speculative() const {
|
||||||
|
if (_speculative == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _speculative->hash();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* add offset to the speculative part of the type
|
||||||
|
*
|
||||||
|
* @param offset offset to add
|
||||||
|
*/
|
||||||
|
const TypePtr* TypePtr::add_offset_speculative(intptr_t offset) const {
|
||||||
|
if (_speculative == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return _speculative->add_offset(offset)->is_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return exact klass from the speculative type if there's one
|
||||||
|
*/
|
||||||
|
ciKlass* TypePtr::speculative_type() const {
|
||||||
|
if (_speculative != NULL && _speculative->isa_oopptr()) {
|
||||||
|
const TypeOopPtr* speculative = _speculative->join(this)->is_oopptr();
|
||||||
|
if (speculative->klass_is_exact()) {
|
||||||
|
return speculative->klass();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return true if speculative type may be null
|
||||||
|
*/
|
||||||
|
bool TypePtr::speculative_maybe_null() const {
|
||||||
|
if (_speculative != NULL) {
|
||||||
|
const TypePtr* speculative = _speculative->join(this)->is_ptr();
|
||||||
|
return speculative->maybe_null();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Same as TypePtr::speculative_type() but return the klass only if
|
||||||
|
* the speculative tells us is not null
|
||||||
|
*/
|
||||||
|
ciKlass* TypePtr::speculative_type_not_null() const {
|
||||||
|
if (speculative_maybe_null()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return speculative_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether new profiling would improve speculative type
|
||||||
|
*
|
||||||
|
* @param exact_kls class from profiling
|
||||||
|
* @param inline_depth inlining depth of profile point
|
||||||
|
*
|
||||||
|
* @return true if type profile is valuable
|
||||||
|
*/
|
||||||
|
bool TypePtr::would_improve_type(ciKlass* exact_kls, int inline_depth) const {
|
||||||
|
// no profiling?
|
||||||
|
if (exact_kls == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// no speculative type or non exact speculative type?
|
||||||
|
if (speculative_type() == NULL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// If the node already has an exact speculative type keep it,
|
||||||
|
// unless it was provided by profiling that is at a deeper
|
||||||
|
// inlining level. Profiling at a higher inlining depth is
|
||||||
|
// expected to be less accurate.
|
||||||
|
if (_speculative->inline_depth() == InlineDepthBottom) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
assert(_speculative->inline_depth() != InlineDepthTop, "can't do the comparison");
|
||||||
|
return inline_depth < _speculative->inline_depth();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether new profiling would improve ptr (= tells us it is non
|
||||||
|
* null)
|
||||||
|
*
|
||||||
|
* @param maybe_null true if profiling tells the ptr may be null
|
||||||
|
*
|
||||||
|
* @return true if ptr profile is valuable
|
||||||
|
*/
|
||||||
|
bool TypePtr::would_improve_ptr(bool maybe_null) const {
|
||||||
|
// profiling doesn't tell us anything useful
|
||||||
|
if (maybe_null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// We already know this is not be null
|
||||||
|
if (!this->maybe_null()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// We already know the speculative type cannot be null
|
||||||
|
if (!speculative_maybe_null()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------dump2------------------------------------------
|
//------------------------------dump2------------------------------------------
|
||||||
@ -2309,6 +2577,32 @@ void TypePtr::dump2( Dict &d, uint depth, outputStream *st ) const {
|
|||||||
if( _offset == OffsetTop ) st->print("+top");
|
if( _offset == OffsetTop ) st->print("+top");
|
||||||
else if( _offset == OffsetBot ) st->print("+bot");
|
else if( _offset == OffsetBot ) st->print("+bot");
|
||||||
else if( _offset ) st->print("+%d", _offset);
|
else if( _offset ) st->print("+%d", _offset);
|
||||||
|
dump_inline_depth(st);
|
||||||
|
dump_speculative(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*dump the speculative part of the type
|
||||||
|
*/
|
||||||
|
void TypePtr::dump_speculative(outputStream *st) const {
|
||||||
|
if (_speculative != NULL) {
|
||||||
|
st->print(" (speculative=");
|
||||||
|
_speculative->dump_on(st);
|
||||||
|
st->print(")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*dump the inline depth of the type
|
||||||
|
*/
|
||||||
|
void TypePtr::dump_inline_depth(outputStream *st) const {
|
||||||
|
if (_inline_depth != InlineDepthBottom) {
|
||||||
|
if (_inline_depth == InlineDepthTop) {
|
||||||
|
st->print(" (inline_depth=InlineDepthTop)");
|
||||||
|
} else {
|
||||||
|
st->print(" (inline_depth=%d)", _inline_depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -2399,7 +2693,7 @@ const Type *TypeRawPtr::xmeet( const Type *t ) const {
|
|||||||
case TypePtr::Null:
|
case TypePtr::Null:
|
||||||
if( _ptr == TypePtr::TopPTR ) return t;
|
if( _ptr == TypePtr::TopPTR ) return t;
|
||||||
return TypeRawPtr::BOTTOM;
|
return TypeRawPtr::BOTTOM;
|
||||||
case TypePtr::NotNull: return TypePtr::make( AnyPtr, meet_ptr(TypePtr::NotNull), tp->meet_offset(0) );
|
case TypePtr::NotNull: return TypePtr::make(AnyPtr, meet_ptr(TypePtr::NotNull), tp->meet_offset(0), tp->speculative(), tp->inline_depth());
|
||||||
case TypePtr::AnyNull:
|
case TypePtr::AnyNull:
|
||||||
if( _ptr == TypePtr::Constant) return this;
|
if( _ptr == TypePtr::Constant) return this;
|
||||||
return make( meet_ptr(TypePtr::AnyNull) );
|
return make( meet_ptr(TypePtr::AnyNull) );
|
||||||
@ -2463,16 +2757,15 @@ void TypeRawPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
|
|||||||
const TypeOopPtr *TypeOopPtr::BOTTOM;
|
const TypeOopPtr *TypeOopPtr::BOTTOM;
|
||||||
|
|
||||||
//------------------------------TypeOopPtr-------------------------------------
|
//------------------------------TypeOopPtr-------------------------------------
|
||||||
TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth)
|
TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset,
|
||||||
: TypePtr(t, ptr, offset),
|
int instance_id, const TypePtr* speculative, int inline_depth)
|
||||||
|
: TypePtr(t, ptr, offset, speculative, inline_depth),
|
||||||
_const_oop(o), _klass(k),
|
_const_oop(o), _klass(k),
|
||||||
_klass_is_exact(xk),
|
_klass_is_exact(xk),
|
||||||
_is_ptr_to_narrowoop(false),
|
_is_ptr_to_narrowoop(false),
|
||||||
_is_ptr_to_narrowklass(false),
|
_is_ptr_to_narrowklass(false),
|
||||||
_is_ptr_to_boxed_value(false),
|
_is_ptr_to_boxed_value(false),
|
||||||
_instance_id(instance_id),
|
_instance_id(instance_id) {
|
||||||
_speculative(speculative),
|
|
||||||
_inline_depth(inline_depth){
|
|
||||||
if (Compile::current()->eliminate_boxing() && (t == InstPtr) &&
|
if (Compile::current()->eliminate_boxing() && (t == InstPtr) &&
|
||||||
(offset > 0) && xk && (k != 0) && k->is_instance_klass()) {
|
(offset > 0) && xk && (k != 0) && k->is_instance_klass()) {
|
||||||
_is_ptr_to_boxed_value = k->as_instance_klass()->is_boxed_value_offset(offset);
|
_is_ptr_to_boxed_value = k->as_instance_klass()->is_boxed_value_offset(offset);
|
||||||
@ -2538,8 +2831,8 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int o
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------make-------------------------------------------
|
//------------------------------make-------------------------------------------
|
||||||
const TypeOopPtr *TypeOopPtr::make(PTR ptr,
|
const TypeOopPtr *TypeOopPtr::make(PTR ptr, int offset, int instance_id,
|
||||||
int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth) {
|
const TypePtr* speculative, int inline_depth) {
|
||||||
assert(ptr != Constant, "no constant generic pointers");
|
assert(ptr != Constant, "no constant generic pointers");
|
||||||
ciKlass* k = Compile::current()->env()->Object_klass();
|
ciKlass* k = Compile::current()->env()->Object_klass();
|
||||||
bool xk = false;
|
bool xk = false;
|
||||||
@ -2582,28 +2875,6 @@ const TypeKlassPtr* TypeOopPtr::as_klass_type() const {
|
|||||||
return TypeKlassPtr::make(xk? Constant: NotNull, k, 0);
|
return TypeKlassPtr::make(xk? Constant: NotNull, k, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Type *TypeOopPtr::xmeet(const Type *t) const {
|
|
||||||
const Type* res = xmeet_helper(t);
|
|
||||||
if (res->isa_oopptr() == NULL) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
const TypeOopPtr* res_oopptr = res->is_oopptr();
|
|
||||||
if (res_oopptr->speculative() != NULL) {
|
|
||||||
// type->speculative() == NULL means that speculation is no better
|
|
||||||
// than type, i.e. type->speculative() == type. So there are 2
|
|
||||||
// ways to represent the fact that we have no useful speculative
|
|
||||||
// data and we should use a single one to be able to test for
|
|
||||||
// equality between types. Check whether type->speculative() ==
|
|
||||||
// type and set speculative to NULL if it is the case.
|
|
||||||
if (res_oopptr->remove_speculative() == res_oopptr->speculative()) {
|
|
||||||
return res_oopptr->remove_speculative();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------meet-------------------------------------------
|
//------------------------------meet-------------------------------------------
|
||||||
// Compute the MEET of two types. It returns a new Type object.
|
// Compute the MEET of two types. It returns a new Type object.
|
||||||
const Type *TypeOopPtr::xmeet_helper(const Type *t) const {
|
const Type *TypeOopPtr::xmeet_helper(const Type *t) const {
|
||||||
@ -2641,19 +2912,20 @@ const Type *TypeOopPtr::xmeet_helper(const Type *t) const {
|
|||||||
const TypePtr *tp = t->is_ptr();
|
const TypePtr *tp = t->is_ptr();
|
||||||
int offset = meet_offset(tp->offset());
|
int offset = meet_offset(tp->offset());
|
||||||
PTR ptr = meet_ptr(tp->ptr());
|
PTR ptr = meet_ptr(tp->ptr());
|
||||||
|
const TypePtr* speculative = xmeet_speculative(tp);
|
||||||
|
int depth = meet_inline_depth(tp->inline_depth());
|
||||||
switch (tp->ptr()) {
|
switch (tp->ptr()) {
|
||||||
case Null:
|
case Null:
|
||||||
if (ptr == Null) return TypePtr::make(AnyPtr, ptr, offset);
|
if (ptr == Null) return TypePtr::make(AnyPtr, ptr, offset, speculative, depth);
|
||||||
// else fall through:
|
// else fall through:
|
||||||
case TopPTR:
|
case TopPTR:
|
||||||
case AnyNull: {
|
case AnyNull: {
|
||||||
int instance_id = meet_instance_id(InstanceTop);
|
int instance_id = meet_instance_id(InstanceTop);
|
||||||
const TypeOopPtr* speculative = _speculative;
|
return make(ptr, offset, instance_id, speculative, depth);
|
||||||
return make(ptr, offset, instance_id, speculative, _inline_depth);
|
|
||||||
}
|
}
|
||||||
case BotPTR:
|
case BotPTR:
|
||||||
case NotNull:
|
case NotNull:
|
||||||
return TypePtr::make(AnyPtr, ptr, offset);
|
return TypePtr::make(AnyPtr, ptr, offset, speculative, depth);
|
||||||
default: typerr(t);
|
default: typerr(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2661,7 +2933,7 @@ const Type *TypeOopPtr::xmeet_helper(const Type *t) const {
|
|||||||
case OopPtr: { // Meeting to other OopPtrs
|
case OopPtr: { // Meeting to other OopPtrs
|
||||||
const TypeOopPtr *tp = t->is_oopptr();
|
const TypeOopPtr *tp = t->is_oopptr();
|
||||||
int instance_id = meet_instance_id(tp->instance_id());
|
int instance_id = meet_instance_id(tp->instance_id());
|
||||||
const TypeOopPtr* speculative = xmeet_speculative(tp);
|
const TypePtr* speculative = xmeet_speculative(tp);
|
||||||
int depth = meet_inline_depth(tp->inline_depth());
|
int depth = meet_inline_depth(tp->inline_depth());
|
||||||
return make(meet_ptr(tp->ptr()), meet_offset(tp->offset()), instance_id, speculative, depth);
|
return make(meet_ptr(tp->ptr()), meet_offset(tp->offset()), instance_id, speculative, depth);
|
||||||
}
|
}
|
||||||
@ -2859,9 +3131,7 @@ const Type *TypeOopPtr::filter_helper(const Type *kills, bool include_speculativ
|
|||||||
bool TypeOopPtr::eq( const Type *t ) const {
|
bool TypeOopPtr::eq( const Type *t ) const {
|
||||||
const TypeOopPtr *a = (const TypeOopPtr*)t;
|
const TypeOopPtr *a = (const TypeOopPtr*)t;
|
||||||
if (_klass_is_exact != a->_klass_is_exact ||
|
if (_klass_is_exact != a->_klass_is_exact ||
|
||||||
_instance_id != a->_instance_id ||
|
_instance_id != a->_instance_id) return false;
|
||||||
!eq_speculative(a) ||
|
|
||||||
_inline_depth != a->_inline_depth) return false;
|
|
||||||
ciObject* one = const_oop();
|
ciObject* one = const_oop();
|
||||||
ciObject* two = a->const_oop();
|
ciObject* two = a->const_oop();
|
||||||
if (one == NULL || two == NULL) {
|
if (one == NULL || two == NULL) {
|
||||||
@ -2878,8 +3148,6 @@ int TypeOopPtr::hash(void) const {
|
|||||||
(const_oop() ? const_oop()->hash() : 0) +
|
(const_oop() ? const_oop()->hash() : 0) +
|
||||||
_klass_is_exact +
|
_klass_is_exact +
|
||||||
_instance_id +
|
_instance_id +
|
||||||
hash_speculative() +
|
|
||||||
_inline_depth +
|
|
||||||
TypePtr::hash();
|
TypePtr::hash();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2903,27 +3171,6 @@ void TypeOopPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
|
|||||||
dump_inline_depth(st);
|
dump_inline_depth(st);
|
||||||
dump_speculative(st);
|
dump_speculative(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*dump the speculative part of the type
|
|
||||||
*/
|
|
||||||
void TypeOopPtr::dump_speculative(outputStream *st) const {
|
|
||||||
if (_speculative != NULL) {
|
|
||||||
st->print(" (speculative=");
|
|
||||||
_speculative->dump_on(st);
|
|
||||||
st->print(")");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TypeOopPtr::dump_inline_depth(outputStream *st) const {
|
|
||||||
if (_inline_depth != InlineDepthBottom) {
|
|
||||||
if (_inline_depth == InlineDepthTop) {
|
|
||||||
st->print(" (inline_depth=InlineDepthTop)");
|
|
||||||
} else {
|
|
||||||
st->print(" (inline_depth=%d)", _inline_depth);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//------------------------------singleton--------------------------------------
|
//------------------------------singleton--------------------------------------
|
||||||
@ -2951,50 +3198,31 @@ const Type* TypeOopPtr::remove_speculative() const {
|
|||||||
return make(_ptr, _offset, _instance_id, NULL, _inline_depth);
|
return make(_ptr, _offset, _instance_id, NULL, _inline_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return same type but drop speculative part if we know we won't use
|
||||||
|
* it
|
||||||
|
*/
|
||||||
|
const Type* TypeOopPtr::cleanup_speculative() const {
|
||||||
|
// If the klass is exact and the ptr is not null then there's
|
||||||
|
// nothing that the speculative type can help us with
|
||||||
|
if (klass_is_exact() && !maybe_null()) {
|
||||||
|
return remove_speculative();
|
||||||
|
}
|
||||||
|
return TypePtr::cleanup_speculative();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return same type but with a different inline depth (used for speculation)
|
* Return same type but with a different inline depth (used for speculation)
|
||||||
*
|
*
|
||||||
* @param depth depth to meet with
|
* @param depth depth to meet with
|
||||||
*/
|
*/
|
||||||
const TypeOopPtr* TypeOopPtr::with_inline_depth(int depth) const {
|
const TypePtr* TypeOopPtr::with_inline_depth(int depth) const {
|
||||||
if (!UseInlineDepthForSpeculativeTypes) {
|
if (!UseInlineDepthForSpeculativeTypes) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
return make(_ptr, _offset, _instance_id, _speculative, depth);
|
return make(_ptr, _offset, _instance_id, _speculative, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check whether new profiling would improve speculative type
|
|
||||||
*
|
|
||||||
* @param exact_kls class from profiling
|
|
||||||
* @param inline_depth inlining depth of profile point
|
|
||||||
*
|
|
||||||
* @return true if type profile is valuable
|
|
||||||
*/
|
|
||||||
bool TypeOopPtr::would_improve_type(ciKlass* exact_kls, int inline_depth) const {
|
|
||||||
// no way to improve an already exact type
|
|
||||||
if (klass_is_exact()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// no profiling?
|
|
||||||
if (exact_kls == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// no speculative type or non exact speculative type?
|
|
||||||
if (speculative_type() == NULL) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// If the node already has an exact speculative type keep it,
|
|
||||||
// unless it was provided by profiling that is at a deeper
|
|
||||||
// inlining level. Profiling at a higher inlining depth is
|
|
||||||
// expected to be less accurate.
|
|
||||||
if (_speculative->inline_depth() == InlineDepthBottom) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
assert(_speculative->inline_depth() != InlineDepthTop, "can't do the comparison");
|
|
||||||
return inline_depth < _speculative->inline_depth();
|
|
||||||
}
|
|
||||||
|
|
||||||
//------------------------------meet_instance_id--------------------------------
|
//------------------------------meet_instance_id--------------------------------
|
||||||
int TypeOopPtr::meet_instance_id( int instance_id ) const {
|
int TypeOopPtr::meet_instance_id( int instance_id ) const {
|
||||||
// Either is 'TOP' instance? Return the other instance!
|
// Either is 'TOP' instance? Return the other instance!
|
||||||
@ -3013,102 +3241,19 @@ int TypeOopPtr::dual_instance_id( ) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* meet of the speculative parts of 2 types
|
* Check whether new profiling would improve speculative type
|
||||||
*
|
*
|
||||||
* @param other type to meet with
|
* @param exact_kls class from profiling
|
||||||
*/
|
* @param inline_depth inlining depth of profile point
|
||||||
const TypeOopPtr* TypeOopPtr::xmeet_speculative(const TypeOopPtr* other) const {
|
|
||||||
bool this_has_spec = (_speculative != NULL);
|
|
||||||
bool other_has_spec = (other->speculative() != NULL);
|
|
||||||
|
|
||||||
if (!this_has_spec && !other_has_spec) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are at a point where control flow meets and one branch has
|
|
||||||
// a speculative type and the other has not, we meet the speculative
|
|
||||||
// type of one branch with the actual type of the other. If the
|
|
||||||
// actual type is exact and the speculative is as well, then the
|
|
||||||
// result is a speculative type which is exact and we can continue
|
|
||||||
// speculation further.
|
|
||||||
const TypeOopPtr* this_spec = _speculative;
|
|
||||||
const TypeOopPtr* other_spec = other->speculative();
|
|
||||||
|
|
||||||
if (!this_has_spec) {
|
|
||||||
this_spec = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!other_has_spec) {
|
|
||||||
other_spec = other;
|
|
||||||
}
|
|
||||||
|
|
||||||
return this_spec->meet_speculative(other_spec)->is_oopptr();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* dual of the speculative part of the type
|
|
||||||
*/
|
|
||||||
const TypeOopPtr* TypeOopPtr::dual_speculative() const {
|
|
||||||
if (_speculative == NULL) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return _speculative->dual()->is_oopptr();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* add offset to the speculative part of the type
|
|
||||||
*
|
*
|
||||||
* @param offset offset to add
|
* @return true if type profile is valuable
|
||||||
*/
|
*/
|
||||||
const TypeOopPtr* TypeOopPtr::add_offset_speculative(intptr_t offset) const {
|
bool TypeOopPtr::would_improve_type(ciKlass* exact_kls, int inline_depth) const {
|
||||||
if (_speculative == NULL) {
|
// no way to improve an already exact type
|
||||||
return NULL;
|
if (klass_is_exact()) {
|
||||||
}
|
|
||||||
return _speculative->add_offset(offset)->is_oopptr();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Are the speculative parts of 2 types equal?
|
|
||||||
*
|
|
||||||
* @param other type to compare this one to
|
|
||||||
*/
|
|
||||||
bool TypeOopPtr::eq_speculative(const TypeOopPtr* other) const {
|
|
||||||
if (_speculative == NULL || other->speculative() == NULL) {
|
|
||||||
return _speculative == other->speculative();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_speculative->base() != other->speculative()->base()) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return TypePtr::would_improve_type(exact_kls, inline_depth);
|
||||||
return _speculative->eq(other->speculative());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hash of the speculative part of the type
|
|
||||||
*/
|
|
||||||
int TypeOopPtr::hash_speculative() const {
|
|
||||||
if (_speculative == NULL) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return _speculative->hash();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* dual of the inline depth for this type (used for speculation)
|
|
||||||
*/
|
|
||||||
int TypeOopPtr::dual_inline_depth() const {
|
|
||||||
return -inline_depth();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* meet of 2 inline depth (used for speculation)
|
|
||||||
*
|
|
||||||
* @param depth depth to meet with
|
|
||||||
*/
|
|
||||||
int TypeOopPtr::meet_inline_depth(int depth) const {
|
|
||||||
return MAX2(inline_depth(), depth);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
@ -3120,8 +3265,10 @@ const TypeInstPtr *TypeInstPtr::MARK;
|
|||||||
const TypeInstPtr *TypeInstPtr::KLASS;
|
const TypeInstPtr *TypeInstPtr::KLASS;
|
||||||
|
|
||||||
//------------------------------TypeInstPtr-------------------------------------
|
//------------------------------TypeInstPtr-------------------------------------
|
||||||
TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int off, int instance_id, const TypeOopPtr* speculative, int inline_depth)
|
TypeInstPtr::TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int off,
|
||||||
: TypeOopPtr(InstPtr, ptr, k, xk, o, off, instance_id, speculative, inline_depth), _name(k->name()) {
|
int instance_id, const TypePtr* speculative, int inline_depth)
|
||||||
|
: TypeOopPtr(InstPtr, ptr, k, xk, o, off, instance_id, speculative, inline_depth),
|
||||||
|
_name(k->name()) {
|
||||||
assert(k != NULL &&
|
assert(k != NULL &&
|
||||||
(k->is_loaded() || o == NULL),
|
(k->is_loaded() || o == NULL),
|
||||||
"cannot have constants with non-loaded klass");
|
"cannot have constants with non-loaded klass");
|
||||||
@ -3134,7 +3281,7 @@ const TypeInstPtr *TypeInstPtr::make(PTR ptr,
|
|||||||
ciObject* o,
|
ciObject* o,
|
||||||
int offset,
|
int offset,
|
||||||
int instance_id,
|
int instance_id,
|
||||||
const TypeOopPtr* speculative,
|
const TypePtr* speculative,
|
||||||
int inline_depth) {
|
int inline_depth) {
|
||||||
assert( !k->is_loaded() || k->is_instance_klass(), "Must be for instance");
|
assert( !k->is_loaded() || k->is_instance_klass(), "Must be for instance");
|
||||||
// Either const_oop() is NULL or else ptr is Constant
|
// Either const_oop() is NULL or else ptr is Constant
|
||||||
@ -3217,7 +3364,7 @@ const TypeInstPtr *TypeInstPtr::xmeet_unloaded(const TypeInstPtr *tinst) const {
|
|||||||
int off = meet_offset(tinst->offset());
|
int off = meet_offset(tinst->offset());
|
||||||
PTR ptr = meet_ptr(tinst->ptr());
|
PTR ptr = meet_ptr(tinst->ptr());
|
||||||
int instance_id = meet_instance_id(tinst->instance_id());
|
int instance_id = meet_instance_id(tinst->instance_id());
|
||||||
const TypeOopPtr* speculative = xmeet_speculative(tinst);
|
const TypePtr* speculative = xmeet_speculative(tinst);
|
||||||
int depth = meet_inline_depth(tinst->inline_depth());
|
int depth = meet_inline_depth(tinst->inline_depth());
|
||||||
|
|
||||||
const TypeInstPtr *loaded = is_loaded() ? this : tinst;
|
const TypeInstPtr *loaded = is_loaded() ? this : tinst;
|
||||||
@ -3295,7 +3442,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
|
|||||||
int offset = meet_offset(tp->offset());
|
int offset = meet_offset(tp->offset());
|
||||||
PTR ptr = meet_ptr(tp->ptr());
|
PTR ptr = meet_ptr(tp->ptr());
|
||||||
int instance_id = meet_instance_id(tp->instance_id());
|
int instance_id = meet_instance_id(tp->instance_id());
|
||||||
const TypeOopPtr* speculative = xmeet_speculative(tp);
|
const TypePtr* speculative = xmeet_speculative(tp);
|
||||||
int depth = meet_inline_depth(tp->inline_depth());
|
int depth = meet_inline_depth(tp->inline_depth());
|
||||||
switch (ptr) {
|
switch (ptr) {
|
||||||
case TopPTR:
|
case TopPTR:
|
||||||
@ -3346,7 +3493,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
|
|||||||
case TopPTR:
|
case TopPTR:
|
||||||
case AnyNull: {
|
case AnyNull: {
|
||||||
int instance_id = meet_instance_id(InstanceTop);
|
int instance_id = meet_instance_id(InstanceTop);
|
||||||
const TypeOopPtr* speculative = xmeet_speculative(tp);
|
const TypePtr* speculative = xmeet_speculative(tp);
|
||||||
int depth = meet_inline_depth(tp->inline_depth());
|
int depth = meet_inline_depth(tp->inline_depth());
|
||||||
return make(ptr, klass(), klass_is_exact(),
|
return make(ptr, klass(), klass_is_exact(),
|
||||||
(ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, depth);
|
(ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, depth);
|
||||||
@ -3354,7 +3501,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
|
|||||||
case NotNull:
|
case NotNull:
|
||||||
case BotPTR: {
|
case BotPTR: {
|
||||||
int instance_id = meet_instance_id(tp->instance_id());
|
int instance_id = meet_instance_id(tp->instance_id());
|
||||||
const TypeOopPtr* speculative = xmeet_speculative(tp);
|
const TypePtr* speculative = xmeet_speculative(tp);
|
||||||
int depth = meet_inline_depth(tp->inline_depth());
|
int depth = meet_inline_depth(tp->inline_depth());
|
||||||
return TypeOopPtr::make(ptr, offset, instance_id, speculative, depth);
|
return TypeOopPtr::make(ptr, offset, instance_id, speculative, depth);
|
||||||
}
|
}
|
||||||
@ -3367,20 +3514,21 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
|
|||||||
const TypePtr *tp = t->is_ptr();
|
const TypePtr *tp = t->is_ptr();
|
||||||
int offset = meet_offset(tp->offset());
|
int offset = meet_offset(tp->offset());
|
||||||
PTR ptr = meet_ptr(tp->ptr());
|
PTR ptr = meet_ptr(tp->ptr());
|
||||||
|
int instance_id = meet_instance_id(InstanceTop);
|
||||||
|
const TypePtr* speculative = xmeet_speculative(tp);
|
||||||
|
int depth = meet_inline_depth(tp->inline_depth());
|
||||||
switch (tp->ptr()) {
|
switch (tp->ptr()) {
|
||||||
case Null:
|
case Null:
|
||||||
if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset);
|
if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, speculative, depth);
|
||||||
// else fall through to AnyNull
|
// else fall through to AnyNull
|
||||||
case TopPTR:
|
case TopPTR:
|
||||||
case AnyNull: {
|
case AnyNull: {
|
||||||
int instance_id = meet_instance_id(InstanceTop);
|
|
||||||
const TypeOopPtr* speculative = _speculative;
|
|
||||||
return make(ptr, klass(), klass_is_exact(),
|
return make(ptr, klass(), klass_is_exact(),
|
||||||
(ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, _inline_depth);
|
(ptr == Constant ? const_oop() : NULL), offset, instance_id, speculative, depth);
|
||||||
}
|
}
|
||||||
case NotNull:
|
case NotNull:
|
||||||
case BotPTR:
|
case BotPTR:
|
||||||
return TypePtr::make(AnyPtr, ptr, offset);
|
return TypePtr::make(AnyPtr, ptr, offset, speculative,depth);
|
||||||
default: typerr(t);
|
default: typerr(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3407,7 +3555,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
|
|||||||
int off = meet_offset( tinst->offset() );
|
int off = meet_offset( tinst->offset() );
|
||||||
PTR ptr = meet_ptr( tinst->ptr() );
|
PTR ptr = meet_ptr( tinst->ptr() );
|
||||||
int instance_id = meet_instance_id(tinst->instance_id());
|
int instance_id = meet_instance_id(tinst->instance_id());
|
||||||
const TypeOopPtr* speculative = xmeet_speculative(tinst);
|
const TypePtr* speculative = xmeet_speculative(tinst);
|
||||||
int depth = meet_inline_depth(tinst->inline_depth());
|
int depth = meet_inline_depth(tinst->inline_depth());
|
||||||
|
|
||||||
// Check for easy case; klasses are equal (and perhaps not loaded!)
|
// Check for easy case; klasses are equal (and perhaps not loaded!)
|
||||||
@ -3563,6 +3711,7 @@ const Type *TypeInstPtr::xmeet_helper(const Type *t) const {
|
|||||||
// class hierarchy - which means we have to fall to at least NotNull.
|
// class hierarchy - which means we have to fall to at least NotNull.
|
||||||
if( ptr == TopPTR || ptr == AnyNull || ptr == Constant )
|
if( ptr == TopPTR || ptr == AnyNull || ptr == Constant )
|
||||||
ptr = NotNull;
|
ptr = NotNull;
|
||||||
|
|
||||||
instance_id = InstanceBot;
|
instance_id = InstanceBot;
|
||||||
|
|
||||||
// Now we find the LCA of Java classes
|
// Now we find the LCA of Java classes
|
||||||
@ -3655,7 +3804,8 @@ void TypeInstPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
|
|||||||
|
|
||||||
//------------------------------add_offset-------------------------------------
|
//------------------------------add_offset-------------------------------------
|
||||||
const TypePtr *TypeInstPtr::add_offset(intptr_t offset) const {
|
const TypePtr *TypeInstPtr::add_offset(intptr_t offset) const {
|
||||||
return make(_ptr, klass(), klass_is_exact(), const_oop(), xadd_offset(offset), _instance_id, add_offset_speculative(offset));
|
return make(_ptr, klass(), klass_is_exact(), const_oop(), xadd_offset(offset),
|
||||||
|
_instance_id, add_offset_speculative(offset), _inline_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Type *TypeInstPtr::remove_speculative() const {
|
const Type *TypeInstPtr::remove_speculative() const {
|
||||||
@ -3663,10 +3813,11 @@ const Type *TypeInstPtr::remove_speculative() const {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth");
|
assert(_inline_depth == InlineDepthTop || _inline_depth == InlineDepthBottom, "non speculative type shouldn't have inline depth");
|
||||||
return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset, _instance_id, NULL, _inline_depth);
|
return make(_ptr, klass(), klass_is_exact(), const_oop(), _offset,
|
||||||
|
_instance_id, NULL, _inline_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
const TypeOopPtr *TypeInstPtr::with_inline_depth(int depth) const {
|
const TypePtr *TypeInstPtr::with_inline_depth(int depth) const {
|
||||||
if (!UseInlineDepthForSpeculativeTypes) {
|
if (!UseInlineDepthForSpeculativeTypes) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -3687,7 +3838,8 @@ const TypeAryPtr *TypeAryPtr::FLOATS;
|
|||||||
const TypeAryPtr *TypeAryPtr::DOUBLES;
|
const TypeAryPtr *TypeAryPtr::DOUBLES;
|
||||||
|
|
||||||
//------------------------------make-------------------------------------------
|
//------------------------------make-------------------------------------------
|
||||||
const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth) {
|
const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset,
|
||||||
|
int instance_id, const TypePtr* speculative, int inline_depth) {
|
||||||
assert(!(k == NULL && ary->_elem->isa_int()),
|
assert(!(k == NULL && ary->_elem->isa_int()),
|
||||||
"integral arrays must be pre-equipped with a class");
|
"integral arrays must be pre-equipped with a class");
|
||||||
if (!xk) xk = ary->ary_must_be_exact();
|
if (!xk) xk = ary->ary_must_be_exact();
|
||||||
@ -3697,7 +3849,9 @@ const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------make-------------------------------------------
|
//------------------------------make-------------------------------------------
|
||||||
const TypeAryPtr *TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth, bool is_autobox_cache) {
|
const TypeAryPtr *TypeAryPtr::make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset,
|
||||||
|
int instance_id, const TypePtr* speculative, int inline_depth,
|
||||||
|
bool is_autobox_cache) {
|
||||||
assert(!(k == NULL && ary->_elem->isa_int()),
|
assert(!(k == NULL && ary->_elem->isa_int()),
|
||||||
"integral arrays must be pre-equipped with a class");
|
"integral arrays must be pre-equipped with a class");
|
||||||
assert( (ptr==Constant && o) || (ptr!=Constant && !o), "" );
|
assert( (ptr==Constant && o) || (ptr!=Constant && !o), "" );
|
||||||
@ -3807,7 +3961,7 @@ const TypeAryPtr* TypeAryPtr::cast_to_stable(bool stable, int stable_dimension)
|
|||||||
|
|
||||||
const TypeAry* new_ary = TypeAry::make(elem, size(), stable);
|
const TypeAry* new_ary = TypeAry::make(elem, size(), stable);
|
||||||
|
|
||||||
return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id);
|
return make(ptr(), const_oop(), new_ary, klass(), klass_is_exact(), _offset, _instance_id, _speculative, _inline_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------stable_dimension--------------------------------
|
//-----------------------------stable_dimension--------------------------------
|
||||||
@ -3868,18 +4022,17 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
|
|||||||
int offset = meet_offset(tp->offset());
|
int offset = meet_offset(tp->offset());
|
||||||
PTR ptr = meet_ptr(tp->ptr());
|
PTR ptr = meet_ptr(tp->ptr());
|
||||||
int depth = meet_inline_depth(tp->inline_depth());
|
int depth = meet_inline_depth(tp->inline_depth());
|
||||||
|
const TypePtr* speculative = xmeet_speculative(tp);
|
||||||
switch (tp->ptr()) {
|
switch (tp->ptr()) {
|
||||||
case TopPTR:
|
case TopPTR:
|
||||||
case AnyNull: {
|
case AnyNull: {
|
||||||
int instance_id = meet_instance_id(InstanceTop);
|
int instance_id = meet_instance_id(InstanceTop);
|
||||||
const TypeOopPtr* speculative = xmeet_speculative(tp);
|
|
||||||
return make(ptr, (ptr == Constant ? const_oop() : NULL),
|
return make(ptr, (ptr == Constant ? const_oop() : NULL),
|
||||||
_ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
|
_ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
|
||||||
}
|
}
|
||||||
case BotPTR:
|
case BotPTR:
|
||||||
case NotNull: {
|
case NotNull: {
|
||||||
int instance_id = meet_instance_id(tp->instance_id());
|
int instance_id = meet_instance_id(tp->instance_id());
|
||||||
const TypeOopPtr* speculative = xmeet_speculative(tp);
|
|
||||||
return TypeOopPtr::make(ptr, offset, instance_id, speculative, depth);
|
return TypeOopPtr::make(ptr, offset, instance_id, speculative, depth);
|
||||||
}
|
}
|
||||||
default: ShouldNotReachHere();
|
default: ShouldNotReachHere();
|
||||||
@ -3891,20 +4044,21 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
|
|||||||
const TypePtr *tp = t->is_ptr();
|
const TypePtr *tp = t->is_ptr();
|
||||||
int offset = meet_offset(tp->offset());
|
int offset = meet_offset(tp->offset());
|
||||||
PTR ptr = meet_ptr(tp->ptr());
|
PTR ptr = meet_ptr(tp->ptr());
|
||||||
|
const TypePtr* speculative = xmeet_speculative(tp);
|
||||||
|
int depth = meet_inline_depth(tp->inline_depth());
|
||||||
switch (tp->ptr()) {
|
switch (tp->ptr()) {
|
||||||
case TopPTR:
|
case TopPTR:
|
||||||
return this;
|
return this;
|
||||||
case BotPTR:
|
case BotPTR:
|
||||||
case NotNull:
|
case NotNull:
|
||||||
return TypePtr::make(AnyPtr, ptr, offset);
|
return TypePtr::make(AnyPtr, ptr, offset, speculative, depth);
|
||||||
case Null:
|
case Null:
|
||||||
if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset);
|
if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, speculative, depth);
|
||||||
// else fall through to AnyNull
|
// else fall through to AnyNull
|
||||||
case AnyNull: {
|
case AnyNull: {
|
||||||
int instance_id = meet_instance_id(InstanceTop);
|
int instance_id = meet_instance_id(InstanceTop);
|
||||||
const TypeOopPtr* speculative = _speculative;
|
|
||||||
return make(ptr, (ptr == Constant ? const_oop() : NULL),
|
return make(ptr, (ptr == Constant ? const_oop() : NULL),
|
||||||
_ary, _klass, _klass_is_exact, offset, instance_id, speculative, _inline_depth);
|
_ary, _klass, _klass_is_exact, offset, instance_id, speculative, depth);
|
||||||
}
|
}
|
||||||
default: ShouldNotReachHere();
|
default: ShouldNotReachHere();
|
||||||
}
|
}
|
||||||
@ -3920,7 +4074,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
|
|||||||
const TypeAry *tary = _ary->meet_speculative(tap->_ary)->is_ary();
|
const TypeAry *tary = _ary->meet_speculative(tap->_ary)->is_ary();
|
||||||
PTR ptr = meet_ptr(tap->ptr());
|
PTR ptr = meet_ptr(tap->ptr());
|
||||||
int instance_id = meet_instance_id(tap->instance_id());
|
int instance_id = meet_instance_id(tap->instance_id());
|
||||||
const TypeOopPtr* speculative = xmeet_speculative(tap);
|
const TypePtr* speculative = xmeet_speculative(tap);
|
||||||
int depth = meet_inline_depth(tap->inline_depth());
|
int depth = meet_inline_depth(tap->inline_depth());
|
||||||
ciKlass* lazy_klass = NULL;
|
ciKlass* lazy_klass = NULL;
|
||||||
if (tary->_elem->isa_int()) {
|
if (tary->_elem->isa_int()) {
|
||||||
@ -3949,7 +4103,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
|
|||||||
// 'this' is exact and super or unrelated:
|
// 'this' is exact and super or unrelated:
|
||||||
(this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) {
|
(this->_klass_is_exact && !klass()->is_subtype_of(tap->klass())))) {
|
||||||
tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
|
tary = TypeAry::make(Type::BOTTOM, tary->_size, tary->_stable);
|
||||||
return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot);
|
return make(NotNull, NULL, tary, lazy_klass, false, off, InstanceBot, speculative, depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool xk = false;
|
bool xk = false;
|
||||||
@ -4001,7 +4155,7 @@ const Type *TypeAryPtr::xmeet_helper(const Type *t) const {
|
|||||||
int offset = meet_offset(tp->offset());
|
int offset = meet_offset(tp->offset());
|
||||||
PTR ptr = meet_ptr(tp->ptr());
|
PTR ptr = meet_ptr(tp->ptr());
|
||||||
int instance_id = meet_instance_id(tp->instance_id());
|
int instance_id = meet_instance_id(tp->instance_id());
|
||||||
const TypeOopPtr* speculative = xmeet_speculative(tp);
|
const TypePtr* speculative = xmeet_speculative(tp);
|
||||||
int depth = meet_inline_depth(tp->inline_depth());
|
int depth = meet_inline_depth(tp->inline_depth());
|
||||||
switch (ptr) {
|
switch (ptr) {
|
||||||
case TopPTR:
|
case TopPTR:
|
||||||
@ -4125,7 +4279,7 @@ const Type *TypeAryPtr::remove_speculative() const {
|
|||||||
return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, NULL, _inline_depth);
|
return make(_ptr, _const_oop, _ary->remove_speculative()->is_ary(), _klass, _klass_is_exact, _offset, _instance_id, NULL, _inline_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
const TypeOopPtr *TypeAryPtr::with_inline_depth(int depth) const {
|
const TypePtr *TypeAryPtr::with_inline_depth(int depth) const {
|
||||||
if (!UseInlineDepthForSpeculativeTypes) {
|
if (!UseInlineDepthForSpeculativeTypes) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
@ -4250,6 +4404,13 @@ const TypeNarrowOop* TypeNarrowOop::make(const TypePtr* type) {
|
|||||||
return (const TypeNarrowOop*)(new TypeNarrowOop(type))->hashcons();
|
return (const TypeNarrowOop*)(new TypeNarrowOop(type))->hashcons();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Type* TypeNarrowOop::remove_speculative() const {
|
||||||
|
return make(_ptrtype->remove_speculative()->is_ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
const Type* TypeNarrowOop::cleanup_speculative() const {
|
||||||
|
return make(_ptrtype->cleanup_speculative()->is_ptr());
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void TypeNarrowOop::dump2( Dict & d, uint depth, outputStream *st ) const {
|
void TypeNarrowOop::dump2( Dict & d, uint depth, outputStream *st ) const {
|
||||||
@ -4376,7 +4537,7 @@ const Type *TypeMetadataPtr::xmeet( const Type *t ) const {
|
|||||||
PTR ptr = meet_ptr(tp->ptr());
|
PTR ptr = meet_ptr(tp->ptr());
|
||||||
switch (tp->ptr()) {
|
switch (tp->ptr()) {
|
||||||
case Null:
|
case Null:
|
||||||
if (ptr == Null) return TypePtr::make(AnyPtr, ptr, offset);
|
if (ptr == Null) return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
|
||||||
// else fall through:
|
// else fall through:
|
||||||
case TopPTR:
|
case TopPTR:
|
||||||
case AnyNull: {
|
case AnyNull: {
|
||||||
@ -4384,7 +4545,7 @@ const Type *TypeMetadataPtr::xmeet( const Type *t ) const {
|
|||||||
}
|
}
|
||||||
case BotPTR:
|
case BotPTR:
|
||||||
case NotNull:
|
case NotNull:
|
||||||
return TypePtr::make(AnyPtr, ptr, offset);
|
return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
|
||||||
default: typerr(t);
|
default: typerr(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4698,12 +4859,12 @@ const Type *TypeKlassPtr::xmeet( const Type *t ) const {
|
|||||||
case TopPTR:
|
case TopPTR:
|
||||||
return this;
|
return this;
|
||||||
case Null:
|
case Null:
|
||||||
if( ptr == Null ) return TypePtr::make( AnyPtr, ptr, offset );
|
if( ptr == Null ) return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
|
||||||
case AnyNull:
|
case AnyNull:
|
||||||
return make( ptr, klass(), offset );
|
return make( ptr, klass(), offset );
|
||||||
case BotPTR:
|
case BotPTR:
|
||||||
case NotNull:
|
case NotNull:
|
||||||
return TypePtr::make(AnyPtr, ptr, offset);
|
return TypePtr::make(AnyPtr, ptr, offset, tp->speculative(), tp->inline_depth());
|
||||||
default: typerr(t);
|
default: typerr(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -224,7 +224,7 @@ public:
|
|||||||
}
|
}
|
||||||
// Variant that keeps the speculative part of the types
|
// Variant that keeps the speculative part of the types
|
||||||
const Type *meet_speculative(const Type *t) const {
|
const Type *meet_speculative(const Type *t) const {
|
||||||
return meet_helper(t, true);
|
return meet_helper(t, true)->cleanup_speculative();
|
||||||
}
|
}
|
||||||
// WIDEN: 'widens' for Ints and other range types
|
// WIDEN: 'widens' for Ints and other range types
|
||||||
virtual const Type *widen( const Type *old, const Type* limit ) const { return this; }
|
virtual const Type *widen( const Type *old, const Type* limit ) const { return this; }
|
||||||
@ -247,7 +247,7 @@ public:
|
|||||||
}
|
}
|
||||||
// Variant that keeps the speculative part of the types
|
// Variant that keeps the speculative part of the types
|
||||||
const Type *join_speculative(const Type *t) const {
|
const Type *join_speculative(const Type *t) const {
|
||||||
return join_helper(t, true);
|
return join_helper(t, true)->cleanup_speculative();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modified version of JOIN adapted to the needs Node::Value.
|
// Modified version of JOIN adapted to the needs Node::Value.
|
||||||
@ -259,7 +259,7 @@ public:
|
|||||||
}
|
}
|
||||||
// Variant that keeps the speculative part of the types
|
// Variant that keeps the speculative part of the types
|
||||||
const Type *filter_speculative(const Type *kills) const {
|
const Type *filter_speculative(const Type *kills) const {
|
||||||
return filter_helper(kills, true);
|
return filter_helper(kills, true)->cleanup_speculative();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
@ -414,15 +414,18 @@ public:
|
|||||||
bool require_constant = false,
|
bool require_constant = false,
|
||||||
bool is_autobox_cache = false);
|
bool is_autobox_cache = false);
|
||||||
|
|
||||||
// Speculative type. See TypeInstPtr
|
// Speculative type helper methods. See TypePtr.
|
||||||
virtual const TypeOopPtr* speculative() const { return NULL; }
|
virtual const TypePtr* speculative() const { return NULL; }
|
||||||
virtual ciKlass* speculative_type() const { return NULL; }
|
virtual ciKlass* speculative_type() const { return NULL; }
|
||||||
const Type* maybe_remove_speculative(bool include_speculative) const;
|
virtual ciKlass* speculative_type_not_null() const { return NULL; }
|
||||||
|
virtual bool speculative_maybe_null() const { return true; }
|
||||||
virtual const Type* remove_speculative() const { return this; }
|
virtual const Type* remove_speculative() const { return this; }
|
||||||
|
virtual const Type* cleanup_speculative() const { return this; }
|
||||||
|
virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const { return exact_kls != NULL; }
|
||||||
|
virtual bool would_improve_ptr(bool maybe_null) const { return !maybe_null; }
|
||||||
|
const Type* maybe_remove_speculative(bool include_speculative) const;
|
||||||
|
|
||||||
virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const {
|
virtual bool maybe_null() const { return true; }
|
||||||
return exact_kls != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// support arrays
|
// support arrays
|
||||||
@ -679,6 +682,7 @@ public:
|
|||||||
virtual const Type *xdual() const; // Compute dual right now.
|
virtual const Type *xdual() const; // Compute dual right now.
|
||||||
bool ary_must_be_exact() const; // true if arrays of such are never generic
|
bool ary_must_be_exact() const; // true if arrays of such are never generic
|
||||||
virtual const Type* remove_speculative() const;
|
virtual const Type* remove_speculative() const;
|
||||||
|
virtual const Type* cleanup_speculative() const;
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
// One type is interface, the other is oop
|
// One type is interface, the other is oop
|
||||||
virtual bool interface_vs_oop(const Type *t) const;
|
virtual bool interface_vs_oop(const Type *t) const;
|
||||||
@ -761,13 +765,48 @@ class TypePtr : public Type {
|
|||||||
public:
|
public:
|
||||||
enum PTR { TopPTR, AnyNull, Constant, Null, NotNull, BotPTR, lastPTR };
|
enum PTR { TopPTR, AnyNull, Constant, Null, NotNull, BotPTR, lastPTR };
|
||||||
protected:
|
protected:
|
||||||
TypePtr( TYPES t, PTR ptr, int offset ) : Type(t), _ptr(ptr), _offset(offset) {}
|
TypePtr(TYPES t, PTR ptr, int offset,
|
||||||
virtual bool eq( const Type *t ) const;
|
const TypePtr* speculative = NULL,
|
||||||
virtual int hash() const; // Type specific hashing
|
int inline_depth = InlineDepthBottom) :
|
||||||
|
Type(t), _ptr(ptr), _offset(offset), _speculative(speculative),
|
||||||
|
_inline_depth(inline_depth) {}
|
||||||
static const PTR ptr_meet[lastPTR][lastPTR];
|
static const PTR ptr_meet[lastPTR][lastPTR];
|
||||||
static const PTR ptr_dual[lastPTR];
|
static const PTR ptr_dual[lastPTR];
|
||||||
static const char * const ptr_msg[lastPTR];
|
static const char * const ptr_msg[lastPTR];
|
||||||
|
|
||||||
|
enum {
|
||||||
|
InlineDepthBottom = INT_MAX,
|
||||||
|
InlineDepthTop = -InlineDepthBottom
|
||||||
|
};
|
||||||
|
|
||||||
|
// Extra type information profiling gave us. We propagate it the
|
||||||
|
// same way the rest of the type info is propagated. If we want to
|
||||||
|
// use it, then we have to emit a guard: this part of the type is
|
||||||
|
// not something we know but something we speculate about the type.
|
||||||
|
const TypePtr* _speculative;
|
||||||
|
// For speculative types, we record at what inlining depth the
|
||||||
|
// profiling point that provided the data is. We want to favor
|
||||||
|
// profile data coming from outer scopes which are likely better for
|
||||||
|
// the current compilation.
|
||||||
|
int _inline_depth;
|
||||||
|
|
||||||
|
// utility methods to work on the speculative part of the type
|
||||||
|
const TypePtr* dual_speculative() const;
|
||||||
|
const TypePtr* xmeet_speculative(const TypePtr* other) const;
|
||||||
|
bool eq_speculative(const TypePtr* other) const;
|
||||||
|
int hash_speculative() const;
|
||||||
|
const TypePtr* add_offset_speculative(intptr_t offset) const;
|
||||||
|
#ifndef PRODUCT
|
||||||
|
void dump_speculative(outputStream *st) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// utility methods to work on the inline depth of the type
|
||||||
|
int dual_inline_depth() const;
|
||||||
|
int meet_inline_depth(int depth) const;
|
||||||
|
#ifndef PRODUCT
|
||||||
|
void dump_inline_depth(outputStream *st) const;
|
||||||
|
#endif
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const int _offset; // Offset into oop, with TOP & BOT
|
const int _offset; // Offset into oop, with TOP & BOT
|
||||||
const PTR _ptr; // Pointer equivalence class
|
const PTR _ptr; // Pointer equivalence class
|
||||||
@ -775,7 +814,9 @@ public:
|
|||||||
const int offset() const { return _offset; }
|
const int offset() const { return _offset; }
|
||||||
const PTR ptr() const { return _ptr; }
|
const PTR ptr() const { return _ptr; }
|
||||||
|
|
||||||
static const TypePtr *make( TYPES t, PTR ptr, int offset );
|
static const TypePtr *make(TYPES t, PTR ptr, int offset,
|
||||||
|
const TypePtr* speculative = NULL,
|
||||||
|
int inline_depth = InlineDepthBottom);
|
||||||
|
|
||||||
// Return a 'ptr' version of this type
|
// Return a 'ptr' version of this type
|
||||||
virtual const Type *cast_to_ptr_type(PTR ptr) const;
|
virtual const Type *cast_to_ptr_type(PTR ptr) const;
|
||||||
@ -784,10 +825,13 @@ public:
|
|||||||
|
|
||||||
int xadd_offset( intptr_t offset ) const;
|
int xadd_offset( intptr_t offset ) const;
|
||||||
virtual const TypePtr *add_offset( intptr_t offset ) const;
|
virtual const TypePtr *add_offset( intptr_t offset ) const;
|
||||||
|
virtual bool eq(const Type *t) const;
|
||||||
|
virtual int hash() const; // Type specific hashing
|
||||||
|
|
||||||
virtual bool singleton(void) const; // TRUE if type is a singleton
|
virtual bool singleton(void) const; // TRUE if type is a singleton
|
||||||
virtual bool empty(void) const; // TRUE if type is vacuous
|
virtual bool empty(void) const; // TRUE if type is vacuous
|
||||||
virtual const Type *xmeet( const Type *t ) const;
|
virtual const Type *xmeet( const Type *t ) const;
|
||||||
|
virtual const Type *xmeet_helper( const Type *t ) const;
|
||||||
int meet_offset( int offset ) const;
|
int meet_offset( int offset ) const;
|
||||||
int dual_offset( ) const;
|
int dual_offset( ) const;
|
||||||
virtual const Type *xdual() const; // Compute dual right now.
|
virtual const Type *xdual() const; // Compute dual right now.
|
||||||
@ -802,6 +846,20 @@ public:
|
|||||||
return ptr_dual[ ptr_meet[ ptr_dual[in_ptr] ] [ dual_ptr() ] ];
|
return ptr_dual[ ptr_meet[ ptr_dual[in_ptr] ] [ dual_ptr() ] ];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Speculative type helper methods.
|
||||||
|
virtual const TypePtr* speculative() const { return _speculative; }
|
||||||
|
int inline_depth() const { return _inline_depth; }
|
||||||
|
virtual ciKlass* speculative_type() const;
|
||||||
|
virtual ciKlass* speculative_type_not_null() const;
|
||||||
|
virtual bool speculative_maybe_null() const;
|
||||||
|
virtual const Type* remove_speculative() const;
|
||||||
|
virtual const Type* cleanup_speculative() const;
|
||||||
|
virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const;
|
||||||
|
virtual bool would_improve_ptr(bool maybe_null) const;
|
||||||
|
virtual const TypePtr* with_inline_depth(int depth) const;
|
||||||
|
|
||||||
|
virtual bool maybe_null() const { return meet_ptr(Null) == ptr(); }
|
||||||
|
|
||||||
// Tests for relation to centerline of type lattice:
|
// Tests for relation to centerline of type lattice:
|
||||||
static bool above_centerline(PTR ptr) { return (ptr <= AnyNull); }
|
static bool above_centerline(PTR ptr) { return (ptr <= AnyNull); }
|
||||||
static bool below_centerline(PTR ptr) { return (ptr >= NotNull); }
|
static bool below_centerline(PTR ptr) { return (ptr >= NotNull); }
|
||||||
@ -850,7 +908,8 @@ public:
|
|||||||
// Some kind of oop (Java pointer), either klass or instance or array.
|
// Some kind of oop (Java pointer), either klass or instance or array.
|
||||||
class TypeOopPtr : public TypePtr {
|
class TypeOopPtr : public TypePtr {
|
||||||
protected:
|
protected:
|
||||||
TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth);
|
TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id,
|
||||||
|
const TypePtr* speculative, int inline_depth);
|
||||||
public:
|
public:
|
||||||
virtual bool eq( const Type *t ) const;
|
virtual bool eq( const Type *t ) const;
|
||||||
virtual int hash() const; // Type specific hashing
|
virtual int hash() const; // Type specific hashing
|
||||||
@ -861,10 +920,6 @@ public:
|
|||||||
};
|
};
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
enum {
|
|
||||||
InlineDepthBottom = INT_MAX,
|
|
||||||
InlineDepthTop = -InlineDepthBottom
|
|
||||||
};
|
|
||||||
// Oop is NULL, unless this is a constant oop.
|
// Oop is NULL, unless this is a constant oop.
|
||||||
ciObject* _const_oop; // Constant oop
|
ciObject* _const_oop; // Constant oop
|
||||||
// If _klass is NULL, then so is _sig. This is an unloaded klass.
|
// If _klass is NULL, then so is _sig. This is an unloaded klass.
|
||||||
@ -880,38 +935,11 @@ protected:
|
|||||||
// This is the the node index of the allocation node creating this instance.
|
// This is the the node index of the allocation node creating this instance.
|
||||||
int _instance_id;
|
int _instance_id;
|
||||||
|
|
||||||
// Extra type information profiling gave us. We propagate it the
|
|
||||||
// same way the rest of the type info is propagated. If we want to
|
|
||||||
// use it, then we have to emit a guard: this part of the type is
|
|
||||||
// not something we know but something we speculate about the type.
|
|
||||||
const TypeOopPtr* _speculative;
|
|
||||||
// For speculative types, we record at what inlining depth the
|
|
||||||
// profiling point that provided the data is. We want to favor
|
|
||||||
// profile data coming from outer scopes which are likely better for
|
|
||||||
// the current compilation.
|
|
||||||
int _inline_depth;
|
|
||||||
|
|
||||||
static const TypeOopPtr* make_from_klass_common(ciKlass* klass, bool klass_change, bool try_for_exact);
|
static const TypeOopPtr* make_from_klass_common(ciKlass* klass, bool klass_change, bool try_for_exact);
|
||||||
|
|
||||||
int dual_instance_id() const;
|
int dual_instance_id() const;
|
||||||
int meet_instance_id(int uid) const;
|
int meet_instance_id(int uid) const;
|
||||||
|
|
||||||
// utility methods to work on the speculative part of the type
|
|
||||||
const TypeOopPtr* dual_speculative() const;
|
|
||||||
const TypeOopPtr* xmeet_speculative(const TypeOopPtr* other) const;
|
|
||||||
bool eq_speculative(const TypeOopPtr* other) const;
|
|
||||||
int hash_speculative() const;
|
|
||||||
const TypeOopPtr* add_offset_speculative(intptr_t offset) const;
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void dump_speculative(outputStream *st) const;
|
|
||||||
#endif
|
|
||||||
// utility methods to work on the inline depth of the type
|
|
||||||
int dual_inline_depth() const;
|
|
||||||
int meet_inline_depth(int depth) const;
|
|
||||||
#ifndef PRODUCT
|
|
||||||
void dump_inline_depth(outputStream *st) const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Do not allow interface-vs.-noninterface joins to collapse to top.
|
// Do not allow interface-vs.-noninterface joins to collapse to top.
|
||||||
virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
|
virtual const Type *filter_helper(const Type *kills, bool include_speculative) const;
|
||||||
|
|
||||||
@ -941,7 +969,9 @@ public:
|
|||||||
bool not_null_elements = false);
|
bool not_null_elements = false);
|
||||||
|
|
||||||
// Make a generic (unclassed) pointer to an oop.
|
// Make a generic (unclassed) pointer to an oop.
|
||||||
static const TypeOopPtr* make(PTR ptr, int offset, int instance_id, const TypeOopPtr* speculative = NULL, int inline_depth = InlineDepthBottom);
|
static const TypeOopPtr* make(PTR ptr, int offset, int instance_id,
|
||||||
|
const TypePtr* speculative = NULL,
|
||||||
|
int inline_depth = InlineDepthBottom);
|
||||||
|
|
||||||
ciObject* const_oop() const { return _const_oop; }
|
ciObject* const_oop() const { return _const_oop; }
|
||||||
virtual ciKlass* klass() const { return _klass; }
|
virtual ciKlass* klass() const { return _klass; }
|
||||||
@ -955,7 +985,6 @@ public:
|
|||||||
bool is_known_instance() const { return _instance_id > 0; }
|
bool is_known_instance() const { return _instance_id > 0; }
|
||||||
int instance_id() const { return _instance_id; }
|
int instance_id() const { return _instance_id; }
|
||||||
bool is_known_instance_field() const { return is_known_instance() && _offset >= 0; }
|
bool is_known_instance_field() const { return is_known_instance() && _offset >= 0; }
|
||||||
virtual const TypeOopPtr* speculative() const { return _speculative; }
|
|
||||||
|
|
||||||
virtual intptr_t get_con() const;
|
virtual intptr_t get_con() const;
|
||||||
|
|
||||||
@ -969,10 +998,13 @@ public:
|
|||||||
const TypeKlassPtr* as_klass_type() const;
|
const TypeKlassPtr* as_klass_type() const;
|
||||||
|
|
||||||
virtual const TypePtr *add_offset( intptr_t offset ) const;
|
virtual const TypePtr *add_offset( intptr_t offset ) const;
|
||||||
// Return same type without a speculative part
|
|
||||||
virtual const Type* remove_speculative() const;
|
|
||||||
|
|
||||||
virtual const Type *xmeet(const Type *t) const;
|
// Speculative type helper methods.
|
||||||
|
virtual const Type* remove_speculative() const;
|
||||||
|
virtual const Type* cleanup_speculative() const;
|
||||||
|
virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const;
|
||||||
|
virtual const TypePtr* with_inline_depth(int depth) const;
|
||||||
|
|
||||||
virtual const Type *xdual() const; // Compute dual right now.
|
virtual const Type *xdual() const; // Compute dual right now.
|
||||||
// the core of the computation of the meet for TypeOopPtr and for its subclasses
|
// the core of the computation of the meet for TypeOopPtr and for its subclasses
|
||||||
virtual const Type *xmeet_helper(const Type *t) const;
|
virtual const Type *xmeet_helper(const Type *t) const;
|
||||||
@ -982,29 +1014,14 @@ public:
|
|||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
virtual void dump2( Dict &d, uint depth, outputStream *st ) const;
|
virtual void dump2( Dict &d, uint depth, outputStream *st ) const;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Return the speculative type if any
|
|
||||||
ciKlass* speculative_type() const {
|
|
||||||
if (_speculative != NULL) {
|
|
||||||
const TypeOopPtr* speculative = _speculative->join(this)->is_oopptr();
|
|
||||||
if (speculative->klass_is_exact()) {
|
|
||||||
return speculative->klass();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
int inline_depth() const {
|
|
||||||
return _inline_depth;
|
|
||||||
}
|
|
||||||
virtual const TypeOopPtr* with_inline_depth(int depth) const;
|
|
||||||
virtual bool would_improve_type(ciKlass* exact_kls, int inline_depth) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//------------------------------TypeInstPtr------------------------------------
|
//------------------------------TypeInstPtr------------------------------------
|
||||||
// Class of Java object pointers, pointing either to non-array Java instances
|
// Class of Java object pointers, pointing either to non-array Java instances
|
||||||
// or to a Klass* (including array klasses).
|
// or to a Klass* (including array klasses).
|
||||||
class TypeInstPtr : public TypeOopPtr {
|
class TypeInstPtr : public TypeOopPtr {
|
||||||
TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id, const TypeOopPtr* speculative, int inline_depth);
|
TypeInstPtr(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id,
|
||||||
|
const TypePtr* speculative, int inline_depth);
|
||||||
virtual bool eq( const Type *t ) const;
|
virtual bool eq( const Type *t ) const;
|
||||||
virtual int hash() const; // Type specific hashing
|
virtual int hash() const; // Type specific hashing
|
||||||
|
|
||||||
@ -1040,7 +1057,10 @@ class TypeInstPtr : public TypeOopPtr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Make a pointer to an oop.
|
// Make a pointer to an oop.
|
||||||
static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL, int inline_depth = InlineDepthBottom);
|
static const TypeInstPtr *make(PTR ptr, ciKlass* k, bool xk, ciObject* o, int offset,
|
||||||
|
int instance_id = InstanceBot,
|
||||||
|
const TypePtr* speculative = NULL,
|
||||||
|
int inline_depth = InlineDepthBottom);
|
||||||
|
|
||||||
/** Create constant type for a constant boxed value */
|
/** Create constant type for a constant boxed value */
|
||||||
const Type* get_const_boxed_value() const;
|
const Type* get_const_boxed_value() const;
|
||||||
@ -1057,9 +1077,10 @@ class TypeInstPtr : public TypeOopPtr {
|
|||||||
virtual const TypeOopPtr *cast_to_instance_id(int instance_id) const;
|
virtual const TypeOopPtr *cast_to_instance_id(int instance_id) const;
|
||||||
|
|
||||||
virtual const TypePtr *add_offset( intptr_t offset ) const;
|
virtual const TypePtr *add_offset( intptr_t offset ) const;
|
||||||
// Return same type without a speculative part
|
|
||||||
|
// Speculative type helper methods.
|
||||||
virtual const Type* remove_speculative() const;
|
virtual const Type* remove_speculative() const;
|
||||||
virtual const TypeOopPtr* with_inline_depth(int depth) const;
|
virtual const TypePtr* with_inline_depth(int depth) const;
|
||||||
|
|
||||||
// the core of the computation of the meet of 2 types
|
// the core of the computation of the meet of 2 types
|
||||||
virtual const Type *xmeet_helper(const Type *t) const;
|
virtual const Type *xmeet_helper(const Type *t) const;
|
||||||
@ -1081,7 +1102,8 @@ class TypeInstPtr : public TypeOopPtr {
|
|||||||
// Class of Java array pointers
|
// Class of Java array pointers
|
||||||
class TypeAryPtr : public TypeOopPtr {
|
class TypeAryPtr : public TypeOopPtr {
|
||||||
TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk,
|
TypeAryPtr( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk,
|
||||||
int offset, int instance_id, bool is_autobox_cache, const TypeOopPtr* speculative, int inline_depth)
|
int offset, int instance_id, bool is_autobox_cache,
|
||||||
|
const TypePtr* speculative, int inline_depth)
|
||||||
: TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id, speculative, inline_depth),
|
: TypeOopPtr(AryPtr,ptr,k,xk,o,offset, instance_id, speculative, inline_depth),
|
||||||
_ary(ary),
|
_ary(ary),
|
||||||
_is_autobox_cache(is_autobox_cache)
|
_is_autobox_cache(is_autobox_cache)
|
||||||
@ -1120,9 +1142,15 @@ public:
|
|||||||
|
|
||||||
bool is_autobox_cache() const { return _is_autobox_cache; }
|
bool is_autobox_cache() const { return _is_autobox_cache; }
|
||||||
|
|
||||||
static const TypeAryPtr *make( PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL, int inline_depth = InlineDepthBottom);
|
static const TypeAryPtr *make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset,
|
||||||
|
int instance_id = InstanceBot,
|
||||||
|
const TypePtr* speculative = NULL,
|
||||||
|
int inline_depth = InlineDepthBottom);
|
||||||
// Constant pointer to array
|
// Constant pointer to array
|
||||||
static const TypeAryPtr *make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot, const TypeOopPtr* speculative = NULL, int inline_depth = InlineDepthBottom, bool is_autobox_cache= false);
|
static const TypeAryPtr *make(PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset,
|
||||||
|
int instance_id = InstanceBot,
|
||||||
|
const TypePtr* speculative = NULL,
|
||||||
|
int inline_depth = InlineDepthBottom, bool is_autobox_cache = false);
|
||||||
|
|
||||||
// Return a 'ptr' version of this type
|
// Return a 'ptr' version of this type
|
||||||
virtual const Type *cast_to_ptr_type(PTR ptr) const;
|
virtual const Type *cast_to_ptr_type(PTR ptr) const;
|
||||||
@ -1136,9 +1164,10 @@ public:
|
|||||||
|
|
||||||
virtual bool empty(void) const; // TRUE if type is vacuous
|
virtual bool empty(void) const; // TRUE if type is vacuous
|
||||||
virtual const TypePtr *add_offset( intptr_t offset ) const;
|
virtual const TypePtr *add_offset( intptr_t offset ) const;
|
||||||
// Return same type without a speculative part
|
|
||||||
|
// Speculative type helper methods.
|
||||||
virtual const Type* remove_speculative() const;
|
virtual const Type* remove_speculative() const;
|
||||||
virtual const TypeOopPtr* with_inline_depth(int depth) const;
|
virtual const TypePtr* with_inline_depth(int depth) const;
|
||||||
|
|
||||||
// the core of the computation of the meet of 2 types
|
// the core of the computation of the meet of 2 types
|
||||||
virtual const Type *xmeet_helper(const Type *t) const;
|
virtual const Type *xmeet_helper(const Type *t) const;
|
||||||
@ -1367,9 +1396,8 @@ public:
|
|||||||
static const TypeNarrowOop *BOTTOM;
|
static const TypeNarrowOop *BOTTOM;
|
||||||
static const TypeNarrowOop *NULL_PTR;
|
static const TypeNarrowOop *NULL_PTR;
|
||||||
|
|
||||||
virtual const Type* remove_speculative() const {
|
virtual const Type* remove_speculative() const;
|
||||||
return make(_ptrtype->remove_speculative()->is_ptr());
|
virtual const Type* cleanup_speculative() const;
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
virtual void dump2( Dict &d, uint depth, outputStream *st ) const;
|
virtual void dump2( Dict &d, uint depth, outputStream *st ) const;
|
||||||
|
@ -254,18 +254,24 @@
|
|||||||
# include "opto/block.hpp"
|
# include "opto/block.hpp"
|
||||||
# include "opto/c2_globals.hpp"
|
# include "opto/c2_globals.hpp"
|
||||||
# include "opto/callnode.hpp"
|
# include "opto/callnode.hpp"
|
||||||
|
# include "opto/castnode.hpp"
|
||||||
# include "opto/cfgnode.hpp"
|
# include "opto/cfgnode.hpp"
|
||||||
# include "opto/compile.hpp"
|
# include "opto/compile.hpp"
|
||||||
# include "opto/connode.hpp"
|
# include "opto/connode.hpp"
|
||||||
|
# include "opto/convertnode.hpp"
|
||||||
|
# include "opto/countbitsnode.hpp"
|
||||||
# include "opto/idealGraphPrinter.hpp"
|
# include "opto/idealGraphPrinter.hpp"
|
||||||
|
# include "opto/intrinsicnode.hpp"
|
||||||
# include "opto/loopnode.hpp"
|
# include "opto/loopnode.hpp"
|
||||||
# include "opto/machnode.hpp"
|
# include "opto/machnode.hpp"
|
||||||
# include "opto/matcher.hpp"
|
# include "opto/matcher.hpp"
|
||||||
# include "opto/memnode.hpp"
|
# include "opto/memnode.hpp"
|
||||||
|
# include "opto/movenode.hpp"
|
||||||
# include "opto/mulnode.hpp"
|
# include "opto/mulnode.hpp"
|
||||||
# include "opto/multnode.hpp"
|
# include "opto/multnode.hpp"
|
||||||
# include "opto/node.hpp"
|
# include "opto/narrowptrnode.hpp"
|
||||||
# include "opto/opcodes.hpp"
|
# include "opto/opcodes.hpp"
|
||||||
|
# include "opto/opaquenode.hpp"
|
||||||
# include "opto/optoreg.hpp"
|
# include "opto/optoreg.hpp"
|
||||||
# include "opto/phase.hpp"
|
# include "opto/phase.hpp"
|
||||||
# include "opto/phaseX.hpp"
|
# include "opto/phaseX.hpp"
|
||||||
|
@ -4005,7 +4005,7 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, v
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
#ifndef TARGET_OS_FAMILY_windows
|
#ifndef CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED
|
||||||
#define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) f()
|
#define CALL_TEST_FUNC_WITH_WRAPPER_IF_NEEDED(f) f()
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user