--- a/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/agent/src/os/linux/LinuxDebuggerLocal.c Thu Dec 10 18:55:58 2015 +0000
@@ -223,9 +223,12 @@
verifyBitness(env, (char *) &buf);
CHECK_EXCEPTION;
+ char err_buf[200];
struct ps_prochandle* ph;
- if ( (ph = Pgrab(jpid)) == NULL) {
- THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the process");
+ if ( (ph = Pgrab(jpid, err_buf, sizeof(err_buf))) == NULL) {
+ char msg[230];
+ snprintf(msg, sizeof(msg), "Can't attach to the process: %s", err_buf);
+ THROW_NEW_DEBUGGER_EXCEPTION(msg);
}
(*env)->SetLongField(env, this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph);
fillThreadsAndLoadObjects(env, this_obj, ph);
--- a/hotspot/agent/src/os/linux/libproc.h Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/agent/src/os/linux/libproc.h Thu Dec 10 18:55:58 2015 +0000
@@ -86,7 +86,7 @@
struct ps_prochandle;
// attach to a process
-struct ps_prochandle* Pgrab(pid_t pid);
+struct ps_prochandle* Pgrab(pid_t pid, char* err_buf, size_t err_buf_len);
// attach to a core dump
struct ps_prochandle* Pgrab_core(const char* execfile, const char* corefile);
--- a/hotspot/agent/src/os/linux/ps_proc.c Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/agent/src/os/linux/ps_proc.c Thu Dec 10 18:55:58 2015 +0000
@@ -215,9 +215,12 @@
}
// attach to a process/thread specified by "pid"
-static bool ptrace_attach(pid_t pid) {
+static bool ptrace_attach(pid_t pid, char* err_buf, size_t err_buf_len) {
if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
- print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid);
+ char buf[200];
+ char* msg = strerror_r(errno, buf, sizeof(buf));
+ snprintf(err_buf, err_buf_len, "ptrace(PTRACE_ATTACH, ..) failed for %d: %s", pid, msg);
+ print_debug("%s\n", err_buf);
return false;
} else {
return ptrace_waitpid(pid);
@@ -370,16 +373,17 @@
};
// attach to the process. One and only one exposed stuff
-struct ps_prochandle* Pgrab(pid_t pid) {
+struct ps_prochandle* Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) {
struct ps_prochandle* ph = NULL;
thread_info* thr = NULL;
if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) {
- print_debug("can't allocate memory for ps_prochandle\n");
+ snprintf(err_buf, err_buf_len, "can't allocate memory for ps_prochandle");
+ print_debug("%s\n", err_buf);
return NULL;
}
- if (ptrace_attach(pid) != true) {
+ if (ptrace_attach(pid, err_buf, err_buf_len) != true) {
free(ph);
return NULL;
}
@@ -402,7 +406,7 @@
thr = ph->threads;
while (thr) {
// don't attach to the main thread again
- if (ph->pid != thr->lwp_id && ptrace_attach(thr->lwp_id) != true) {
+ if (ph->pid != thr->lwp_id && ptrace_attach(thr->lwp_id, err_buf, err_buf_len) != true) {
// even if one attach fails, we get return NULL
Prelease(ph);
return NULL;
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/CommandProcessor.java Thu Dec 10 18:55:58 2015 +0000
@@ -1446,7 +1446,7 @@
if (type.equals("threads")) {
Threads threads = VM.getVM().getThreads();
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
- Address base = thread.getBaseOfStackPointer();
+ Address base = thread.getStackBase();
Address end = thread.getLastJavaSP();
if (end == null) continue;
if (end.lessThan(base)) {
@@ -1454,11 +1454,13 @@
base = end;
end = tmp;
}
- out.println("Searching " + base + " " + end);
+ //out.println("Searching " + base + " " + end);
while (base != null && base.lessThan(end)) {
Address val = base.getAddressAt(0);
if (AddressOps.equal(val, value)) {
- out.println(base);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ thread.printThreadIDOn(new PrintStream(bos));
+ out.println("found on the stack of thread " + bos.toString() + " at " + base);
}
base = base.addOffsetTo(stride);
}
@@ -1601,6 +1603,8 @@
thread.printThreadIDOn(new PrintStream(bos));
if (all || bos.toString().equals(name)) {
out.println("Thread " + bos.toString() + " Address " + thread.getAddress());
+ thread.printInfoOn(out);
+ out.println(" ");
if (!all) return;
}
}
@@ -1618,6 +1622,8 @@
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
thread.printThreadIDOn(out);
out.println(" " + thread.getThreadName());
+ thread.printInfoOn(out);
+ out.println("\n...");
}
}
}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/HSDB.java Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/HSDB.java Thu Dec 10 18:55:58 2015 +0000
@@ -125,10 +125,14 @@
}
}
- // close this tool without calling System.exit
- protected void closeUI() {
- workerThread.shutdown();
- frame.dispose();
+ private class CloseUI extends WindowAdapter {
+
+ @Override
+ public void windowClosing(WindowEvent e) {
+ workerThread.shutdown();
+ frame.dispose();
+ }
+
}
public void run() {
@@ -144,7 +148,8 @@
frame = new JFrame("HSDB - HotSpot Debugger");
frame.setSize(800, 600);
- frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+ frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
+ frame.addWindowListener(new CloseUI());
JMenuBar menuBar = new JMenuBar();
@@ -207,7 +212,8 @@
item = createMenuItem("Exit",
new ActionListener() {
public void actionPerformed(ActionEvent e) {
- closeUI();
+ workerThread.shutdown();
+ frame.dispose();
}
});
item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, ActionEvent.ALT_MASK));
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/runtime/JavaThread.java Thu Dec 10 18:55:58 2015 +0000
@@ -416,7 +416,7 @@
} else {
tty.println("No Java frames present");
}
- tty.println("Base of Stack: " + getBaseOfStackPointer());
+ tty.println("Base of Stack: " + getStackBase());
tty.println("Last_Java_SP: " + getLastJavaSP());
tty.println("Last_Java_FP: " + getLastJavaFP());
tty.println("Last_Java_PC: " + getLastJavaPC());
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/ui/classbrowser/HTMLGenerator.java Thu Dec 10 18:55:58 2015 +0000
@@ -1921,6 +1921,15 @@
buf.link(genPCHref(addressToLong(pc)), pc.toString());
}
+ if (!method.isStatic() && !method.isNative()) {
+ OopHandle oopHandle = vf.getLocals().oopHandleAt(0);
+
+ if (oopHandle != null) {
+ buf.append(", oop = ");
+ buf.append(oopHandle.toString());
+ }
+ }
+
if (vf.isCompiledFrame()) {
buf.append(" (Compiled");
}
--- a/hotspot/make/linux/makefiles/gcc.make Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/make/linux/makefiles/gcc.make Thu Dec 10 18:55:58 2015 +0000
@@ -261,7 +261,11 @@
OPT_CFLAGS = $(OPT_CFLAGS/$(OPT_CFLAGS_DEFAULT)) $(OPT_EXTRAS)
# Variable tracking size limit exceeded for VMStructs::init()
-OPT_CFLAGS/vmStructs.o += -fno-var-tracking-assignments
+ifeq "$(shell expr \( $(CC_VER_MAJOR) \> 4 \) \| \( \( $(CC_VER_MAJOR) = 4 \) \& \( $(CC_VER_MINOR) \>= 3 \) \))" "1"
+ # GCC >= 4.3
+ # Gcc 4.1.2 does not support this flag, nor does it have problems compiling the file.
+ OPT_CFLAGS/vmStructs.o += -fno-var-tracking-assignments
+endif
# The gcc compiler segv's on ia64 when compiling bytecodeInterpreter.cpp
# if we use expensive-optimizations
--- a/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/cpu/aarch64/vm/stubGenerator_aarch64.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -1973,7 +1973,7 @@
// c_rarg4 - input length
//
// Output:
- // rax - input length
+ // x0 - input length
//
address generate_cipherBlockChaining_decryptAESCrypt() {
assert(UseAES, "need AES instructions and misaligned SSE support");
@@ -2035,7 +2035,7 @@
__ br(Assembler::EQ, L_rounds_52);
__ aesd(v0, v17); __ aesimc(v0, v0);
- __ aesd(v0, v17); __ aesimc(v0, v0);
+ __ aesd(v0, v18); __ aesimc(v0, v0);
__ BIND(L_rounds_52);
__ aesd(v0, v19); __ aesimc(v0, v0);
__ aesd(v0, v20); __ aesimc(v0, v0);
--- a/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/cpu/sparc/vm/nativeInst_sparc.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -433,7 +433,7 @@
void NativeMovConstReg32::print() {
- tty->print_cr(INTPTR_FORMAT ": mov reg, " INTPTR_FORMAT, instruction_address(), data());
+ tty->print_cr(INTPTR_FORMAT ": mov reg, " INTPTR_FORMAT, p2i(instruction_address()), data());
}
--- a/hotspot/src/cpu/sparc/vm/sparc.ad Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/cpu/sparc/vm/sparc.ad Thu Dec 10 18:55:58 2015 +0000
@@ -1651,6 +1651,7 @@
#endif // !_LP64
Unimplemented();
+ return 0;
}
#ifndef PRODUCT
--- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -35,7 +35,10 @@
unsigned int VM_Version::_L2_data_cache_line_size = 0;
void VM_Version::initialize() {
- _features = determine_features();
+
+ assert(_features != VM_Version::unknown_m, "System pre-initialization is not complete.");
+ guarantee(VM_Version::has_v9(), "only SPARC v9 is supported");
+
PrefetchCopyIntervalInBytes = prefetch_copy_interval_in_bytes();
PrefetchScanIntervalInBytes = prefetch_scan_interval_in_bytes();
PrefetchFieldsAhead = prefetch_fields_ahead();
@@ -60,8 +63,6 @@
FLAG_SET_DEFAULT(AllocatePrefetchStyle, 1);
}
- guarantee(VM_Version::has_v9(), "only SPARC v9 is supported");
-
UseSSE = 0; // Only on x86 and x64
_supports_cx8 = has_v9();
--- a/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/cpu/sparc/vm/vm_version_sparc.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -127,6 +127,8 @@
// Initialization
static void initialize();
+ static void init_before_ergo() { _features = determine_features(); }
+
// Instruction support
static bool has_v8() { return (_features & v8_instructions_m) != 0; }
static bool has_v9() { return (_features & v9_instructions_m) != 0; }
--- a/hotspot/src/os/aix/vm/os_aix.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/os/aix/vm/os_aix.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -3431,8 +3431,12 @@
}
} else if (os::Aix::get_our_sigflags(sig) != 0 && (int)act.sa_flags != os::Aix::get_our_sigflags(sig)) {
tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN));
- tty->print("expected:" PTR32_FORMAT, os::Aix::get_our_sigflags(sig));
- tty->print_cr(" found:" PTR32_FORMAT, act.sa_flags);
+ tty->print("expected:");
+ os::Posix::print_sa_flags(tty, os::Aix::get_our_sigflags(sig));
+ tty->cr();
+ tty->print(" found:");
+ os::Posix::print_sa_flags(tty, act.sa_flags);
+ tty->cr();
// No need to check this sig any longer
sigaddset(&check_signal_done, sig);
}
--- a/hotspot/src/os/bsd/vm/os_bsd.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/os/bsd/vm/os_bsd.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -3382,8 +3382,12 @@
}
} else if(os::Bsd::get_our_sigflags(sig) != 0 && (int)act.sa_flags != os::Bsd::get_our_sigflags(sig)) {
tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN));
- tty->print("expected:" PTR32_FORMAT, os::Bsd::get_our_sigflags(sig));
- tty->print_cr(" found:" PTR32_FORMAT, act.sa_flags);
+ tty->print("expected:");
+ os::Posix::print_sa_flags(tty, os::Bsd::get_our_sigflags(sig));
+ tty->cr();
+ tty->print(" found:");
+ os::Posix::print_sa_flags(tty, act.sa_flags);
+ tty->cr();
// No need to check this sig any longer
sigaddset(&check_signal_done, sig);
}
--- a/hotspot/src/os/linux/vm/os_linux.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -4533,8 +4533,12 @@
}
} else if(os::Linux::get_our_sigflags(sig) != 0 && (int)act.sa_flags != os::Linux::get_our_sigflags(sig)) {
tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN));
- tty->print("expected:" PTR32_FORMAT, os::Linux::get_our_sigflags(sig));
- tty->print_cr(" found:" PTR32_FORMAT, act.sa_flags);
+ tty->print("expected:");
+ os::Posix::print_sa_flags(tty, os::Linux::get_our_sigflags(sig));
+ tty->cr();
+ tty->print(" found:");
+ os::Posix::print_sa_flags(tty, act.sa_flags);
+ tty->cr();
// No need to check this sig any longer
sigaddset(&check_signal_done, sig);
}
--- a/hotspot/src/os/posix/vm/os_posix.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/os/posix/vm/os_posix.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -736,12 +736,12 @@
}
// Returns:
-// "invalid (<num>)" for an invalid signal number
+// NULL for an invalid signal number
// "SIG<num>" for a valid but unknown signal number
// signal name otherwise.
const char* os::exception_name(int sig, char* buf, size_t size) {
if (!os::Posix::is_valid_signal(sig)) {
- jio_snprintf(buf, size, "invalid (%d)", sig);
+ return NULL;
}
const char* const name = os::Posix::get_signal_name(sig, buf, size);
if (strcmp(name, "UNKNOWN") == 0) {
--- a/hotspot/src/os/solaris/vm/os_solaris.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/os/solaris/vm/os_solaris.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -4058,8 +4058,12 @@
}
} else if(os::Solaris::get_our_sigflags(sig) != 0 && act.sa_flags != os::Solaris::get_our_sigflags(sig)) {
tty->print("Warning: %s handler flags ", exception_name(sig, buf, O_BUFLEN));
- tty->print("expected:" PTR32_FORMAT, os::Solaris::get_our_sigflags(sig));
- tty->print_cr(" found:" PTR32_FORMAT, act.sa_flags);
+ tty->print("expected:");
+ os::Posix::print_sa_flags(tty, os::Solaris::get_our_sigflags(sig));
+ tty->cr();
+ tty->print(" found:");
+ os::Posix::print_sa_flags(tty, act.sa_flags);
+ tty->cr();
// No need to check this sig any longer
sigaddset(&check_signal_done, sig);
}
--- a/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/os_cpu/aix_ppc/vm/os_aix_ppc.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -28,6 +28,7 @@
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "interpreter/interpreter.hpp"
--- a/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -27,6 +27,7 @@
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "interpreter/interpreter.hpp"
--- a/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/os_cpu/linux_aarch64/vm/os_linux_aarch64.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -28,6 +28,7 @@
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "code/nativeInst.hpp"
--- a/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/os_cpu/linux_ppc/vm/os_linux_ppc.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -28,6 +28,7 @@
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "interpreter/interpreter.hpp"
--- a/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -27,6 +27,7 @@
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "interpreter/interpreter.hpp"
@@ -347,9 +348,9 @@
}
void os::Linux::ucontext_set_pc(ucontext_t* uc, address pc) {
- sigcontext_t* ctx = (sigcontext_t*) uc;
- SIG_PC(ctx) = (intptr_t)addr;
- SIG_NPC(ctx) = (intptr_t)(addr+4);
+ sigcontext* ctx = (sigcontext*) uc;
+ SIG_PC(ctx) = (intptr_t)pc;
+ SIG_NPC(ctx) = (intptr_t)(pc+4);
}
intptr_t* os::Linux::ucontext_get_sp(ucontext_t *uc) {
@@ -695,6 +696,7 @@
VMError::report_and_die(t, sig, pc, info, ucVoid);
ShouldNotReachHere();
+ return false;
}
void os::Linux::init_thread_fpu_state(void) {
--- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -27,6 +27,7 @@
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "interpreter/interpreter.hpp"
--- a/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/os_cpu/solaris_sparc/vm/os_solaris_sparc.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -551,6 +551,7 @@
VMError::report_and_die(t, sig, pc, info, ucVoid);
ShouldNotReachHere();
+ return false;
}
void os::print_context(outputStream *st, void *context) {
--- a/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/os_cpu/solaris_x86/vm/os_solaris_x86.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -27,6 +27,7 @@
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
#include "interpreter/interpreter.hpp"
--- a/hotspot/src/share/vm/classfile/classFileError.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/classFileError.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -33,28 +33,39 @@
PRAGMA_DIAG_PUSH
PRAGMA_FORMAT_NONLITERAL_IGNORED
-void ClassFileParser::classfile_parse_error(const char* msg, TRAPS) {
- ResourceMark rm(THREAD);
- Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(),
- msg, _class_name->as_C_string());
+void ClassFileParser::classfile_parse_error(const char* msg, TRAPS) const {
+ assert(_class_name != NULL, "invariant");
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(),
+ msg, _class_name->as_C_string());
+}
+
+void ClassFileParser::classfile_parse_error(const char* msg,
+ int index,
+ TRAPS) const {
+ assert(_class_name != NULL, "invariant");
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(),
+ msg, index, _class_name->as_C_string());
}
-void ClassFileParser::classfile_parse_error(const char* msg, int index, TRAPS) {
- ResourceMark rm(THREAD);
- Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(),
- msg, index, _class_name->as_C_string());
+void ClassFileParser::classfile_parse_error(const char* msg,
+ const char* name,
+ TRAPS) const {
+ assert(_class_name != NULL, "invariant");
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(),
+ msg, name, _class_name->as_C_string());
}
-void ClassFileParser::classfile_parse_error(const char* msg, const char *name, TRAPS) {
- ResourceMark rm(THREAD);
- Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(),
- msg, name, _class_name->as_C_string());
-}
-
-void ClassFileParser::classfile_parse_error(const char* msg, int index, const char *name, TRAPS) {
- ResourceMark rm(THREAD);
- Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(),
- msg, index, name, _class_name->as_C_string());
+void ClassFileParser::classfile_parse_error(const char* msg,
+ int index,
+ const char* name,
+ TRAPS) const {
+ assert(_class_name != NULL, "invariant");
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_ClassFormatError(),
+ msg, index, name, _class_name->as_C_string());
}
PRAGMA_DIAG_POP
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -21,9 +21,9 @@
* questions.
*
*/
-
#include "precompiled.hpp"
#include "classfile/classFileParser.hpp"
+#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/defaultMethods.hpp"
@@ -37,16 +37,17 @@
#include "memory/allocation.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/oopFactory.hpp"
-#include "memory/referenceType.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.inline.hpp"
-#include "oops/constantPool.hpp"
+#include "oops/annotations.hpp"
#include "oops/fieldStreams.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/instanceMirrorKlass.hpp"
#include "oops/klass.inline.hpp"
#include "oops/klassVtable.hpp"
+#include "oops/metadata.hpp"
#include "oops/method.hpp"
+#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "prims/jvm.h"
#include "prims/jvmtiExport.hpp"
@@ -58,6 +59,7 @@
#include "runtime/timer.hpp"
#include "services/classLoadingService.hpp"
#include "services/threadService.hpp"
+#include "trace/traceMacros.hpp"
#include "utilities/array.hpp"
#include "utilities/exceptions.hpp"
#include "utilities/globalDefinitions.hpp"
@@ -98,20 +100,25 @@
// Extension method support.
#define JAVA_8_VERSION 52
-void ClassFileParser::parse_constant_pool_entries(int length, TRAPS) {
+enum { LegalClass, LegalField, LegalMethod }; // used to verify unqualified names
+
+void ClassFileParser::parse_constant_pool_entries(const ClassFileStream* const stream,
+ ConstantPool* cp,
+ const int length,
+ TRAPS) {
+ assert(stream != NULL, "invariant");
+ assert(cp != NULL, "invariant");
+
// Use a local copy of ClassFileStream. It helps the C++ compiler to optimize
// this function (_current can be allocated in a register, with scalar
// replacement of aggregates). The _current pointer is copied back to
// stream() when this function returns. DON'T call another method within
// this method that uses stream().
- ClassFileStream* cfs0 = stream();
- ClassFileStream cfs1 = *cfs0;
- ClassFileStream* cfs = &cfs1;
-#ifdef ASSERT
- assert(cfs->allocated_on_stack(),"should be local");
- u1* old_current = cfs0->current();
-#endif
- Handle class_loader(THREAD, _loader_data->class_loader());
+ const ClassFileStream cfs1 = *stream;
+ const ClassFileStream* const cfs = &cfs1;
+
+ assert(cfs->allocated_on_stack(), "should be local");
+ debug_only(const u1* const old_current = stream->current();)
// Used for batching symbol allocations.
const char* names[SymbolTable::symbol_alloc_batch_size];
@@ -125,48 +132,43 @@
// Each of the following case guarantees one more byte in the stream
// for the following tag or the access_flags following constant pool,
// so we don't need bounds-check for reading tag.
- u1 tag = cfs->get_u1_fast();
+ const u1 tag = cfs->get_u1_fast();
switch (tag) {
- case JVM_CONSTANT_Class :
- {
- cfs->guarantee_more(3, CHECK); // name_index, tag/access_flags
- u2 name_index = cfs->get_u2_fast();
- _cp->klass_index_at_put(index, name_index);
- }
+ case JVM_CONSTANT_Class : {
+ cfs->guarantee_more(3, CHECK); // name_index, tag/access_flags
+ const u2 name_index = cfs->get_u2_fast();
+ cp->klass_index_at_put(index, name_index);
break;
- case JVM_CONSTANT_Fieldref :
- {
- cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags
- u2 class_index = cfs->get_u2_fast();
- u2 name_and_type_index = cfs->get_u2_fast();
- _cp->field_at_put(index, class_index, name_and_type_index);
- }
+ }
+ case JVM_CONSTANT_Fieldref: {
+ cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags
+ const u2 class_index = cfs->get_u2_fast();
+ const u2 name_and_type_index = cfs->get_u2_fast();
+ cp->field_at_put(index, class_index, name_and_type_index);
break;
- case JVM_CONSTANT_Methodref :
- {
- cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags
- u2 class_index = cfs->get_u2_fast();
- u2 name_and_type_index = cfs->get_u2_fast();
- _cp->method_at_put(index, class_index, name_and_type_index);
- }
+ }
+ case JVM_CONSTANT_Methodref: {
+ cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags
+ const u2 class_index = cfs->get_u2_fast();
+ const u2 name_and_type_index = cfs->get_u2_fast();
+ cp->method_at_put(index, class_index, name_and_type_index);
break;
- case JVM_CONSTANT_InterfaceMethodref :
- {
- cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags
- u2 class_index = cfs->get_u2_fast();
- u2 name_and_type_index = cfs->get_u2_fast();
- _cp->interface_method_at_put(index, class_index, name_and_type_index);
- }
+ }
+ case JVM_CONSTANT_InterfaceMethodref: {
+ cfs->guarantee_more(5, CHECK); // class_index, name_and_type_index, tag/access_flags
+ const u2 class_index = cfs->get_u2_fast();
+ const u2 name_and_type_index = cfs->get_u2_fast();
+ cp->interface_method_at_put(index, class_index, name_and_type_index);
break;
- case JVM_CONSTANT_String :
- {
- cfs->guarantee_more(3, CHECK); // string_index, tag/access_flags
- u2 string_index = cfs->get_u2_fast();
- _cp->string_index_at_put(index, string_index);
- }
+ }
+ case JVM_CONSTANT_String : {
+ cfs->guarantee_more(3, CHECK); // string_index, tag/access_flags
+ const u2 string_index = cfs->get_u2_fast();
+ cp->string_index_at_put(index, string_index);
break;
+ }
case JVM_CONSTANT_MethodHandle :
- case JVM_CONSTANT_MethodType :
+ case JVM_CONSTANT_MethodType: {
if (_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
classfile_parse_error(
"Class file version does not support constant tag %u in class file %s",
@@ -174,379 +176,401 @@
}
if (tag == JVM_CONSTANT_MethodHandle) {
cfs->guarantee_more(4, CHECK); // ref_kind, method_index, tag/access_flags
- u1 ref_kind = cfs->get_u1_fast();
- u2 method_index = cfs->get_u2_fast();
- _cp->method_handle_index_at_put(index, ref_kind, method_index);
- } else if (tag == JVM_CONSTANT_MethodType) {
+ const u1 ref_kind = cfs->get_u1_fast();
+ const u2 method_index = cfs->get_u2_fast();
+ cp->method_handle_index_at_put(index, ref_kind, method_index);
+ }
+ else if (tag == JVM_CONSTANT_MethodType) {
cfs->guarantee_more(3, CHECK); // signature_index, tag/access_flags
- u2 signature_index = cfs->get_u2_fast();
- _cp->method_type_index_at_put(index, signature_index);
- } else {
+ const u2 signature_index = cfs->get_u2_fast();
+ cp->method_type_index_at_put(index, signature_index);
+ }
+ else {
ShouldNotReachHere();
}
break;
- case JVM_CONSTANT_InvokeDynamic :
- {
- if (_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
- classfile_parse_error(
+ }
+ case JVM_CONSTANT_InvokeDynamic : {
+ if (_major_version < Verifier::INVOKEDYNAMIC_MAJOR_VERSION) {
+ classfile_parse_error(
"Class file version does not support constant tag %u in class file %s",
tag, CHECK);
- }
- cfs->guarantee_more(5, CHECK); // bsm_index, nt, tag/access_flags
- u2 bootstrap_specifier_index = cfs->get_u2_fast();
- u2 name_and_type_index = cfs->get_u2_fast();
- if (_max_bootstrap_specifier_index < (int) bootstrap_specifier_index)
- _max_bootstrap_specifier_index = (int) bootstrap_specifier_index; // collect for later
- _cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index);
+ }
+ cfs->guarantee_more(5, CHECK); // bsm_index, nt, tag/access_flags
+ const u2 bootstrap_specifier_index = cfs->get_u2_fast();
+ const u2 name_and_type_index = cfs->get_u2_fast();
+ if (_max_bootstrap_specifier_index < (int) bootstrap_specifier_index) {
+ _max_bootstrap_specifier_index = (int) bootstrap_specifier_index; // collect for later
}
+ cp->invoke_dynamic_at_put(index, bootstrap_specifier_index, name_and_type_index);
break;
- case JVM_CONSTANT_Integer :
- {
- cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags
- u4 bytes = cfs->get_u4_fast();
- _cp->int_at_put(index, (jint) bytes);
- }
+ }
+ case JVM_CONSTANT_Integer: {
+ cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags
+ const u4 bytes = cfs->get_u4_fast();
+ cp->int_at_put(index, (jint)bytes);
break;
- case JVM_CONSTANT_Float :
- {
- cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags
- u4 bytes = cfs->get_u4_fast();
- _cp->float_at_put(index, *(jfloat*)&bytes);
- }
+ }
+ case JVM_CONSTANT_Float: {
+ cfs->guarantee_more(5, CHECK); // bytes, tag/access_flags
+ const u4 bytes = cfs->get_u4_fast();
+ cp->float_at_put(index, *(jfloat*)&bytes);
break;
- case JVM_CONSTANT_Long :
+ }
+ case JVM_CONSTANT_Long: {
// A mangled type might cause you to overrun allocated memory
- guarantee_property(index+1 < length,
+ guarantee_property(index + 1 < length,
"Invalid constant pool entry %u in class file %s",
- index, CHECK);
- {
- cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags
- u8 bytes = cfs->get_u8_fast();
- _cp->long_at_put(index, bytes);
- }
+ index,
+ CHECK);
+ cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags
+ const u8 bytes = cfs->get_u8_fast();
+ cp->long_at_put(index, bytes);
index++; // Skip entry following eigth-byte constant, see JVM book p. 98
break;
- case JVM_CONSTANT_Double :
+ }
+ case JVM_CONSTANT_Double: {
// A mangled type might cause you to overrun allocated memory
guarantee_property(index+1 < length,
"Invalid constant pool entry %u in class file %s",
- index, CHECK);
- {
- cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags
- u8 bytes = cfs->get_u8_fast();
- _cp->double_at_put(index, *(jdouble*)&bytes);
- }
+ index,
+ CHECK);
+ cfs->guarantee_more(9, CHECK); // bytes, tag/access_flags
+ const u8 bytes = cfs->get_u8_fast();
+ cp->double_at_put(index, *(jdouble*)&bytes);
index++; // Skip entry following eigth-byte constant, see JVM book p. 98
break;
- case JVM_CONSTANT_NameAndType :
- {
- cfs->guarantee_more(5, CHECK); // name_index, signature_index, tag/access_flags
- u2 name_index = cfs->get_u2_fast();
- u2 signature_index = cfs->get_u2_fast();
- _cp->name_and_type_at_put(index, name_index, signature_index);
+ }
+ case JVM_CONSTANT_NameAndType: {
+ cfs->guarantee_more(5, CHECK); // name_index, signature_index, tag/access_flags
+ const u2 name_index = cfs->get_u2_fast();
+ const u2 signature_index = cfs->get_u2_fast();
+ cp->name_and_type_at_put(index, name_index, signature_index);
+ break;
+ }
+ case JVM_CONSTANT_Utf8 : {
+ cfs->guarantee_more(2, CHECK); // utf8_length
+ u2 utf8_length = cfs->get_u2_fast();
+ const u1* utf8_buffer = cfs->get_u1_buffer();
+ assert(utf8_buffer != NULL, "null utf8 buffer");
+ // Got utf8 string, guarantee utf8_length+1 bytes, set stream position forward.
+ cfs->guarantee_more(utf8_length+1, CHECK); // utf8 string, tag/access_flags
+ cfs->skip_u1_fast(utf8_length);
+
+ // Before storing the symbol, make sure it's legal
+ if (_need_verify) {
+ verify_legal_utf8(utf8_buffer, utf8_length, CHECK);
+ }
+
+ if (has_cp_patch_at(index)) {
+ Handle patch = clear_cp_patch_at(index);
+ guarantee_property(java_lang_String::is_instance(patch()),
+ "Illegal utf8 patch at %d in class file %s",
+ index,
+ CHECK);
+ const char* const str = java_lang_String::as_utf8_string(patch());
+ // (could use java_lang_String::as_symbol instead, but might as well batch them)
+ utf8_buffer = (const u1*) str;
+ utf8_length = (int) strlen(str);
+ }
+
+ unsigned int hash;
+ Symbol* const result = SymbolTable::lookup_only((const char*)utf8_buffer,
+ utf8_length,
+ hash);
+ if (result == NULL) {
+ names[names_count] = (const char*)utf8_buffer;
+ lengths[names_count] = utf8_length;
+ indices[names_count] = index;
+ hashValues[names_count++] = hash;
+ if (names_count == SymbolTable::symbol_alloc_batch_size) {
+ SymbolTable::new_symbols(_loader_data,
+ cp,
+ names_count,
+ names,
+ lengths,
+ indices,
+ hashValues,
+ CHECK);
+ names_count = 0;
+ }
+ } else {
+ cp->symbol_at_put(index, result);
}
break;
- case JVM_CONSTANT_Utf8 :
- {
- cfs->guarantee_more(2, CHECK); // utf8_length
- u2 utf8_length = cfs->get_u2_fast();
- u1* utf8_buffer = cfs->get_u1_buffer();
- assert(utf8_buffer != NULL, "null utf8 buffer");
- // Got utf8 string, guarantee utf8_length+1 bytes, set stream position forward.
- cfs->guarantee_more(utf8_length+1, CHECK); // utf8 string, tag/access_flags
- cfs->skip_u1_fast(utf8_length);
-
- // Before storing the symbol, make sure it's legal
- if (_need_verify) {
- verify_legal_utf8((unsigned char*)utf8_buffer, utf8_length, CHECK);
- }
-
- if (has_cp_patch_at(index)) {
- Handle patch = clear_cp_patch_at(index);
- guarantee_property(java_lang_String::is_instance(patch()),
- "Illegal utf8 patch at %d in class file %s",
- index, CHECK);
- char* str = java_lang_String::as_utf8_string(patch());
- // (could use java_lang_String::as_symbol instead, but might as well batch them)
- utf8_buffer = (u1*) str;
- utf8_length = (int) strlen(str);
- }
-
- unsigned int hash;
- Symbol* result = SymbolTable::lookup_only((char*)utf8_buffer, utf8_length, hash);
- if (result == NULL) {
- names[names_count] = (char*)utf8_buffer;
- lengths[names_count] = utf8_length;
- indices[names_count] = index;
- hashValues[names_count++] = hash;
- if (names_count == SymbolTable::symbol_alloc_batch_size) {
- SymbolTable::new_symbols(_loader_data, _cp, names_count, names, lengths, indices, hashValues, CHECK);
- names_count = 0;
- }
- } else {
- _cp->symbol_at_put(index, result);
- }
- }
+ }
+ default: {
+ classfile_parse_error("Unknown constant tag %u in class file %s",
+ tag,
+ CHECK);
break;
- default:
- classfile_parse_error(
- "Unknown constant tag %u in class file %s", tag, CHECK);
- break;
- }
- }
+ }
+ } // end of switch(tag)
+ } // end of for
// Allocate the remaining symbols
if (names_count > 0) {
- SymbolTable::new_symbols(_loader_data, _cp, names_count, names, lengths, indices, hashValues, CHECK);
+ SymbolTable::new_symbols(_loader_data,
+ cp,
+ names_count,
+ names,
+ lengths,
+ indices,
+ hashValues,
+ CHECK);
}
- // Copy _current pointer of local copy back to stream().
-#ifdef ASSERT
- assert(cfs0->current() == old_current, "non-exclusive use of stream()");
-#endif
- cfs0->set_current(cfs1.current());
+ // Copy _current pointer of local copy back to stream.
+ assert(stream->current() == old_current, "non-exclusive use of stream");
+ stream->set_current(cfs1.current());
+
}
-bool inline valid_cp_range(int index, int length) { return (index > 0 && index < length); }
-
-inline Symbol* check_symbol_at(constantPoolHandle cp, int index) {
- if (valid_cp_range(index, cp->length()) && cp->tag_at(index).is_utf8())
+static inline bool valid_cp_range(int index, int length) {
+ return (index > 0 && index < length);
+}
+
+static inline Symbol* check_symbol_at(const ConstantPool* cp, int index) {
+ assert(cp != NULL, "invariant");
+ if (valid_cp_range(index, cp->length()) && cp->tag_at(index).is_utf8()) {
return cp->symbol_at(index);
- else
- return NULL;
+ }
+ return NULL;
}
#ifdef ASSERT
PRAGMA_DIAG_PUSH
PRAGMA_FORMAT_NONLITERAL_IGNORED
-void ClassFileParser::report_assert_property_failure(const char* msg, TRAPS) {
+void ClassFileParser::report_assert_property_failure(const char* msg, TRAPS) const {
ResourceMark rm(THREAD);
fatal(msg, _class_name->as_C_string());
}
-void ClassFileParser::report_assert_property_failure(const char* msg, int index, TRAPS) {
+void ClassFileParser::report_assert_property_failure(const char* msg,
+ int index,
+ TRAPS) const {
ResourceMark rm(THREAD);
fatal(msg, index, _class_name->as_C_string());
}
PRAGMA_DIAG_POP
#endif
-constantPoolHandle ClassFileParser::parse_constant_pool(TRAPS) {
- ClassFileStream* cfs = stream();
- constantPoolHandle nullHandle;
-
- cfs->guarantee_more(3, CHECK_(nullHandle)); // length, first cp tag
- u2 length = cfs->get_u2_fast();
- guarantee_property(
- length >= 1, "Illegal constant pool size %u in class file %s",
- length, CHECK_(nullHandle));
- ConstantPool* constant_pool = ConstantPool::allocate(_loader_data, length,
- CHECK_(nullHandle));
- _cp = constant_pool; // save in case of errors
- constantPoolHandle cp (THREAD, constant_pool);
+void ClassFileParser::parse_constant_pool(const ClassFileStream* const stream,
+ ConstantPool* const cp,
+ const int length,
+ TRAPS) {
+ assert(cp != NULL, "invariant");
+ assert(stream != NULL, "invariant");
// parsing constant pool entries
- parse_constant_pool_entries(length, CHECK_(nullHandle));
+ parse_constant_pool_entries(stream, cp, length, CHECK);
int index = 1; // declared outside of loops for portability
- // first verification pass - validate cross references and fixup class and string constants
+ // first verification pass - validate cross references
+ // and fixup class and string constants
for (index = 1; index < length; index++) { // Index 0 is unused
- jbyte tag = cp->tag_at(index).value();
+ const jbyte tag = cp->tag_at(index).value();
switch (tag) {
- case JVM_CONSTANT_Class :
+ case JVM_CONSTANT_Class: {
ShouldNotReachHere(); // Only JVM_CONSTANT_ClassIndex should be present
break;
- case JVM_CONSTANT_Fieldref :
+ }
+ case JVM_CONSTANT_Fieldref:
// fall through
- case JVM_CONSTANT_Methodref :
+ case JVM_CONSTANT_Methodref:
// fall through
- case JVM_CONSTANT_InterfaceMethodref : {
+ case JVM_CONSTANT_InterfaceMethodref: {
if (!_need_verify) break;
- int klass_ref_index = cp->klass_ref_index_at(index);
- int name_and_type_ref_index = cp->name_and_type_ref_index_at(index);
+ const int klass_ref_index = cp->klass_ref_index_at(index);
+ const int name_and_type_ref_index = cp->name_and_type_ref_index_at(index);
check_property(valid_klass_reference_at(klass_ref_index),
"Invalid constant pool index %u in class file %s",
- klass_ref_index,
- CHECK_(nullHandle));
+ klass_ref_index, CHECK);
check_property(valid_cp_range(name_and_type_ref_index, length) &&
- cp->tag_at(name_and_type_ref_index).is_name_and_type(),
- "Invalid constant pool index %u in class file %s",
- name_and_type_ref_index,
- CHECK_(nullHandle));
+ cp->tag_at(name_and_type_ref_index).is_name_and_type(),
+ "Invalid constant pool index %u in class file %s",
+ name_and_type_ref_index, CHECK);
break;
}
- case JVM_CONSTANT_String :
+ case JVM_CONSTANT_String: {
ShouldNotReachHere(); // Only JVM_CONSTANT_StringIndex should be present
break;
- case JVM_CONSTANT_Integer :
+ }
+ case JVM_CONSTANT_Integer:
break;
- case JVM_CONSTANT_Float :
+ case JVM_CONSTANT_Float:
break;
- case JVM_CONSTANT_Long :
- case JVM_CONSTANT_Double :
+ case JVM_CONSTANT_Long:
+ case JVM_CONSTANT_Double: {
index++;
check_property(
(index < length && cp->tag_at(index).is_invalid()),
"Improper constant pool long/double index %u in class file %s",
- index, CHECK_(nullHandle));
- break;
- case JVM_CONSTANT_NameAndType : {
- if (!_need_verify) break;
- int name_ref_index = cp->name_ref_index_at(index);
- int signature_ref_index = cp->signature_ref_index_at(index);
- check_property(valid_symbol_at(name_ref_index),
- "Invalid constant pool index %u in class file %s",
- name_ref_index, CHECK_(nullHandle));
- check_property(valid_symbol_at(signature_ref_index),
- "Invalid constant pool index %u in class file %s",
- signature_ref_index, CHECK_(nullHandle));
+ index, CHECK);
break;
}
- case JVM_CONSTANT_Utf8 :
+ case JVM_CONSTANT_NameAndType: {
+ if (!_need_verify) break;
+ const int name_ref_index = cp->name_ref_index_at(index);
+ const int signature_ref_index = cp->signature_ref_index_at(index);
+ check_property(valid_symbol_at(name_ref_index),
+ "Invalid constant pool index %u in class file %s",
+ name_ref_index, CHECK);
+ check_property(valid_symbol_at(signature_ref_index),
+ "Invalid constant pool index %u in class file %s",
+ signature_ref_index, CHECK);
break;
- case JVM_CONSTANT_UnresolvedClass : // fall-through
- case JVM_CONSTANT_UnresolvedClassInError:
+ }
+ case JVM_CONSTANT_Utf8:
+ break;
+ case JVM_CONSTANT_UnresolvedClass: // fall-through
+ case JVM_CONSTANT_UnresolvedClassInError: {
ShouldNotReachHere(); // Only JVM_CONSTANT_ClassIndex should be present
break;
- case JVM_CONSTANT_ClassIndex :
- {
- int class_index = cp->klass_index_at(index);
- check_property(valid_symbol_at(class_index),
- "Invalid constant pool index %u in class file %s",
- class_index, CHECK_(nullHandle));
- cp->unresolved_klass_at_put(index, cp->symbol_at(class_index));
- }
+ }
+ case JVM_CONSTANT_ClassIndex: {
+ const int class_index = cp->klass_index_at(index);
+ check_property(valid_symbol_at(class_index),
+ "Invalid constant pool index %u in class file %s",
+ class_index, CHECK);
+ cp->unresolved_klass_at_put(index, cp->symbol_at(class_index));
break;
- case JVM_CONSTANT_StringIndex :
- {
- int string_index = cp->string_index_at(index);
- check_property(valid_symbol_at(string_index),
- "Invalid constant pool index %u in class file %s",
- string_index, CHECK_(nullHandle));
- Symbol* sym = cp->symbol_at(string_index);
- cp->unresolved_string_at_put(index, sym);
- }
+ }
+ case JVM_CONSTANT_StringIndex: {
+ const int string_index = cp->string_index_at(index);
+ check_property(valid_symbol_at(string_index),
+ "Invalid constant pool index %u in class file %s",
+ string_index, CHECK);
+ Symbol* const sym = cp->symbol_at(string_index);
+ cp->unresolved_string_at_put(index, sym);
break;
- case JVM_CONSTANT_MethodHandle :
- {
- int ref_index = cp->method_handle_index_at(index);
- check_property(
- valid_cp_range(ref_index, length),
- "Invalid constant pool index %u in class file %s",
- ref_index, CHECK_(nullHandle));
- constantTag tag = cp->tag_at(ref_index);
- int ref_kind = cp->method_handle_ref_kind_at(index);
- switch (ref_kind) {
+ }
+ case JVM_CONSTANT_MethodHandle: {
+ const int ref_index = cp->method_handle_index_at(index);
+ check_property(valid_cp_range(ref_index, length),
+ "Invalid constant pool index %u in class file %s",
+ ref_index, CHECK);
+ const constantTag tag = cp->tag_at(ref_index);
+ const int ref_kind = cp->method_handle_ref_kind_at(index);
+
+ switch (ref_kind) {
case JVM_REF_getField:
case JVM_REF_getStatic:
case JVM_REF_putField:
- case JVM_REF_putStatic:
+ case JVM_REF_putStatic: {
check_property(
tag.is_field(),
"Invalid constant pool index %u in class file %s (not a field)",
- ref_index, CHECK_(nullHandle));
+ ref_index, CHECK);
break;
+ }
case JVM_REF_invokeVirtual:
- case JVM_REF_newInvokeSpecial:
+ case JVM_REF_newInvokeSpecial: {
check_property(
tag.is_method(),
"Invalid constant pool index %u in class file %s (not a method)",
- ref_index, CHECK_(nullHandle));
+ ref_index, CHECK);
break;
+ }
case JVM_REF_invokeStatic:
- case JVM_REF_invokeSpecial:
- check_property(tag.is_method() ||
- ((_major_version >= JAVA_8_VERSION) && tag.is_interface_method()),
- "Invalid constant pool index %u in class file %s (not a method)",
- ref_index, CHECK_(nullHandle));
- break;
- case JVM_REF_invokeInterface:
+ case JVM_REF_invokeSpecial: {
+ check_property(
+ tag.is_method() ||
+ ((_major_version >= JAVA_8_VERSION) && tag.is_interface_method()),
+ "Invalid constant pool index %u in class file %s (not a method)",
+ ref_index, CHECK);
+ break;
+ }
+ case JVM_REF_invokeInterface: {
check_property(
tag.is_interface_method(),
"Invalid constant pool index %u in class file %s (not an interface method)",
- ref_index, CHECK_(nullHandle));
+ ref_index, CHECK);
break;
- default:
+ }
+ default: {
classfile_parse_error(
"Bad method handle kind at constant pool index %u in class file %s",
- index, CHECK_(nullHandle));
+ index, CHECK);
}
- // Keep the ref_index unchanged. It will be indirected at link-time.
- }
+ } // switch(refkind)
+ // Keep the ref_index unchanged. It will be indirected at link-time.
break;
- case JVM_CONSTANT_MethodType :
- {
- int ref_index = cp->method_type_index_at(index);
- check_property(valid_symbol_at(ref_index),
- "Invalid constant pool index %u in class file %s",
- ref_index, CHECK_(nullHandle));
- }
+ } // case MethodHandle
+ case JVM_CONSTANT_MethodType: {
+ const int ref_index = cp->method_type_index_at(index);
+ check_property(valid_symbol_at(ref_index),
+ "Invalid constant pool index %u in class file %s",
+ ref_index, CHECK);
break;
- case JVM_CONSTANT_InvokeDynamic :
- {
- int name_and_type_ref_index = cp->invoke_dynamic_name_and_type_ref_index_at(index);
- check_property(valid_cp_range(name_and_type_ref_index, length) &&
- cp->tag_at(name_and_type_ref_index).is_name_and_type(),
- "Invalid constant pool index %u in class file %s",
- name_and_type_ref_index,
- CHECK_(nullHandle));
- // bootstrap specifier index must be checked later, when BootstrapMethods attr is available
- break;
- }
- default:
+ }
+ case JVM_CONSTANT_InvokeDynamic: {
+ const int name_and_type_ref_index =
+ cp->invoke_dynamic_name_and_type_ref_index_at(index);
+
+ check_property(valid_cp_range(name_and_type_ref_index, length) &&
+ cp->tag_at(name_and_type_ref_index).is_name_and_type(),
+ "Invalid constant pool index %u in class file %s",
+ name_and_type_ref_index, CHECK);
+ // bootstrap specifier index must be checked later,
+ // when BootstrapMethods attr is available
+ break;
+ }
+ default: {
fatal("bad constant pool tag value %u", cp->tag_at(index).value());
ShouldNotReachHere();
break;
- } // end of switch
+ }
+ } // switch(tag)
} // end of for
if (_cp_patches != NULL) {
// need to treat this_class specially...
int this_class_index;
{
- cfs->guarantee_more(8, CHECK_(nullHandle)); // flags, this_class, super_class, infs_len
- u1* mark = cfs->current();
- u2 flags = cfs->get_u2_fast();
- this_class_index = cfs->get_u2_fast();
- cfs->set_current(mark); // revert to mark
+ stream->guarantee_more(8, CHECK); // flags, this_class, super_class, infs_len
+ const u1* const mark = stream->current();
+ stream->skip_u2_fast(1); // skip flags
+ this_class_index = stream->get_u2_fast();
+ stream->set_current(mark); // revert to mark
}
for (index = 1; index < length; index++) { // Index 0 is unused
if (has_cp_patch_at(index)) {
guarantee_property(index != this_class_index,
- "Illegal constant pool patch to self at %d in class file %s",
- index, CHECK_(nullHandle));
- patch_constant_pool(cp, index, cp_patch_at(index), CHECK_(nullHandle));
+ "Illegal constant pool patch to self at %d in class file %s",
+ index, CHECK);
+ patch_constant_pool(cp, index, cp_patch_at(index), CHECK);
}
}
}
if (!_need_verify) {
- return cp;
+ return;
}
// second verification pass - checks the strings are of the right format.
// but not yet to the other entries
for (index = 1; index < length; index++) {
- jbyte tag = cp->tag_at(index).value();
+ const jbyte tag = cp->tag_at(index).value();
switch (tag) {
case JVM_CONSTANT_UnresolvedClass: {
- Symbol* class_name = cp->klass_name_at(index);
+ const Symbol* const class_name = cp->klass_name_at(index);
// check the name, even if _cp_patches will overwrite it
- verify_legal_class_name(class_name, CHECK_(nullHandle));
+ verify_legal_class_name(class_name, CHECK);
break;
}
case JVM_CONSTANT_NameAndType: {
if (_need_verify && _major_version >= JAVA_7_VERSION) {
- int sig_index = cp->signature_ref_index_at(index);
- int name_index = cp->name_ref_index_at(index);
- Symbol* name = cp->symbol_at(name_index);
- Symbol* sig = cp->symbol_at(sig_index);
+ const int sig_index = cp->signature_ref_index_at(index);
+ const int name_index = cp->name_ref_index_at(index);
+ const Symbol* const name = cp->symbol_at(name_index);
+ const Symbol* const sig = cp->symbol_at(sig_index);
if (sig->byte_at(0) == JVM_SIGNATURE_FUNC) {
- verify_legal_method_signature(name, sig, CHECK_(nullHandle));
+ verify_legal_method_signature(name, sig, CHECK);
} else {
- verify_legal_field_signature(name, sig, CHECK_(nullHandle));
+ verify_legal_field_signature(name, sig, CHECK);
}
}
break;
@@ -555,47 +579,50 @@
case JVM_CONSTANT_Fieldref:
case JVM_CONSTANT_Methodref:
case JVM_CONSTANT_InterfaceMethodref: {
- int name_and_type_ref_index = cp->name_and_type_ref_index_at(index);
+ const int name_and_type_ref_index =
+ cp->name_and_type_ref_index_at(index);
// already verified to be utf8
- int name_ref_index = cp->name_ref_index_at(name_and_type_ref_index);
+ const int name_ref_index =
+ cp->name_ref_index_at(name_and_type_ref_index);
// already verified to be utf8
- int signature_ref_index = cp->signature_ref_index_at(name_and_type_ref_index);
- Symbol* name = cp->symbol_at(name_ref_index);
- Symbol* signature = cp->symbol_at(signature_ref_index);
+ const int signature_ref_index =
+ cp->signature_ref_index_at(name_and_type_ref_index);
+ const Symbol* const name = cp->symbol_at(name_ref_index);
+ const Symbol* const signature = cp->symbol_at(signature_ref_index);
if (tag == JVM_CONSTANT_Fieldref) {
- verify_legal_field_name(name, CHECK_(nullHandle));
+ verify_legal_field_name(name, CHECK);
if (_need_verify && _major_version >= JAVA_7_VERSION) {
// Signature is verified above, when iterating NameAndType_info.
// Need only to be sure it's the right type.
if (signature->byte_at(0) == JVM_SIGNATURE_FUNC) {
throwIllegalSignature(
- "Field", name, signature, CHECK_(nullHandle));
+ "Field", name, signature, CHECK);
}
} else {
- verify_legal_field_signature(name, signature, CHECK_(nullHandle));
+ verify_legal_field_signature(name, signature, CHECK);
}
} else {
- verify_legal_method_name(name, CHECK_(nullHandle));
+ verify_legal_method_name(name, CHECK);
if (_need_verify && _major_version >= JAVA_7_VERSION) {
// Signature is verified above, when iterating NameAndType_info.
// Need only to be sure it's the right type.
if (signature->byte_at(0) != JVM_SIGNATURE_FUNC) {
throwIllegalSignature(
- "Method", name, signature, CHECK_(nullHandle));
+ "Method", name, signature, CHECK);
}
} else {
- verify_legal_method_signature(name, signature, CHECK_(nullHandle));
+ verify_legal_method_signature(name, signature, CHECK);
}
if (tag == JVM_CONSTANT_Methodref) {
// 4509014: If a class method name begins with '<', it must be "<init>".
assert(name != NULL, "method name in constant pool is null");
- unsigned int name_len = name->utf8_length();
+ const unsigned int name_len = name->utf8_length();
assert(name_len > 0, "bad method name"); // already verified as legal name
if (name->byte_at(0) == '<') {
if (name != vmSymbols::object_initializer_name()) {
classfile_parse_error(
"Bad method name at constant pool index %u in class file %s",
- name_ref_index, CHECK_(nullHandle));
+ name_ref_index, CHECK);
}
}
}
@@ -603,84 +630,88 @@
break;
}
case JVM_CONSTANT_MethodHandle: {
- int ref_index = cp->method_handle_index_at(index);
- int ref_kind = cp->method_handle_ref_kind_at(index);
+ const int ref_index = cp->method_handle_index_at(index);
+ const int ref_kind = cp->method_handle_ref_kind_at(index);
switch (ref_kind) {
- case JVM_REF_invokeVirtual:
- case JVM_REF_invokeStatic:
- case JVM_REF_invokeSpecial:
- case JVM_REF_newInvokeSpecial:
- {
- int name_and_type_ref_index = cp->name_and_type_ref_index_at(ref_index);
- int name_ref_index = cp->name_ref_index_at(name_and_type_ref_index);
- Symbol* name = cp->symbol_at(name_ref_index);
+ case JVM_REF_invokeVirtual:
+ case JVM_REF_invokeStatic:
+ case JVM_REF_invokeSpecial:
+ case JVM_REF_newInvokeSpecial: {
+ const int name_and_type_ref_index =
+ cp->name_and_type_ref_index_at(ref_index);
+ const int name_ref_index =
+ cp->name_ref_index_at(name_and_type_ref_index);
+ const Symbol* const name = cp->symbol_at(name_ref_index);
if (ref_kind == JVM_REF_newInvokeSpecial) {
if (name != vmSymbols::object_initializer_name()) {
classfile_parse_error(
"Bad constructor name at constant pool index %u in class file %s",
- name_ref_index, CHECK_(nullHandle));
+ name_ref_index, CHECK);
}
} else {
if (name == vmSymbols::object_initializer_name()) {
classfile_parse_error(
"Bad method name at constant pool index %u in class file %s",
- name_ref_index, CHECK_(nullHandle));
+ name_ref_index, CHECK);
}
}
+ break;
}
- break;
// Other ref_kinds are already fully checked in previous pass.
- }
+ } // switch(ref_kind)
break;
}
case JVM_CONSTANT_MethodType: {
- Symbol* no_name = vmSymbols::type_name(); // place holder
- Symbol* signature = cp->method_type_signature_at(index);
- verify_legal_method_signature(no_name, signature, CHECK_(nullHandle));
+ const Symbol* const no_name = vmSymbols::type_name(); // place holder
+ const Symbol* const signature = cp->method_type_signature_at(index);
+ verify_legal_method_signature(no_name, signature, CHECK);
break;
}
case JVM_CONSTANT_Utf8: {
assert(cp->symbol_at(index)->refcount() != 0, "count corrupted");
}
- } // end of switch
+ } // switch(tag)
} // end of for
-
- return cp;
}
-
-void ClassFileParser::patch_constant_pool(const constantPoolHandle& cp, int index, Handle patch, TRAPS) {
+void ClassFileParser::patch_constant_pool(ConstantPool* cp,
+ int index,
+ Handle patch,
+ TRAPS) {
+ assert(cp != NULL, "invariant");
+
BasicType patch_type = T_VOID;
switch (cp->tag_at(index).value()) {
- case JVM_CONSTANT_UnresolvedClass :
- // Patching a class means pre-resolving it.
- // The name in the constant pool is ignored.
- if (java_lang_Class::is_instance(patch())) {
- guarantee_property(!java_lang_Class::is_primitive(patch()),
- "Illegal class patch at %d in class file %s",
- index, CHECK);
- cp->klass_at_put(index, java_lang_Class::as_Klass(patch()));
- } else {
- guarantee_property(java_lang_String::is_instance(patch()),
- "Illegal class patch at %d in class file %s",
- index, CHECK);
- Symbol* name = java_lang_String::as_symbol(patch(), CHECK);
- cp->unresolved_klass_at_put(index, name);
+ case JVM_CONSTANT_UnresolvedClass: {
+ // Patching a class means pre-resolving it.
+ // The name in the constant pool is ignored.
+ if (java_lang_Class::is_instance(patch())) {
+ guarantee_property(!java_lang_Class::is_primitive(patch()),
+ "Illegal class patch at %d in class file %s",
+ index, CHECK);
+ cp->klass_at_put(index, java_lang_Class::as_Klass(patch()));
+ } else {
+ guarantee_property(java_lang_String::is_instance(patch()),
+ "Illegal class patch at %d in class file %s",
+ index, CHECK);
+ Symbol* const name = java_lang_String::as_symbol(patch(), CHECK);
+ cp->unresolved_klass_at_put(index, name);
+ }
+ break;
}
- break;
-
- case JVM_CONSTANT_String :
- // skip this patch and don't clear it. Needs the oop array for resolved
- // references to be created first.
- return;
-
- case JVM_CONSTANT_Integer : patch_type = T_INT; goto patch_prim;
- case JVM_CONSTANT_Float : patch_type = T_FLOAT; goto patch_prim;
- case JVM_CONSTANT_Long : patch_type = T_LONG; goto patch_prim;
- case JVM_CONSTANT_Double : patch_type = T_DOUBLE; goto patch_prim;
- patch_prim:
+
+ case JVM_CONSTANT_String: {
+ // skip this patch and don't clear it. Needs the oop array for resolved
+ // references to be created first.
+ return;
+ }
+ case JVM_CONSTANT_Integer: patch_type = T_INT; goto patch_prim;
+ case JVM_CONSTANT_Float: patch_type = T_FLOAT; goto patch_prim;
+ case JVM_CONSTANT_Long: patch_type = T_LONG; goto patch_prim;
+ case JVM_CONSTANT_Double: patch_type = T_DOUBLE; goto patch_prim;
+ patch_prim:
{
jvalue value;
BasicType value_type = java_lang_boxing_object::get_value(patch(), &value);
@@ -688,39 +719,37 @@
"Illegal primitive patch at %d in class file %s",
index, CHECK);
switch (value_type) {
- case T_INT: cp->int_at_put(index, value.i); break;
- case T_FLOAT: cp->float_at_put(index, value.f); break;
- case T_LONG: cp->long_at_put(index, value.j); break;
- case T_DOUBLE: cp->double_at_put(index, value.d); break;
- default: assert(false, "");
+ case T_INT: cp->int_at_put(index, value.i); break;
+ case T_FLOAT: cp->float_at_put(index, value.f); break;
+ case T_LONG: cp->long_at_put(index, value.j); break;
+ case T_DOUBLE: cp->double_at_put(index, value.d); break;
+ default: assert(false, "");
}
- }
+ } // end patch_prim label
break;
- default:
- // %%% TODO: put method handles into CONSTANT_InterfaceMethodref, etc.
- guarantee_property(!has_cp_patch_at(index),
- "Illegal unexpected patch at %d in class file %s",
- index, CHECK);
- return;
- }
+ default: {
+ // %%% TODO: put method handles into CONSTANT_InterfaceMethodref, etc.
+ guarantee_property(!has_cp_patch_at(index),
+ "Illegal unexpected patch at %d in class file %s",
+ index, CHECK);
+ return;
+ }
+ } // end of switch(tag)
// On fall-through, mark the patch as used.
clear_cp_patch_at(index);
}
-
-
class NameSigHash: public ResourceObj {
public:
- Symbol* _name; // name
- Symbol* _sig; // signature
- NameSigHash* _next; // Next entry in hash table
+ const Symbol* _name; // name
+ const Symbol* _sig; // signature
+ NameSigHash* _next; // Next entry in hash table
};
-
-#define HASH_ROW_SIZE 256
-
-unsigned int hash(Symbol* name, Symbol* sig) {
+static const int HASH_ROW_SIZE = 256;
+
+static unsigned int hash(const Symbol* name, const Symbol* sig) {
unsigned int raw_hash = 0;
raw_hash += ((unsigned int)(uintptr_t)name) >> (LogHeapWordSize + 2);
raw_hash += ((unsigned int)(uintptr_t)sig) >> LogHeapWordSize;
@@ -729,16 +758,15 @@
}
-void initialize_hashtable(NameSigHash** table) {
+static void initialize_hashtable(NameSigHash** table) {
memset((void*)table, 0, sizeof(NameSigHash*) * HASH_ROW_SIZE);
}
-
// Return false if the name/sig combination is found in table.
// Return true if no duplicate is found. And name/sig is added as a new entry in table.
// The old format checker uses heap sort to find duplicates.
// NOTE: caller should guarantee that GC doesn't happen during the life cycle
// of table since we don't expect Symbol*'s to move.
-bool put_after_lookup(Symbol* name, Symbol* sig, NameSigHash** table) {
+static bool put_after_lookup(const Symbol* name, const Symbol* sig, NameSigHash** table) {
assert(name != NULL, "name in constant pool is NULL");
// First lookup for duplicates
@@ -763,69 +791,78 @@
return true;
}
-
-Array<Klass*>* ClassFileParser::parse_interfaces(int length,
- Handle protection_domain,
- Symbol* class_name,
- bool* has_default_methods,
- TRAPS) {
- if (length == 0) {
+// Side-effects: populates the _local_interfaces field
+void ClassFileParser::parse_interfaces(const ClassFileStream* const stream,
+ const int itfs_len,
+ ConstantPool* const cp,
+ bool* const has_default_methods,
+ TRAPS) {
+ assert(stream != NULL, "invariant");
+ assert(cp != NULL, "invariant");
+ assert(has_default_methods != NULL, "invariant");
+
+ if (itfs_len == 0) {
_local_interfaces = Universe::the_empty_klass_array();
} else {
- ClassFileStream* cfs = stream();
- assert(length > 0, "only called for length>0");
- _local_interfaces = MetadataFactory::new_array<Klass*>(_loader_data, length, NULL, CHECK_NULL);
+ assert(itfs_len > 0, "only called for len>0");
+ _local_interfaces = MetadataFactory::new_array<Klass*>(_loader_data, itfs_len, NULL, CHECK);
int index;
- for (index = 0; index < length; index++) {
- u2 interface_index = cfs->get_u2(CHECK_NULL);
+ for (index = 0; index < itfs_len; index++) {
+ const u2 interface_index = stream->get_u2(CHECK);
KlassHandle interf;
check_property(
valid_klass_reference_at(interface_index),
"Interface name has bad constant pool index %u in class file %s",
- interface_index, CHECK_NULL);
- if (_cp->tag_at(interface_index).is_klass()) {
- interf = KlassHandle(THREAD, _cp->resolved_klass_at(interface_index));
+ interface_index, CHECK);
+ if (cp->tag_at(interface_index).is_klass()) {
+ interf = KlassHandle(THREAD, cp->resolved_klass_at(interface_index));
} else {
- Symbol* unresolved_klass = _cp->klass_name_at(interface_index);
+ Symbol* const unresolved_klass = cp->klass_name_at(interface_index);
// Don't need to check legal name because it's checked when parsing constant pool.
// But need to make sure it's not an array type.
guarantee_property(unresolved_klass->byte_at(0) != JVM_SIGNATURE_ARRAY,
- "Bad interface name in class file %s", CHECK_NULL);
- Handle class_loader(THREAD, _loader_data->class_loader());
+ "Bad interface name in class file %s", CHECK);
// Call resolve_super so classcircularity is checked
- Klass* k = SystemDictionary::resolve_super_or_fail(class_name,
- unresolved_klass, class_loader, protection_domain,
- false, CHECK_NULL);
+ const Klass* const k =
+ SystemDictionary::resolve_super_or_fail(_class_name,
+ unresolved_klass,
+ _loader_data->class_loader(),
+ _protection_domain,
+ false,
+ CHECK);
interf = KlassHandle(THREAD, k);
}
if (!interf()->is_interface()) {
- THROW_MSG_(vmSymbols::java_lang_IncompatibleClassChangeError(), "Implementing class", NULL);
+ THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(),
+ "Implementing class");
}
+
if (InstanceKlass::cast(interf())->has_default_methods()) {
*has_default_methods = true;
}
_local_interfaces->at_put(index, interf());
}
- if (!_need_verify || length <= 1) {
- return _local_interfaces;
+ if (!_need_verify || itfs_len <= 1) {
+ return;
}
// Check if there's any duplicates in interfaces
ResourceMark rm(THREAD);
- NameSigHash** interface_names = NEW_RESOURCE_ARRAY_IN_THREAD(
- THREAD, NameSigHash*, HASH_ROW_SIZE);
+ NameSigHash** interface_names = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD,
+ NameSigHash*,
+ HASH_ROW_SIZE);
initialize_hashtable(interface_names);
bool dup = false;
{
debug_only(No_Safepoint_Verifier nsv;)
- for (index = 0; index < length; index++) {
- Klass* k = _local_interfaces->at(index);
- Symbol* name = k->name();
+ for (index = 0; index < itfs_len; index++) {
+ const Klass* const k = _local_interfaces->at(index);
+ const Symbol* const name = InstanceKlass::cast(k)->name();
// If no duplicates, add (name, NULL) in hashtable interface_names.
if (!put_after_lookup(name, NULL, interface_names)) {
dup = true;
@@ -834,79 +871,339 @@
}
}
if (dup) {
- classfile_parse_error("Duplicate interface name in class file %s", CHECK_NULL);
+ classfile_parse_error("Duplicate interface name in class file %s", CHECK);
}
}
- return _local_interfaces;
}
-
-void ClassFileParser::verify_constantvalue(int constantvalue_index, int signature_index, TRAPS) {
+void ClassFileParser::verify_constantvalue(const ConstantPool* const cp,
+ int constantvalue_index,
+ int signature_index,
+ TRAPS) const {
// Make sure the constant pool entry is of a type appropriate to this field
guarantee_property(
(constantvalue_index > 0 &&
- constantvalue_index < _cp->length()),
+ constantvalue_index < cp->length()),
"Bad initial value index %u in ConstantValue attribute in class file %s",
constantvalue_index, CHECK);
- constantTag value_type = _cp->tag_at(constantvalue_index);
- switch ( _cp->basic_type_for_signature_at(signature_index) ) {
- case T_LONG:
- guarantee_property(value_type.is_long(), "Inconsistent constant value type in class file %s", CHECK);
+
+ const constantTag value_type = cp->tag_at(constantvalue_index);
+ switch(cp->basic_type_for_signature_at(signature_index)) {
+ case T_LONG: {
+ guarantee_property(value_type.is_long(),
+ "Inconsistent constant value type in class file %s",
+ CHECK);
+ break;
+ }
+ case T_FLOAT: {
+ guarantee_property(value_type.is_float(),
+ "Inconsistent constant value type in class file %s",
+ CHECK);
break;
- case T_FLOAT:
- guarantee_property(value_type.is_float(), "Inconsistent constant value type in class file %s", CHECK);
+ }
+ case T_DOUBLE: {
+ guarantee_property(value_type.is_double(),
+ "Inconsistent constant value type in class file %s",
+ CHECK);
+ break;
+ }
+ case T_BYTE:
+ case T_CHAR:
+ case T_SHORT:
+ case T_BOOLEAN:
+ case T_INT: {
+ guarantee_property(value_type.is_int(),
+ "Inconsistent constant value type in class file %s",
+ CHECK);
+ break;
+ }
+ case T_OBJECT: {
+ guarantee_property((cp->symbol_at(signature_index)->equals("Ljava/lang/String;")
+ && value_type.is_string()),
+ "Bad string initial value in class file %s",
+ CHECK);
break;
- case T_DOUBLE:
- guarantee_property(value_type.is_double(), "Inconsistent constant value type in class file %s", CHECK);
+ }
+ default: {
+ classfile_parse_error("Unable to set initial value %u in class file %s",
+ constantvalue_index,
+ CHECK);
+ }
+ }
+}
+
+class AnnotationCollector : public ResourceObj{
+public:
+ enum Location { _in_field, _in_method, _in_class };
+ enum ID {
+ _unknown = 0,
+ _method_CallerSensitive,
+ _method_ForceInline,
+ _method_DontInline,
+ _method_InjectedProfile,
+ _method_LambdaForm_Compiled,
+ _method_LambdaForm_Hidden,
+ _method_HotSpotIntrinsicCandidate,
+ _jdk_internal_vm_annotation_Contended,
+ _field_Stable,
+ _annotation_LIMIT
+ };
+ const Location _location;
+ int _annotations_present;
+ u2 _contended_group;
+
+ AnnotationCollector(Location location)
+ : _location(location), _annotations_present(0)
+ {
+ assert((int)_annotation_LIMIT <= (int)sizeof(_annotations_present) * BitsPerByte, "");
+ }
+ // If this annotation name has an ID, report it (or _none).
+ ID annotation_index(const ClassLoaderData* loader_data, const Symbol* name);
+ // Set the annotation name:
+ void set_annotation(ID id) {
+ assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
+ _annotations_present |= nth_bit((int)id);
+ }
+
+ void remove_annotation(ID id) {
+ assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
+ _annotations_present &= ~nth_bit((int)id);
+ }
+
+ // Report if the annotation is present.
+ bool has_any_annotations() const { return _annotations_present != 0; }
+ bool has_annotation(ID id) const { return (nth_bit((int)id) & _annotations_present) != 0; }
+
+ void set_contended_group(u2 group) { _contended_group = group; }
+ u2 contended_group() const { return _contended_group; }
+
+ bool is_contended() const { return has_annotation(_jdk_internal_vm_annotation_Contended); }
+
+ void set_stable(bool stable) { set_annotation(_field_Stable); }
+ bool is_stable() const { return has_annotation(_field_Stable); }
+};
+
+// This class also doubles as a holder for metadata cleanup.
+class ClassFileParser::FieldAnnotationCollector : public AnnotationCollector {
+private:
+ ClassLoaderData* _loader_data;
+ AnnotationArray* _field_annotations;
+ AnnotationArray* _field_type_annotations;
+public:
+ FieldAnnotationCollector(ClassLoaderData* loader_data) :
+ AnnotationCollector(_in_field),
+ _loader_data(loader_data),
+ _field_annotations(NULL),
+ _field_type_annotations(NULL) {}
+ ~FieldAnnotationCollector();
+ void apply_to(FieldInfo* f);
+ AnnotationArray* field_annotations() { return _field_annotations; }
+ AnnotationArray* field_type_annotations() { return _field_type_annotations; }
+
+ void set_field_annotations(AnnotationArray* a) { _field_annotations = a; }
+ void set_field_type_annotations(AnnotationArray* a) { _field_type_annotations = a; }
+};
+
+class MethodAnnotationCollector : public AnnotationCollector{
+public:
+ MethodAnnotationCollector() : AnnotationCollector(_in_method) { }
+ void apply_to(methodHandle m);
+};
+
+class ClassFileParser::ClassAnnotationCollector : public AnnotationCollector{
+public:
+ ClassAnnotationCollector() : AnnotationCollector(_in_class) { }
+ void apply_to(InstanceKlass* ik);
+};
+
+
+static int skip_annotation_value(const u1*, int, int); // fwd decl
+
+// Skip an annotation. Return >=limit if there is any problem.
+static int skip_annotation(const u1* buffer, int limit, int index) {
+ assert(buffer != NULL, "invariant");
+ // annotation := atype:u2 do(nmem:u2) {member:u2 value}
+ // value := switch (tag:u1) { ... }
+ index += 2; // skip atype
+ if ((index += 2) >= limit) return limit; // read nmem
+ int nmem = Bytes::get_Java_u2((address)buffer + index - 2);
+ while (--nmem >= 0 && index < limit) {
+ index += 2; // skip member
+ index = skip_annotation_value(buffer, limit, index);
+ }
+ return index;
+}
+
+// Skip an annotation value. Return >=limit if there is any problem.
+static int skip_annotation_value(const u1* buffer, int limit, int index) {
+ assert(buffer != NULL, "invariant");
+
+ // value := switch (tag:u1) {
+ // case B, C, I, S, Z, D, F, J, c: con:u2;
+ // case e: e_class:u2 e_name:u2;
+ // case s: s_con:u2;
+ // case [: do(nval:u2) {value};
+ // case @: annotation;
+ // case s: s_con:u2;
+ // }
+ if ((index += 1) >= limit) return limit; // read tag
+ const u1 tag = buffer[index - 1];
+ switch (tag) {
+ case 'B':
+ case 'C':
+ case 'I':
+ case 'S':
+ case 'Z':
+ case 'D':
+ case 'F':
+ case 'J':
+ case 'c':
+ case 's':
+ index += 2; // skip con or s_con
break;
- case T_BYTE: case T_CHAR: case T_SHORT: case T_BOOLEAN: case T_INT:
- guarantee_property(value_type.is_int(), "Inconsistent constant value type in class file %s", CHECK);
+ case 'e':
+ index += 4; // skip e_class, e_name
break;
- case T_OBJECT:
- guarantee_property((_cp->symbol_at(signature_index)->equals("Ljava/lang/String;")
- && value_type.is_string()),
- "Bad string initial value in class file %s", CHECK);
+ case '[':
+ {
+ if ((index += 2) >= limit) return limit; // read nval
+ int nval = Bytes::get_Java_u2((address)buffer + index - 2);
+ while (--nval >= 0 && index < limit) {
+ index = skip_annotation_value(buffer, limit, index);
+ }
+ }
+ break;
+ case '@':
+ index = skip_annotation(buffer, limit, index);
break;
default:
- classfile_parse_error(
- "Unable to set initial value %u in class file %s",
- constantvalue_index, CHECK);
+ return limit; // bad tag byte
+ }
+ return index;
+}
+
+// Sift through annotations, looking for those significant to the VM:
+static void parse_annotations(const ConstantPool* const cp,
+ const u1* buffer, int limit,
+ AnnotationCollector* coll,
+ ClassLoaderData* loader_data,
+ TRAPS) {
+
+ assert(cp != NULL, "invariant");
+ assert(buffer != NULL, "invariant");
+ assert(coll != NULL, "invariant");
+ assert(loader_data != NULL, "invariant");
+
+ // annotations := do(nann:u2) {annotation}
+ int index = 0;
+ if ((index += 2) >= limit) return; // read nann
+ int nann = Bytes::get_Java_u2((address)buffer + index - 2);
+ enum { // initial annotation layout
+ atype_off = 0, // utf8 such as 'Ljava/lang/annotation/Retention;'
+ count_off = 2, // u2 such as 1 (one value)
+ member_off = 4, // utf8 such as 'value'
+ tag_off = 6, // u1 such as 'c' (type) or 'e' (enum)
+ e_tag_val = 'e',
+ e_type_off = 7, // utf8 such as 'Ljava/lang/annotation/RetentionPolicy;'
+ e_con_off = 9, // utf8 payload, such as 'SOURCE', 'CLASS', 'RUNTIME'
+ e_size = 11, // end of 'e' annotation
+ c_tag_val = 'c', // payload is type
+ c_con_off = 7, // utf8 payload, such as 'I'
+ c_size = 9, // end of 'c' annotation
+ s_tag_val = 's', // payload is String
+ s_con_off = 7, // utf8 payload, such as 'Ljava/lang/String;'
+ s_size = 9,
+ min_size = 6 // smallest possible size (zero members)
+ };
+ while ((--nann) >= 0 && (index - 2 + min_size <= limit)) {
+ int index0 = index;
+ index = skip_annotation(buffer, limit, index);
+ const u1* const abase = buffer + index0;
+ const int atype = Bytes::get_Java_u2((address)abase + atype_off);
+ const int count = Bytes::get_Java_u2((address)abase + count_off);
+ const Symbol* const aname = check_symbol_at(cp, atype);
+ if (aname == NULL) break; // invalid annotation name
+ const Symbol* member = NULL;
+ if (count >= 1) {
+ const int member_index = Bytes::get_Java_u2((address)abase + member_off);
+ member = check_symbol_at(cp, member_index);
+ if (member == NULL) break; // invalid member name
+ }
+
+ // Here is where parsing particular annotations will take place.
+ AnnotationCollector::ID id = coll->annotation_index(loader_data, aname);
+ if (AnnotationCollector::_unknown == id) continue;
+ coll->set_annotation(id);
+
+ if (AnnotationCollector::_jdk_internal_vm_annotation_Contended == id) {
+ // @Contended can optionally specify the contention group.
+ //
+ // Contended group defines the equivalence class over the fields:
+ // the fields within the same contended group are not treated distinct.
+ // The only exception is default group, which does not incur the
+ // equivalence. Naturally, contention group for classes is meaningless.
+ //
+ // While the contention group is specified as String, annotation
+ // values are already interned, and we might as well use the constant
+ // pool index as the group tag.
+ //
+ u2 group_index = 0; // default contended group
+ if (count == 1
+ && s_size == (index - index0) // match size
+ && s_tag_val == *(abase + tag_off)
+ && member == vmSymbols::value_name()) {
+ group_index = Bytes::get_Java_u2((address)abase + s_con_off);
+ if (cp->symbol_at(group_index)->utf8_length() == 0) {
+ group_index = 0; // default contended group
+ }
+ }
+ coll->set_contended_group(group_index);
+ }
}
}
// Parse attributes for a field.
-void ClassFileParser::parse_field_attributes(u2 attributes_count,
+void ClassFileParser::parse_field_attributes(const ClassFileStream* const cfs,
+ u2 attributes_count,
bool is_static, u2 signature_index,
- u2* constantvalue_index_addr,
- bool* is_synthetic_addr,
- u2* generic_signature_index_addr,
+ u2* const constantvalue_index_addr,
+ bool* const is_synthetic_addr,
+ u2* const generic_signature_index_addr,
ClassFileParser::FieldAnnotationCollector* parsed_annotations,
TRAPS) {
- ClassFileStream* cfs = stream();
- assert(attributes_count > 0, "length should be greater than 0");
+ assert(cfs != NULL, "invariant");
+ assert(constantvalue_index_addr != NULL, "invariant");
+ assert(is_synthetic_addr != NULL, "invariant");
+ assert(generic_signature_index_addr != NULL, "invariant");
+ assert(parsed_annotations != NULL, "invariant");
+ assert(attributes_count > 0, "attributes_count should be greater than 0");
+
u2 constantvalue_index = 0;
u2 generic_signature_index = 0;
bool is_synthetic = false;
- u1* runtime_visible_annotations = NULL;
+ const u1* runtime_visible_annotations = NULL;
int runtime_visible_annotations_length = 0;
- u1* runtime_invisible_annotations = NULL;
+ const u1* runtime_invisible_annotations = NULL;
int runtime_invisible_annotations_length = 0;
- u1* runtime_visible_type_annotations = NULL;
+ const u1* runtime_visible_type_annotations = NULL;
int runtime_visible_type_annotations_length = 0;
- u1* runtime_invisible_type_annotations = NULL;
+ const u1* runtime_invisible_type_annotations = NULL;
int runtime_invisible_type_annotations_length = 0;
bool runtime_invisible_annotations_exists = false;
bool runtime_invisible_type_annotations_exists = false;
+ const ConstantPool* const cp = _cp;
+
while (attributes_count--) {
cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length
- u2 attribute_name_index = cfs->get_u2_fast();
- u4 attribute_length = cfs->get_u4_fast();
+ const u2 attribute_name_index = cfs->get_u2_fast();
+ const u4 attribute_length = cfs->get_u4_fast();
check_property(valid_symbol_at(attribute_name_index),
"Invalid field attribute index %u in class file %s",
attribute_name_index,
CHECK);
- Symbol* attribute_name = _cp->symbol_at(attribute_name_index);
+
+ const Symbol* const attribute_name = cp->symbol_at(attribute_name_index);
if (is_static && attribute_name == vmSymbols::tag_constant_value()) {
// ignore if non-static
if (constantvalue_index != 0) {
@@ -916,9 +1213,10 @@
attribute_length == 2,
"Invalid ConstantValue field attribute length %u in class file %s",
attribute_length, CHECK);
+
constantvalue_index = cfs->get_u2(CHECK);
if (_need_verify) {
- verify_constantvalue(constantvalue_index, signature_index, CHECK);
+ verify_constantvalue(cp, constantvalue_index, signature_index, CHECK);
}
} else if (attribute_name == vmSymbols::tag_synthetic()) {
if (attribute_length != 0) {
@@ -940,7 +1238,7 @@
"Wrong size %u for field's Signature attribute in class file %s",
attribute_length, CHECK);
}
- generic_signature_index = parse_generic_signature_attribute(CHECK);
+ generic_signature_index = parse_generic_signature_attribute(cfs, CHECK);
} else if (attribute_name == vmSymbols::tag_runtime_visible_annotations()) {
if (runtime_visible_annotations != NULL) {
classfile_parse_error(
@@ -949,9 +1247,12 @@
runtime_visible_annotations_length = attribute_length;
runtime_visible_annotations = cfs->get_u1_buffer();
assert(runtime_visible_annotations != NULL, "null visible annotations");
- parse_annotations(runtime_visible_annotations,
+ parse_annotations(cp,
+ runtime_visible_annotations,
runtime_visible_annotations_length,
- parsed_annotations);
+ parsed_annotations,
+ _loader_data,
+ CHECK);
cfs->skip_u1(runtime_visible_annotations_length, CHECK);
} else if (attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
if (runtime_invisible_annotations_exists) {
@@ -1081,7 +1382,7 @@
return result;
}
-class FieldAllocationCount: public ResourceObj {
+class ClassFileParser::FieldAllocationCount : public ResourceObj {
public:
u2 count[MAX_FIELD_ALLOCATION_TYPE];
@@ -1100,18 +1401,33 @@
}
};
-Array<u2>* ClassFileParser::parse_fields(Symbol* class_name,
- bool is_interface,
- FieldAllocationCount *fac,
- u2* java_fields_count_ptr, TRAPS) {
- ClassFileStream* cfs = stream();
- cfs->guarantee_more(2, CHECK_NULL); // length
- u2 length = cfs->get_u2_fast();
+// Side-effects: populates the _fields, _fields_annotations,
+// _fields_type_annotations fields
+void ClassFileParser::parse_fields(const ClassFileStream* const cfs,
+ bool is_interface,
+ FieldAllocationCount* const fac,
+ ConstantPool* cp,
+ const int cp_size,
+ u2* const java_fields_count_ptr,
+ TRAPS) {
+
+ assert(cfs != NULL, "invariant");
+ assert(fac != NULL, "invariant");
+ assert(cp != NULL, "invariant");
+ assert(java_fields_count_ptr != NULL, "invariant");
+
+ assert(NULL == _fields, "invariant");
+ assert(NULL == _fields_annotations, "invariant");
+ assert(NULL == _fields_type_annotations, "invariant");
+
+ cfs->guarantee_more(2, CHECK); // length
+ const u2 length = cfs->get_u2_fast();
*java_fields_count_ptr = length;
int num_injected = 0;
- InjectedField* injected = JavaClasses::get_injected(class_name, &num_injected);
- int total_fields = length + num_injected;
+ const InjectedField* const injected = JavaClasses::get_injected(_class_name,
+ &num_injected);
+ const int total_fields = length + num_injected;
// The field array starts with tuples of shorts
// [access, name index, sig index, initial value index, byte offset].
@@ -1134,62 +1450,70 @@
// index. After parsing all fields, the data are copied to a permanent
// array and any unused slots will be discarded.
ResourceMark rm(THREAD);
- u2* fa = NEW_RESOURCE_ARRAY_IN_THREAD(
- THREAD, u2, total_fields * (FieldInfo::field_slots + 1));
+ u2* const fa = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD,
+ u2,
+ total_fields * (FieldInfo::field_slots + 1));
// The generic signature slots start after all other fields' data.
int generic_signature_slot = total_fields * FieldInfo::field_slots;
int num_generic_signature = 0;
for (int n = 0; n < length; n++) {
- cfs->guarantee_more(8, CHECK_NULL); // access_flags, name_index, descriptor_index, attributes_count
+ // access_flags, name_index, descriptor_index, attributes_count
+ cfs->guarantee_more(8, CHECK);
AccessFlags access_flags;
- jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_FIELD_MODIFIERS;
- verify_legal_field_modifiers(flags, is_interface, CHECK_NULL);
+ const jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_FIELD_MODIFIERS;
+ verify_legal_field_modifiers(flags, is_interface, CHECK);
access_flags.set_flags(flags);
- u2 name_index = cfs->get_u2_fast();
- int cp_size = _cp->length();
+ const u2 name_index = cfs->get_u2_fast();
check_property(valid_symbol_at(name_index),
"Invalid constant pool index %u for field name in class file %s",
- name_index,
- CHECK_NULL);
- Symbol* name = _cp->symbol_at(name_index);
- verify_legal_field_name(name, CHECK_NULL);
-
- u2 signature_index = cfs->get_u2_fast();
+ name_index, CHECK);
+ const Symbol* const name = cp->symbol_at(name_index);
+ verify_legal_field_name(name, CHECK);
+
+ const u2 signature_index = cfs->get_u2_fast();
check_property(valid_symbol_at(signature_index),
"Invalid constant pool index %u for field signature in class file %s",
- signature_index, CHECK_NULL);
- Symbol* sig = _cp->symbol_at(signature_index);
- verify_legal_field_signature(name, sig, CHECK_NULL);
+ signature_index, CHECK);
+ const Symbol* const sig = cp->symbol_at(signature_index);
+ verify_legal_field_signature(name, sig, CHECK);
u2 constantvalue_index = 0;
bool is_synthetic = false;
u2 generic_signature_index = 0;
- bool is_static = access_flags.is_static();
+ const bool is_static = access_flags.is_static();
FieldAnnotationCollector parsed_annotations(_loader_data);
- u2 attributes_count = cfs->get_u2_fast();
+ const u2 attributes_count = cfs->get_u2_fast();
if (attributes_count > 0) {
- parse_field_attributes(attributes_count, is_static, signature_index,
- &constantvalue_index, &is_synthetic,
- &generic_signature_index, &parsed_annotations,
- CHECK_NULL);
+ parse_field_attributes(cfs,
+ attributes_count,
+ is_static,
+ signature_index,
+ &constantvalue_index,
+ &is_synthetic,
+ &generic_signature_index,
+ &parsed_annotations,
+ CHECK);
+
if (parsed_annotations.field_annotations() != NULL) {
if (_fields_annotations == NULL) {
_fields_annotations = MetadataFactory::new_array<AnnotationArray*>(
_loader_data, length, NULL,
- CHECK_NULL);
+ CHECK);
}
_fields_annotations->at_put(n, parsed_annotations.field_annotations());
parsed_annotations.set_field_annotations(NULL);
}
if (parsed_annotations.field_type_annotations() != NULL) {
if (_fields_type_annotations == NULL) {
- _fields_type_annotations = MetadataFactory::new_array<AnnotationArray*>(
- _loader_data, length, NULL,
- CHECK_NULL);
+ _fields_type_annotations =
+ MetadataFactory::new_array<AnnotationArray*>(_loader_data,
+ length,
+ NULL,
+ CHECK);
}
_fields_type_annotations->at_put(n, parsed_annotations.field_type_annotations());
parsed_annotations.set_field_type_annotations(NULL);
@@ -1206,15 +1530,15 @@
}
}
- FieldInfo* field = FieldInfo::from_field_array(fa, n);
+ FieldInfo* const field = FieldInfo::from_field_array(fa, n);
field->initialize(access_flags.as_short(),
name_index,
signature_index,
constantvalue_index);
- BasicType type = _cp->basic_type_for_signature_at(signature_index);
+ const BasicType type = cp->basic_type_for_signature_at(signature_index);
// Remember how many oops we encountered and compute allocation type
- FieldAllocationType atype = fac->update(is_static, type);
+ const FieldAllocationType atype = fac->update(is_static, type);
field->set_allocation_type(atype);
// After field is initialized with type, we can augment it with aux info
@@ -1227,13 +1551,13 @@
for (int n = 0; n < num_injected; n++) {
// Check for duplicates
if (injected[n].may_be_java) {
- Symbol* name = injected[n].name();
- Symbol* signature = injected[n].signature();
+ const Symbol* const name = injected[n].name();
+ const Symbol* const signature = injected[n].signature();
bool duplicate = false;
for (int i = 0; i < length; i++) {
- FieldInfo* f = FieldInfo::from_field_array(fa, i);
- if (name == _cp->symbol_at(f->name_index()) &&
- signature == _cp->symbol_at(f->signature_index())) {
+ const FieldInfo* const f = FieldInfo::from_field_array(fa, i);
+ if (name == cp->symbol_at(f->name_index()) &&
+ signature == cp->symbol_at(f->signature_index())) {
// Symbol is desclared in Java so skip this one
duplicate = true;
break;
@@ -1246,40 +1570,41 @@
}
// Injected field
- FieldInfo* field = FieldInfo::from_field_array(fa, index);
+ FieldInfo* const field = FieldInfo::from_field_array(fa, index);
field->initialize(JVM_ACC_FIELD_INTERNAL,
injected[n].name_index,
injected[n].signature_index,
0);
- BasicType type = FieldType::basic_type(injected[n].signature());
+ const BasicType type = FieldType::basic_type(injected[n].signature());
// Remember how many oops we encountered and compute allocation type
- FieldAllocationType atype = fac->update(false, type);
+ const FieldAllocationType atype = fac->update(false, type);
field->set_allocation_type(atype);
index++;
}
}
- // Now copy the fields' data from the temporary resource array.
+ assert(NULL == _fields, "invariant");
+
+ _fields =
+ MetadataFactory::new_array<u2>(_loader_data,
+ index * FieldInfo::field_slots + num_generic_signature,
+ CHECK);
// Sometimes injected fields already exist in the Java source so
// the fields array could be too long. In that case the
// fields array is trimed. Also unused slots that were reserved
// for generic signature indexes are discarded.
- Array<u2>* fields = MetadataFactory::new_array<u2>(
- _loader_data, index * FieldInfo::field_slots + num_generic_signature,
- CHECK_NULL);
- _fields = fields; // save in case of error
{
int i = 0;
for (; i < index * FieldInfo::field_slots; i++) {
- fields->at_put(i, fa[i]);
+ _fields->at_put(i, fa[i]);
}
for (int j = total_fields * FieldInfo::field_slots;
j < generic_signature_slot; j++) {
- fields->at_put(i++, fa[j]);
+ _fields->at_put(i++, fa[j]);
}
- assert(i == fields->length(), "");
+ assert(_fields->length() == i, "");
}
if (_need_verify && length > 1) {
@@ -1291,9 +1616,9 @@
bool dup = false;
{
debug_only(No_Safepoint_Verifier nsv;)
- for (AllFieldStream fs(fields, _cp); !fs.done(); fs.next()) {
- Symbol* name = fs.name();
- Symbol* sig = fs.signature();
+ for (AllFieldStream fs(_fields, cp); !fs.done(); fs.next()) {
+ const Symbol* const name = fs.name();
+ const Symbol* const sig = fs.signature();
// If no duplicates, add name/signature in hashtable names_and_sigs.
if (!put_after_lookup(name, sig, names_and_sigs)) {
dup = true;
@@ -1303,36 +1628,39 @@
}
if (dup) {
classfile_parse_error("Duplicate field name&signature in class file %s",
- CHECK_NULL);
+ CHECK);
}
}
-
- return fields;
}
-static void copy_u2_with_conversion(u2* dest, u2* src, int length) {
+static void copy_u2_with_conversion(u2* dest, const u2* src, int length) {
while (length-- > 0) {
*dest++ = Bytes::get_Java_u2((u1*) (src++));
}
}
-
-u2* ClassFileParser::parse_exception_table(u4 code_length,
- u4 exception_table_length,
- TRAPS) {
- ClassFileStream* cfs = stream();
-
- u2* exception_table_start = cfs->get_u2_buffer();
+const u2* ClassFileParser::parse_exception_table(const ClassFileStream* const cfs,
+ u4 code_length,
+ u4 exception_table_length,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
+
+ const u2* const exception_table_start = cfs->get_u2_buffer();
assert(exception_table_start != NULL, "null exception table");
- cfs->guarantee_more(8 * exception_table_length, CHECK_NULL); // start_pc, end_pc, handler_pc, catch_type_index
+
+ cfs->guarantee_more(8 * exception_table_length, CHECK_NULL); // start_pc,
+ // end_pc,
+ // handler_pc,
+ // catch_type_index
+
// Will check legal target after parsing code array in verifier.
if (_need_verify) {
for (unsigned int i = 0; i < exception_table_length; i++) {
- u2 start_pc = cfs->get_u2_fast();
- u2 end_pc = cfs->get_u2_fast();
- u2 handler_pc = cfs->get_u2_fast();
- u2 catch_type_index = cfs->get_u2_fast();
+ const u2 start_pc = cfs->get_u2_fast();
+ const u2 end_pc = cfs->get_u2_fast();
+ const u2 handler_pc = cfs->get_u2_fast();
+ const u2 catch_type_index = cfs->get_u2_fast();
guarantee_property((start_pc < end_pc) && (end_pc <= code_length),
"Illegal exception table range in class file %s",
CHECK_NULL);
@@ -1350,14 +1678,16 @@
return exception_table_start;
}
-void ClassFileParser::parse_linenumber_table(
- u4 code_attribute_length, u4 code_length,
- CompressedLineNumberWriteStream** write_stream, TRAPS) {
- ClassFileStream* cfs = stream();
+void ClassFileParser::parse_linenumber_table(u4 code_attribute_length,
+ u4 code_length,
+ CompressedLineNumberWriteStream**const write_stream,
+ TRAPS) {
+
+ const ClassFileStream* const cfs = _stream;
unsigned int num_entries = cfs->get_u2(CHECK);
// Each entry is a u2 start_pc, and a u2 line_number
- unsigned int length_in_bytes = num_entries * (sizeof(u2) + sizeof(u2));
+ const unsigned int length_in_bytes = num_entries * (sizeof(u2) * 2);
// Verify line number attribute and table length
check_property(
@@ -1371,13 +1701,13 @@
(*write_stream) = new CompressedLineNumberWriteStream(length_in_bytes);
} else {
(*write_stream) = new CompressedLineNumberWriteStream(
- linenumbertable_buffer, fixed_buffer_size);
+ _linenumbertable_buffer, fixed_buffer_size);
}
}
while (num_entries-- > 0) {
- u2 bci = cfs->get_u2_fast(); // start_pc
- u2 line = cfs->get_u2_fast(); // line_number
+ const u2 bci = cfs->get_u2_fast(); // start_pc
+ const u2 line = cfs->get_u2_fast(); // line_number
guarantee_property(bci < code_length,
"Invalid pc in LineNumberTable in class file %s", CHECK);
(*write_stream)->write_pair(bci, line);
@@ -1422,7 +1752,8 @@
u2 slot;
};
-void copy_lvt_element(Classfile_LVT_Element *src, LocalVariableTableElement *lvt) {
+static void copy_lvt_element(const Classfile_LVT_Element* const src,
+ LocalVariableTableElement* const lvt) {
lvt->start_bci = Bytes::get_Java_u2((u1*) &src->start_bci);
lvt->length = Bytes::get_Java_u2((u1*) &src->length);
lvt->name_cp_index = Bytes::get_Java_u2((u1*) &src->name_cp_index);
@@ -1432,36 +1763,41 @@
}
// Function is used to parse both attributes:
-// LocalVariableTable (LVT) and LocalVariableTypeTable (LVTT)
-u2* ClassFileParser::parse_localvariable_table(u4 code_length,
- u2 max_locals,
- u4 code_attribute_length,
- u2* localvariable_table_length,
- bool isLVTT,
- TRAPS) {
- ClassFileStream* cfs = stream();
- const char * tbl_name = (isLVTT) ? "LocalVariableTypeTable" : "LocalVariableTable";
+// LocalVariableTable (LVT) and LocalVariableTypeTable (LVTT)
+const u2* ClassFileParser::parse_localvariable_table(const ClassFileStream* cfs,
+ u4 code_length,
+ u2 max_locals,
+ u4 code_attribute_length,
+ u2* const localvariable_table_length,
+ bool isLVTT,
+ TRAPS) {
+ const char* const tbl_name = (isLVTT) ? "LocalVariableTypeTable" : "LocalVariableTable";
*localvariable_table_length = cfs->get_u2(CHECK_NULL);
- unsigned int size = (*localvariable_table_length) * sizeof(Classfile_LVT_Element) / sizeof(u2);
+ const unsigned int size =
+ (*localvariable_table_length) * sizeof(Classfile_LVT_Element) / sizeof(u2);
+
+ const ConstantPool* const cp = _cp;
+
// Verify local variable table attribute has right length
if (_need_verify) {
guarantee_property(code_attribute_length == (sizeof(*localvariable_table_length) + size * sizeof(u2)),
"%s has wrong length in class file %s", tbl_name, CHECK_NULL);
}
- u2* localvariable_table_start = cfs->get_u2_buffer();
+
+ const u2* const localvariable_table_start = cfs->get_u2_buffer();
assert(localvariable_table_start != NULL, "null local variable table");
if (!_need_verify) {
cfs->skip_u2_fast(size);
} else {
cfs->guarantee_more(size * 2, CHECK_NULL);
for(int i = 0; i < (*localvariable_table_length); i++) {
- u2 start_pc = cfs->get_u2_fast();
- u2 length = cfs->get_u2_fast();
- u2 name_index = cfs->get_u2_fast();
- u2 descriptor_index = cfs->get_u2_fast();
- u2 index = cfs->get_u2_fast();
+ const u2 start_pc = cfs->get_u2_fast();
+ const u2 length = cfs->get_u2_fast();
+ const u2 name_index = cfs->get_u2_fast();
+ const u2 descriptor_index = cfs->get_u2_fast();
+ const u2 index = cfs->get_u2_fast();
// Assign to a u4 to avoid overflow
- u4 end_pc = (u4)start_pc + (u4)length;
+ const u4 end_pc = (u4)start_pc + (u4)length;
if (start_pc >= code_length) {
classfile_parse_error(
@@ -1473,7 +1809,7 @@
"Invalid length %u in %s in class file %s",
length, tbl_name, CHECK_NULL);
}
- int cp_size = _cp->length();
+ const int cp_size = cp->length();
guarantee_property(valid_symbol_at(name_index),
"Name index %u in %s has bad constant type in class file %s",
name_index, tbl_name, CHECK_NULL);
@@ -1481,8 +1817,8 @@
"Signature index %u in %s has bad constant type in class file %s",
descriptor_index, tbl_name, CHECK_NULL);
- Symbol* name = _cp->symbol_at(name_index);
- Symbol* sig = _cp->symbol_at(descriptor_index);
+ const Symbol* const name = cp->symbol_at(name_index);
+ const Symbol* const sig = cp->symbol_at(descriptor_index);
verify_legal_field_name(name, CHECK_NULL);
u2 extra_slot = 0;
if (!isLVTT) {
@@ -1503,24 +1839,29 @@
}
-void ClassFileParser::parse_type_array(u2 array_length, u4 code_length, u4* u1_index, u4* u2_index,
- u1* u1_array, u2* u2_array, TRAPS) {
- ClassFileStream* cfs = stream();
+void ClassFileParser::parse_type_array(u2 array_length,
+ u4 code_length,
+ u4* const u1_index,
+ u4* const u2_index,
+ u1* const u1_array,
+ u2* const u2_array,
+ TRAPS) {
+ const ClassFileStream* const cfs = _stream;
u2 index = 0; // index in the array with long/double occupying two slots
u4 i1 = *u1_index;
u4 i2 = *u2_index + 1;
for(int i = 0; i < array_length; i++) {
- u1 tag = u1_array[i1++] = cfs->get_u1(CHECK);
+ const u1 tag = u1_array[i1++] = cfs->get_u1(CHECK);
index++;
if (tag == ITEM_Long || tag == ITEM_Double) {
index++;
} else if (tag == ITEM_Object) {
- u2 class_index = u2_array[i2++] = cfs->get_u2(CHECK);
+ const u2 class_index = u2_array[i2++] = cfs->get_u2(CHECK);
guarantee_property(valid_klass_reference_at(class_index),
"Bad class index %u in StackMap in class file %s",
class_index, CHECK);
} else if (tag == ITEM_Uninitialized) {
- u2 offset = u2_array[i2++] = cfs->get_u2(CHECK);
+ const u2 offset = u2_array[i2++] = cfs->get_u2(CHECK);
guarantee_property(
offset < code_length,
"Bad uninitialized type offset %u in StackMap in class file %s",
@@ -1537,39 +1878,47 @@
*u2_index = i2;
}
-u1* ClassFileParser::parse_stackmap_table(
- u4 code_attribute_length, TRAPS) {
- if (code_attribute_length == 0)
+static const u1* parse_stackmap_table(const ClassFileStream* const cfs,
+ u4 code_attribute_length,
+ bool need_verify,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
+
+ if (0 == code_attribute_length) {
return NULL;
-
- ClassFileStream* cfs = stream();
- u1* stackmap_table_start = cfs->get_u1_buffer();
+ }
+
+ const u1* const stackmap_table_start = cfs->get_u1_buffer();
assert(stackmap_table_start != NULL, "null stackmap table");
// check code_attribute_length first
- stream()->skip_u1(code_attribute_length, CHECK_NULL);
-
- if (!_need_verify && !DumpSharedSpaces) {
+ cfs->skip_u1(code_attribute_length, CHECK_NULL);
+
+ if (!need_verify && !DumpSharedSpaces) {
return NULL;
}
return stackmap_table_start;
}
-u2* ClassFileParser::parse_checked_exceptions(u2* checked_exceptions_length,
- u4 method_attribute_length,
- TRAPS) {
- ClassFileStream* cfs = stream();
+const u2* ClassFileParser::parse_checked_exceptions(const ClassFileStream* const cfs,
+ u2* const checked_exceptions_length,
+ u4 method_attribute_length,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
+ assert(checked_exceptions_length != NULL, "invariant");
+
cfs->guarantee_more(2, CHECK_NULL); // checked_exceptions_length
*checked_exceptions_length = cfs->get_u2_fast();
- unsigned int size = (*checked_exceptions_length) * sizeof(CheckedExceptionElement) / sizeof(u2);
- u2* checked_exceptions_start = cfs->get_u2_buffer();
+ const unsigned int size =
+ (*checked_exceptions_length) * sizeof(CheckedExceptionElement) / sizeof(u2);
+ const u2* const checked_exceptions_start = cfs->get_u2_buffer();
assert(checked_exceptions_start != NULL, "null checked exceptions");
if (!_need_verify) {
cfs->skip_u2_fast(size);
} else {
// Verify each value in the checked exception table
u2 checked_exception;
- u2 len = *checked_exceptions_length;
+ const u2 len = *checked_exceptions_length;
cfs->guarantee_more(2 * len, CHECK_NULL);
for (int i = 0; i < len; i++) {
checked_exception = cfs->get_u2_fast();
@@ -1588,8 +1937,13 @@
return checked_exceptions_start;
}
-void ClassFileParser::throwIllegalSignature(
- const char* type, Symbol* name, Symbol* sig, TRAPS) {
+void ClassFileParser::throwIllegalSignature(const char* type,
+ const Symbol* name,
+ const Symbol* sig,
+ TRAPS) const {
+ assert(name != NULL, "invariant");
+ assert(sig != NULL, "invariant");
+
ResourceMark rm(THREAD);
Exceptions::fthrow(THREAD_AND_LOCATION,
vmSymbols::java_lang_ClassFormatError(),
@@ -1597,181 +1951,74 @@
name->as_C_string(), _class_name->as_C_string(), sig->as_C_string());
}
-// Skip an annotation. Return >=limit if there is any problem.
-int ClassFileParser::skip_annotation(u1* buffer, int limit, int index) {
- // annotation := atype:u2 do(nmem:u2) {member:u2 value}
- // value := switch (tag:u1) { ... }
- index += 2; // skip atype
- if ((index += 2) >= limit) return limit; // read nmem
- int nmem = Bytes::get_Java_u2(buffer+index-2);
- while (--nmem >= 0 && index < limit) {
- index += 2; // skip member
- index = skip_annotation_value(buffer, limit, index);
- }
- return index;
-}
-
-// Skip an annotation value. Return >=limit if there is any problem.
-int ClassFileParser::skip_annotation_value(u1* buffer, int limit, int index) {
- // value := switch (tag:u1) {
- // case B, C, I, S, Z, D, F, J, c: con:u2;
- // case e: e_class:u2 e_name:u2;
- // case s: s_con:u2;
- // case [: do(nval:u2) {value};
- // case @: annotation;
- // case s: s_con:u2;
- // }
- if ((index += 1) >= limit) return limit; // read tag
- u1 tag = buffer[index-1];
- switch (tag) {
- case 'B': case 'C': case 'I': case 'S': case 'Z':
- case 'D': case 'F': case 'J': case 'c': case 's':
- index += 2; // skip con or s_con
- break;
- case 'e':
- index += 4; // skip e_class, e_name
- break;
- case '[':
- {
- if ((index += 2) >= limit) return limit; // read nval
- int nval = Bytes::get_Java_u2(buffer+index-2);
- while (--nval >= 0 && index < limit) {
- index = skip_annotation_value(buffer, limit, index);
- }
- }
- break;
- case '@':
- index = skip_annotation(buffer, limit, index);
- break;
- default:
- return limit; // bad tag byte
- }
- return index;
-}
-
-// Sift through annotations, looking for those significant to the VM:
-void ClassFileParser::parse_annotations(u1* buffer, int limit,
- ClassFileParser::AnnotationCollector* coll) {
- // annotations := do(nann:u2) {annotation}
- int index = 0;
- if ((index += 2) >= limit) return; // read nann
- int nann = Bytes::get_Java_u2(buffer+index-2);
- enum { // initial annotation layout
- atype_off = 0, // utf8 such as 'Ljava/lang/annotation/Retention;'
- count_off = 2, // u2 such as 1 (one value)
- member_off = 4, // utf8 such as 'value'
- tag_off = 6, // u1 such as 'c' (type) or 'e' (enum)
- e_tag_val = 'e',
- e_type_off = 7, // utf8 such as 'Ljava/lang/annotation/RetentionPolicy;'
- e_con_off = 9, // utf8 payload, such as 'SOURCE', 'CLASS', 'RUNTIME'
- e_size = 11, // end of 'e' annotation
- c_tag_val = 'c', // payload is type
- c_con_off = 7, // utf8 payload, such as 'I'
- c_size = 9, // end of 'c' annotation
- s_tag_val = 's', // payload is String
- s_con_off = 7, // utf8 payload, such as 'Ljava/lang/String;'
- s_size = 9,
- min_size = 6 // smallest possible size (zero members)
- };
- while ((--nann) >= 0 && (index-2 + min_size <= limit)) {
- int index0 = index;
- index = skip_annotation(buffer, limit, index);
- u1* abase = buffer + index0;
- int atype = Bytes::get_Java_u2(abase + atype_off);
- int count = Bytes::get_Java_u2(abase + count_off);
- Symbol* aname = check_symbol_at(_cp, atype);
- if (aname == NULL) break; // invalid annotation name
- Symbol* member = NULL;
- if (count >= 1) {
- int member_index = Bytes::get_Java_u2(abase + member_off);
- member = check_symbol_at(_cp, member_index);
- if (member == NULL) break; // invalid member name
- }
-
- // Here is where parsing particular annotations will take place.
- AnnotationCollector::ID id = coll->annotation_index(_loader_data, aname);
- if (id == AnnotationCollector::_unknown) continue;
- coll->set_annotation(id);
-
- if (id == AnnotationCollector::_jdk_internal_vm_annotation_Contended) {
- // @Contended can optionally specify the contention group.
- //
- // Contended group defines the equivalence class over the fields:
- // the fields within the same contended group are not treated distinct.
- // The only exception is default group, which does not incur the
- // equivalence. Naturally, contention group for classes is meaningless.
- //
- // While the contention group is specified as String, annotation
- // values are already interned, and we might as well use the constant
- // pool index as the group tag.
- //
- u2 group_index = 0; // default contended group
- if (count == 1
- && s_size == (index - index0) // match size
- && s_tag_val == *(abase + tag_off)
- && member == vmSymbols::value_name()) {
- group_index = Bytes::get_Java_u2(abase + s_con_off);
- if (_cp->symbol_at(group_index)->utf8_length() == 0) {
- group_index = 0; // default contended group
- }
- }
- coll->set_contended_group(group_index);
- }
- }
-}
-
-ClassFileParser::AnnotationCollector::ID
-ClassFileParser::AnnotationCollector::annotation_index(ClassLoaderData* loader_data,
- Symbol* name) {
- vmSymbols::SID sid = vmSymbols::find_sid(name);
+AnnotationCollector::ID
+AnnotationCollector::annotation_index(const ClassLoaderData* loader_data,
+ const Symbol* name) {
+ const vmSymbols::SID sid = vmSymbols::find_sid(name);
// Privileged code can use all annotations. Other code silently drops some.
const bool privileged = loader_data->is_the_null_class_loader_data() ||
loader_data->is_ext_class_loader_data() ||
loader_data->is_anonymous();
switch (sid) {
- case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_reflect_CallerSensitive_signature):
- if (_location != _in_method) break; // only allow for methods
- if (!privileged) break; // only allow in privileged code
- return _method_CallerSensitive;
- case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_ForceInline_signature):
- if (_location != _in_method) break; // only allow for methods
- if (!privileged) break; // only allow in privileged code
- return _method_ForceInline;
- case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_DontInline_signature):
- if (_location != _in_method) break; // only allow for methods
- if (!privileged) break; // only allow in privileged code
- return _method_DontInline;
- case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_InjectedProfile_signature):
- if (_location != _in_method) break; // only allow for methods
- if (!privileged) break; // only allow in privileged code
- return _method_InjectedProfile;
- case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Compiled_signature):
- if (_location != _in_method) break; // only allow for methods
- if (!privileged) break; // only allow in privileged code
- return _method_LambdaForm_Compiled;
- case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Hidden_signature):
- if (_location != _in_method) break; // only allow for methods
- if (!privileged) break; // only allow in privileged code
- return _method_LambdaForm_Hidden;
- case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_HotSpotIntrinsicCandidate_signature):
- if (_location != _in_method) break; // only allow for methods
- if (!privileged) break; // only allow in privileged code
- return _method_HotSpotIntrinsicCandidate;
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(sun_reflect_CallerSensitive_signature): {
+ if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
+ return _method_CallerSensitive;
+ }
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_ForceInline_signature): {
+ if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
+ return _method_ForceInline;
+ }
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_DontInline_signature): {
+ if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
+ return _method_DontInline;
+ }
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_InjectedProfile_signature): {
+ if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
+ return _method_InjectedProfile;
+ }
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Compiled_signature): {
+ if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
+ return _method_LambdaForm_Compiled;
+ }
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_LambdaForm_Hidden_signature): {
+ if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
+ return _method_LambdaForm_Hidden;
+ }
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_HotSpotIntrinsicCandidate_signature): {
+ if (_location != _in_method) break; // only allow for methods
+ if (!privileged) break; // only allow in privileged code
+ return _method_HotSpotIntrinsicCandidate;
+ }
#if INCLUDE_JVMCI
- case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_vm_ci_hotspot_Stable_signature):
- if (_location != _in_field) break; // only allow for fields
- if (!privileged) break; // only allow in privileged code
- return _field_Stable;
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_vm_ci_hotspot_Stable_signature): {
+ if (_location != _in_field) break; // only allow for fields
+ if (!privileged) break; // only allow in privileged code
+ return _field_Stable;
+ }
#endif
- case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_Stable_signature):
- if (_location != _in_field) break; // only allow for fields
- if (!privileged) break; // only allow in privileged code
- return _field_Stable;
- case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_Contended_signature):
- if (_location != _in_field && _location != _in_class) break; // only allow for fields and classes
- if (!EnableContended || (RestrictContended && !privileged)) break; // honor privileges
- return _jdk_internal_vm_annotation_Contended;
- default: break;
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(java_lang_invoke_Stable_signature): {
+ if (_location != _in_field) break; // only allow for fields
+ if (!privileged) break; // only allow in privileged code
+ return _field_Stable;
+ }
+ case vmSymbols::VM_SYMBOL_ENUM_NAME(jdk_internal_vm_annotation_Contended_signature): {
+ if (_location != _in_field && _location != _in_class) {
+ break; // only allow for fields and classes
+ }
+ if (!EnableContended || (RestrictContended && !privileged)) {
+ break; // honor privileges
+ }
+ return _jdk_internal_vm_annotation_Contended;
+ }
+ default: {
+ break;
+ }
}
return AnnotationCollector::_unknown;
}
@@ -1789,7 +2036,7 @@
MetadataFactory::free_array<u1>(_loader_data, _field_type_annotations);
}
-void ClassFileParser::MethodAnnotationCollector::apply_to(methodHandle m) {
+void MethodAnnotationCollector::apply_to(methodHandle m) {
if (has_annotation(_method_CallerSensitive))
m->set_caller_sensitive(true);
if (has_annotation(_method_ForceInline))
@@ -1806,11 +2053,11 @@
m->set_intrinsic_candidate(true);
}
-void ClassFileParser::ClassAnnotationCollector::apply_to(instanceKlassHandle k) {
- k->set_is_contended(is_contended());
+void ClassFileParser::ClassAnnotationCollector::apply_to(InstanceKlass* ik) {
+ assert(ik != NULL, "invariant");
+ ik->set_is_contended(is_contended());
}
-
#define MAX_ARGS_SIZE 255
#define MAX_CODE_SIZE 65535
#define INITIAL_MAX_LVT_NUMBER 256
@@ -1828,13 +2075,13 @@
* Each LVTT entry has to match some LVT entry.
* - HotSpot internal LVT keeps natural ordering of class file LVT entries.
*/
-void ClassFileParser::copy_localvariable_table(ConstMethod* cm,
+void ClassFileParser::copy_localvariable_table(const ConstMethod* cm,
int lvt_cnt,
- u2* localvariable_table_length,
- u2** localvariable_table_start,
+ u2* const localvariable_table_length,
+ const u2**const localvariable_table_start,
int lvtt_cnt,
- u2* localvariable_type_table_length,
- u2** localvariable_type_table_start,
+ u2* const localvariable_type_table_length,
+ const u2**const localvariable_type_table_start,
TRAPS) {
ResourceMark rm(THREAD);
@@ -1842,10 +2089,10 @@
typedef ResourceHashtable<LocalVariableTableElement, LocalVariableTableElement*,
&LVT_Hash::hash, &LVT_Hash::equals> LVT_HashTable;
- LVT_HashTable* table = new LVT_HashTable();
+ LVT_HashTable* const table = new LVT_HashTable();
// To fill LocalVariableTable in
- Classfile_LVT_Element* cf_lvt;
+ const Classfile_LVT_Element* cf_lvt;
LocalVariableTableElement* lvt = cm->localvariable_table_start();
for (int tbl_no = 0; tbl_no < lvt_cnt; tbl_no++) {
@@ -1865,7 +2112,7 @@
}
// To merge LocalVariableTable and LocalVariableTypeTable
- Classfile_LVT_Element* cf_lvtt;
+ const Classfile_LVT_Element* cf_lvtt;
LocalVariableTableElement lvtt_elem;
for (int tbl_no = 0; tbl_no < lvtt_cnt; tbl_no++) {
@@ -1895,19 +2142,19 @@
void ClassFileParser::copy_method_annotations(ConstMethod* cm,
- u1* runtime_visible_annotations,
+ const u1* runtime_visible_annotations,
int runtime_visible_annotations_length,
- u1* runtime_invisible_annotations,
+ const u1* runtime_invisible_annotations,
int runtime_invisible_annotations_length,
- u1* runtime_visible_parameter_annotations,
+ const u1* runtime_visible_parameter_annotations,
int runtime_visible_parameter_annotations_length,
- u1* runtime_invisible_parameter_annotations,
+ const u1* runtime_invisible_parameter_annotations,
int runtime_invisible_parameter_annotations_length,
- u1* runtime_visible_type_annotations,
+ const u1* runtime_visible_type_annotations,
int runtime_visible_type_annotations_length,
- u1* runtime_invisible_type_annotations,
+ const u1* runtime_invisible_type_annotations,
int runtime_invisible_type_annotations_length,
- u1* annotation_default,
+ const u1* annotation_default,
int annotation_default_length,
TRAPS) {
@@ -1963,33 +2210,37 @@
// from the method back up to the containing klass. These flag values
// are added to klass's access_flags.
-methodHandle ClassFileParser::parse_method(bool is_interface,
- AccessFlags *promoted_flags,
- TRAPS) {
- ClassFileStream* cfs = stream();
- methodHandle nullHandle;
+Method* ClassFileParser::parse_method(const ClassFileStream* const cfs,
+ bool is_interface,
+ const ConstantPool* cp,
+ AccessFlags* const promoted_flags,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
+ assert(cp != NULL, "invariant");
+ assert(promoted_flags != NULL, "invariant");
+
ResourceMark rm(THREAD);
- // Parse fixed parts
- cfs->guarantee_more(8, CHECK_(nullHandle)); // access_flags, name_index, descriptor_index, attributes_count
+ // Parse fixed parts:
+ // access_flags, name_index, descriptor_index, attributes_count
+ cfs->guarantee_more(8, CHECK_NULL);
int flags = cfs->get_u2_fast();
- u2 name_index = cfs->get_u2_fast();
- int cp_size = _cp->length();
+ const u2 name_index = cfs->get_u2_fast();
+ const int cp_size = cp->length();
check_property(
valid_symbol_at(name_index),
"Illegal constant pool index %u for method name in class file %s",
- name_index, CHECK_(nullHandle));
- Symbol* name = _cp->symbol_at(name_index);
- verify_legal_method_name(name, CHECK_(nullHandle));
-
- u2 signature_index = cfs->get_u2_fast();
+ name_index, CHECK_NULL);
+ const Symbol* const name = cp->symbol_at(name_index);
+ verify_legal_method_name(name, CHECK_NULL);
+
+ const u2 signature_index = cfs->get_u2_fast();
guarantee_property(
valid_symbol_at(signature_index),
"Illegal constant pool index %u for method signature in class file %s",
- signature_index, CHECK_(nullHandle));
- Symbol* signature = _cp->symbol_at(signature_index);
-
- AccessFlags access_flags;
+ signature_index, CHECK_NULL);
+ const Symbol* const signature = cp->symbol_at(signature_index);
+
if (name == vmSymbols::class_initializer_name()) {
// We ignore the other access flags for a valid class initializer.
// (JVM Spec 2nd ed., chapter 4.6)
@@ -1998,37 +2249,37 @@
} else if ((flags & JVM_ACC_STATIC) == JVM_ACC_STATIC) {
flags &= JVM_ACC_STATIC | JVM_ACC_STRICT;
} else {
- classfile_parse_error("Method <clinit> is not static in class file %s", CHECK_(nullHandle));
+ classfile_parse_error("Method <clinit> is not static in class file %s", CHECK_NULL);
}
} else {
- verify_legal_method_modifiers(flags, is_interface, name, CHECK_(nullHandle));
+ verify_legal_method_modifiers(flags, is_interface, name, CHECK_NULL);
}
if (name == vmSymbols::object_initializer_name() && is_interface) {
- classfile_parse_error("Interface cannot have a method named <init>, class file %s", CHECK_(nullHandle));
+ classfile_parse_error("Interface cannot have a method named <init>, class file %s", CHECK_NULL);
}
int args_size = -1; // only used when _need_verify is true
if (_need_verify) {
args_size = ((flags & JVM_ACC_STATIC) ? 0 : 1) +
- verify_legal_method_signature(name, signature, CHECK_(nullHandle));
+ verify_legal_method_signature(name, signature, CHECK_NULL);
if (args_size > MAX_ARGS_SIZE) {
- classfile_parse_error("Too many arguments in method signature in class file %s", CHECK_(nullHandle));
+ classfile_parse_error("Too many arguments in method signature in class file %s", CHECK_NULL);
}
}
- access_flags.set_flags(flags & JVM_RECOGNIZED_METHOD_MODIFIERS);
+ AccessFlags access_flags(flags & JVM_RECOGNIZED_METHOD_MODIFIERS);
// Default values for code and exceptions attribute elements
u2 max_stack = 0;
u2 max_locals = 0;
u4 code_length = 0;
- u1* code_start = 0;
+ const u1* code_start = 0;
u2 exception_table_length = 0;
- u2* exception_table_start = NULL;
+ const u2* exception_table_start = NULL;
Array<int>* exception_handlers = Universe::the_empty_int_array();
u2 checked_exceptions_length = 0;
- u2* checked_exceptions_start = NULL;
+ const u2* checked_exceptions_start = NULL;
CompressedLineNumberWriteStream* linenumber_table = NULL;
int linenumber_table_length = 0;
int total_lvt_length = 0;
@@ -2038,98 +2289,102 @@
u2 max_lvt_cnt = INITIAL_MAX_LVT_NUMBER;
u2 max_lvtt_cnt = INITIAL_MAX_LVT_NUMBER;
u2* localvariable_table_length = NULL;
- u2** localvariable_table_start = NULL;
+ const u2** localvariable_table_start = NULL;
u2* localvariable_type_table_length = NULL;
- u2** localvariable_type_table_start = NULL;
+ const u2** localvariable_type_table_start = NULL;
int method_parameters_length = -1;
- u1* method_parameters_data = NULL;
+ const u1* method_parameters_data = NULL;
bool method_parameters_seen = false;
bool parsed_code_attribute = false;
bool parsed_checked_exceptions_attribute = false;
bool parsed_stackmap_attribute = false;
// stackmap attribute - JDK1.5
- u1* stackmap_data = NULL;
+ const u1* stackmap_data = NULL;
int stackmap_data_length = 0;
u2 generic_signature_index = 0;
MethodAnnotationCollector parsed_annotations;
- u1* runtime_visible_annotations = NULL;
+ const u1* runtime_visible_annotations = NULL;
int runtime_visible_annotations_length = 0;
- u1* runtime_invisible_annotations = NULL;
+ const u1* runtime_invisible_annotations = NULL;
int runtime_invisible_annotations_length = 0;
- u1* runtime_visible_parameter_annotations = NULL;
+ const u1* runtime_visible_parameter_annotations = NULL;
int runtime_visible_parameter_annotations_length = 0;
- u1* runtime_invisible_parameter_annotations = NULL;
+ const u1* runtime_invisible_parameter_annotations = NULL;
int runtime_invisible_parameter_annotations_length = 0;
- u1* runtime_visible_type_annotations = NULL;
+ const u1* runtime_visible_type_annotations = NULL;
int runtime_visible_type_annotations_length = 0;
- u1* runtime_invisible_type_annotations = NULL;
+ const u1* runtime_invisible_type_annotations = NULL;
int runtime_invisible_type_annotations_length = 0;
bool runtime_invisible_annotations_exists = false;
bool runtime_invisible_type_annotations_exists = false;
bool runtime_invisible_parameter_annotations_exists = false;
- u1* annotation_default = NULL;
+ const u1* annotation_default = NULL;
int annotation_default_length = 0;
// Parse code and exceptions attribute
u2 method_attributes_count = cfs->get_u2_fast();
while (method_attributes_count--) {
- cfs->guarantee_more(6, CHECK_(nullHandle)); // method_attribute_name_index, method_attribute_length
- u2 method_attribute_name_index = cfs->get_u2_fast();
- u4 method_attribute_length = cfs->get_u4_fast();
+ cfs->guarantee_more(6, CHECK_NULL); // method_attribute_name_index, method_attribute_length
+ const u2 method_attribute_name_index = cfs->get_u2_fast();
+ const u4 method_attribute_length = cfs->get_u4_fast();
check_property(
valid_symbol_at(method_attribute_name_index),
"Invalid method attribute name index %u in class file %s",
- method_attribute_name_index, CHECK_(nullHandle));
-
- Symbol* method_attribute_name = _cp->symbol_at(method_attribute_name_index);
+ method_attribute_name_index, CHECK_NULL);
+
+ const Symbol* const method_attribute_name = cp->symbol_at(method_attribute_name_index);
if (method_attribute_name == vmSymbols::tag_code()) {
// Parse Code attribute
if (_need_verify) {
guarantee_property(
!access_flags.is_native() && !access_flags.is_abstract(),
"Code attribute in native or abstract methods in class file %s",
- CHECK_(nullHandle));
+ CHECK_NULL);
}
if (parsed_code_attribute) {
- classfile_parse_error("Multiple Code attributes in class file %s", CHECK_(nullHandle));
+ classfile_parse_error("Multiple Code attributes in class file %s",
+ CHECK_NULL);
}
parsed_code_attribute = true;
// Stack size, locals size, and code size
if (_major_version == 45 && _minor_version <= 2) {
- cfs->guarantee_more(4, CHECK_(nullHandle));
+ cfs->guarantee_more(4, CHECK_NULL);
max_stack = cfs->get_u1_fast();
max_locals = cfs->get_u1_fast();
code_length = cfs->get_u2_fast();
} else {
- cfs->guarantee_more(8, CHECK_(nullHandle));
+ cfs->guarantee_more(8, CHECK_NULL);
max_stack = cfs->get_u2_fast();
max_locals = cfs->get_u2_fast();
code_length = cfs->get_u4_fast();
}
if (_need_verify) {
guarantee_property(args_size <= max_locals,
- "Arguments can't fit into locals in class file %s", CHECK_(nullHandle));
+ "Arguments can't fit into locals in class file %s",
+ CHECK_NULL);
guarantee_property(code_length > 0 && code_length <= MAX_CODE_SIZE,
"Invalid method Code length %u in class file %s",
- code_length, CHECK_(nullHandle));
+ code_length, CHECK_NULL);
}
// Code pointer
code_start = cfs->get_u1_buffer();
assert(code_start != NULL, "null code start");
- cfs->guarantee_more(code_length, CHECK_(nullHandle));
+ cfs->guarantee_more(code_length, CHECK_NULL);
cfs->skip_u1_fast(code_length);
// Exception handler table
- cfs->guarantee_more(2, CHECK_(nullHandle)); // exception_table_length
+ cfs->guarantee_more(2, CHECK_NULL); // exception_table_length
exception_table_length = cfs->get_u2_fast();
if (exception_table_length > 0) {
- exception_table_start =
- parse_exception_table(code_length, exception_table_length, CHECK_(nullHandle));
+ exception_table_start = parse_exception_table(cfs,
+ code_length,
+ exception_table_length,
+ CHECK_NULL);
}
// Parse additional attributes in code attribute
- cfs->guarantee_more(2, CHECK_(nullHandle)); // code_attributes_count
+ cfs->guarantee_more(2, CHECK_NULL); // code_attributes_count
u2 code_attributes_count = cfs->get_u2_fast();
unsigned int calculated_attribute_length = 0;
@@ -2152,111 +2407,119 @@
sizeof(u2) ); // catch_type_index
while (code_attributes_count--) {
- cfs->guarantee_more(6, CHECK_(nullHandle)); // code_attribute_name_index, code_attribute_length
- u2 code_attribute_name_index = cfs->get_u2_fast();
- u4 code_attribute_length = cfs->get_u4_fast();
+ cfs->guarantee_more(6, CHECK_NULL); // code_attribute_name_index, code_attribute_length
+ const u2 code_attribute_name_index = cfs->get_u2_fast();
+ const u4 code_attribute_length = cfs->get_u4_fast();
calculated_attribute_length += code_attribute_length +
sizeof(code_attribute_name_index) +
sizeof(code_attribute_length);
check_property(valid_symbol_at(code_attribute_name_index),
"Invalid code attribute name index %u in class file %s",
code_attribute_name_index,
- CHECK_(nullHandle));
+ CHECK_NULL);
if (LoadLineNumberTables &&
- _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_line_number_table()) {
+ cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_line_number_table()) {
// Parse and compress line number table
- parse_linenumber_table(code_attribute_length, code_length,
- &linenumber_table, CHECK_(nullHandle));
+ parse_linenumber_table(code_attribute_length,
+ code_length,
+ &linenumber_table,
+ CHECK_NULL);
} else if (LoadLocalVariableTables &&
- _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_table()) {
+ cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_table()) {
// Parse local variable table
if (!lvt_allocated) {
localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, INITIAL_MAX_LVT_NUMBER);
localvariable_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
- THREAD, u2*, INITIAL_MAX_LVT_NUMBER);
+ THREAD, const u2*, INITIAL_MAX_LVT_NUMBER);
localvariable_type_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, INITIAL_MAX_LVT_NUMBER);
localvariable_type_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
- THREAD, u2*, INITIAL_MAX_LVT_NUMBER);
+ THREAD, const u2*, INITIAL_MAX_LVT_NUMBER);
lvt_allocated = true;
}
if (lvt_cnt == max_lvt_cnt) {
max_lvt_cnt <<= 1;
localvariable_table_length = REALLOC_RESOURCE_ARRAY(u2, localvariable_table_length, lvt_cnt, max_lvt_cnt);
- localvariable_table_start = REALLOC_RESOURCE_ARRAY(u2*, localvariable_table_start, lvt_cnt, max_lvt_cnt);
+ localvariable_table_start = REALLOC_RESOURCE_ARRAY(const u2*, localvariable_table_start, lvt_cnt, max_lvt_cnt);
}
localvariable_table_start[lvt_cnt] =
- parse_localvariable_table(code_length,
+ parse_localvariable_table(cfs,
+ code_length,
max_locals,
code_attribute_length,
&localvariable_table_length[lvt_cnt],
false, // is not LVTT
- CHECK_(nullHandle));
+ CHECK_NULL);
total_lvt_length += localvariable_table_length[lvt_cnt];
lvt_cnt++;
} else if (LoadLocalVariableTypeTables &&
_major_version >= JAVA_1_5_VERSION &&
- _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_type_table()) {
+ cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_local_variable_type_table()) {
if (!lvt_allocated) {
localvariable_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, INITIAL_MAX_LVT_NUMBER);
localvariable_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
- THREAD, u2*, INITIAL_MAX_LVT_NUMBER);
+ THREAD, const u2*, INITIAL_MAX_LVT_NUMBER);
localvariable_type_table_length = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, INITIAL_MAX_LVT_NUMBER);
localvariable_type_table_start = NEW_RESOURCE_ARRAY_IN_THREAD(
- THREAD, u2*, INITIAL_MAX_LVT_NUMBER);
+ THREAD, const u2*, INITIAL_MAX_LVT_NUMBER);
lvt_allocated = true;
}
// Parse local variable type table
if (lvtt_cnt == max_lvtt_cnt) {
max_lvtt_cnt <<= 1;
localvariable_type_table_length = REALLOC_RESOURCE_ARRAY(u2, localvariable_type_table_length, lvtt_cnt, max_lvtt_cnt);
- localvariable_type_table_start = REALLOC_RESOURCE_ARRAY(u2*, localvariable_type_table_start, lvtt_cnt, max_lvtt_cnt);
+ localvariable_type_table_start = REALLOC_RESOURCE_ARRAY(const u2*, localvariable_type_table_start, lvtt_cnt, max_lvtt_cnt);
}
localvariable_type_table_start[lvtt_cnt] =
- parse_localvariable_table(code_length,
+ parse_localvariable_table(cfs,
+ code_length,
max_locals,
code_attribute_length,
&localvariable_type_table_length[lvtt_cnt],
true, // is LVTT
- CHECK_(nullHandle));
+ CHECK_NULL);
lvtt_cnt++;
} else if (_major_version >= Verifier::STACKMAP_ATTRIBUTE_MAJOR_VERSION &&
- _cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_stack_map_table()) {
+ cp->symbol_at(code_attribute_name_index) == vmSymbols::tag_stack_map_table()) {
// Stack map is only needed by the new verifier in JDK1.5.
if (parsed_stackmap_attribute) {
- classfile_parse_error("Multiple StackMapTable attributes in class file %s", CHECK_(nullHandle));
+ classfile_parse_error("Multiple StackMapTable attributes in class file %s", CHECK_NULL);
}
- stackmap_data = parse_stackmap_table(code_attribute_length, CHECK_(nullHandle));
+ stackmap_data = parse_stackmap_table(cfs, code_attribute_length, _need_verify, CHECK_NULL);
stackmap_data_length = code_attribute_length;
parsed_stackmap_attribute = true;
} else {
// Skip unknown attributes
- cfs->skip_u1(code_attribute_length, CHECK_(nullHandle));
+ cfs->skip_u1(code_attribute_length, CHECK_NULL);
}
}
// check method attribute length
if (_need_verify) {
guarantee_property(method_attribute_length == calculated_attribute_length,
- "Code segment has wrong length in class file %s", CHECK_(nullHandle));
+ "Code segment has wrong length in class file %s",
+ CHECK_NULL);
}
} else if (method_attribute_name == vmSymbols::tag_exceptions()) {
// Parse Exceptions attribute
if (parsed_checked_exceptions_attribute) {
- classfile_parse_error("Multiple Exceptions attributes in class file %s", CHECK_(nullHandle));
+ classfile_parse_error("Multiple Exceptions attributes in class file %s",
+ CHECK_NULL);
}
parsed_checked_exceptions_attribute = true;
checked_exceptions_start =
- parse_checked_exceptions(&checked_exceptions_length,
+ parse_checked_exceptions(cfs,
+ &checked_exceptions_length,
method_attribute_length,
- CHECK_(nullHandle));
+ CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_method_parameters()) {
// reject multiple method parameters
if (method_parameters_seen) {
- classfile_parse_error("Multiple MethodParameters attributes in class file %s", CHECK_(nullHandle));
+ classfile_parse_error("Multiple MethodParameters attributes in class file %s",
+ CHECK_NULL);
}
method_parameters_seen = true;
method_parameters_length = cfs->get_u1_fast();
@@ -2264,7 +2527,7 @@
if (method_attribute_length != real_length) {
classfile_parse_error(
"Invalid MethodParameters method attribute length %u in class file",
- method_attribute_length, CHECK_(nullHandle));
+ method_attribute_length, CHECK_NULL);
}
method_parameters_data = cfs->get_u1_buffer();
cfs->skip_u2_fast(method_parameters_length);
@@ -2276,7 +2539,7 @@
if (method_attribute_length != 0) {
classfile_parse_error(
"Invalid Synthetic method attribute length %u in class file %s",
- method_attribute_length, CHECK_(nullHandle));
+ method_attribute_length, CHECK_NULL);
}
// Should we check that there hasn't already been a synthetic attribute?
access_flags.set_is_synthetic();
@@ -2284,31 +2547,37 @@
if (method_attribute_length != 0) {
classfile_parse_error(
"Invalid Deprecated method attribute length %u in class file %s",
- method_attribute_length, CHECK_(nullHandle));
+ method_attribute_length, CHECK_NULL);
}
} else if (_major_version >= JAVA_1_5_VERSION) {
if (method_attribute_name == vmSymbols::tag_signature()) {
if (method_attribute_length != 2) {
classfile_parse_error(
"Invalid Signature attribute length %u in class file %s",
- method_attribute_length, CHECK_(nullHandle));
+ method_attribute_length, CHECK_NULL);
}
- generic_signature_index = parse_generic_signature_attribute(CHECK_(nullHandle));
+ generic_signature_index = parse_generic_signature_attribute(cfs, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_runtime_visible_annotations()) {
if (runtime_visible_annotations != NULL) {
classfile_parse_error(
- "Multiple RuntimeVisibleAnnotations attributes for method in class file %s", CHECK_(nullHandle));
+ "Multiple RuntimeVisibleAnnotations attributes for method in class file %s",
+ CHECK_NULL);
}
runtime_visible_annotations_length = method_attribute_length;
runtime_visible_annotations = cfs->get_u1_buffer();
assert(runtime_visible_annotations != NULL, "null visible annotations");
- parse_annotations(runtime_visible_annotations,
- runtime_visible_annotations_length, &parsed_annotations);
- cfs->skip_u1(runtime_visible_annotations_length, CHECK_(nullHandle));
+ parse_annotations(cp,
+ runtime_visible_annotations,
+ runtime_visible_annotations_length,
+ &parsed_annotations,
+ _loader_data,
+ CHECK_NULL);
+ cfs->skip_u1(runtime_visible_annotations_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_runtime_invisible_annotations()) {
if (runtime_invisible_annotations_exists) {
classfile_parse_error(
- "Multiple RuntimeInvisibleAnnotations attributes for method in class file %s", CHECK_(nullHandle));
+ "Multiple RuntimeInvisibleAnnotations attributes for method in class file %s",
+ CHECK_NULL);
}
runtime_invisible_annotations_exists = true;
if (PreserveAllAnnotations) {
@@ -2316,54 +2585,57 @@
runtime_invisible_annotations = cfs->get_u1_buffer();
assert(runtime_invisible_annotations != NULL, "null invisible annotations");
}
- cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
+ cfs->skip_u1(method_attribute_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_runtime_visible_parameter_annotations()) {
if (runtime_visible_parameter_annotations != NULL) {
classfile_parse_error(
- "Multiple RuntimeVisibleParameterAnnotations attributes for method in class file %s", CHECK_(nullHandle));
+ "Multiple RuntimeVisibleParameterAnnotations attributes for method in class file %s",
+ CHECK_NULL);
}
runtime_visible_parameter_annotations_length = method_attribute_length;
runtime_visible_parameter_annotations = cfs->get_u1_buffer();
assert(runtime_visible_parameter_annotations != NULL, "null visible parameter annotations");
- cfs->skip_u1(runtime_visible_parameter_annotations_length, CHECK_(nullHandle));
+ cfs->skip_u1(runtime_visible_parameter_annotations_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_runtime_invisible_parameter_annotations()) {
if (runtime_invisible_parameter_annotations_exists) {
classfile_parse_error(
- "Multiple RuntimeInvisibleParameterAnnotations attributes for method in class file %s", CHECK_(nullHandle));
+ "Multiple RuntimeInvisibleParameterAnnotations attributes for method in class file %s",
+ CHECK_NULL);
}
runtime_invisible_parameter_annotations_exists = true;
if (PreserveAllAnnotations) {
runtime_invisible_parameter_annotations_length = method_attribute_length;
runtime_invisible_parameter_annotations = cfs->get_u1_buffer();
- assert(runtime_invisible_parameter_annotations != NULL, "null invisible parameter annotations");
+ assert(runtime_invisible_parameter_annotations != NULL,
+ "null invisible parameter annotations");
}
- cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
+ cfs->skip_u1(method_attribute_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_annotation_default()) {
if (annotation_default != NULL) {
classfile_parse_error(
"Multiple AnnotationDefault attributes for method in class file %s",
- CHECK_(nullHandle));
+ CHECK_NULL);
}
annotation_default_length = method_attribute_length;
annotation_default = cfs->get_u1_buffer();
assert(annotation_default != NULL, "null annotation default");
- cfs->skip_u1(annotation_default_length, CHECK_(nullHandle));
+ cfs->skip_u1(annotation_default_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_runtime_visible_type_annotations()) {
if (runtime_visible_type_annotations != NULL) {
classfile_parse_error(
"Multiple RuntimeVisibleTypeAnnotations attributes for method in class file %s",
- CHECK_(nullHandle));
+ CHECK_NULL);
}
runtime_visible_type_annotations_length = method_attribute_length;
runtime_visible_type_annotations = cfs->get_u1_buffer();
assert(runtime_visible_type_annotations != NULL, "null visible type annotations");
// No need for the VM to parse Type annotations
- cfs->skip_u1(runtime_visible_type_annotations_length, CHECK_(nullHandle));
+ cfs->skip_u1(runtime_visible_type_annotations_length, CHECK_NULL);
} else if (method_attribute_name == vmSymbols::tag_runtime_invisible_type_annotations()) {
if (runtime_invisible_type_annotations_exists) {
classfile_parse_error(
"Multiple RuntimeInvisibleTypeAnnotations attributes for method in class file %s",
- CHECK_(nullHandle));
+ CHECK_NULL);
} else {
runtime_invisible_type_annotations_exists = true;
}
@@ -2372,14 +2644,14 @@
runtime_invisible_type_annotations = cfs->get_u1_buffer();
assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
}
- cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
+ cfs->skip_u1(method_attribute_length, CHECK_NULL);
} else {
// Skip unknown attributes
- cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
+ cfs->skip_u1(method_attribute_length, CHECK_NULL);
}
} else {
// Skip unknown attributes
- cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
+ cfs->skip_u1(method_attribute_length, CHECK_NULL);
}
}
@@ -2390,8 +2662,11 @@
// Make sure there's at least one Code attribute in non-native/non-abstract method
if (_need_verify) {
- guarantee_property(access_flags.is_native() || access_flags.is_abstract() || parsed_code_attribute,
- "Absent Code attribute in method that is not native or abstract in class file %s", CHECK_(nullHandle));
+ guarantee_property(access_flags.is_native() ||
+ access_flags.is_abstract() ||
+ parsed_code_attribute,
+ "Absent Code attribute in method that is not native or abstract in class file %s",
+ CHECK_NULL);
}
// All sizing information for a Method* is finally available, now create it
@@ -2411,9 +2686,12 @@
annotation_default_length,
0);
- Method* m = Method::allocate(
- _loader_data, code_length, access_flags, &sizes,
- ConstMethod::NORMAL, CHECK_(nullHandle));
+ Method* const m = Method::allocate(_loader_data,
+ code_length,
+ access_flags,
+ &sizes,
+ ConstMethod::NORMAL,
+ CHECK_NULL);
ClassLoadingService::add_class_method_size(m->size()*HeapWordSize);
@@ -2423,7 +2701,7 @@
m->set_signature_index(signature_index);
#ifdef CC_INTERP
// hmm is there a gc issue here??
- ResultTypeFinder rtf(_cp->symbol_at(signature_index));
+ ResultTypeFinder rtf(cp->symbol_at(signature_index));
m->set_result_index(rtf.type());
#endif
@@ -2443,17 +2721,20 @@
m->set_max_stack(max_stack);
m->set_max_locals(max_locals);
if (stackmap_data != NULL) {
- m->constMethod()->copy_stackmap_data(_loader_data, stackmap_data,
- stackmap_data_length, CHECK_NULL);
+ m->constMethod()->copy_stackmap_data(_loader_data,
+ (u1*)stackmap_data,
+ stackmap_data_length,
+ CHECK_NULL);
}
// Copy byte codes
- m->set_code(code_start);
+ m->set_code((u1*)code_start);
// Copy line number table
if (linenumber_table != NULL) {
memcpy(m->compressed_linenumber_table(),
- linenumber_table->buffer(), linenumber_table_length);
+ linenumber_table->buffer(),
+ linenumber_table_length);
}
// Copy exception table
@@ -2461,35 +2742,40 @@
int size =
exception_table_length * sizeof(ExceptionTableElement) / sizeof(u2);
copy_u2_with_conversion((u2*) m->exception_table_start(),
- exception_table_start, size);
+ exception_table_start, size);
}
// Copy method parameters
if (method_parameters_length > 0) {
MethodParametersElement* elem = m->constMethod()->method_parameters_start();
for (int i = 0; i < method_parameters_length; i++) {
- elem[i].name_cp_index = Bytes::get_Java_u2(method_parameters_data);
+ elem[i].name_cp_index = Bytes::get_Java_u2((address)method_parameters_data);
method_parameters_data += 2;
- elem[i].flags = Bytes::get_Java_u2(method_parameters_data);
+ elem[i].flags = Bytes::get_Java_u2((address)method_parameters_data);
method_parameters_data += 2;
}
}
// Copy checked exceptions
if (checked_exceptions_length > 0) {
- int size = checked_exceptions_length * sizeof(CheckedExceptionElement) / sizeof(u2);
- copy_u2_with_conversion((u2*) m->checked_exceptions_start(), checked_exceptions_start, size);
+ const int size =
+ checked_exceptions_length * sizeof(CheckedExceptionElement) / sizeof(u2);
+ copy_u2_with_conversion((u2*) m->checked_exceptions_start(),
+ checked_exceptions_start,
+ size);
}
// Copy class file LVT's/LVTT's into the HotSpot internal LVT.
if (total_lvt_length > 0) {
promoted_flags->set_has_localvariable_table();
- copy_localvariable_table(m->constMethod(), lvt_cnt,
+ copy_localvariable_table(m->constMethod(),
+ lvt_cnt,
localvariable_table_length,
localvariable_table_start,
lvtt_cnt,
localvariable_type_table_length,
- localvariable_type_table_start, CHECK_NULL);
+ localvariable_type_table_start,
+ CHECK_NULL);
}
if (parsed_annotations.has_any_annotations())
@@ -2535,25 +2821,37 @@
// The promoted_flags parameter is used to pass relevant access_flags
// from the methods back up to the containing klass. These flag values
// are added to klass's access_flags.
-
-Array<Method*>* ClassFileParser::parse_methods(bool is_interface,
- AccessFlags* promoted_flags,
- bool* has_final_method,
- bool* declares_default_methods,
- TRAPS) {
- ClassFileStream* cfs = stream();
- cfs->guarantee_more(2, CHECK_NULL); // length
- u2 length = cfs->get_u2_fast();
+// Side-effects: populates the _methods field in the parser
+void ClassFileParser::parse_methods(const ClassFileStream* const cfs,
+ bool is_interface,
+ AccessFlags* promoted_flags,
+ bool* has_final_method,
+ bool* declares_default_methods,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
+ assert(promoted_flags != NULL, "invariant");
+ assert(has_final_method != NULL, "invariant");
+ assert(declares_default_methods != NULL, "invariant");
+
+ assert(NULL == _methods, "invariant");
+
+ cfs->guarantee_more(2, CHECK); // length
+ const u2 length = cfs->get_u2_fast();
if (length == 0) {
_methods = Universe::the_empty_method_array();
} else {
- _methods = MetadataFactory::new_array<Method*>(_loader_data, length, NULL, CHECK_NULL);
+ _methods = MetadataFactory::new_array<Method*>(_loader_data,
+ length,
+ NULL,
+ CHECK);
HandleMark hm(THREAD);
for (int index = 0; index < length; index++) {
- methodHandle method = parse_method(is_interface,
- promoted_flags,
- CHECK_NULL);
+ Method* method = parse_method(cfs,
+ is_interface,
+ _cp,
+ promoted_flags,
+ CHECK);
if (method->is_final()) {
*has_final_method = true;
@@ -2564,7 +2862,7 @@
&& !method->is_abstract() && !method->is_static()) {
*declares_default_methods = true;
}
- _methods->at_put(index, method());
+ _methods->at_put(index, method);
}
if (_need_verify && length > 1) {
@@ -2577,7 +2875,7 @@
{
debug_only(No_Safepoint_Verifier nsv;)
for (int i = 0; i < length; i++) {
- Method* m = _methods->at(i);
+ const Method* const m = _methods->at(i);
// If no duplicates, add name/signature in hashtable names_and_sigs.
if (!put_after_lookup(m->name(), m->signature(), names_and_sigs)) {
dup = true;
@@ -2587,16 +2885,14 @@
}
if (dup) {
classfile_parse_error("Duplicate method name&signature in class file %s",
- CHECK_NULL);
+ CHECK);
}
}
}
- return _methods;
}
-
-intArray* ClassFileParser::sort_methods(Array<Method*>* methods) {
- int length = methods->length();
+static const intArray* sort_methods(Array<Method*>* methods) {
+ const int length = methods->length();
// If JVMTI original method ordering or sharing is enabled we have to
// remember the original class file ordering.
// We temporarily use the vtable_index field in the Method* to store the
@@ -2604,7 +2900,7 @@
// Put the method ordering in the shared archive.
if (JvmtiExport::can_maintain_original_method_order() || DumpSharedSpaces) {
for (int index = 0; index < length; index++) {
- Method* m = methods->at(index);
+ Method* const m = methods->at(index);
assert(!m->valid_vtable_index(), "vtable index should not be set");
m->set_vtable_index(index);
}
@@ -2619,8 +2915,8 @@
if (JvmtiExport::can_maintain_original_method_order() || DumpSharedSpaces) {
method_ordering = new intArray(length);
for (int index = 0; index < length; index++) {
- Method* m = methods->at(index);
- int old_index = m->vtable_index();
+ Method* const m = methods->at(index);
+ const int old_index = m->vtable_index();
assert(old_index >= 0 && old_index < length, "invalid method index");
method_ordering->at_put(index, old_index);
m->set_vtable_index(Method::invalid_vtable_index);
@@ -2630,10 +2926,12 @@
}
// Parse generic_signature attribute for methods and fields
-u2 ClassFileParser::parse_generic_signature_attribute(TRAPS) {
- ClassFileStream* cfs = stream();
+u2 ClassFileParser::parse_generic_signature_attribute(const ClassFileStream* const cfs,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
+
cfs->guarantee_more(2, CHECK_0); // generic_signature_index
- u2 generic_signature_index = cfs->get_u2_fast();
+ const u2 generic_signature_index = cfs->get_u2_fast();
check_property(
valid_symbol_at(generic_signature_index),
"Invalid Signature attribute at constant pool index %u in class file %s",
@@ -2641,10 +2939,13 @@
return generic_signature_index;
}
-void ClassFileParser::parse_classfile_sourcefile_attribute(TRAPS) {
- ClassFileStream* cfs = stream();
+void ClassFileParser::parse_classfile_sourcefile_attribute(const ClassFileStream* const cfs,
+ TRAPS) {
+
+ assert(cfs != NULL, "invariant");
+
cfs->guarantee_more(2, CHECK); // sourcefile_index
- u2 sourcefile_index = cfs->get_u2_fast();
+ const u2 sourcefile_index = cfs->get_u2_fast();
check_property(
valid_symbol_at(sourcefile_index),
"Invalid SourceFile attribute at constant pool index %u in class file %s",
@@ -2652,22 +2953,23 @@
set_class_sourcefile_index(sourcefile_index);
}
-
-
-void ClassFileParser::parse_classfile_source_debug_extension_attribute(int length, TRAPS) {
- ClassFileStream* cfs = stream();
- u1* sde_buffer = cfs->get_u1_buffer();
+void ClassFileParser::parse_classfile_source_debug_extension_attribute(const ClassFileStream* const cfs,
+ int length,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
+
+ const u1* const sde_buffer = cfs->get_u1_buffer();
assert(sde_buffer != NULL, "null sde buffer");
// Don't bother storing it if there is no way to retrieve it
if (JvmtiExport::can_get_source_debug_extension()) {
assert((length+1) > length, "Overflow checking");
- u1* sde = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, u1, length+1);
+ u1* const sde = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, u1, length+1);
for (int i = 0; i < length; i++) {
sde[i] = sde_buffer[i];
}
sde[length] = '\0';
- set_class_sde_buffer((char*)sde, length);
+ set_class_sde_buffer((const char*)sde, length);
}
// Got utf8 string, set stream position forward
cfs->skip_u1(length, CHECK);
@@ -2675,16 +2977,20 @@
// Inner classes can be static, private or protected (classic VM does this)
-#define RECOGNIZED_INNER_CLASS_MODIFIERS (JVM_RECOGNIZED_CLASS_MODIFIERS | JVM_ACC_PRIVATE | JVM_ACC_PROTECTED | JVM_ACC_STATIC)
+#define RECOGNIZED_INNER_CLASS_MODIFIERS ( JVM_RECOGNIZED_CLASS_MODIFIERS | \
+ JVM_ACC_PRIVATE | \
+ JVM_ACC_PROTECTED | \
+ JVM_ACC_STATIC \
+ )
// Return number of classes in the inner classes attribute table
-u2 ClassFileParser::parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start,
+u2 ClassFileParser::parse_classfile_inner_classes_attribute(const ClassFileStream* const cfs,
+ const u1* const inner_classes_attribute_start,
bool parsed_enclosingmethod_attribute,
u2 enclosing_method_class_index,
u2 enclosing_method_method_index,
TRAPS) {
- ClassFileStream* cfs = stream();
- u1* current_mark = cfs->current();
+ const u1* const current_mark = cfs->current();
u2 length = 0;
if (inner_classes_attribute_start != NULL) {
cfs->set_current(inner_classes_attribute_start);
@@ -2701,29 +3007,29 @@
// ...
// enclosing_method_class_index,
// enclosing_method_method_index]
- int size = length * 4 + (parsed_enclosingmethod_attribute ? 2 : 0);
- Array<u2>* inner_classes = MetadataFactory::new_array<u2>(_loader_data, size, CHECK_0);
+ const int size = length * 4 + (parsed_enclosingmethod_attribute ? 2 : 0);
+ Array<u2>* const inner_classes = MetadataFactory::new_array<u2>(_loader_data, size, CHECK_0);
_inner_classes = inner_classes;
int index = 0;
- int cp_size = _cp->length();
+ const int cp_size = _cp->length();
cfs->guarantee_more(8 * length, CHECK_0); // 4-tuples of u2
for (int n = 0; n < length; n++) {
// Inner class index
- u2 inner_class_info_index = cfs->get_u2_fast();
+ const u2 inner_class_info_index = cfs->get_u2_fast();
check_property(
valid_klass_reference_at(inner_class_info_index),
"inner_class_info_index %u has bad constant type in class file %s",
inner_class_info_index, CHECK_0);
// Outer class index
- u2 outer_class_info_index = cfs->get_u2_fast();
+ const u2 outer_class_info_index = cfs->get_u2_fast();
check_property(
outer_class_info_index == 0 ||
valid_klass_reference_at(outer_class_info_index),
"outer_class_info_index %u has bad constant type in class file %s",
outer_class_info_index, CHECK_0);
// Inner class name
- u2 inner_name_index = cfs->get_u2_fast();
+ const u2 inner_name_index = cfs->get_u2_fast();
check_property(
inner_name_index == 0 || valid_symbol_at(inner_name_index),
"inner_name_index %u has bad constant type in class file %s",
@@ -2733,14 +3039,13 @@
"Class is both outer and inner class in class file %s", CHECK_0);
}
// Access flags
- AccessFlags inner_access_flags;
jint flags = cfs->get_u2_fast() & RECOGNIZED_INNER_CLASS_MODIFIERS;
if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
// Set abstract bit for old class files for backward compatibility
flags |= JVM_ACC_ABSTRACT;
}
verify_legal_class_modifiers(flags, CHECK_0);
- inner_access_flags.set_flags(flags);
+ AccessFlags inner_access_flags(flags);
inner_classes->at_put(index++, inner_class_info_index);
inner_classes->at_put(index++, outer_class_info_index);
@@ -2779,9 +3084,10 @@
set_class_synthetic_flag(true);
}
-void ClassFileParser::parse_classfile_signature_attribute(TRAPS) {
- ClassFileStream* cfs = stream();
- u2 signature_index = cfs->get_u2(CHECK);
+void ClassFileParser::parse_classfile_signature_attribute(const ClassFileStream* const cfs, TRAPS) {
+ assert(cfs != NULL, "invariant");
+
+ const u2 signature_index = cfs->get_u2(CHECK);
check_property(
valid_symbol_at(signature_index),
"Invalid constant pool index %u in Signature attribute in class file %s",
@@ -2789,9 +3095,14 @@
set_class_generic_signature_index(signature_index);
}
-void ClassFileParser::parse_classfile_bootstrap_methods_attribute(u4 attribute_byte_length, TRAPS) {
- ClassFileStream* cfs = stream();
- u1* current_start = cfs->current();
+void ClassFileParser::parse_classfile_bootstrap_methods_attribute(const ClassFileStream* const cfs,
+ ConstantPool* cp,
+ u4 attribute_byte_length,
+ TRAPS) {
+ assert(cfs != NULL, "invariant");
+ assert(cp != NULL, "invariant");
+
+ const u1* const current_start = cfs->current();
guarantee_property(attribute_byte_length >= sizeof(u2),
"Invalid BootstrapMethods attribute length %u in class file %s",
@@ -2800,7 +3111,7 @@
cfs->guarantee_more(attribute_byte_length, CHECK);
- int attribute_array_length = cfs->get_u2_fast();
+ const int attribute_array_length = cfs->get_u2_fast();
guarantee_property(_max_bootstrap_specifier_index < attribute_array_length,
"Short length on BootstrapMethods in class file %s",
@@ -2810,21 +3121,22 @@
// The attribute contains a counted array of counted tuples of shorts,
// represending bootstrap specifiers:
// length*{bootstrap_method_index, argument_count*{argument_index}}
- int operand_count = (attribute_byte_length - sizeof(u2)) / sizeof(u2);
+ const int operand_count = (attribute_byte_length - sizeof(u2)) / sizeof(u2);
// operand_count = number of shorts in attr, except for leading length
// The attribute is copied into a short[] array.
// The array begins with a series of short[2] pairs, one for each tuple.
- int index_size = (attribute_array_length * 2);
-
- Array<u2>* operands = MetadataFactory::new_array<u2>(_loader_data, index_size + operand_count, CHECK);
+ const int index_size = (attribute_array_length * 2);
+
+ Array<u2>* const operands =
+ MetadataFactory::new_array<u2>(_loader_data, index_size + operand_count, CHECK);
// Eagerly assign operands so they will be deallocated with the constant
// pool if there is an error.
- _cp->set_operands(operands);
+ cp->set_operands(operands);
int operand_fill_index = index_size;
- int cp_size = _cp->length();
+ const int cp_size = cp->length();
for (int n = 0; n < attribute_array_length; n++) {
// Store a 32-bit offset into the header of the operand array.
@@ -2832,11 +3144,11 @@
// Read a bootstrap specifier.
cfs->guarantee_more(sizeof(u2) * 2, CHECK); // bsm, argc
- u2 bootstrap_method_index = cfs->get_u2_fast();
- u2 argument_count = cfs->get_u2_fast();
+ const u2 bootstrap_method_index = cfs->get_u2_fast();
+ const u2 argument_count = cfs->get_u2_fast();
check_property(
valid_cp_range(bootstrap_method_index, cp_size) &&
- _cp->tag_at(bootstrap_method_index).is_method_handle(),
+ cp->tag_at(bootstrap_method_index).is_method_handle(),
"bootstrap_method_index %u has bad constant type in class file %s",
bootstrap_method_index,
CHECK);
@@ -2850,26 +3162,29 @@
cfs->guarantee_more(sizeof(u2) * argument_count, CHECK); // argv[argc]
for (int j = 0; j < argument_count; j++) {
- u2 argument_index = cfs->get_u2_fast();
+ const u2 argument_index = cfs->get_u2_fast();
check_property(
valid_cp_range(argument_index, cp_size) &&
- _cp->tag_at(argument_index).is_loadable_constant(),
+ cp->tag_at(argument_index).is_loadable_constant(),
"argument_index %u has bad constant type in class file %s",
argument_index,
CHECK);
operands->at_put(operand_fill_index++, argument_index);
}
}
-
- u1* current_end = cfs->current();
- guarantee_property(current_end == current_start + attribute_byte_length,
+ guarantee_property(current_start + attribute_byte_length == cfs->current(),
"Bad length on BootstrapMethods in class file %s",
CHECK);
}
-void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotationCollector* parsed_annotations,
+void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cfs,
+ ConstantPool* cp,
+ ClassFileParser::ClassAnnotationCollector* parsed_annotations,
TRAPS) {
- ClassFileStream* cfs = stream();
+ assert(cfs != NULL, "invariant");
+ assert(cp != NULL, "invariant");
+ assert(parsed_annotations != NULL, "invariant");
+
// Set inner classes attribute to default sentinel
_inner_classes = Universe::the_empty_short_array();
cfs->guarantee_more(2, CHECK); // attributes_count
@@ -2878,31 +3193,31 @@
bool parsed_innerclasses_attribute = false;
bool parsed_enclosingmethod_attribute = false;
bool parsed_bootstrap_methods_attribute = false;
- u1* runtime_visible_annotations = NULL;
+ const u1* runtime_visible_annotations = NULL;
int runtime_visible_annotations_length = 0;
- u1* runtime_invisible_annotations = NULL;
+ const u1* runtime_invisible_annotations = NULL;
int runtime_invisible_annotations_length = 0;
- u1* runtime_visible_type_annotations = NULL;
+ const u1* runtime_visible_type_annotations = NULL;
int runtime_visible_type_annotations_length = 0;
- u1* runtime_invisible_type_annotations = NULL;
+ const u1* runtime_invisible_type_annotations = NULL;
int runtime_invisible_type_annotations_length = 0;
bool runtime_invisible_type_annotations_exists = false;
bool runtime_invisible_annotations_exists = false;
bool parsed_source_debug_ext_annotations_exist = false;
- u1* inner_classes_attribute_start = NULL;
+ const u1* inner_classes_attribute_start = NULL;
u4 inner_classes_attribute_length = 0;
u2 enclosing_method_class_index = 0;
u2 enclosing_method_method_index = 0;
// Iterate over attributes
while (attributes_count--) {
cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length
- u2 attribute_name_index = cfs->get_u2_fast();
- u4 attribute_length = cfs->get_u4_fast();
+ const u2 attribute_name_index = cfs->get_u2_fast();
+ const u4 attribute_length = cfs->get_u4_fast();
check_property(
valid_symbol_at(attribute_name_index),
"Attribute name has bad constant pool index %u in class file %s",
attribute_name_index, CHECK);
- Symbol* tag = _cp->symbol_at(attribute_name_index);
+ const Symbol* const tag = cp->symbol_at(attribute_name_index);
if (tag == vmSymbols::tag_source_file()) {
// Check for SourceFile tag
if (_need_verify) {
@@ -2913,7 +3228,7 @@
} else {
parsed_sourcefile_attribute = true;
}
- parse_classfile_sourcefile_attribute(CHECK);
+ parse_classfile_sourcefile_attribute(cfs, CHECK);
} else if (tag == vmSymbols::tag_source_debug_extension()) {
// Check for SourceDebugExtension tag
if (parsed_source_debug_ext_annotations_exist) {
@@ -2921,7 +3236,7 @@
"Multiple SourceDebugExtension attributes in class file %s", CHECK);
}
parsed_source_debug_ext_annotations_exist = true;
- parse_classfile_source_debug_extension_attribute((int)attribute_length, CHECK);
+ parse_classfile_source_debug_extension_attribute(cfs, (int)attribute_length, CHECK);
} else if (tag == vmSymbols::tag_inner_classes()) {
// Check for InnerClasses tag
if (parsed_innerclasses_attribute) {
@@ -2955,7 +3270,7 @@
"Wrong Signature attribute length %u in class file %s",
attribute_length, CHECK);
}
- parse_classfile_signature_attribute(CHECK);
+ parse_classfile_signature_attribute(cfs, CHECK);
} else if (tag == vmSymbols::tag_runtime_visible_annotations()) {
if (runtime_visible_annotations != NULL) {
classfile_parse_error(
@@ -2964,9 +3279,12 @@
runtime_visible_annotations_length = attribute_length;
runtime_visible_annotations = cfs->get_u1_buffer();
assert(runtime_visible_annotations != NULL, "null visible annotations");
- parse_annotations(runtime_visible_annotations,
+ parse_annotations(cp,
+ runtime_visible_annotations,
runtime_visible_annotations_length,
- parsed_annotations);
+ parsed_annotations,
+ _loader_data,
+ CHECK);
cfs->skip_u1(runtime_visible_annotations_length, CHECK);
} else if (tag == vmSymbols::tag_runtime_invisible_annotations()) {
if (runtime_invisible_annotations_exists) {
@@ -2999,8 +3317,8 @@
check_property(valid_klass_reference_at(enclosing_method_class_index),
"Invalid or out-of-bounds class index in EnclosingMethod attribute in class file %s", CHECK);
if (enclosing_method_method_index != 0 &&
- (!_cp->is_within_bounds(enclosing_method_method_index) ||
- !_cp->tag_at(enclosing_method_method_index).is_name_and_type())) {
+ (!cp->is_within_bounds(enclosing_method_method_index) ||
+ !cp->tag_at(enclosing_method_method_index).is_name_and_type())) {
classfile_parse_error("Invalid or out-of-bounds method index in EnclosingMethod attribute in class file %s", CHECK);
}
} else if (tag == vmSymbols::tag_bootstrap_methods() &&
@@ -3008,7 +3326,7 @@
if (parsed_bootstrap_methods_attribute)
classfile_parse_error("Multiple BootstrapMethods attributes in class file %s", CHECK);
parsed_bootstrap_methods_attribute = true;
- parse_classfile_bootstrap_methods_attribute(attribute_length, CHECK);
+ parse_classfile_bootstrap_methods_attribute(cfs, cp, attribute_length, CHECK);
} else if (tag == vmSymbols::tag_runtime_visible_type_annotations()) {
if (runtime_visible_type_annotations != NULL) {
classfile_parse_error(
@@ -3053,7 +3371,8 @@
CHECK);
if (parsed_innerclasses_attribute || parsed_enclosingmethod_attribute) {
- u2 num_of_classes = parse_classfile_inner_classes_attribute(
+ const u2 num_of_classes = parse_classfile_inner_classes_attribute(
+ cfs,
inner_classes_attribute_start,
parsed_innerclasses_attribute,
enclosing_method_class_index,
@@ -3072,7 +3391,9 @@
}
}
-void ClassFileParser::apply_parsed_class_attributes(instanceKlassHandle k) {
+void ClassFileParser::apply_parsed_class_attributes(InstanceKlass* k) {
+ assert(k != NULL, "invariant");
+
if (_synthetic_flag)
k->set_is_synthetic();
if (_sourcefile_index != 0) {
@@ -3097,7 +3418,7 @@
return;
}
- Annotations* annotations = Annotations::allocate(_loader_data, CHECK);
+ Annotations* const annotations = Annotations::allocate(_loader_data, CHECK);
annotations->set_class_annotations(_annotations);
annotations->set_class_type_annotations(_type_annotations);
annotations->set_fields_annotations(_fields_annotations);
@@ -3117,9 +3438,11 @@
// Transfer ownership of metadata allocated to the InstanceKlass.
void ClassFileParser::apply_parsed_class_metadata(
- instanceKlassHandle this_klass,
+ InstanceKlass* this_klass,
int java_fields_count, TRAPS) {
- _cp->set_pool_holder(this_klass());
+ assert(this_klass != NULL, "invariant");
+
+ _cp->set_pool_holder(this_klass);
this_klass->set_constants(_cp);
this_klass->set_fields(_fields, java_fields_count);
this_klass->set_methods(_methods);
@@ -3132,10 +3455,11 @@
clear_class_metadata();
}
-AnnotationArray* ClassFileParser::assemble_annotations(u1* runtime_visible_annotations,
+AnnotationArray* ClassFileParser::assemble_annotations(const u1* const runtime_visible_annotations,
int runtime_visible_annotations_length,
- u1* runtime_invisible_annotations,
- int runtime_invisible_annotations_length, TRAPS) {
+ const u1* const runtime_invisible_annotations,
+ int runtime_invisible_annotations_length,
+ TRAPS) {
AnnotationArray* annotations = NULL;
if (runtime_visible_annotations != NULL ||
runtime_invisible_annotations != NULL) {
@@ -3158,9 +3482,13 @@
return annotations;
}
-instanceKlassHandle ClassFileParser::parse_super_class(int super_class_index,
- TRAPS) {
- instanceKlassHandle super_klass;
+const InstanceKlass* ClassFileParser::parse_super_class(ConstantPool* const cp,
+ const int super_class_index,
+ const bool need_verify,
+ TRAPS) {
+ assert(cp != NULL, "invariant");
+ const InstanceKlass* super_klass = NULL;
+
if (super_class_index == 0) {
check_property(_class_name == vmSymbols::java_lang_Object(),
"Invalid superclass index %u in class file %s",
@@ -3174,15 +3502,14 @@
// The class name should be legal because it is checked when parsing constant pool.
// However, make sure it is not an array type.
bool is_array = false;
- if (_cp->tag_at(super_class_index).is_klass()) {
- super_klass = instanceKlassHandle(THREAD, _cp->resolved_klass_at(super_class_index));
- if (_need_verify) {
+ if (cp->tag_at(super_class_index).is_klass()) {
+ super_klass = InstanceKlass::cast(cp->resolved_klass_at(super_class_index));
+ if (need_verify)
is_array = super_klass->is_array_klass();
- }
- } else if (_need_verify) {
- is_array = (_cp->klass_name_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY);
+ } else if (need_verify) {
+ is_array = (cp->klass_name_at(super_class_index)->byte_at(0) == JVM_SIGNATURE_ARRAY);
}
- if (_need_verify) {
+ if (need_verify) {
guarantee_property(!is_array,
"Bad superclass name in class file %s", CHECK_NULL);
}
@@ -3190,9 +3517,78 @@
return super_klass;
}
+static unsigned int compute_oop_map_count(const InstanceKlass* super,
+ unsigned int nonstatic_oop_map_count,
+ int first_nonstatic_oop_offset) {
+
+ unsigned int map_count =
+ NULL == super ? 0 : super->nonstatic_oop_map_count();
+ if (nonstatic_oop_map_count > 0) {
+ // We have oops to add to map
+ if (map_count == 0) {
+ map_count = nonstatic_oop_map_count;
+ }
+ else {
+ // Check whether we should add a new map block or whether the last one can
+ // be extended
+ const OopMapBlock* const first_map = super->start_of_nonstatic_oop_maps();
+ const OopMapBlock* const last_map = first_map + map_count - 1;
+
+ const int next_offset = last_map->offset() + last_map->count() * heapOopSize;
+ if (next_offset == first_nonstatic_oop_offset) {
+ // There is no gap bettwen superklass's last oop field and first
+ // local oop field, merge maps.
+ nonstatic_oop_map_count -= 1;
+ }
+ else {
+ // Superklass didn't end with a oop field, add extra maps
+ assert(next_offset < first_nonstatic_oop_offset, "just checking");
+ }
+ map_count += nonstatic_oop_map_count;
+ }
+ }
+ return map_count;
+}
+
+#ifndef PRODUCT
+static void print_field_layout(const Symbol* name,
+ Array<u2>* fields,
+ constantPoolHandle cp,
+ int instance_size,
+ int instance_fields_start,
+ int instance_fields_end,
+ int static_fields_end) {
+
+ assert(name != NULL, "invariant");
+
+ tty->print("%s: field layout\n", name->as_klass_external_name());
+ tty->print(" @%3d %s\n", instance_fields_start, "--- instance fields start ---");
+ for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) {
+ if (!fs.access_flags().is_static()) {
+ tty->print(" @%3d \"%s\" %s\n",
+ fs.offset(),
+ fs.name()->as_klass_external_name(),
+ fs.signature()->as_klass_external_name());
+ }
+ }
+ tty->print(" @%3d %s\n", instance_fields_end, "--- instance fields end ---");
+ tty->print(" @%3d %s\n", instance_size * wordSize, "--- instance ends ---");
+ tty->print(" @%3d %s\n", InstanceMirrorKlass::offset_of_static_fields(), "--- static fields start ---");
+ for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) {
+ if (fs.access_flags().is_static()) {
+ tty->print(" @%3d \"%s\" %s\n",
+ fs.offset(),
+ fs.name()->as_klass_external_name(),
+ fs.signature()->as_klass_external_name());
+ }
+ }
+ tty->print(" @%3d %s\n", static_fields_end, "--- static fields end ---");
+ tty->print("\n");
+}
+#endif
// Values needed for oopmap and InstanceKlass creation
-class FieldLayoutInfo : public StackObj {
+class ClassFileParser::FieldLayoutInfo : public ResourceObj {
public:
int* nonstatic_oop_offsets;
unsigned int* nonstatic_oop_counts;
@@ -3205,27 +3601,17 @@
};
// Layout fields and fill in FieldLayoutInfo. Could use more refactoring!
-void ClassFileParser::layout_fields(Handle class_loader,
- FieldAllocationCount* fac,
- ClassAnnotationCollector* parsed_annotations,
+void ClassFileParser::layout_fields(ConstantPool* cp,
+ const FieldAllocationCount* fac,
+ const ClassAnnotationCollector* parsed_annotations,
FieldLayoutInfo* info,
TRAPS) {
+ assert(cp != NULL, "invariant");
+
// Field size and offset computation
- int nonstatic_field_size = _super_klass() == NULL ? 0 : _super_klass()->nonstatic_field_size();
- int next_static_oop_offset = 0;
- int next_static_double_offset = 0;
- int next_static_word_offset = 0;
- int next_static_short_offset = 0;
- int next_static_byte_offset = 0;
- int next_nonstatic_oop_offset = 0;
- int next_nonstatic_double_offset = 0;
- int next_nonstatic_word_offset = 0;
- int next_nonstatic_short_offset = 0;
- int next_nonstatic_byte_offset = 0;
- int first_nonstatic_oop_offset = 0;
- int next_nonstatic_field_offset = 0;
- int next_nonstatic_padded_offset = 0;
+ int nonstatic_field_size = _super_klass == NULL ? 0 :
+ _super_klass->nonstatic_field_size();
// Count the contended fields by type.
//
@@ -3233,7 +3619,7 @@
// The layout code below will also ignore the static fields.
int nonstatic_contended_count = 0;
FieldAllocationCount fac_contended;
- for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) {
+ for (AllFieldStream fs(_fields, cp); !fs.done(); fs.next()) {
FieldAllocationType atype = (FieldAllocationType) fs.allocation_type();
if (fs.is_contended()) {
fac_contended.count[atype]++;
@@ -3245,28 +3631,28 @@
// Calculate the starting byte offsets
- next_static_oop_offset = InstanceMirrorKlass::offset_of_static_fields();
- next_static_double_offset = next_static_oop_offset +
- ((fac->count[STATIC_OOP]) * heapOopSize);
+ int next_static_oop_offset = InstanceMirrorKlass::offset_of_static_fields();
+ int next_static_double_offset = next_static_oop_offset +
+ ((fac->count[STATIC_OOP]) * heapOopSize);
if ( fac->count[STATIC_DOUBLE] &&
(Universe::field_type_should_be_aligned(T_DOUBLE) ||
Universe::field_type_should_be_aligned(T_LONG)) ) {
next_static_double_offset = align_size_up(next_static_double_offset, BytesPerLong);
}
- next_static_word_offset = next_static_double_offset +
- ((fac->count[STATIC_DOUBLE]) * BytesPerLong);
- next_static_short_offset = next_static_word_offset +
- ((fac->count[STATIC_WORD]) * BytesPerInt);
- next_static_byte_offset = next_static_short_offset +
- ((fac->count[STATIC_SHORT]) * BytesPerShort);
+ int next_static_word_offset = next_static_double_offset +
+ ((fac->count[STATIC_DOUBLE]) * BytesPerLong);
+ int next_static_short_offset = next_static_word_offset +
+ ((fac->count[STATIC_WORD]) * BytesPerInt);
+ int next_static_byte_offset = next_static_short_offset +
+ ((fac->count[STATIC_SHORT]) * BytesPerShort);
int nonstatic_fields_start = instanceOopDesc::base_offset_in_bytes() +
nonstatic_field_size * heapOopSize;
- next_nonstatic_field_offset = nonstatic_fields_start;
-
- bool is_contended_class = parsed_annotations->is_contended();
+ int next_nonstatic_field_offset = nonstatic_fields_start;
+
+ const bool is_contended_class = parsed_annotations->is_contended();
// Class is contended, pad before all the fields
if (is_contended_class) {
@@ -3288,9 +3674,10 @@
fac->count[NONSTATIC_SHORT] + fac->count[NONSTATIC_BYTE] +
fac->count[NONSTATIC_OOP];
- bool super_has_nonstatic_fields =
- (_super_klass() != NULL && _super_klass->has_nonstatic_fields());
- bool has_nonstatic_fields = super_has_nonstatic_fields || (nonstatic_fields_count != 0);
+ const bool super_has_nonstatic_fields =
+ (_super_klass != NULL && _super_klass->has_nonstatic_fields());
+ const bool has_nonstatic_fields =
+ super_has_nonstatic_fields || (nonstatic_fields_count != 0);
// Prepare list of oops for oop map generation.
@@ -3303,20 +3690,18 @@
//
// TODO: We add +1 to always allocate non-zero resource arrays; we need
// to figure out if we still need to do this.
- int* nonstatic_oop_offsets;
- unsigned int* nonstatic_oop_counts;
unsigned int nonstatic_oop_map_count = 0;
unsigned int max_nonstatic_oop_maps = fac->count[NONSTATIC_OOP] + 1;
- nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD(
+ int* nonstatic_oop_offsets = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, int, max_nonstatic_oop_maps);
- nonstatic_oop_counts = NEW_RESOURCE_ARRAY_IN_THREAD(
+ unsigned int* const nonstatic_oop_counts = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, unsigned int, max_nonstatic_oop_maps);
- first_nonstatic_oop_offset = 0; // will be set for first oop field
+ int first_nonstatic_oop_offset = 0; // will be set for first oop field
bool compact_fields = CompactFields;
- int allocation_style = FieldsAllocationStyle;
+ int allocation_style = FieldsAllocationStyle;
if( allocation_style < 0 || allocation_style > 2 ) { // Out of range?
assert(false, "0 <= FieldsAllocationStyle <= 2");
allocation_style = 1; // Optimistic
@@ -3325,7 +3710,7 @@
// The next classes have predefined hard-coded fields offsets
// (see in JavaClasses::compute_hard_coded_offsets()).
// Use default fields allocation order for them.
- if( (allocation_style != 0 || compact_fields ) && class_loader.is_null() &&
+ if( (allocation_style != 0 || compact_fields ) && _loader_data->class_loader() == NULL &&
(_class_name == vmSymbols::java_lang_AssertionStatusDirectives() ||
_class_name == vmSymbols::java_lang_Class() ||
_class_name == vmSymbols::java_lang_ClassLoader() ||
@@ -3346,6 +3731,9 @@
compact_fields = false; // Don't compact fields
}
+ int next_nonstatic_oop_offset = 0;
+ int next_nonstatic_double_offset = 0;
+
// Rearrange fields for a given allocation style
if( allocation_style == 0 ) {
// Fields order: oops, longs/doubles, ints, shorts/chars, bytes, padded fields
@@ -3357,12 +3745,12 @@
next_nonstatic_double_offset = next_nonstatic_field_offset;
} else if( allocation_style == 2 ) {
// Fields allocation: oops fields in super and sub classes are together.
- if( nonstatic_field_size > 0 && _super_klass() != NULL &&
+ if( nonstatic_field_size > 0 && _super_klass != NULL &&
_super_klass->nonstatic_oop_map_size() > 0 ) {
- unsigned int map_count = _super_klass->nonstatic_oop_map_count();
- OopMapBlock* first_map = _super_klass->start_of_nonstatic_oop_maps();
- OopMapBlock* last_map = first_map + map_count - 1;
- int next_offset = last_map->offset() + (last_map->count() * heapOopSize);
+ const unsigned int map_count = _super_klass->nonstatic_oop_map_count();
+ const OopMapBlock* const first_map = _super_klass->start_of_nonstatic_oop_maps();
+ const OopMapBlock* const last_map = first_map + map_count - 1;
+ const int next_offset = last_map->offset() + (last_map->count() * heapOopSize);
if (next_offset == next_nonstatic_field_offset) {
allocation_style = 0; // allocate oops first
next_nonstatic_oop_offset = next_nonstatic_field_offset;
@@ -3378,48 +3766,48 @@
ShouldNotReachHere();
}
- int nonstatic_oop_space_count = 0;
- int nonstatic_word_space_count = 0;
- int nonstatic_short_space_count = 0;
- int nonstatic_byte_space_count = 0;
- int nonstatic_oop_space_offset = 0;
- int nonstatic_word_space_offset = 0;
+ int nonstatic_oop_space_count = 0;
+ int nonstatic_word_space_count = 0;
+ int nonstatic_short_space_count = 0;
+ int nonstatic_byte_space_count = 0;
+ int nonstatic_oop_space_offset = 0;
+ int nonstatic_word_space_offset = 0;
int nonstatic_short_space_offset = 0;
- int nonstatic_byte_space_offset = 0;
+ int nonstatic_byte_space_offset = 0;
// Try to squeeze some of the fields into the gaps due to
// long/double alignment.
- if( nonstatic_double_count > 0 ) {
+ if (nonstatic_double_count > 0) {
int offset = next_nonstatic_double_offset;
next_nonstatic_double_offset = align_size_up(offset, BytesPerLong);
- if( compact_fields && offset != next_nonstatic_double_offset ) {
+ if (compact_fields && offset != next_nonstatic_double_offset) {
// Allocate available fields into the gap before double field.
int length = next_nonstatic_double_offset - offset;
assert(length == BytesPerInt, "");
nonstatic_word_space_offset = offset;
- if( nonstatic_word_count > 0 ) {
+ if (nonstatic_word_count > 0) {
nonstatic_word_count -= 1;
nonstatic_word_space_count = 1; // Only one will fit
length -= BytesPerInt;
offset += BytesPerInt;
}
nonstatic_short_space_offset = offset;
- while( length >= BytesPerShort && nonstatic_short_count > 0 ) {
+ while (length >= BytesPerShort && nonstatic_short_count > 0) {
nonstatic_short_count -= 1;
nonstatic_short_space_count += 1;
length -= BytesPerShort;
offset += BytesPerShort;
}
nonstatic_byte_space_offset = offset;
- while( length > 0 && nonstatic_byte_count > 0 ) {
+ while (length > 0 && nonstatic_byte_count > 0) {
nonstatic_byte_count -= 1;
nonstatic_byte_space_count += 1;
length -= 1;
}
// Allocate oop field in the gap if there are no other fields for that.
nonstatic_oop_space_offset = offset;
- if( length >= heapOopSize && nonstatic_oop_count > 0 &&
- allocation_style != 0 ) { // when oop fields not first
+ if (length >= heapOopSize && nonstatic_oop_count > 0 &&
+ allocation_style != 0) { // when oop fields not first
nonstatic_oop_count -= 1;
nonstatic_oop_space_count = 1; // Only one will fit
length -= heapOopSize;
@@ -3428,14 +3816,14 @@
}
}
- next_nonstatic_word_offset = next_nonstatic_double_offset +
- (nonstatic_double_count * BytesPerLong);
- next_nonstatic_short_offset = next_nonstatic_word_offset +
- (nonstatic_word_count * BytesPerInt);
- next_nonstatic_byte_offset = next_nonstatic_short_offset +
- (nonstatic_short_count * BytesPerShort);
- next_nonstatic_padded_offset = next_nonstatic_byte_offset +
- nonstatic_byte_count;
+ int next_nonstatic_word_offset = next_nonstatic_double_offset +
+ (nonstatic_double_count * BytesPerLong);
+ int next_nonstatic_short_offset = next_nonstatic_word_offset +
+ (nonstatic_word_count * BytesPerInt);
+ int next_nonstatic_byte_offset = next_nonstatic_short_offset +
+ (nonstatic_short_count * BytesPerShort);
+ int next_nonstatic_padded_offset = next_nonstatic_byte_offset +
+ nonstatic_byte_count;
// let oops jump before padding with this allocation style
if( allocation_style == 1 ) {
@@ -3449,7 +3837,7 @@
// Iterate over fields again and compute correct offsets.
// The field allocation type was temporarily stored in the offset slot.
// oop fields are located before non-oop fields (static and non-static).
- for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) {
+ for (AllFieldStream fs(_fields, cp); !fs.done(); fs.next()) {
// skip already laid out fields
if (fs.is_offset_set()) continue;
@@ -3458,7 +3846,7 @@
if (fs.is_contended() && !fs.access_flags().is_static()) continue;
int real_offset = 0;
- FieldAllocationType atype = (FieldAllocationType) fs.allocation_type();
+ const FieldAllocationType atype = (const FieldAllocationType) fs.allocation_type();
// pack the rest of the fields
switch (atype) {
@@ -3567,8 +3955,8 @@
next_nonstatic_padded_offset += ContendedPaddingWidth;
// collect all contended groups
- BitMap bm(_cp->size());
- for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) {
+ BitMap bm(cp->size());
+ for (AllFieldStream fs(_fields, cp); !fs.done(); fs.next()) {
// skip already laid out fields
if (fs.is_offset_set()) continue;
@@ -3580,7 +3968,7 @@
int current_group = -1;
while ((current_group = (int)bm.get_next_one_offset(current_group + 1)) != (int)bm.size()) {
- for (AllFieldStream fs(_fields, _cp); !fs.done(); fs.next()) {
+ for (AllFieldStream fs(_fields, cp); !fs.done(); fs.next()) {
// skip already laid out fields
if (fs.is_offset_set()) continue;
@@ -3714,7 +4102,7 @@
if (PrintFieldLayout) {
print_field_layout(_class_name,
_fields,
- _cp,
+ cp,
instance_size,
nonstatic_fields_start,
nonstatic_fields_end,
@@ -3733,751 +4121,13 @@
info->has_nonstatic_fields = has_nonstatic_fields;
}
-
-instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
- ClassLoaderData* loader_data,
- Handle protection_domain,
- KlassHandle host_klass,
- GrowableArray<Handle>* cp_patches,
- TempNewSymbol& parsed_name,
- bool verify,
- TRAPS) {
-
- // When a retransformable agent is attached, JVMTI caches the
- // class bytes that existed before the first retransformation.
- // If RedefineClasses() was used before the retransformable
- // agent attached, then the cached class bytes may not be the
- // original class bytes.
- JvmtiCachedClassFileData *cached_class_file = NULL;
- Handle class_loader(THREAD, loader_data->class_loader());
- bool has_default_methods = false;
- bool declares_default_methods = false;
- ResourceMark rm(THREAD);
-
- ClassFileStream* cfs = stream();
- // Timing
- assert(THREAD->is_Java_thread(), "must be a JavaThread");
- JavaThread* jt = (JavaThread*) THREAD;
-
- PerfClassTraceTime ctimer(ClassLoader::perf_class_parse_time(),
- ClassLoader::perf_class_parse_selftime(),
- NULL,
- jt->get_thread_stat()->perf_recursion_counts_addr(),
- jt->get_thread_stat()->perf_timers_addr(),
- PerfClassTraceTime::PARSE_CLASS);
-
- init_parsed_class_attributes(loader_data);
-
- if (JvmtiExport::should_post_class_file_load_hook()) {
- // Get the cached class file bytes (if any) from the class that
- // is being redefined or retransformed. We use jvmti_thread_state()
- // instead of JvmtiThreadState::state_for(jt) so we don't allocate
- // a JvmtiThreadState any earlier than necessary. This will help
- // avoid the bug described by 7126851.
- JvmtiThreadState *state = jt->jvmti_thread_state();
- if (state != NULL) {
- KlassHandle *h_class_being_redefined =
- state->get_class_being_redefined();
- if (h_class_being_redefined != NULL) {
- instanceKlassHandle ikh_class_being_redefined =
- instanceKlassHandle(THREAD, (*h_class_being_redefined)());
- cached_class_file = ikh_class_being_redefined->get_cached_class_file();
- }
- }
-
- unsigned char* ptr = cfs->buffer();
- unsigned char* end_ptr = cfs->buffer() + cfs->length();
-
- JvmtiExport::post_class_file_load_hook(name, class_loader(), protection_domain,
- &ptr, &end_ptr, &cached_class_file);
-
- if (ptr != cfs->buffer()) {
- // JVMTI agent has modified class file data.
- // Set new class file stream using JVMTI agent modified
- // class file data.
- cfs = new ClassFileStream(ptr, end_ptr - ptr, cfs->source());
- set_stream(cfs);
- }
- }
-
- _host_klass = host_klass;
- _cp_patches = cp_patches;
-
- instanceKlassHandle nullHandle;
-
- // Figure out whether we can skip format checking (matching classic VM behavior)
- if (DumpSharedSpaces) {
- // verify == true means it's a 'remote' class (i.e., non-boot class)
- // Verification decision is based on BytecodeVerificationRemote flag
- // for those classes.
- _need_verify = (verify) ? BytecodeVerificationRemote :
- BytecodeVerificationLocal;
- } else {
- _need_verify = Verifier::should_verify_for(class_loader(), verify);
- }
-
- // Set the verify flag in stream
- cfs->set_verify(_need_verify);
-
- // Save the class file name for easier error message printing.
- _class_name = (name != NULL) ? name : vmSymbols::unknown_class_name();
-
- cfs->guarantee_more(8, CHECK_(nullHandle)); // magic, major, minor
- // Magic value
- u4 magic = cfs->get_u4_fast();
- guarantee_property(magic == JAVA_CLASSFILE_MAGIC,
- "Incompatible magic value %u in class file %s",
- magic, CHECK_(nullHandle));
-
- // Version numbers
- u2 minor_version = cfs->get_u2_fast();
- u2 major_version = cfs->get_u2_fast();
-
- if (DumpSharedSpaces && major_version < JAVA_1_5_VERSION) {
- ResourceMark rm;
- warning("Pre JDK 1.5 class not supported by CDS: %u.%u %s",
- major_version, minor_version, name->as_C_string());
- Exceptions::fthrow(
- THREAD_AND_LOCATION,
- vmSymbols::java_lang_UnsupportedClassVersionError(),
- "Unsupported major.minor version for dump time %u.%u",
- major_version,
- minor_version);
- }
-
- // Check version numbers - we check this even with verifier off
- if (!is_supported_version(major_version, minor_version)) {
- if (name == NULL) {
- Exceptions::fthrow(
- THREAD_AND_LOCATION,
- vmSymbols::java_lang_UnsupportedClassVersionError(),
- "Unsupported class file version %u.%u, "
- "this version of the Java Runtime only recognizes class file versions up to %u.%u",
- major_version,
- minor_version,
- JAVA_MAX_SUPPORTED_VERSION,
- JAVA_MAX_SUPPORTED_MINOR_VERSION);
- } else {
- ResourceMark rm(THREAD);
- Exceptions::fthrow(
- THREAD_AND_LOCATION,
- vmSymbols::java_lang_UnsupportedClassVersionError(),
- "%s has been compiled by a more recent version of the Java Runtime (class file version %u.%u), "
- "this version of the Java Runtime only recognizes class file versions up to %u.%u",
- name->as_C_string(),
- major_version,
- minor_version,
- JAVA_MAX_SUPPORTED_VERSION,
- JAVA_MAX_SUPPORTED_MINOR_VERSION);
- }
- return nullHandle;
- }
-
- _major_version = major_version;
- _minor_version = minor_version;
-
-
- // Check if verification needs to be relaxed for this class file
- // Do not restrict it to jdk1.0 or jdk1.1 to maintain backward compatibility (4982376)
- _relax_verify = Verifier::relax_verify_for(class_loader());
-
- // Constant pool
- constantPoolHandle cp = parse_constant_pool(CHECK_(nullHandle));
-
- int cp_size = cp->length();
-
- cfs->guarantee_more(8, CHECK_(nullHandle)); // flags, this_class, super_class, infs_len
-
- // Access flags
- AccessFlags access_flags;
- jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS;
-
- if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
- // Set abstract bit for old class files for backward compatibility
- flags |= JVM_ACC_ABSTRACT;
- }
- verify_legal_class_modifiers(flags, CHECK_(nullHandle));
- access_flags.set_flags(flags);
-
- // This class and superclass
- u2 this_class_index = cfs->get_u2_fast();
- check_property(
- valid_cp_range(this_class_index, cp_size) &&
- cp->tag_at(this_class_index).is_unresolved_klass(),
- "Invalid this class index %u in constant pool in class file %s",
- this_class_index, CHECK_(nullHandle));
-
- Symbol* class_name = cp->klass_name_at(this_class_index);
- assert(class_name != NULL, "class_name can't be null");
-
- // It's important to set parsed_name *before* resolving the super class.
- // (it's used for cleanup by the caller if parsing fails)
- parsed_name = class_name;
- // parsed_name is returned and can be used if there's an error, so add to
- // its reference count. Caller will decrement the refcount.
- parsed_name->increment_refcount();
-
- // Update _class_name which could be null previously to be class_name
- _class_name = class_name;
-
- // Don't need to check whether this class name is legal or not.
- // It has been checked when constant pool is parsed.
- // However, make sure it is not an array type.
- if (_need_verify) {
- guarantee_property(class_name->byte_at(0) != JVM_SIGNATURE_ARRAY,
- "Bad class name in class file %s",
- CHECK_(nullHandle));
- }
-
- Klass* preserve_this_klass; // for storing result across HandleMark
-
- // release all handles when parsing is done
- { HandleMark hm(THREAD);
-
- // Checks if name in class file matches requested name
- if (name != NULL && class_name != name) {
- ResourceMark rm(THREAD);
- Exceptions::fthrow(
- THREAD_AND_LOCATION,
- vmSymbols::java_lang_NoClassDefFoundError(),
- "%s (wrong name: %s)",
- name->as_C_string(),
- class_name->as_C_string()
- );
- return nullHandle;
- }
-
- if (TraceClassLoadingPreorder) {
- tty->print("[Loading %s", (name != NULL) ? name->as_klass_external_name() : "NoName");
- if (cfs->source() != NULL) tty->print(" from %s", cfs->source());
- tty->print_cr("]");
- }
-#if INCLUDE_CDS
- if (DumpLoadedClassList != NULL && cfs->source() != NULL && classlist_file->is_open()) {
- // Only dump the classes that can be stored into CDS archive
- if (SystemDictionaryShared::is_sharing_possible(loader_data)) {
- if (name != NULL) {
- ResourceMark rm(THREAD);
- classlist_file->print_cr("%s", name->as_C_string());
- classlist_file->flush();
- }
- }
- }
-#endif
-
- u2 super_class_index = cfs->get_u2_fast();
- instanceKlassHandle super_klass = parse_super_class(super_class_index,
- CHECK_NULL);
-
- // Interfaces
- u2 itfs_len = cfs->get_u2_fast();
- Array<Klass*>* local_interfaces =
- parse_interfaces(itfs_len, protection_domain, _class_name,
- &has_default_methods, CHECK_(nullHandle));
-
- u2 java_fields_count = 0;
- // Fields (offsets are filled in later)
- FieldAllocationCount fac;
- Array<u2>* fields = parse_fields(class_name,
- access_flags.is_interface(),
- &fac, &java_fields_count,
- CHECK_(nullHandle));
- // Methods
- bool has_final_method = false;
- AccessFlags promoted_flags;
- promoted_flags.set_flags(0);
- Array<Method*>* methods = parse_methods(access_flags.is_interface(),
- &promoted_flags,
- &has_final_method,
- &declares_default_methods,
- CHECK_(nullHandle));
-
- if (declares_default_methods) {
- has_default_methods = true;
- }
-
- // Additional attributes
- ClassAnnotationCollector parsed_annotations;
- parse_classfile_attributes(&parsed_annotations, CHECK_(nullHandle));
-
- // Finalize the Annotations metadata object,
- // now that all annotation arrays have been created.
- create_combined_annotations(CHECK_(nullHandle));
-
- // Make sure this is the end of class file stream
- guarantee_property(cfs->at_eos(), "Extra bytes at the end of class file %s", CHECK_(nullHandle));
-
- // We check super class after class file is parsed and format is checked
- if (super_class_index > 0 && super_klass.is_null()) {
- Symbol* sk = cp->klass_name_at(super_class_index);
- if (access_flags.is_interface()) {
- // Before attempting to resolve the superclass, check for class format
- // errors not checked yet.
- guarantee_property(sk == vmSymbols::java_lang_Object(),
- "Interfaces must have java.lang.Object as superclass in class file %s",
- CHECK_(nullHandle));
- }
- Klass* k = SystemDictionary::resolve_super_or_fail(class_name, sk,
- class_loader,
- protection_domain,
- true,
- CHECK_(nullHandle));
-
- KlassHandle kh (THREAD, k);
- super_klass = instanceKlassHandle(THREAD, kh());
- }
- if (super_klass.not_null()) {
-
- if (super_klass->has_default_methods()) {
- has_default_methods = true;
- }
-
- if (super_klass->is_interface()) {
- ResourceMark rm(THREAD);
- Exceptions::fthrow(
- THREAD_AND_LOCATION,
- vmSymbols::java_lang_IncompatibleClassChangeError(),
- "class %s has interface %s as super class",
- class_name->as_klass_external_name(),
- super_klass->external_name()
- );
- return nullHandle;
- }
- // Make sure super class is not final
- if (super_klass->is_final()) {
- THROW_MSG_(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class", nullHandle);
- }
- }
-
- // save super klass for error handling.
- _super_klass = super_klass;
-
- // Compute the transitive list of all unique interfaces implemented by this class
- _transitive_interfaces =
- compute_transitive_interfaces(super_klass, local_interfaces, CHECK_(nullHandle));
-
- // sort methods
- intArray* method_ordering = sort_methods(methods);
-
- // promote flags from parse_methods() to the klass' flags
- access_flags.add_promoted_flags(promoted_flags.as_int());
-
- // Size of Java vtable (in words)
- int vtable_size = 0;
- int itable_size = 0;
- int num_miranda_methods = 0;
-
- GrowableArray<Method*> all_mirandas(20);
-
- klassVtable::compute_vtable_size_and_num_mirandas(
- &vtable_size, &num_miranda_methods, &all_mirandas, super_klass(), methods,
- access_flags, class_loader, class_name, local_interfaces,
- CHECK_(nullHandle));
-
- // Size of Java itable (in words)
- itable_size = access_flags.is_interface() ? 0 : klassItable::compute_itable_size(_transitive_interfaces);
-
- FieldLayoutInfo info;
- layout_fields(class_loader, &fac, &parsed_annotations, &info, CHECK_NULL);
-
- int total_oop_map_size2 =
- InstanceKlass::nonstatic_oop_map_size(info.total_oop_map_count);
-
- // Compute reference type
- ReferenceType rt;
- if (super_klass() == NULL) {
- rt = REF_NONE;
- } else {
- rt = super_klass->reference_type();
- }
-
- // We can now create the basic Klass* for this klass
- _klass = InstanceKlass::allocate_instance_klass(loader_data,
- vtable_size,
- itable_size,
- info.static_field_size,
- total_oop_map_size2,
- rt,
- access_flags,
- name,
- super_klass(),
- !host_klass.is_null(),
- CHECK_(nullHandle));
- instanceKlassHandle this_klass (THREAD, _klass);
-
- assert(this_klass->static_field_size() == info.static_field_size, "sanity");
- assert(this_klass->nonstatic_oop_map_count() == info.total_oop_map_count,
- "sanity");
-
- // Fill in information already parsed
- this_klass->set_should_verify_class(verify);
- jint lh = Klass::instance_layout_helper(info.instance_size, false);
- this_klass->set_layout_helper(lh);
- assert(this_klass->is_instance_klass(), "layout is correct");
- assert(this_klass->size_helper() == info.instance_size, "correct size_helper");
- // Not yet: supers are done below to support the new subtype-checking fields
- //this_klass->set_super(super_klass());
- this_klass->set_class_loader_data(loader_data);
- this_klass->set_nonstatic_field_size(info.nonstatic_field_size);
- this_klass->set_has_nonstatic_fields(info.has_nonstatic_fields);
- this_klass->set_static_oop_field_count(fac.count[STATIC_OOP]);
-
- apply_parsed_class_metadata(this_klass, java_fields_count, CHECK_NULL);
-
- if (has_final_method) {
- this_klass->set_has_final_method();
- }
- this_klass->copy_method_ordering(method_ordering, CHECK_NULL);
- // The InstanceKlass::_methods_jmethod_ids cache
- // is managed on the assumption that the initial cache
- // size is equal to the number of methods in the class. If
- // that changes, then InstanceKlass::idnum_can_increment()
- // has to be changed accordingly.
- this_klass->set_initial_method_idnum(methods->length());
- this_klass->set_name(cp->klass_name_at(this_class_index));
- if (is_anonymous()) // I am well known to myself
- cp->klass_at_put(this_class_index, this_klass()); // eagerly resolve
-
- this_klass->set_minor_version(minor_version);
- this_klass->set_major_version(major_version);
- this_klass->set_has_default_methods(has_default_methods);
- this_klass->set_declares_default_methods(declares_default_methods);
-
- if (!host_klass.is_null()) {
- assert (this_klass->is_anonymous(), "should be the same");
- this_klass->set_host_klass(host_klass());
- }
-
- // Set up Method*::intrinsic_id as soon as we know the names of methods.
- // (We used to do this lazily, but now we query it in Rewriter,
- // which is eagerly done for every method, so we might as well do it now,
- // when everything is fresh in memory.)
- vmSymbols::SID klass_id = Method::klass_id_for_intrinsics(this_klass());
- if (klass_id != vmSymbols::NO_SID) {
- for (int j = 0; j < methods->length(); j++) {
- Method* method = methods->at(j);
- method->init_intrinsic_id();
-
- if (CheckIntrinsics) {
- // Check if an intrinsic is defined for method 'method',
- // but the method is not annotated with @HotSpotIntrinsicCandidate.
- if (method->intrinsic_id() != vmIntrinsics::_none &&
- !method->intrinsic_candidate()) {
- tty->print("Compiler intrinsic is defined for method [%s], "
- "but the method is not annotated with @HotSpotIntrinsicCandidate.%s",
- method->name_and_sig_as_C_string(),
- NOT_DEBUG(" Method will not be inlined.") DEBUG_ONLY(" Exiting.")
- );
- tty->cr();
- DEBUG_ONLY(vm_exit(1));
- }
- // Check is the method 'method' is annotated with @HotSpotIntrinsicCandidate,
- // but there is no intrinsic available for it.
- if (method->intrinsic_candidate() &&
- method->intrinsic_id() == vmIntrinsics::_none) {
- tty->print("Method [%s] is annotated with @HotSpotIntrinsicCandidate, "
- "but no compiler intrinsic is defined for the method.%s",
- method->name_and_sig_as_C_string(),
- NOT_DEBUG("") DEBUG_ONLY(" Exiting.")
- );
- tty->cr();
- DEBUG_ONLY(vm_exit(1));
- }
- }
- }
-
-#ifdef ASSERT
- if (CheckIntrinsics) {
- // Check for orphan methods in the current class. A method m
- // of a class C is orphan if an intrinsic is defined for method m,
- // but class C does not declare m.
- // The check is potentially expensive, therefore it is available
- // only in debug builds.
-
- for (int id = vmIntrinsics::FIRST_ID; id < (int)vmIntrinsics::ID_LIMIT; id++) {
- if (id == vmIntrinsics::_compiledLambdaForm) {
- // The _compiledLamdbdaForm intrinsic is a special marker for bytecode
- // generated for the JVM from a LambdaForm and therefore no method
- // is defined for it.
- continue;
- }
-
- if (vmIntrinsics::class_for(vmIntrinsics::ID_from(id)) == klass_id) {
- // Check if the current class contains a method with the same
- // name, flags, signature.
- bool match = false;
- for (int j = 0; j < methods->length(); j++) {
- Method* method = methods->at(j);
- if (id == method->intrinsic_id()) {
- match = true;
- break;
- }
- }
-
- if (!match) {
- char buf[1000];
- tty->print("Compiler intrinsic is defined for method [%s], "
- "but the method is not available in class [%s].%s",
- vmIntrinsics::short_name_as_C_string(vmIntrinsics::ID_from(id), buf, sizeof(buf)),
- this_klass->name()->as_C_string(),
- NOT_DEBUG("") DEBUG_ONLY(" Exiting.")
- );
- tty->cr();
- DEBUG_ONLY(vm_exit(1));
- }
- }
- }
- }
-#endif // ASSERT
- }
-
-
- if (cached_class_file != NULL) {
- // JVMTI: we have an InstanceKlass now, tell it about the cached bytes
- this_klass->set_cached_class_file(cached_class_file);
- }
-
- // Fill in field values obtained by parse_classfile_attributes
- if (parsed_annotations.has_any_annotations())
- parsed_annotations.apply_to(this_klass);
- apply_parsed_class_attributes(this_klass);
-
- // Miranda methods
- if ((num_miranda_methods > 0) ||
- // if this class introduced new miranda methods or
- (super_klass.not_null() && (super_klass->has_miranda_methods()))
- // super class exists and this class inherited miranda methods
- ) {
- this_klass->set_has_miranda_methods(); // then set a flag
- }
-
- // Fill in information needed to compute superclasses.
- this_klass->initialize_supers(super_klass(), CHECK_(nullHandle));
-
- // Initialize itable offset tables
- klassItable::setup_itable_offset_table(this_klass);
-
- // Compute transitive closure of interfaces this class implements
- // Do final class setup
- fill_oop_maps(this_klass, info.nonstatic_oop_map_count, info.nonstatic_oop_offsets, info.nonstatic_oop_counts);
-
- // Fill in has_finalizer, has_vanilla_constructor, and layout_helper
- set_precomputed_flags(this_klass);
-
- // reinitialize modifiers, using the InnerClasses attribute
- int computed_modifiers = this_klass->compute_modifier_flags(CHECK_(nullHandle));
- this_klass->set_modifier_flags(computed_modifiers);
-
- // check if this class can access its super class
- check_super_class_access(this_klass, CHECK_(nullHandle));
-
- // check if this class can access its superinterfaces
- check_super_interface_access(this_klass, CHECK_(nullHandle));
-
- // check if this class overrides any final method
- check_final_method_override(this_klass, CHECK_(nullHandle));
-
- // check that if this class is an interface then it doesn't have static methods
- if (this_klass->is_interface()) {
- /* An interface in a JAVA 8 classfile can be static */
- if (_major_version < JAVA_8_VERSION) {
- check_illegal_static_method(this_klass, CHECK_(nullHandle));
- }
- }
-
- // Allocate mirror and initialize static fields
- java_lang_Class::create_mirror(this_klass, class_loader, protection_domain,
- CHECK_(nullHandle));
-
- // Generate any default methods - default methods are interface methods
- // that have a default implementation. This is new with Lambda project.
- if (has_default_methods ) {
- DefaultMethods::generate_default_methods(
- this_klass(), &all_mirandas, CHECK_(nullHandle));
- }
-
- // Update the loader_data graph.
- record_defined_class_dependencies(this_klass, CHECK_NULL);
-
- ClassLoadingService::notify_class_loaded(InstanceKlass::cast(this_klass()),
- false /* not shared class */);
-
- if (TraceClassLoading) {
- ResourceMark rm;
- // print in a single call to reduce interleaving of output
- if (cfs->source() != NULL) {
- tty->print("[Loaded %s from %s]\n", this_klass->external_name(),
- cfs->source());
- } else if (class_loader.is_null()) {
- Klass* caller =
- THREAD->is_Java_thread()
- ? ((JavaThread*)THREAD)->security_get_caller_class(1)
- : NULL;
- // caller can be NULL, for example, during a JVMTI VM_Init hook
- if (caller != NULL) {
- tty->print("[Loaded %s by instance of %s]\n",
- this_klass->external_name(),
- caller->external_name());
- } else {
- tty->print("[Loaded %s]\n", this_klass->external_name());
- }
- } else {
- tty->print("[Loaded %s from %s]\n", this_klass->external_name(),
- class_loader->klass()->external_name());
- }
- }
-
- if (TraceClassResolution) {
- ResourceMark rm;
- // print out the superclass.
- const char * from = this_klass()->external_name();
- if (this_klass->java_super() != NULL) {
- tty->print("RESOLVE %s %s (super)\n", from, this_klass->java_super()->external_name());
- }
- // print out each of the interface classes referred to by this class.
- Array<Klass*>* local_interfaces = this_klass->local_interfaces();
- if (local_interfaces != NULL) {
- int length = local_interfaces->length();
- for (int i = 0; i < length; i++) {
- Klass* k = local_interfaces->at(i);
- const char * to = k->external_name();
- tty->print("RESOLVE %s %s (interface)\n", from, to);
- }
- }
- }
-
- // preserve result across HandleMark
- preserve_this_klass = this_klass();
- }
-
- // Create new handle outside HandleMark (might be needed for
- // Extended Class Redefinition)
- instanceKlassHandle this_klass (THREAD, preserve_this_klass);
- debug_only(this_klass->verify();)
-
- // Clear class if no error has occurred so destructor doesn't deallocate it
- _klass = NULL;
- return this_klass;
-}
-
-// Destructor to clean up if there's an error
-ClassFileParser::~ClassFileParser() {
- MetadataFactory::free_metadata(_loader_data, _cp);
- MetadataFactory::free_array<u2>(_loader_data, _fields);
-
- // Free methods
- InstanceKlass::deallocate_methods(_loader_data, _methods);
-
- // beware of the Universe::empty_blah_array!!
- if (_inner_classes != Universe::the_empty_short_array()) {
- MetadataFactory::free_array<u2>(_loader_data, _inner_classes);
- }
-
- // Free interfaces
- InstanceKlass::deallocate_interfaces(_loader_data, _super_klass(),
- _local_interfaces, _transitive_interfaces);
-
- if (_combined_annotations != NULL) {
- // After all annotations arrays have been created, they are installed into the
- // Annotations object that will be assigned to the InstanceKlass being created.
-
- // Deallocate the Annotations object and the installed annotations arrays.
- _combined_annotations->deallocate_contents(_loader_data);
-
- // If the _combined_annotations pointer is non-NULL,
- // then the other annotations fields should have been cleared.
- assert(_annotations == NULL, "Should have been cleared");
- assert(_type_annotations == NULL, "Should have been cleared");
- assert(_fields_annotations == NULL, "Should have been cleared");
- assert(_fields_type_annotations == NULL, "Should have been cleared");
- } else {
- // If the annotations arrays were not installed into the Annotations object,
- // then they have to be deallocated explicitly.
- MetadataFactory::free_array<u1>(_loader_data, _annotations);
- MetadataFactory::free_array<u1>(_loader_data, _type_annotations);
- Annotations::free_contents(_loader_data, _fields_annotations);
- Annotations::free_contents(_loader_data, _fields_type_annotations);
- }
-
- clear_class_metadata();
-
- // deallocate the klass if already created. Don't directly deallocate, but add
- // to the deallocate list so that the klass is removed from the CLD::_klasses list
- // at a safepoint.
- if (_klass != NULL) {
- _loader_data->add_to_deallocate_list(_klass);
- }
- _klass = NULL;
-}
-
-void ClassFileParser::print_field_layout(Symbol* name,
- Array<u2>* fields,
- const constantPoolHandle& cp,
- int instance_size,
- int instance_fields_start,
- int instance_fields_end,
- int static_fields_end) {
- tty->print("%s: field layout\n", name->as_klass_external_name());
- tty->print(" @%3d %s\n", instance_fields_start, "--- instance fields start ---");
- for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) {
- if (!fs.access_flags().is_static()) {
- tty->print(" @%3d \"%s\" %s\n",
- fs.offset(),
- fs.name()->as_klass_external_name(),
- fs.signature()->as_klass_external_name());
- }
- }
- tty->print(" @%3d %s\n", instance_fields_end, "--- instance fields end ---");
- tty->print(" @%3d %s\n", instance_size * wordSize, "--- instance ends ---");
- tty->print(" @%3d %s\n", InstanceMirrorKlass::offset_of_static_fields(), "--- static fields start ---");
- for (AllFieldStream fs(fields, cp); !fs.done(); fs.next()) {
- if (fs.access_flags().is_static()) {
- tty->print(" @%3d \"%s\" %s\n",
- fs.offset(),
- fs.name()->as_klass_external_name(),
- fs.signature()->as_klass_external_name());
- }
- }
- tty->print(" @%3d %s\n", static_fields_end, "--- static fields end ---");
- tty->print("\n");
-}
-
-unsigned int
-ClassFileParser::compute_oop_map_count(instanceKlassHandle super,
- unsigned int nonstatic_oop_map_count,
- int first_nonstatic_oop_offset) {
- unsigned int map_count =
- super.is_null() ? 0 : super->nonstatic_oop_map_count();
- if (nonstatic_oop_map_count > 0) {
- // We have oops to add to map
- if (map_count == 0) {
- map_count = nonstatic_oop_map_count;
- } else {
- // Check whether we should add a new map block or whether the last one can
- // be extended
- OopMapBlock* const first_map = super->start_of_nonstatic_oop_maps();
- OopMapBlock* const last_map = first_map + map_count - 1;
-
- int next_offset = last_map->offset() + last_map->count() * heapOopSize;
- if (next_offset == first_nonstatic_oop_offset) {
- // There is no gap bettwen superklass's last oop field and first
- // local oop field, merge maps.
- nonstatic_oop_map_count -= 1;
- } else {
- // Superklass didn't end with a oop field, add extra maps
- assert(next_offset < first_nonstatic_oop_offset, "just checking");
- }
- map_count += nonstatic_oop_map_count;
- }
- }
- return map_count;
-}
-
-
-void ClassFileParser::fill_oop_maps(instanceKlassHandle k,
- unsigned int nonstatic_oop_map_count,
- int* nonstatic_oop_offsets,
- unsigned int* nonstatic_oop_counts) {
+static void fill_oop_maps(const InstanceKlass* k,
+ unsigned int nonstatic_oop_map_count,
+ const int* nonstatic_oop_offsets,
+ const unsigned int* nonstatic_oop_counts) {
+
+ assert(k != NULL, "invariant");
+
OopMapBlock* this_oop_map = k->start_of_nonstatic_oop_maps();
const InstanceKlass* const super = k->superklass();
const unsigned int super_count = super ? super->nonstatic_oop_map_count() : 0;
@@ -4513,22 +4163,24 @@
}
-void ClassFileParser::set_precomputed_flags(instanceKlassHandle k) {
- Klass* super = k->super();
+void ClassFileParser::set_precomputed_flags(InstanceKlass* ik) {
+ assert(ik != NULL, "invariant");
+
+ const Klass* const super = ik->super();
// Check if this klass has an empty finalize method (i.e. one with return bytecode only),
// in which case we don't have to register objects as finalizable
if (!_has_empty_finalizer) {
if (_has_finalizer ||
(super != NULL && super->has_finalizer())) {
- k->set_has_finalizer();
+ ik->set_has_finalizer();
}
}
#ifdef ASSERT
bool f = false;
- Method* m = k->lookup_method(vmSymbols::finalize_method_name(),
- vmSymbols::void_method_signature());
+ const Method* const m = ik->lookup_method(vmSymbols::finalize_method_name(),
+ vmSymbols::void_method_signature());
if (m != NULL && !m->is_empty_method()) {
f = true;
}
@@ -4536,70 +4188,74 @@
// Spec doesn't prevent agent from redefinition of empty finalizer.
// Despite the fact that it's generally bad idea and redefined finalizer
// will not work as expected we shouldn't abort vm in this case
- if (!k->has_redefined_this_or_super()) {
- assert(f == k->has_finalizer(), "inconsistent has_finalizer");
+ if (!ik->has_redefined_this_or_super()) {
+ assert(ik->has_finalizer() == f, "inconsistent has_finalizer");
}
#endif
// Check if this klass supports the java.lang.Cloneable interface
if (SystemDictionary::Cloneable_klass_loaded()) {
- if (k->is_subtype_of(SystemDictionary::Cloneable_klass())) {
- k->set_is_cloneable();
+ if (ik->is_subtype_of(SystemDictionary::Cloneable_klass())) {
+ ik->set_is_cloneable();
}
}
// Check if this klass has a vanilla default constructor
if (super == NULL) {
// java.lang.Object has empty default constructor
- k->set_has_vanilla_constructor();
+ ik->set_has_vanilla_constructor();
} else {
if (super->has_vanilla_constructor() &&
_has_vanilla_constructor) {
- k->set_has_vanilla_constructor();
+ ik->set_has_vanilla_constructor();
}
#ifdef ASSERT
bool v = false;
if (super->has_vanilla_constructor()) {
- Method* constructor = k->find_method(vmSymbols::object_initializer_name(
-), vmSymbols::void_method_signature());
+ const Method* const constructor =
+ ik->find_method(vmSymbols::object_initializer_name(),
+ vmSymbols::void_method_signature());
if (constructor != NULL && constructor->is_vanilla_constructor()) {
v = true;
}
}
- assert(v == k->has_vanilla_constructor(), "inconsistent has_vanilla_constructor");
+ assert(v == ik->has_vanilla_constructor(), "inconsistent has_vanilla_constructor");
#endif
}
// If it cannot be fast-path allocated, set a bit in the layout helper.
// See documentation of InstanceKlass::can_be_fastpath_allocated().
- assert(k->size_helper() > 0, "layout_helper is initialized");
- if ((!RegisterFinalizersAtInit && k->has_finalizer())
- || k->is_abstract() || k->is_interface()
- || (k->name() == vmSymbols::java_lang_Class() && k->class_loader() == NULL)
- || k->size_helper() >= FastAllocateSizeLimit) {
+ assert(ik->size_helper() > 0, "layout_helper is initialized");
+ if ((!RegisterFinalizersAtInit && ik->has_finalizer())
+ || ik->is_abstract() || ik->is_interface()
+ || (ik->name() == vmSymbols::java_lang_Class() && ik->class_loader() == NULL)
+ || ik->size_helper() >= FastAllocateSizeLimit) {
// Forbid fast-path allocation.
- jint lh = Klass::instance_layout_helper(k->size_helper(), true);
- k->set_layout_helper(lh);
+ const jint lh = Klass::instance_layout_helper(ik->size_helper(), true);
+ ik->set_layout_helper(lh);
}
}
// Attach super classes and interface classes to class loader data
-void ClassFileParser::record_defined_class_dependencies(instanceKlassHandle defined_klass, TRAPS) {
- ClassLoaderData * defining_loader_data = defined_klass->class_loader_data();
+static void record_defined_class_dependencies(const InstanceKlass* defined_klass,
+ TRAPS) {
+ assert(defined_klass != NULL, "invariant");
+
+ ClassLoaderData* const defining_loader_data = defined_klass->class_loader_data();
if (defining_loader_data->is_the_null_class_loader_data()) {
// Dependencies to null class loader data are implicit.
return;
} else {
// add super class dependency
- Klass* super = defined_klass->super();
+ Klass* const super = defined_klass->super();
if (super != NULL) {
defining_loader_data->record_dependency(super, CHECK);
}
// add super interface dependencies
- Array<Klass*>* local_interfaces = defined_klass->local_interfaces();
+ const Array<Klass*>* const local_interfaces = defined_klass->local_interfaces();
if (local_interfaces != NULL) {
- int length = local_interfaces->length();
+ const int length = local_interfaces->length();
for (int i = 0; i < length; i++) {
defining_loader_data->record_dependency(local_interfaces->at(i), CHECK);
}
@@ -4609,31 +4265,36 @@
// utility methods for appending an array with check for duplicates
-void append_interfaces(GrowableArray<Klass*>* result, Array<Klass*>* ifs) {
+static void append_interfaces(GrowableArray<Klass*>* result,
+ const Array<Klass*>* const ifs) {
// iterate over new interfaces
for (int i = 0; i < ifs->length(); i++) {
- Klass* e = ifs->at(i);
+ Klass* const e = ifs->at(i);
assert(e->is_klass() && InstanceKlass::cast(e)->is_interface(), "just checking");
// add new interface
result->append_if_missing(e);
}
}
-Array<Klass*>* ClassFileParser::compute_transitive_interfaces(
- instanceKlassHandle super,
- Array<Klass*>* local_ifs, TRAPS) {
+static Array<Klass*>* compute_transitive_interfaces(const InstanceKlass* super,
+ Array<Klass*>* local_ifs,
+ ClassLoaderData* loader_data,
+ TRAPS) {
+ assert(local_ifs != NULL, "invariant");
+ assert(loader_data != NULL, "invariant");
+
// Compute maximum size for transitive interfaces
int max_transitive_size = 0;
int super_size = 0;
// Add superclass transitive interfaces size
- if (super.not_null()) {
+ if (super != NULL) {
super_size = super->transitive_interfaces()->length();
max_transitive_size += super_size;
}
// Add local interfaces' super interfaces
- int local_size = local_ifs->length();
+ const int local_size = local_ifs->length();
for (int i = 0; i < local_size; i++) {
- Klass* l = local_ifs->at(i);
+ Klass* const l = local_ifs->at(i);
max_transitive_size += InstanceKlass::cast(l)->transitive_interfaces()->length();
}
// Finally add local interfaces
@@ -4650,38 +4311,40 @@
return local_ifs;
} else {
ResourceMark rm;
- GrowableArray<Klass*>* result = new GrowableArray<Klass*>(max_transitive_size);
+ GrowableArray<Klass*>* const result = new GrowableArray<Klass*>(max_transitive_size);
// Copy down from superclass
- if (super.not_null()) {
+ if (super != NULL) {
append_interfaces(result, super->transitive_interfaces());
}
// Copy down from local interfaces' superinterfaces
- for (int i = 0; i < local_ifs->length(); i++) {
- Klass* l = local_ifs->at(i);
+ for (int i = 0; i < local_size; i++) {
+ Klass* const l = local_ifs->at(i);
append_interfaces(result, InstanceKlass::cast(l)->transitive_interfaces());
}
// Finally add local interfaces
append_interfaces(result, local_ifs);
// length will be less than the max_transitive_size if duplicates were removed
- int length = result->length();
+ const int length = result->length();
assert(length <= max_transitive_size, "just checking");
- Array<Klass*>* new_result = MetadataFactory::new_array<Klass*>(_loader_data, length, CHECK_NULL);
+ Array<Klass*>* const new_result =
+ MetadataFactory::new_array<Klass*>(loader_data, length, CHECK_NULL);
for (int i = 0; i < length; i++) {
- Klass* e = result->at(i);
- assert(e != NULL, "just checking");
+ Klass* const e = result->at(i);
+ assert(e != NULL, "just checking");
new_result->at_put(i, e);
}
return new_result;
}
}
-void ClassFileParser::check_super_class_access(instanceKlassHandle this_klass, TRAPS) {
- Klass* super = this_klass->super();
+static void check_super_class_access(const InstanceKlass* this_klass, TRAPS) {
+ assert(this_klass != NULL, "invariant");
+ const Klass* const super = this_klass->super();
if ((super != NULL) &&
- (!Reflection::verify_class_access(this_klass(), super, false))) {
+ (!Reflection::verify_class_access(this_klass, super, false))) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
@@ -4695,13 +4358,14 @@
}
-void ClassFileParser::check_super_interface_access(instanceKlassHandle this_klass, TRAPS) {
- Array<Klass*>* local_interfaces = this_klass->local_interfaces();
- int lng = local_interfaces->length();
+static void check_super_interface_access(const InstanceKlass* this_klass, TRAPS) {
+ assert(this_klass != NULL, "invariant");
+ const Array<Klass*>* const local_interfaces = this_klass->local_interfaces();
+ const int lng = local_interfaces->length();
for (int i = lng - 1; i >= 0; i--) {
- Klass* k = local_interfaces->at(i);
+ Klass* const k = local_interfaces->at(i);
assert (k != NULL && k->is_interface(), "invalid interface");
- if (!Reflection::verify_class_access(this_klass(), k, false)) {
+ if (!Reflection::verify_class_access(this_klass, k, false)) {
ResourceMark rm(THREAD);
Exceptions::fthrow(
THREAD_AND_LOCATION,
@@ -4716,22 +4380,23 @@
}
-void ClassFileParser::check_final_method_override(instanceKlassHandle this_klass, TRAPS) {
- Array<Method*>* methods = this_klass->methods();
- int num_methods = methods->length();
+static void check_final_method_override(const InstanceKlass* this_klass, TRAPS) {
+ assert(this_klass != NULL, "invariant");
+ const Array<Method*>* const methods = this_klass->methods();
+ const int num_methods = methods->length();
// go thru each method and check if it overrides a final method
for (int index = 0; index < num_methods; index++) {
- Method* m = methods->at(index);
+ const Method* const m = methods->at(index);
// skip private, static, and <init> methods
if ((!m->is_private() && !m->is_static()) &&
(m->name() != vmSymbols::object_initializer_name())) {
- Symbol* name = m->name();
- Symbol* signature = m->signature();
- Klass* k = this_klass->super();
- Method* super_m = NULL;
+ const Symbol* const name = m->name();
+ const Symbol* const signature = m->signature();
+ const Klass* k = this_klass->super();
+ const Method* super_m = NULL;
while (k != NULL) {
// skip supers that don't have final methods.
if (k->has_final_method()) {
@@ -4743,7 +4408,7 @@
if (super_m->is_final() && !super_m->is_static() &&
// matching method in super is final, and not static
- (Reflection::verify_field_access(this_klass(),
+ (Reflection::verify_field_access(this_klass,
super_m->method_holder(),
super_m->method_holder(),
super_m->access_flags(), false))
@@ -4775,13 +4440,14 @@
// assumes that this_klass is an interface
-void ClassFileParser::check_illegal_static_method(instanceKlassHandle this_klass, TRAPS) {
+static void check_illegal_static_method(const InstanceKlass* this_klass, TRAPS) {
+ assert(this_klass != NULL, "invariant");
assert(this_klass->is_interface(), "not an interface");
- Array<Method*>* methods = this_klass->methods();
- int num_methods = methods->length();
+ const Array<Method*>* methods = this_klass->methods();
+ const int num_methods = methods->length();
for (int index = 0; index < num_methods; index++) {
- Method* m = methods->at(index);
+ const Method* const m = methods->at(index);
// if m is static and not the init method, throw a verify error
if ((m->is_static()) && (m->name() != vmSymbols::class_initializer_name())) {
ResourceMark rm(THREAD);
@@ -4799,7 +4465,7 @@
// utility methods for format checking
-void ClassFileParser::verify_legal_class_modifiers(jint flags, TRAPS) {
+void ClassFileParser::verify_legal_class_modifiers(jint flags, TRAPS) const {
if (!_need_verify) { return; }
const bool is_interface = (flags & JVM_ACC_INTERFACE) != 0;
@@ -4825,7 +4491,7 @@
}
}
-bool ClassFileParser::has_illegal_visibility(jint flags) {
+static bool has_illegal_visibility(jint flags) {
const bool is_public = (flags & JVM_ACC_PUBLIC) != 0;
const bool is_protected = (flags & JVM_ACC_PROTECTED) != 0;
const bool is_private = (flags & JVM_ACC_PRIVATE) != 0;
@@ -4835,16 +4501,17 @@
(is_protected && is_private));
}
-bool ClassFileParser::is_supported_version(u2 major, u2 minor) {
- u2 max_version = JAVA_MAX_SUPPORTED_VERSION;
+static bool is_supported_version(u2 major, u2 minor){
+ const u2 max_version = JAVA_MAX_SUPPORTED_VERSION;
return (major >= JAVA_MIN_SUPPORTED_VERSION) &&
(major <= max_version) &&
((major != max_version) ||
(minor <= JAVA_MAX_SUPPORTED_MINOR_VERSION));
}
-void ClassFileParser::verify_legal_field_modifiers(
- jint flags, bool is_interface, TRAPS) {
+void ClassFileParser::verify_legal_field_modifiers(jint flags,
+ bool is_interface,
+ TRAPS) const {
if (!_need_verify) { return; }
const bool is_public = (flags & JVM_ACC_PUBLIC) != 0;
@@ -4882,8 +4549,10 @@
}
}
-void ClassFileParser::verify_legal_method_modifiers(
- jint flags, bool is_interface, Symbol* name, TRAPS) {
+void ClassFileParser::verify_legal_method_modifiers(jint flags,
+ bool is_interface,
+ const Symbol* name,
+ TRAPS) const {
if (!_need_verify) { return; }
const bool is_public = (flags & JVM_ACC_PUBLIC) != 0;
@@ -4962,10 +4631,12 @@
}
}
-void ClassFileParser::verify_legal_utf8(const unsigned char* buffer, int length, TRAPS) {
+void ClassFileParser::verify_legal_utf8(const unsigned char* buffer,
+ int length,
+ TRAPS) const {
assert(_need_verify, "only called when _need_verify is true");
int i = 0;
- int count = length >> 2;
+ const int count = length >> 2;
for (int k=0; k<count; k++) {
unsigned char b0 = buffer[i];
unsigned char b1 = buffer[i+1];
@@ -4974,10 +4645,10 @@
// For an unsigned char v,
// (v | v - 1) is < 128 (highest bit 0) for 0 < v < 128;
// (v | v - 1) is >= 128 (highest bit 1) for v == 0 or v >= 128.
- unsigned char res = b0 | b0 - 1 |
- b1 | b1 - 1 |
- b2 | b2 - 1 |
- b3 | b3 - 1;
+ const unsigned char res = b0 | b0 - 1 |
+ b1 | b1 - 1 |
+ b2 | b2 - 1 |
+ b3 | b3 - 1;
if (res >= 128) break;
i += 4;
}
@@ -5025,8 +4696,193 @@
} // end of for
}
+// Unqualified names may not contain the characters '.', ';', '[', or '/'.
+// Method names also may not contain the characters '<' or '>', unless <init>
+// or <clinit>. Note that method names may not be <init> or <clinit> in this
+// method. Because these names have been checked as special cases before
+// calling this method in verify_legal_method_name.
+static bool verify_unqualified_name(const char* name,
+ unsigned int length,
+ int type) {
+ for (const char* p = name; p != name + length;) {
+ jchar ch = *p;
+ if (ch < 128) {
+ p++;
+ if (ch == '.' || ch == ';' || ch == '[') {
+ return false; // do not permit '.', ';', or '['
+ }
+ if (type != LegalClass && ch == '/') {
+ return false; // do not permit '/' unless it's class name
+ }
+ if (type == LegalMethod && (ch == '<' || ch == '>')) {
+ return false; // do not permit '<' or '>' in method names
+ }
+ }
+ else {
+ char* tmp_p = UTF8::next(p, &ch);
+ p = tmp_p;
+ }
+ }
+ return true;
+}
+
+// Take pointer to a string. Skip over the longest part of the string that could
+// be taken as a fieldname. Allow '/' if slash_ok is true.
+// Return a pointer to just past the fieldname.
+// Return NULL if no fieldname at all was found, or in the case of slash_ok
+// being true, we saw consecutive slashes (meaning we were looking for a
+// qualified path but found something that was badly-formed).
+static const char* skip_over_field_name(const char* name,
+ bool slash_ok,
+ unsigned int length) {
+ const char* p;
+ jboolean last_is_slash = false;
+ jboolean not_first_ch = false;
+
+ for (p = name; p != name + length; not_first_ch = true) {
+ const char* old_p = p;
+ jchar ch = *p;
+ if (ch < 128) {
+ p++;
+ // quick check for ascii
+ if ((ch >= 'a' && ch <= 'z') ||
+ (ch >= 'A' && ch <= 'Z') ||
+ (ch == '_' || ch == '$') ||
+ (not_first_ch && ch >= '0' && ch <= '9')) {
+ last_is_slash = false;
+ continue;
+ }
+ if (slash_ok && ch == '/') {
+ if (last_is_slash) {
+ return NULL; // Don't permit consecutive slashes
+ }
+ last_is_slash = true;
+ continue;
+ }
+ }
+ else {
+ jint unicode_ch;
+ char* tmp_p = UTF8::next_character(p, &unicode_ch);
+ p = tmp_p;
+ last_is_slash = false;
+ // Check if ch is Java identifier start or is Java identifier part
+ // 4672820: call java.lang.Character methods directly without generating separate tables.
+ EXCEPTION_MARK;
+
+ // return value
+ JavaValue result(T_BOOLEAN);
+ // Set up the arguments to isJavaIdentifierStart and isJavaIdentifierPart
+ JavaCallArguments args;
+ args.push_int(unicode_ch);
+
+ // public static boolean isJavaIdentifierStart(char ch);
+ JavaCalls::call_static(&result,
+ SystemDictionary::Character_klass(),
+ vmSymbols::isJavaIdentifierStart_name(),
+ vmSymbols::int_bool_signature(),
+ &args,
+ THREAD);
+
+ if (HAS_PENDING_EXCEPTION) {
+ CLEAR_PENDING_EXCEPTION;
+ return 0;
+ }
+ if (result.get_jboolean()) {
+ continue;
+ }
+
+ if (not_first_ch) {
+ // public static boolean isJavaIdentifierPart(char ch);
+ JavaCalls::call_static(&result,
+ SystemDictionary::Character_klass(),
+ vmSymbols::isJavaIdentifierPart_name(),
+ vmSymbols::int_bool_signature(),
+ &args,
+ THREAD);
+
+ if (HAS_PENDING_EXCEPTION) {
+ CLEAR_PENDING_EXCEPTION;
+ return 0;
+ }
+
+ if (result.get_jboolean()) {
+ continue;
+ }
+ }
+ }
+ return (not_first_ch) ? old_p : NULL;
+ }
+ return (not_first_ch) ? p : NULL;
+}
+
+// Take pointer to a string. Skip over the longest part of the string that could
+// be taken as a field signature. Allow "void" if void_ok.
+// Return a pointer to just past the signature.
+// Return NULL if no legal signature is found.
+const char* ClassFileParser::skip_over_field_signature(const char* signature,
+ bool void_ok,
+ unsigned int length,
+ TRAPS) const {
+ unsigned int array_dim = 0;
+ while (length > 0) {
+ switch (signature[0]) {
+ case JVM_SIGNATURE_VOID: if (!void_ok) { return NULL; }
+ case JVM_SIGNATURE_BOOLEAN:
+ case JVM_SIGNATURE_BYTE:
+ case JVM_SIGNATURE_CHAR:
+ case JVM_SIGNATURE_SHORT:
+ case JVM_SIGNATURE_INT:
+ case JVM_SIGNATURE_FLOAT:
+ case JVM_SIGNATURE_LONG:
+ case JVM_SIGNATURE_DOUBLE:
+ return signature + 1;
+ case JVM_SIGNATURE_CLASS: {
+ if (_major_version < JAVA_1_5_VERSION) {
+ // Skip over the class name if one is there
+ const char* const p = skip_over_field_name(signature + 1, true, --length);
+
+ // The next character better be a semicolon
+ if (p && (p - signature) > 1 && p[0] == ';') {
+ return p + 1;
+ }
+ }
+ else {
+ // 4900761: For class version > 48, any unicode is allowed in class name.
+ length--;
+ signature++;
+ while (length > 0 && signature[0] != ';') {
+ if (signature[0] == '.') {
+ classfile_parse_error("Class name contains illegal character '.' in descriptor in class file %s", CHECK_0);
+ }
+ length--;
+ signature++;
+ }
+ if (signature[0] == ';') { return signature + 1; }
+ }
+
+ return NULL;
+ }
+ case JVM_SIGNATURE_ARRAY:
+ array_dim++;
+ if (array_dim > 255) {
+ // 4277370: array descriptor is valid only if it represents 255 or fewer dimensions.
+ classfile_parse_error("Array type descriptor has more than 255 dimensions in class file %s", CHECK_0);
+ }
+ // The rest of what's there better be a legal signature
+ signature++;
+ length--;
+ void_ok = false;
+ break;
+
+ default:
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
// Checks if name is a legal class name.
-void ClassFileParser::verify_legal_class_name(Symbol* name, TRAPS) {
+void ClassFileParser::verify_legal_class_name(const Symbol* name, TRAPS) const {
if (!_need_verify || _relax_verify) { return; }
char buf[fixed_buffer_size];
@@ -5035,7 +4891,7 @@
bool legal = false;
if (length > 0) {
- char* p;
+ const char* p;
if (bytes[0] == JVM_SIGNATURE_ARRAY) {
p = skip_over_field_signature(bytes, false, length, CHECK);
legal = (p != NULL) && ((p - bytes) == (int)length);
@@ -5054,6 +4910,7 @@
}
if (!legal) {
ResourceMark rm(THREAD);
+ assert(_class_name != NULL, "invariant");
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_ClassFormatError(),
@@ -5065,7 +4922,7 @@
}
// Checks if name is a legal field name.
-void ClassFileParser::verify_legal_field_name(Symbol* name, TRAPS) {
+void ClassFileParser::verify_legal_field_name(const Symbol* name, TRAPS) const {
if (!_need_verify || _relax_verify) { return; }
char buf[fixed_buffer_size];
@@ -5076,7 +4933,7 @@
if (length > 0) {
if (_major_version < JAVA_1_5_VERSION) {
if (bytes[0] != '<') {
- char* p = skip_over_field_name(bytes, false, length);
+ const char* p = skip_over_field_name(bytes, false, length);
legal = (p != NULL) && ((p - bytes) == (int)length);
}
} else {
@@ -5087,6 +4944,7 @@
if (!legal) {
ResourceMark rm(THREAD);
+ assert(_class_name != NULL, "invariant");
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_ClassFormatError(),
@@ -5098,7 +4956,7 @@
}
// Checks if name is a legal method name.
-void ClassFileParser::verify_legal_method_name(Symbol* name, TRAPS) {
+void ClassFileParser::verify_legal_method_name(const Symbol* name, TRAPS) const {
if (!_need_verify || _relax_verify) { return; }
assert(name != NULL, "method name is null");
@@ -5113,7 +4971,7 @@
legal = true;
}
} else if (_major_version < JAVA_1_5_VERSION) {
- char* p;
+ const char* p;
p = skip_over_field_name(bytes, false, length);
legal = (p != NULL) && ((p - bytes) == (int)length);
} else {
@@ -5124,6 +4982,7 @@
if (!legal) {
ResourceMark rm(THREAD);
+ assert(_class_name != NULL, "invariant");
Exceptions::fthrow(
THREAD_AND_LOCATION,
vmSymbols::java_lang_ClassFormatError(),
@@ -5136,13 +4995,15 @@
// Checks if signature is a legal field signature.
-void ClassFileParser::verify_legal_field_signature(Symbol* name, Symbol* signature, TRAPS) {
+void ClassFileParser::verify_legal_field_signature(const Symbol* name,
+ const Symbol* signature,
+ TRAPS) const {
if (!_need_verify) { return; }
char buf[fixed_buffer_size];
- char* bytes = signature->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size);
- unsigned int length = signature->utf8_length();
- char* p = skip_over_field_signature(bytes, false, length, CHECK);
+ const char* const bytes = signature->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size);
+ const unsigned int length = signature->utf8_length();
+ const char* const p = skip_over_field_signature(bytes, false, length, CHECK);
if (p == NULL || (p - bytes) != (int)length) {
throwIllegalSignature("Field", name, signature, CHECK);
@@ -5151,7 +5012,9 @@
// Checks if signature is a legal method signature.
// Returns number of parameters
-int ClassFileParser::verify_legal_method_signature(Symbol* name, Symbol* signature, TRAPS) {
+int ClassFileParser::verify_legal_method_signature(const Symbol* name,
+ const Symbol* signature,
+ TRAPS) const {
if (!_need_verify) {
// make sure caller's args_size will be less than 0 even for non-static
// method so it will be recomputed in compute_size_of_parameters().
@@ -5168,9 +5031,9 @@
unsigned int args_size = 0;
char buf[fixed_buffer_size];
- char* p = signature->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size);
+ const char* p = signature->as_utf8_flexible_buffer(THREAD, buf, fixed_buffer_size);
unsigned int length = signature->utf8_length();
- char* nextp;
+ const char* nextp;
// The first character must be a '('
if ((length > 0) && (*p++ == JVM_SIGNATURE_FUNC)) {
@@ -5208,188 +5071,823 @@
return 0;
}
-
-// Unqualified names may not contain the characters '.', ';', '[', or '/'.
-// Method names also may not contain the characters '<' or '>', unless <init>
-// or <clinit>. Note that method names may not be <init> or <clinit> in this
-// method. Because these names have been checked as special cases before
-// calling this method in verify_legal_method_name.
-bool ClassFileParser::verify_unqualified_name(
- char* name, unsigned int length, int type) {
- jchar ch;
-
- for (char* p = name; p != name + length; ) {
- ch = *p;
- if (ch < 128) {
- p++;
- if (ch == '.' || ch == ';' || ch == '[' ) {
- return false; // do not permit '.', ';', or '['
+int ClassFileParser::static_field_size() const {
+ assert(_field_info != NULL, "invariant");
+ return _field_info->static_field_size;
+}
+
+int ClassFileParser::total_oop_map_count() const {
+ assert(_field_info != NULL, "invariant");
+ return _field_info->total_oop_map_count;
+}
+
+jint ClassFileParser::layout_size() const {
+ assert(_field_info != NULL, "invariant");
+ return _field_info->instance_size;
+}
+
+static void check_methods_for_intrinsics(const InstanceKlass* ik,
+ const Array<Method*>* methods) {
+ assert(ik != NULL, "invariant");
+ assert(methods != NULL, "invariant");
+
+ // Set up Method*::intrinsic_id as soon as we know the names of methods.
+ // (We used to do this lazily, but now we query it in Rewriter,
+ // which is eagerly done for every method, so we might as well do it now,
+ // when everything is fresh in memory.)
+ const vmSymbols::SID klass_id = Method::klass_id_for_intrinsics(ik);
+
+ if (klass_id != vmSymbols::NO_SID) {
+ for (int j = 0; j < methods->length(); ++j) {
+ Method* method = methods->at(j);
+ method->init_intrinsic_id();
+
+ if (CheckIntrinsics) {
+ // Check if an intrinsic is defined for method 'method',
+ // but the method is not annotated with @HotSpotIntrinsicCandidate.
+ if (method->intrinsic_id() != vmIntrinsics::_none &&
+ !method->intrinsic_candidate()) {
+ tty->print("Compiler intrinsic is defined for method [%s], "
+ "but the method is not annotated with @HotSpotIntrinsicCandidate.%s",
+ method->name_and_sig_as_C_string(),
+ NOT_DEBUG(" Method will not be inlined.") DEBUG_ONLY(" Exiting.")
+ );
+ tty->cr();
+ DEBUG_ONLY(vm_exit(1));
+ }
+ // Check is the method 'method' is annotated with @HotSpotIntrinsicCandidate,
+ // but there is no intrinsic available for it.
+ if (method->intrinsic_candidate() &&
+ method->intrinsic_id() == vmIntrinsics::_none) {
+ tty->print("Method [%s] is annotated with @HotSpotIntrinsicCandidate, "
+ "but no compiler intrinsic is defined for the method.%s",
+ method->name_and_sig_as_C_string(),
+ NOT_DEBUG("") DEBUG_ONLY(" Exiting.")
+ );
+ tty->cr();
+ DEBUG_ONLY(vm_exit(1));
+ }
}
- if (type != LegalClass && ch == '/') {
- return false; // do not permit '/' unless it's class name
- }
- if (type == LegalMethod && (ch == '<' || ch == '>')) {
- return false; // do not permit '<' or '>' in method names
- }
- } else {
- char* tmp_p = UTF8::next(p, &ch);
- p = tmp_p;
+ } // end for
+
+#ifdef ASSERT
+ if (CheckIntrinsics) {
+ // Check for orphan methods in the current class. A method m
+ // of a class C is orphan if an intrinsic is defined for method m,
+ // but class C does not declare m.
+ // The check is potentially expensive, therefore it is available
+ // only in debug builds.
+
+ for (int id = vmIntrinsics::FIRST_ID; id < (int)vmIntrinsics::ID_LIMIT; ++id) {
+ if (vmIntrinsics::_compiledLambdaForm == id) {
+ // The _compiledLamdbdaForm intrinsic is a special marker for bytecode
+ // generated for the JVM from a LambdaForm and therefore no method
+ // is defined for it.
+ continue;
+ }
+
+ if (vmIntrinsics::class_for(vmIntrinsics::ID_from(id)) == klass_id) {
+ // Check if the current class contains a method with the same
+ // name, flags, signature.
+ bool match = false;
+ for (int j = 0; j < methods->length(); ++j) {
+ const Method* method = methods->at(j);
+ if (method->intrinsic_id() == id) {
+ match = true;
+ break;
+ }
+ }
+
+ if (!match) {
+ char buf[1000];
+ tty->print("Compiler intrinsic is defined for method [%s], "
+ "but the method is not available in class [%s].%s",
+ vmIntrinsics::short_name_as_C_string(vmIntrinsics::ID_from(id),
+ buf, sizeof(buf)),
+ ik->name()->as_C_string(),
+ NOT_DEBUG("") DEBUG_ONLY(" Exiting.")
+ );
+ tty->cr();
+ DEBUG_ONLY(vm_exit(1));
+ }
+ }
+ } // end for
+ } // CheckIntrinsics
+#endif // ASSERT
+ }
+}
+
+InstanceKlass* ClassFileParser::create_instance_klass(TRAPS) {
+ if (_klass != NULL) {
+ return _klass;
+ }
+
+ InstanceKlass* const ik =
+ InstanceKlass::allocate_instance_klass(*this, CHECK_NULL);
+
+ fill_instance_klass(ik, CHECK_NULL);
+
+ assert(_klass == ik, "invariant");
+
+ return ik;
+}
+
+void ClassFileParser::fill_instance_klass(InstanceKlass* ik, TRAPS) {
+ assert(ik != NULL, "invariant");
+
+ set_klass_to_deallocate(ik);
+
+ assert(_field_info != NULL, "invariant");
+ assert(ik->static_field_size() == _field_info->static_field_size, "sanity");
+ assert(ik->nonstatic_oop_map_count() == _field_info->total_oop_map_count,
+ "sanity");
+
+ assert(ik->is_instance_klass(), "sanity");
+ assert(ik->size_helper() == _field_info->instance_size, "sanity");
+
+ // Fill in information already parsed
+ ik->set_should_verify_class(_need_verify);
+
+ // Not yet: supers are done below to support the new subtype-checking fields
+ ik->set_class_loader_data(_loader_data);
+ ik->set_nonstatic_field_size(_field_info->nonstatic_field_size);
+ ik->set_has_nonstatic_fields(_field_info->has_nonstatic_fields);
+ assert(_fac != NULL, "invariant");
+ ik->set_static_oop_field_count(_fac->count[STATIC_OOP]);
+
+ // this transfers ownership of a lot of arrays from
+ // the parser onto the InstanceKlass*
+ apply_parsed_class_metadata(ik, _java_fields_count, CHECK);
+
+ // note that is not safe to use the fields in the parser from this point on
+ assert(NULL == _cp, "invariant");
+ assert(NULL == _fields, "invariant");
+ assert(NULL == _methods, "invariant");
+ assert(NULL == _inner_classes, "invariant");
+ assert(NULL == _local_interfaces, "invariant");
+ assert(NULL == _transitive_interfaces, "invariant");
+ assert(NULL == _combined_annotations, "invariant");
+
+ if (_has_final_method) {
+ ik->set_has_final_method();
+ }
+
+ ik->copy_method_ordering(_method_ordering, CHECK);
+ // The InstanceKlass::_methods_jmethod_ids cache
+ // is managed on the assumption that the initial cache
+ // size is equal to the number of methods in the class. If
+ // that changes, then InstanceKlass::idnum_can_increment()
+ // has to be changed accordingly.
+ ik->set_initial_method_idnum(ik->methods()->length());
+
+ ik->set_name(_class_name);
+
+ if (is_anonymous()) {
+ // I am well known to myself
+ ik->constants()->klass_at_put(_this_class_index, ik); // eagerly resolve
+ }
+
+ ik->set_minor_version(_minor_version);
+ ik->set_major_version(_major_version);
+ ik->set_has_default_methods(_has_default_methods);
+ ik->set_declares_default_methods(_declares_default_methods);
+
+ if (_host_klass != NULL) {
+ assert (ik->is_anonymous(), "should be the same");
+ ik->set_host_klass(_host_klass);
+ }
+
+ const Array<Method*>* const methods = ik->methods();
+ assert(methods != NULL, "invariant");
+ const int methods_len = methods->length();
+
+ check_methods_for_intrinsics(ik, methods);
+
+ // Fill in field values obtained by parse_classfile_attributes
+ if (_parsed_annotations->has_any_annotations()) {
+ _parsed_annotations->apply_to(ik);
+ }
+
+ apply_parsed_class_attributes(ik);
+
+ // Miranda methods
+ if ((_num_miranda_methods > 0) ||
+ // if this class introduced new miranda methods or
+ (_super_klass != NULL && _super_klass->has_miranda_methods())
+ // super class exists and this class inherited miranda methods
+ ) {
+ ik->set_has_miranda_methods(); // then set a flag
+ }
+
+ // Fill in information needed to compute superclasses.
+ ik->initialize_supers(const_cast<InstanceKlass*>(_super_klass), CHECK);
+
+ // Initialize itable offset tables
+ klassItable::setup_itable_offset_table(ik);
+
+ // Compute transitive closure of interfaces this class implements
+ // Do final class setup
+ fill_oop_maps(ik,
+ _field_info->nonstatic_oop_map_count,
+ _field_info->nonstatic_oop_offsets,
+ _field_info->nonstatic_oop_counts);
+
+ // Fill in has_finalizer, has_vanilla_constructor, and layout_helper
+ set_precomputed_flags(ik);
+
+ // check if this class can access its super class
+ check_super_class_access(ik, CHECK);
+
+ // check if this class can access its superinterfaces
+ check_super_interface_access(ik, CHECK);
+
+ // check if this class overrides any final method
+ check_final_method_override(ik, CHECK);
+
+ // check that if this class is an interface then it doesn't have static methods
+ if (ik->is_interface()) {
+ /* An interface in a JAVA 8 classfile can be static */
+ if (_major_version < JAVA_8_VERSION) {
+ check_illegal_static_method(ik, CHECK);
}
}
- return true;
-}
-
-
-// Take pointer to a string. Skip over the longest part of the string that could
-// be taken as a fieldname. Allow '/' if slash_ok is true.
-// Return a pointer to just past the fieldname.
-// Return NULL if no fieldname at all was found, or in the case of slash_ok
-// being true, we saw consecutive slashes (meaning we were looking for a
-// qualified path but found something that was badly-formed).
-char* ClassFileParser::skip_over_field_name(char* name, bool slash_ok, unsigned int length) {
- char* p;
- jchar ch;
- jboolean last_is_slash = false;
- jboolean not_first_ch = false;
-
- for (p = name; p != name + length; not_first_ch = true) {
- char* old_p = p;
- ch = *p;
- if (ch < 128) {
- p++;
- // quick check for ascii
- if ((ch >= 'a' && ch <= 'z') ||
- (ch >= 'A' && ch <= 'Z') ||
- (ch == '_' || ch == '$') ||
- (not_first_ch && ch >= '0' && ch <= '9')) {
- last_is_slash = false;
- continue;
- }
- if (slash_ok && ch == '/') {
- if (last_is_slash) {
- return NULL; // Don't permit consecutive slashes
+
+ // Allocate mirror and initialize static fields
+ // The create_mirror() call will also call compute_modifiers()
+ java_lang_Class::create_mirror(ik,
+ _loader_data->class_loader(),
+ _protection_domain,
+ CHECK);
+
+ assert(_all_mirandas != NULL, "invariant");
+
+ // Generate any default methods - default methods are interface methods
+ // that have a default implementation. This is new with Lambda project.
+ if (_has_default_methods ) {
+ DefaultMethods::generate_default_methods(ik,
+ _all_mirandas,
+ CHECK);
+ }
+
+ // Update the loader_data graph.
+ record_defined_class_dependencies(ik, CHECK);
+
+ ClassLoadingService::notify_class_loaded(ik, false /* not shared class */);
+
+ if (!is_internal()) {
+ if (TraceClassLoading) {
+ ResourceMark rm;
+ // print in a single call to reduce interleaving of output
+ if (_stream->source() != NULL) {
+ tty->print("[Loaded %s from %s]\n",
+ ik->external_name(),
+ _stream->source());
+ } else if (_loader_data->class_loader() == NULL) {
+ const Klass* const caller =
+ THREAD->is_Java_thread()
+ ? ((JavaThread*)THREAD)->security_get_caller_class(1)
+ : NULL;
+ // caller can be NULL, for example, during a JVMTI VM_Init hook
+ if (caller != NULL) {
+ tty->print("[Loaded %s by instance of %s]\n",
+ ik->external_name(),
+ caller->external_name());
+ } else {
+ tty->print("[Loaded %s]\n", ik->external_name());
}
- last_is_slash = true;
- continue;
+ } else {
+ tty->print("[Loaded %s from %s]\n", ik->external_name(),
+ _loader_data->class_loader()->klass()->external_name());
}
- } else {
- jint unicode_ch;
- char* tmp_p = UTF8::next_character(p, &unicode_ch);
- p = tmp_p;
- last_is_slash = false;
- // Check if ch is Java identifier start or is Java identifier part
- // 4672820: call java.lang.Character methods directly without generating separate tables.
- EXCEPTION_MARK;
- instanceKlassHandle klass (THREAD, SystemDictionary::Character_klass());
-
- // return value
- JavaValue result(T_BOOLEAN);
- // Set up the arguments to isJavaIdentifierStart and isJavaIdentifierPart
- JavaCallArguments args;
- args.push_int(unicode_ch);
-
- // public static boolean isJavaIdentifierStart(char ch);
- JavaCalls::call_static(&result,
- klass,
- vmSymbols::isJavaIdentifierStart_name(),
- vmSymbols::int_bool_signature(),
- &args,
- THREAD);
-
- if (HAS_PENDING_EXCEPTION) {
- CLEAR_PENDING_EXCEPTION;
- return 0;
+ }
+
+ if (TraceClassResolution) {
+ ResourceMark rm;
+ // print out the superclass.
+ const char * from = ik->external_name();
+ if (ik->java_super() != NULL) {
+ tty->print("RESOLVE %s %s (super)\n",
+ from,
+ ik->java_super()->external_name());
}
- if (result.get_jboolean()) {
- continue;
- }
-
- if (not_first_ch) {
- // public static boolean isJavaIdentifierPart(char ch);
- JavaCalls::call_static(&result,
- klass,
- vmSymbols::isJavaIdentifierPart_name(),
- vmSymbols::int_bool_signature(),
- &args,
- THREAD);
-
- if (HAS_PENDING_EXCEPTION) {
- CLEAR_PENDING_EXCEPTION;
- return 0;
- }
-
- if (result.get_jboolean()) {
- continue;
+ // print out each of the interface classes referred to by this class.
+ const Array<Klass*>* const local_interfaces = ik->local_interfaces();
+ if (local_interfaces != NULL) {
+ const int length = local_interfaces->length();
+ for (int i = 0; i < length; i++) {
+ const Klass* const k = local_interfaces->at(i);
+ const char * to = k->external_name();
+ tty->print("RESOLVE %s %s (interface)\n", from, to);
}
}
}
- return (not_first_ch) ? old_p : NULL;
}
- return (not_first_ch) ? p : NULL;
+
+ TRACE_INIT_ID(ik);
+
+ // If we reach here, all is well.
+ // Now remove the InstanceKlass* from the _klass_to_deallocate field
+ // in order for it to not be destroyed in the ClassFileParser destructor.
+ set_klass_to_deallocate(NULL);
+
+ // it's official
+ set_klass(ik);
+
+ debug_only(ik->verify();)
+}
+
+ClassFileParser::ClassFileParser(ClassFileStream* stream,
+ Symbol* name,
+ ClassLoaderData* loader_data,
+ Handle protection_domain,
+ TempNewSymbol* parsed_name,
+ const Klass* host_klass,
+ GrowableArray<Handle>* cp_patches,
+ Publicity pub_level,
+ TRAPS) :
+ _stream(stream),
+ _requested_name(name),
+ _loader_data(loader_data),
+ _host_klass(host_klass),
+ _cp_patches(cp_patches),
+ _parsed_name(parsed_name),
+ _super_klass(),
+ _cp(NULL),
+ _fields(NULL),
+ _methods(NULL),
+ _inner_classes(NULL),
+ _local_interfaces(NULL),
+ _transitive_interfaces(NULL),
+ _combined_annotations(NULL),
+ _annotations(NULL),
+ _type_annotations(NULL),
+ _fields_annotations(NULL),
+ _fields_type_annotations(NULL),
+ _klass(NULL),
+ _klass_to_deallocate(NULL),
+ _parsed_annotations(NULL),
+ _fac(NULL),
+ _field_info(NULL),
+ _method_ordering(NULL),
+ _all_mirandas(NULL),
+ _vtable_size(0),
+ _itable_size(0),
+ _num_miranda_methods(0),
+ _rt(REF_NONE),
+ _protection_domain(protection_domain),
+ _access_flags(),
+ _pub_level(pub_level),
+ _synthetic_flag(false),
+ _sde_length(false),
+ _sde_buffer(NULL),
+ _sourcefile_index(0),
+ _generic_signature_index(0),
+ _major_version(0),
+ _minor_version(0),
+ _this_class_index(0),
+ _super_class_index(0),
+ _itfs_len(0),
+ _java_fields_count(0),
+ _need_verify(false),
+ _relax_verify(false),
+ _has_default_methods(false),
+ _declares_default_methods(false),
+ _has_final_method(false),
+ _has_finalizer(false),
+ _has_empty_finalizer(false),
+ _has_vanilla_constructor(false),
+ _max_bootstrap_specifier_index(-1) {
+
+ _class_name = name != NULL ? name : vmSymbols::unknown_class_name();
+
+ assert(THREAD->is_Java_thread(), "invariant");
+ assert(_loader_data != NULL, "invariant");
+ assert(stream != NULL, "invariant");
+ assert(_stream != NULL, "invariant");
+ assert(_stream->buffer() == _stream->current(), "invariant");
+ assert(_class_name != NULL, "invariant");
+ assert(0 == _access_flags.as_int(), "invariant");
+
+ // Figure out whether we can skip format checking (matching classic VM behavior)
+ if (DumpSharedSpaces) {
+ // verify == true means it's a 'remote' class (i.e., non-boot class)
+ // Verification decision is based on BytecodeVerificationRemote flag
+ // for those classes.
+ _need_verify = (stream->need_verify()) ? BytecodeVerificationRemote :
+ BytecodeVerificationLocal;
+ }
+ else {
+ _need_verify = Verifier::should_verify_for(_loader_data->class_loader(),
+ stream->need_verify());
+ }
+
+ // synch back verification state to stream
+ stream->set_verify(_need_verify);
+
+ // Check if verification needs to be relaxed for this class file
+ // Do not restrict it to jdk1.0 or jdk1.1 to maintain backward compatibility (4982376)
+ _relax_verify = Verifier::relax_verify_for(_loader_data->class_loader());
+
+ parse_stream(stream, CHECK);
+
+ post_process_parsed_stream(stream, _cp, CHECK);
+}
+
+void ClassFileParser::clear_class_metadata() {
+ // metadata created before the instance klass is created. Must be
+ // deallocated if classfile parsing returns an error.
+ _cp = NULL;
+ _fields = NULL;
+ _methods = NULL;
+ _inner_classes = NULL;
+ _local_interfaces = NULL;
+ _transitive_interfaces = NULL;
+ _combined_annotations = NULL;
+ _annotations = _type_annotations = NULL;
+ _fields_annotations = _fields_type_annotations = NULL;
+}
+
+// Destructor to clean up
+ClassFileParser::~ClassFileParser() {
+ if (_cp != NULL) {
+ MetadataFactory::free_metadata(_loader_data, _cp);
+ }
+ if (_fields != NULL) {
+ MetadataFactory::free_array<u2>(_loader_data, _fields);
+ }
+
+ if (_methods != NULL) {
+ // Free methods
+ InstanceKlass::deallocate_methods(_loader_data, _methods);
+ }
+
+ // beware of the Universe::empty_blah_array!!
+ if (_inner_classes != NULL && _inner_classes != Universe::the_empty_short_array()) {
+ MetadataFactory::free_array<u2>(_loader_data, _inner_classes);
+ }
+
+ // Free interfaces
+ InstanceKlass::deallocate_interfaces(_loader_data, _super_klass,
+ _local_interfaces, _transitive_interfaces);
+
+ if (_combined_annotations != NULL) {
+ // After all annotations arrays have been created, they are installed into the
+ // Annotations object that will be assigned to the InstanceKlass being created.
+
+ // Deallocate the Annotations object and the installed annotations arrays.
+ _combined_annotations->deallocate_contents(_loader_data);
+
+ // If the _combined_annotations pointer is non-NULL,
+ // then the other annotations fields should have been cleared.
+ assert(_annotations == NULL, "Should have been cleared");
+ assert(_type_annotations == NULL, "Should have been cleared");
+ assert(_fields_annotations == NULL, "Should have been cleared");
+ assert(_fields_type_annotations == NULL, "Should have been cleared");
+ } else {
+ // If the annotations arrays were not installed into the Annotations object,
+ // then they have to be deallocated explicitly.
+ MetadataFactory::free_array<u1>(_loader_data, _annotations);
+ MetadataFactory::free_array<u1>(_loader_data, _type_annotations);
+ Annotations::free_contents(_loader_data, _fields_annotations);
+ Annotations::free_contents(_loader_data, _fields_type_annotations);
+ }
+
+ clear_class_metadata();
+
+ // deallocate the klass if already created. Don't directly deallocate, but add
+ // to the deallocate list so that the klass is removed from the CLD::_klasses list
+ // at a safepoint.
+ if (_klass_to_deallocate != NULL) {
+ _loader_data->add_to_deallocate_list(_klass_to_deallocate);
+ }
}
-
-// Take pointer to a string. Skip over the longest part of the string that could
-// be taken as a field signature. Allow "void" if void_ok.
-// Return a pointer to just past the signature.
-// Return NULL if no legal signature is found.
-char* ClassFileParser::skip_over_field_signature(char* signature,
- bool void_ok,
- unsigned int length,
+void ClassFileParser::parse_stream(const ClassFileStream* const stream,
+ TRAPS) {
+
+ assert(stream != NULL, "invariant");
+ assert(_class_name != NULL, "invariant");
+
+ // BEGIN STREAM PARSING
+ stream->guarantee_more(8, CHECK); // magic, major, minor
+ // Magic value
+ const u4 magic = stream->get_u4_fast();
+ guarantee_property(magic == JAVA_CLASSFILE_MAGIC,
+ "Incompatible magic value %u in class file %s",
+ magic, CHECK);
+
+ // Version numbers
+ _minor_version = stream->get_u2_fast();
+ _major_version = stream->get_u2_fast();
+
+ if (DumpSharedSpaces && _major_version < JAVA_1_5_VERSION) {
+ ResourceMark rm;
+ warning("Pre JDK 1.5 class not supported by CDS: %u.%u %s",
+ _major_version, _minor_version, _class_name->as_C_string());
+ Exceptions::fthrow(
+ THREAD_AND_LOCATION,
+ vmSymbols::java_lang_UnsupportedClassVersionError(),
+ "Unsupported major.minor version for dump time %u.%u",
+ _major_version,
+ _minor_version);
+ }
+
+ // Check version numbers - we check this even with verifier off
+ if (!is_supported_version(_major_version, _minor_version)) {
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(
+ THREAD_AND_LOCATION,
+ vmSymbols::java_lang_UnsupportedClassVersionError(),
+ "%s has been compiled by a more recent version of the Java Runtime (class file version %u.%u), "
+ "this version of the Java Runtime only recognizes class file versions up to %u.%u",
+ _class_name->as_C_string(),
+ _major_version,
+ _minor_version,
+ JAVA_MAX_SUPPORTED_VERSION,
+ JAVA_MAX_SUPPORTED_MINOR_VERSION);
+ return;
+ }
+
+ stream->guarantee_more(3, CHECK); // length, first cp tag
+ const u2 cp_size = stream->get_u2_fast();
+
+ guarantee_property(
+ cp_size >= 1, "Illegal constant pool size %u in class file %s",
+ cp_size, CHECK);
+
+ _cp = ConstantPool::allocate(_loader_data,
+ cp_size,
+ CHECK);
+
+ ConstantPool* const cp = _cp;
+
+ parse_constant_pool(stream, cp, cp_size, CHECK);
+
+ assert(cp_size == (const u2)cp->length(), "invariant");
+
+ // ACCESS FLAGS
+ stream->guarantee_more(8, CHECK); // flags, this_class, super_class, infs_len
+
+ // Access flags
+ jint flags = stream->get_u2_fast() & JVM_RECOGNIZED_CLASS_MODIFIERS;
+
+ if ((flags & JVM_ACC_INTERFACE) && _major_version < JAVA_6_VERSION) {
+ // Set abstract bit for old class files for backward compatibility
+ flags |= JVM_ACC_ABSTRACT;
+ }
+
+ _access_flags.set_flags(flags);
+
+ verify_legal_class_modifiers((jint)_access_flags.as_int(), CHECK);
+
+ // This class and superclass
+ _this_class_index = stream->get_u2_fast();
+ check_property(
+ valid_cp_range(_this_class_index, cp_size) &&
+ cp->tag_at(_this_class_index).is_unresolved_klass(),
+ "Invalid this class index %u in constant pool in class file %s",
+ _this_class_index, CHECK);
+
+ Symbol* const class_name_in_cp = cp->klass_name_at(_this_class_index);
+ assert(class_name_in_cp != NULL, "class_name can't be null");
+
+ if (_parsed_name != NULL) {
+ // It's important to set parsed_name *before* resolving the super class.
+ // (it's used for cleanup by the caller if parsing fails)
+ *_parsed_name = class_name_in_cp;
+ // parsed_name is returned and can be used if there's an error, so add to
+ // its reference count. Caller will decrement the refcount.
+ (*_parsed_name)->increment_refcount();
+ }
+
+ // Update _class_name which could be null previously
+ // to reflect the name in the constant pool
+ _class_name = class_name_in_cp;
+
+ // Don't need to check whether this class name is legal or not.
+ // It has been checked when constant pool is parsed.
+ // However, make sure it is not an array type.
+ if (_need_verify) {
+ guarantee_property(_class_name->byte_at(0) != JVM_SIGNATURE_ARRAY,
+ "Bad class name in class file %s",
+ CHECK);
+ }
+
+ // Checks if name in class file matches requested name
+ if (_requested_name != NULL && _requested_name != _class_name) {
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(
+ THREAD_AND_LOCATION,
+ vmSymbols::java_lang_NoClassDefFoundError(),
+ "%s (wrong name: %s)",
+ _class_name->as_C_string(),
+ _requested_name != NULL ? _requested_name->as_C_string() : "NoName"
+ );
+ return;
+ }
+
+ if (!is_internal()) {
+ if (TraceClassLoadingPreorder) {
+ tty->print("[Loading %s",
+ _class_name->as_klass_external_name());
+
+ if (stream->source() != NULL) {
+ tty->print(" from %s", stream->source());
+ }
+ tty->print_cr("]");
+ }
+#if INCLUDE_CDS
+ if (DumpLoadedClassList != NULL && stream->source() != NULL && classlist_file->is_open()) {
+ // Only dump the classes that can be stored into CDS archive
+ if (SystemDictionaryShared::is_sharing_possible(_loader_data)) {
+ ResourceMark rm(THREAD);
+ classlist_file->print_cr("%s", _class_name->as_C_string());
+ classlist_file->flush();
+ }
+ }
+#endif
+ }
+
+ // SUPERKLASS
+ _super_class_index = stream->get_u2_fast();
+ _super_klass = parse_super_class(cp,
+ _super_class_index,
+ _need_verify,
+ CHECK);
+
+ // Interfaces
+ _itfs_len = stream->get_u2_fast();
+ parse_interfaces(stream,
+ _itfs_len,
+ cp,
+ &_has_default_methods,
+ CHECK);
+
+ assert(_local_interfaces != NULL, "invariant");
+
+ // Fields (offsets are filled in later)
+ _fac = new FieldAllocationCount();
+ parse_fields(stream,
+ _access_flags.is_interface(),
+ _fac,
+ cp,
+ cp_size,
+ &_java_fields_count,
+ CHECK);
+
+ assert(_fields != NULL, "invariant");
+
+ // Methods
+ AccessFlags promoted_flags;
+ parse_methods(stream,
+ _access_flags.is_interface(),
+ &promoted_flags,
+ &_has_final_method,
+ &_declares_default_methods,
+ CHECK);
+
+ assert(_methods != NULL, "invariant");
+
+ // promote flags from parse_methods() to the klass' flags
+ _access_flags.add_promoted_flags(promoted_flags.as_int());
+
+ if (_declares_default_methods) {
+ _has_default_methods = true;
+ }
+
+ // Additional attributes/annotations
+ _parsed_annotations = new ClassAnnotationCollector();
+ parse_classfile_attributes(stream, cp, _parsed_annotations, CHECK);
+
+ assert(_inner_classes != NULL, "invariant");
+
+ // Finalize the Annotations metadata object,
+ // now that all annotation arrays have been created.
+ create_combined_annotations(CHECK);
+
+ // Make sure this is the end of class file stream
+ guarantee_property(stream->at_eos(),
+ "Extra bytes at the end of class file %s",
+ CHECK);
+
+ // all bytes in stream read and parsed
+}
+
+void ClassFileParser::post_process_parsed_stream(const ClassFileStream* const stream,
+ ConstantPool* cp,
TRAPS) {
- unsigned int array_dim = 0;
- while (length > 0) {
- switch (signature[0]) {
- case JVM_SIGNATURE_VOID: if (!void_ok) { return NULL; }
- case JVM_SIGNATURE_BOOLEAN:
- case JVM_SIGNATURE_BYTE:
- case JVM_SIGNATURE_CHAR:
- case JVM_SIGNATURE_SHORT:
- case JVM_SIGNATURE_INT:
- case JVM_SIGNATURE_FLOAT:
- case JVM_SIGNATURE_LONG:
- case JVM_SIGNATURE_DOUBLE:
- return signature + 1;
- case JVM_SIGNATURE_CLASS: {
- if (_major_version < JAVA_1_5_VERSION) {
- // Skip over the class name if one is there
- char* p = skip_over_field_name(signature + 1, true, --length);
-
- // The next character better be a semicolon
- if (p && (p - signature) > 1 && p[0] == ';') {
- return p + 1;
- }
- } else {
- // 4900761: For class version > 48, any unicode is allowed in class name.
- length--;
- signature++;
- while (length > 0 && signature[0] != ';') {
- if (signature[0] == '.') {
- classfile_parse_error("Class name contains illegal character '.' in descriptor in class file %s", CHECK_0);
- }
- length--;
- signature++;
- }
- if (signature[0] == ';') { return signature + 1; }
- }
-
- return NULL;
+ assert(stream != NULL, "invariant");
+ assert(stream->at_eos(), "invariant");
+ assert(cp != NULL, "invariant");
+ assert(_loader_data != NULL, "invariant");
+
+ // We check super class after class file is parsed and format is checked
+ if (_super_class_index > 0 && NULL ==_super_klass) {
+ Symbol* const super_class_name = cp->klass_name_at(_super_class_index);
+ if (_access_flags.is_interface()) {
+ // Before attempting to resolve the superclass, check for class format
+ // errors not checked yet.
+ guarantee_property(super_class_name == vmSymbols::java_lang_Object(),
+ "Interfaces must have java.lang.Object as superclass in class file %s",
+ CHECK);
}
- case JVM_SIGNATURE_ARRAY:
- array_dim++;
- if (array_dim > 255) {
- // 4277370: array descriptor is valid only if it represents 255 or fewer dimensions.
- classfile_parse_error("Array type descriptor has more than 255 dimensions in class file %s", CHECK_0);
- }
- // The rest of what's there better be a legal signature
- signature++;
- length--;
- void_ok = false;
- break;
-
- default:
- return NULL;
+ _super_klass = (const InstanceKlass*)
+ SystemDictionary::resolve_super_or_fail(_class_name,
+ super_class_name,
+ _loader_data->class_loader(),
+ _protection_domain,
+ true,
+ CHECK);
+ }
+
+ if (_super_klass != NULL) {
+ if (_super_klass->has_default_methods()) {
+ _has_default_methods = true;
+ }
+
+ if (_super_klass->is_interface()) {
+ ResourceMark rm(THREAD);
+ Exceptions::fthrow(
+ THREAD_AND_LOCATION,
+ vmSymbols::java_lang_IncompatibleClassChangeError(),
+ "class %s has interface %s as super class",
+ _class_name->as_klass_external_name(),
+ _super_klass->external_name()
+ );
+ return;
+ }
+ // Make sure super class is not final
+ if (_super_klass->is_final()) {
+ THROW_MSG(vmSymbols::java_lang_VerifyError(), "Cannot inherit from final class");
}
}
- return NULL;
+
+ // Compute the transitive list of all unique interfaces implemented by this class
+ _transitive_interfaces =
+ compute_transitive_interfaces(_super_klass,
+ _local_interfaces,
+ _loader_data,
+ CHECK);
+
+ assert(_transitive_interfaces != NULL, "invariant");
+
+ // sort methods
+ _method_ordering = sort_methods(_methods);
+
+ _all_mirandas = new GrowableArray<Method*>(20);
+
+ klassVtable::compute_vtable_size_and_num_mirandas(&_vtable_size,
+ &_num_miranda_methods,
+ _all_mirandas,
+ _super_klass,
+ _methods,
+ _access_flags,
+ _loader_data->class_loader(),
+ _class_name,
+ _local_interfaces,
+ CHECK);
+
+ // Size of Java itable (in words)
+ _itable_size = _access_flags.is_interface() ? 0 :
+ klassItable::compute_itable_size(_transitive_interfaces);
+
+ assert(_fac != NULL, "invariant");
+ assert(_parsed_annotations != NULL, "invariant");
+
+ _field_info = new FieldLayoutInfo();
+ layout_fields(cp, _fac, _parsed_annotations, _field_info, CHECK);
+
+ // Compute reference typ
+ _rt = (NULL ==_super_klass) ? REF_NONE : _super_klass->reference_type();
+
}
+
+void ClassFileParser::set_klass(InstanceKlass* klass) {
+
+#ifdef ASSERT
+ if (klass != NULL) {
+ assert(NULL == _klass, "leaking?");
+ }
+#endif
+
+ _klass = klass;
+}
+
+void ClassFileParser::set_klass_to_deallocate(InstanceKlass* klass) {
+
+#ifdef ASSERT
+ if (klass != NULL) {
+ assert(NULL == _klass_to_deallocate, "leaking?");
+ }
+#endif
+
+ _klass_to_deallocate = klass;
+}
+
+// Caller responsible for ResourceMark
+// clone stream with rewound position
+const ClassFileStream* ClassFileParser::clone_stream() const {
+ assert(_stream != NULL, "invariant");
+
+ return _stream->clone();
+}
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -25,33 +25,123 @@
#ifndef SHARE_VM_CLASSFILE_CLASSFILEPARSER_HPP
#define SHARE_VM_CLASSFILE_CLASSFILEPARSER_HPP
-#include "classfile/classFileStream.hpp"
-#include "classfile/symbolTable.hpp"
-#include "oops/annotations.hpp"
+#include "memory/referenceType.hpp"
+#include "runtime/handles.inline.hpp"
#include "oops/constantPool.hpp"
#include "oops/typeArrayOop.hpp"
#include "utilities/accessFlags.hpp"
+class Annotations;
+template <typename T>
+class Array;
+class ClassFileStream;
+class ClassLoaderData;
class CompressedLineNumberWriteStream;
-class FieldAllocationCount;
+class ConstMethod;
class FieldInfo;
-class FieldLayoutInfo;
-
+template <typename T>
+class GrowableArray;
+class InstanceKlass;
+class intArray;
+class Symbol;
+class TempNewSymbol;
// Parser for for .class files
//
// The bytes describing the class file structure is read from a Stream object
class ClassFileParser VALUE_OBJ_CLASS_SPEC {
+
+ class ClassAnnotationCollector;
+ class FieldAllocationCount;
+ class FieldAnnotationCollector;
+ class FieldLayoutInfo;
+
+ public:
+ // The ClassFileParser has an associated "publicity" level
+ // It is used to control which subsystems (if any)
+ // will observe the parsing (logging, events, tracing).
+ // Default level is "BROADCAST", which is equivalent to
+ // a "public" parsing attempt.
+ //
+ // "INTERNAL" level should be entirely private to the
+ // caller - this allows for internal reuse of ClassFileParser
+ //
+ enum Publicity {
+ INTERNAL,
+ BROADCAST,
+ NOF_PUBLICITY_LEVELS
+ };
+
private:
+ const ClassFileStream* _stream; // Actual input stream
+ const Symbol* _requested_name;
+ Symbol* _class_name;
+ mutable ClassLoaderData* _loader_data;
+ const Klass* _host_klass;
+ GrowableArray<Handle>* _cp_patches; // overrides for CP entries
+ TempNewSymbol* _parsed_name;
+
+ // Metadata created before the instance klass is created. Must be deallocated
+ // if not transferred to the InstanceKlass upon successful class loading
+ // in which case these pointers have been set to NULL.
+ const InstanceKlass* _super_klass;
+ ConstantPool* _cp;
+ Array<u2>* _fields;
+ Array<Method*>* _methods;
+ Array<u2>* _inner_classes;
+ Array<Klass*>* _local_interfaces;
+ Array<Klass*>* _transitive_interfaces;
+ Annotations* _combined_annotations;
+ AnnotationArray* _annotations;
+ AnnotationArray* _type_annotations;
+ Array<AnnotationArray*>* _fields_annotations;
+ Array<AnnotationArray*>* _fields_type_annotations;
+ InstanceKlass* _klass; // InstanceKlass* once created.
+ InstanceKlass* _klass_to_deallocate; // an InstanceKlass* to be destroyed
+
+ ClassAnnotationCollector* _parsed_annotations;
+ FieldAllocationCount* _fac;
+ FieldLayoutInfo* _field_info;
+ const intArray* _method_ordering;
+ GrowableArray<Method*>* _all_mirandas;
+
+ enum { fixed_buffer_size = 128 };
+ u_char _linenumbertable_buffer[fixed_buffer_size];
+
+ // Size of Java vtable (in words)
+ int _vtable_size;
+ int _itable_size;
+
+ int _num_miranda_methods;
+
+ ReferenceType _rt;
+ Handle _protection_domain;
+ AccessFlags _access_flags;
+
+ // for tracing and notifications
+ Publicity _pub_level;
+
+ // class attributes parsed before the instance klass is created:
+ bool _synthetic_flag;
+ int _sde_length;
+ const char* _sde_buffer;
+ u2 _sourcefile_index;
+ u2 _generic_signature_index;
+
+ u2 _major_version;
+ u2 _minor_version;
+ u2 _this_class_index;
+ u2 _super_class_index;
+ u2 _itfs_len;
+ u2 _java_fields_count;
+
bool _need_verify;
bool _relax_verify;
- u2 _major_version;
- u2 _minor_version;
- Symbol* _class_name;
- ClassLoaderData* _loader_data;
- KlassHandle _host_klass;
- GrowableArray<Handle>* _cp_patches; // overrides for CP entries
+
+ bool _has_default_methods;
+ bool _declares_default_methods;
+ bool _has_final_method;
// precomputed flags
bool _has_finalizer;
@@ -59,270 +149,164 @@
bool _has_vanilla_constructor;
int _max_bootstrap_specifier_index; // detects BSS values
- // class attributes parsed before the instance klass is created:
- bool _synthetic_flag;
- int _sde_length;
- char* _sde_buffer;
- u2 _sourcefile_index;
- u2 _generic_signature_index;
+ void parse_stream(const ClassFileStream* const stream, TRAPS);
- // Metadata created before the instance klass is created. Must be deallocated
- // if not transferred to the InstanceKlass upon successful class loading
- // in which case these pointers have been set to NULL.
- instanceKlassHandle _super_klass;
- ConstantPool* _cp;
- Array<u2>* _fields;
- Array<Method*>* _methods;
- Array<u2>* _inner_classes;
- Array<Klass*>* _local_interfaces;
- Array<Klass*>* _transitive_interfaces;
- Annotations* _combined_annotations;
- AnnotationArray* _annotations;
- AnnotationArray* _type_annotations;
- Array<AnnotationArray*>* _fields_annotations;
- Array<AnnotationArray*>* _fields_type_annotations;
- InstanceKlass* _klass; // InstanceKlass once created.
+ void post_process_parsed_stream(const ClassFileStream* const stream,
+ ConstantPool* cp,
+ TRAPS);
+
+ void fill_instance_klass(InstanceKlass* ik, TRAPS);
+ void set_klass(InstanceKlass* instance);
void set_class_synthetic_flag(bool x) { _synthetic_flag = x; }
void set_class_sourcefile_index(u2 x) { _sourcefile_index = x; }
void set_class_generic_signature_index(u2 x) { _generic_signature_index = x; }
- void set_class_sde_buffer(char* x, int len) { _sde_buffer = x; _sde_length = len; }
+ void set_class_sde_buffer(const char* x, int len) { _sde_buffer = x; _sde_length = len; }
void create_combined_annotations(TRAPS);
-
- void init_parsed_class_attributes(ClassLoaderData* loader_data) {
- _loader_data = loader_data;
- _synthetic_flag = false;
- _sourcefile_index = 0;
- _generic_signature_index = 0;
- _sde_buffer = NULL;
- _sde_length = 0;
- // initialize the other flags too:
- _has_finalizer = _has_empty_finalizer = _has_vanilla_constructor = false;
- _max_bootstrap_specifier_index = -1;
- clear_class_metadata();
- _klass = NULL;
- }
- void apply_parsed_class_attributes(instanceKlassHandle k); // update k
- void apply_parsed_class_metadata(instanceKlassHandle k, int fields_count, TRAPS);
- void clear_class_metadata() {
- // metadata created before the instance klass is created. Must be
- // deallocated if classfile parsing returns an error.
- _cp = NULL;
- _fields = NULL;
- _methods = NULL;
- _inner_classes = NULL;
- _local_interfaces = NULL;
- _transitive_interfaces = NULL;
- _combined_annotations = NULL;
- _annotations = _type_annotations = NULL;
- _fields_annotations = _fields_type_annotations = NULL;
- }
-
- class AnnotationCollector {
- public:
- enum Location { _in_field, _in_method, _in_class };
- enum ID {
- _unknown = 0,
- _method_CallerSensitive,
- _method_ForceInline,
- _method_DontInline,
- _method_InjectedProfile,
- _method_LambdaForm_Compiled,
- _method_LambdaForm_Hidden,
- _method_HotSpotIntrinsicCandidate,
- _jdk_internal_vm_annotation_Contended,
- _field_Stable,
- _annotation_LIMIT
- };
- const Location _location;
- int _annotations_present;
- u2 _contended_group;
-
- AnnotationCollector(Location location)
- : _location(location), _annotations_present(0)
- {
- assert((int)_annotation_LIMIT <= (int)sizeof(_annotations_present) * BitsPerByte, "");
- }
- // If this annotation name has an ID, report it (or _none).
- ID annotation_index(ClassLoaderData* loader_data, Symbol* name);
- // Set the annotation name:
- void set_annotation(ID id) {
- assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
- _annotations_present |= nth_bit((int)id);
- }
-
- void remove_annotation(ID id) {
- assert((int)id >= 0 && (int)id < (int)_annotation_LIMIT, "oob");
- _annotations_present &= ~nth_bit((int)id);
- }
-
- // Report if the annotation is present.
- bool has_any_annotations() const { return _annotations_present != 0; }
- bool has_annotation(ID id) const { return (nth_bit((int)id) & _annotations_present) != 0; }
-
- void set_contended_group(u2 group) { _contended_group = group; }
- u2 contended_group() const { return _contended_group; }
-
- bool is_contended() const { return has_annotation(_jdk_internal_vm_annotation_Contended); }
-
- void set_stable(bool stable) { set_annotation(_field_Stable); }
- bool is_stable() const { return has_annotation(_field_Stable); }
- };
-
- // This class also doubles as a holder for metadata cleanup.
- class FieldAnnotationCollector: public AnnotationCollector {
- ClassLoaderData* _loader_data;
- AnnotationArray* _field_annotations;
- AnnotationArray* _field_type_annotations;
- public:
- FieldAnnotationCollector(ClassLoaderData* loader_data) :
- AnnotationCollector(_in_field),
- _loader_data(loader_data),
- _field_annotations(NULL),
- _field_type_annotations(NULL) {}
- void apply_to(FieldInfo* f);
- ~FieldAnnotationCollector();
- AnnotationArray* field_annotations() { return _field_annotations; }
- AnnotationArray* field_type_annotations() { return _field_type_annotations; }
-
- void set_field_annotations(AnnotationArray* a) { _field_annotations = a; }
- void set_field_type_annotations(AnnotationArray* a) { _field_type_annotations = a; }
- };
-
- class MethodAnnotationCollector: public AnnotationCollector {
- public:
- MethodAnnotationCollector() : AnnotationCollector(_in_method) { }
- void apply_to(methodHandle m);
- };
- class ClassAnnotationCollector: public AnnotationCollector {
- public:
- ClassAnnotationCollector() : AnnotationCollector(_in_class) { }
- void apply_to(instanceKlassHandle k);
- };
-
- enum { fixed_buffer_size = 128 };
- u_char linenumbertable_buffer[fixed_buffer_size];
-
- ClassFileStream* _stream; // Actual input stream
-
- enum { LegalClass, LegalField, LegalMethod }; // used to verify unqualified names
-
- // Accessors
- ClassFileStream* stream() { return _stream; }
- void set_stream(ClassFileStream* st) { _stream = st; }
+ void apply_parsed_class_attributes(InstanceKlass* k); // update k
+ void apply_parsed_class_metadata(InstanceKlass* k, int fields_count, TRAPS);
+ void clear_class_metadata();
// Constant pool parsing
- void parse_constant_pool_entries(int length, TRAPS);
+ void parse_constant_pool_entries(const ClassFileStream* const stream,
+ ConstantPool* cp,
+ const int length,
+ TRAPS);
- constantPoolHandle parse_constant_pool(TRAPS);
+ void parse_constant_pool(const ClassFileStream* const cfs,
+ ConstantPool* const cp,
+ const int length,
+ TRAPS);
// Interface parsing
- Array<Klass*>* parse_interfaces(int length,
- Handle protection_domain,
- Symbol* class_name,
- bool* has_default_methods,
- TRAPS);
- void record_defined_class_dependencies(instanceKlassHandle defined_klass, TRAPS);
+ void parse_interfaces(const ClassFileStream* const stream,
+ const int itfs_len,
+ ConstantPool* const cp,
+ bool* has_default_methods,
+ TRAPS);
- instanceKlassHandle parse_super_class(int super_class_index, TRAPS);
+ const InstanceKlass* parse_super_class(ConstantPool* const cp,
+ const int super_class_index,
+ const bool need_verify,
+ TRAPS);
+
// Field parsing
- void parse_field_attributes(u2 attributes_count,
- bool is_static, u2 signature_index,
- u2* constantvalue_index_addr,
- bool* is_synthetic_addr,
- u2* generic_signature_index_addr,
+ void parse_field_attributes(const ClassFileStream* const cfs,
+ u2 attributes_count,
+ bool is_static,
+ u2 signature_index,
+ u2* const constantvalue_index_addr,
+ bool* const is_synthetic_addr,
+ u2* const generic_signature_index_addr,
FieldAnnotationCollector* parsed_annotations,
TRAPS);
- Array<u2>* parse_fields(Symbol* class_name,
- bool is_interface,
- FieldAllocationCount *fac,
- u2* java_fields_count_ptr, TRAPS);
- void print_field_layout(Symbol* name,
- Array<u2>* fields,
- const constantPoolHandle& cp,
- int instance_size,
- int instance_fields_start,
- int instance_fields_end,
- int static_fields_end);
+ void parse_fields(const ClassFileStream* const cfs,
+ bool is_interface,
+ FieldAllocationCount* const fac,
+ ConstantPool* cp,
+ const int cp_size,
+ u2* const java_fields_count_ptr,
+ TRAPS);
// Method parsing
- methodHandle parse_method(bool is_interface,
- AccessFlags* promoted_flags,
- TRAPS);
- Array<Method*>* parse_methods(bool is_interface,
- AccessFlags* promoted_flags,
- bool* has_final_method,
- bool* declares_default_methods,
- TRAPS);
- intArray* sort_methods(Array<Method*>* methods);
+ Method* parse_method(const ClassFileStream* const cfs,
+ bool is_interface,
+ const ConstantPool* cp,
+ AccessFlags* const promoted_flags,
+ TRAPS);
+
+ void parse_methods(const ClassFileStream* const cfs,
+ bool is_interface,
+ AccessFlags* const promoted_flags,
+ bool* const has_final_method,
+ bool* const declares_default_methods,
+ TRAPS);
+
+ const u2* parse_exception_table(const ClassFileStream* const stream,
+ u4 code_length,
+ u4 exception_table_length,
+ TRAPS);
- u2* parse_exception_table(u4 code_length, u4 exception_table_length,
- TRAPS);
- void parse_linenumber_table(
- u4 code_attribute_length, u4 code_length,
- CompressedLineNumberWriteStream** write_stream, TRAPS);
- u2* parse_localvariable_table(u4 code_length, u2 max_locals, u4 code_attribute_length,
- u2* localvariable_table_length,
- bool isLVTT, TRAPS);
- u2* parse_checked_exceptions(u2* checked_exceptions_length, u4 method_attribute_length,
- TRAPS);
- void parse_type_array(u2 array_length, u4 code_length, u4* u1_index, u4* u2_index,
- u1* u1_array, u2* u2_array, TRAPS);
- u1* parse_stackmap_table(u4 code_attribute_length, TRAPS);
+ void parse_linenumber_table(u4 code_attribute_length,
+ u4 code_length,
+ CompressedLineNumberWriteStream**const write_stream,
+ TRAPS);
+
+ const u2* parse_localvariable_table(const ClassFileStream* const cfs,
+ u4 code_length,
+ u2 max_locals,
+ u4 code_attribute_length,
+ u2* const localvariable_table_length,
+ bool isLVTT,
+ TRAPS);
+
+ const u2* parse_checked_exceptions(const ClassFileStream* const cfs,
+ u2* const checked_exceptions_length,
+ u4 method_attribute_length,
+ TRAPS);
+
+ void parse_type_array(u2 array_length,
+ u4 code_length,
+ u4* const u1_index,
+ u4* const u2_index,
+ u1* const u1_array,
+ u2* const u2_array,
+ TRAPS);
// Classfile attribute parsing
- u2 parse_generic_signature_attribute(TRAPS);
- void parse_classfile_sourcefile_attribute(TRAPS);
- void parse_classfile_source_debug_extension_attribute(int length, TRAPS);
- u2 parse_classfile_inner_classes_attribute(u1* inner_classes_attribute_start,
+ u2 parse_generic_signature_attribute(const ClassFileStream* const cfs, TRAPS);
+ void parse_classfile_sourcefile_attribute(const ClassFileStream* const cfs, TRAPS);
+ void parse_classfile_source_debug_extension_attribute(const ClassFileStream* const cfs,
+ int length,
+ TRAPS);
+
+ u2 parse_classfile_inner_classes_attribute(const ClassFileStream* const cfs,
+ const u1* const inner_classes_attribute_start,
bool parsed_enclosingmethod_attribute,
u2 enclosing_method_class_index,
u2 enclosing_method_method_index,
TRAPS);
- void parse_classfile_attributes(ClassAnnotationCollector* parsed_annotations,
+
+ void parse_classfile_attributes(const ClassFileStream* const cfs,
+ ConstantPool* cp,
+ ClassAnnotationCollector* parsed_annotations,
TRAPS);
+
void parse_classfile_synthetic_attribute(TRAPS);
- void parse_classfile_signature_attribute(TRAPS);
- void parse_classfile_bootstrap_methods_attribute(u4 attribute_length, TRAPS);
+ void parse_classfile_signature_attribute(const ClassFileStream* const cfs, TRAPS);
+ void parse_classfile_bootstrap_methods_attribute(const ClassFileStream* const cfs,
+ ConstantPool* cp,
+ u4 attribute_length,
+ TRAPS);
// Annotations handling
- AnnotationArray* assemble_annotations(u1* runtime_visible_annotations,
+ AnnotationArray* assemble_annotations(const u1* const runtime_visible_annotations,
int runtime_visible_annotations_length,
- u1* runtime_invisible_annotations,
- int runtime_invisible_annotations_length, TRAPS);
- int skip_annotation(u1* buffer, int limit, int index);
- int skip_annotation_value(u1* buffer, int limit, int index);
- void parse_annotations(u1* buffer, int limit,
- /* Results (currently, only one result is supported): */
- AnnotationCollector* result);
+ const u1* const runtime_invisible_annotations,
+ int runtime_invisible_annotations_length,
+ TRAPS);
- // Final setup
- unsigned int compute_oop_map_count(instanceKlassHandle super,
- unsigned int nonstatic_oop_count,
- int first_nonstatic_oop_offset);
- void fill_oop_maps(instanceKlassHandle k,
- unsigned int nonstatic_oop_map_count,
- int* nonstatic_oop_offsets,
- unsigned int* nonstatic_oop_counts);
- void set_precomputed_flags(instanceKlassHandle k);
- Array<Klass*>* compute_transitive_interfaces(instanceKlassHandle super,
- Array<Klass*>* local_ifs, TRAPS);
+ void set_precomputed_flags(InstanceKlass* k);
// Format checker methods
- void classfile_parse_error(const char* msg, TRAPS);
- void classfile_parse_error(const char* msg, int index, TRAPS);
- void classfile_parse_error(const char* msg, const char *name, TRAPS);
- void classfile_parse_error(const char* msg, int index, const char *name, TRAPS);
- inline void guarantee_property(bool b, const char* msg, TRAPS) {
+ void classfile_parse_error(const char* msg, TRAPS) const;
+ void classfile_parse_error(const char* msg, int index, TRAPS) const;
+ void classfile_parse_error(const char* msg, const char *name, TRAPS) const;
+ void classfile_parse_error(const char* msg,
+ int index,
+ const char *name,
+ TRAPS) const;
+
+ inline void guarantee_property(bool b, const char* msg, TRAPS) const {
if (!b) { classfile_parse_error(msg, CHECK); }
}
- void report_assert_property_failure(const char* msg, TRAPS) PRODUCT_RETURN;
- void report_assert_property_failure(const char* msg, int index, TRAPS) PRODUCT_RETURN;
+ void report_assert_property_failure(const char* msg, TRAPS) const PRODUCT_RETURN;
+ void report_assert_property_failure(const char* msg, int index, TRAPS) const PRODUCT_RETURN;
- inline void assert_property(bool b, const char* msg, TRAPS) {
+ inline void assert_property(bool b, const char* msg, TRAPS) const {
#ifdef ASSERT
if (!b) {
report_assert_property_failure(msg, THREAD);
@@ -330,7 +314,7 @@
#endif
}
- inline void assert_property(bool b, const char* msg, int index, TRAPS) {
+ inline void assert_property(bool b, const char* msg, int index, TRAPS) const {
#ifdef ASSERT
if (!b) {
report_assert_property_failure(msg, index, THREAD);
@@ -338,7 +322,10 @@
#endif
}
- inline void check_property(bool property, const char* msg, int index, TRAPS) {
+ inline void check_property(bool property,
+ const char* msg,
+ int index,
+ TRAPS) const {
if (_need_verify) {
guarantee_property(property, msg, index, CHECK);
} else {
@@ -346,7 +333,7 @@
}
}
- inline void check_property(bool property, const char* msg, TRAPS) {
+ inline void check_property(bool property, const char* msg, TRAPS) const {
if (_need_verify) {
guarantee_property(property, msg, CHECK);
} else {
@@ -354,136 +341,177 @@
}
}
- inline void guarantee_property(bool b, const char* msg, int index, TRAPS) {
+ inline void guarantee_property(bool b,
+ const char* msg,
+ int index,
+ TRAPS) const {
if (!b) { classfile_parse_error(msg, index, CHECK); }
}
- inline void guarantee_property(bool b, const char* msg, const char *name, TRAPS) {
+
+ inline void guarantee_property(bool b,
+ const char* msg,
+ const char *name,
+ TRAPS) const {
if (!b) { classfile_parse_error(msg, name, CHECK); }
}
- inline void guarantee_property(bool b, const char* msg, int index, const char *name, TRAPS) {
+
+ inline void guarantee_property(bool b,
+ const char* msg,
+ int index,
+ const char *name,
+ TRAPS) const {
if (!b) { classfile_parse_error(msg, index, name, CHECK); }
}
- void throwIllegalSignature(
- const char* type, Symbol* name, Symbol* sig, TRAPS);
+ void throwIllegalSignature(const char* type,
+ const Symbol* name,
+ const Symbol* sig,
+ TRAPS) const;
- bool is_supported_version(u2 major, u2 minor);
- bool has_illegal_visibility(jint flags);
+ void verify_constantvalue(const ConstantPool* const cp,
+ int constantvalue_index,
+ int signature_index,
+ TRAPS) const;
+
+ void verify_legal_utf8(const unsigned char* buffer, int length, TRAPS) const;
+ void verify_legal_class_name(const Symbol* name, TRAPS) const;
+ void verify_legal_field_name(const Symbol* name, TRAPS) const;
+ void verify_legal_method_name(const Symbol* name, TRAPS) const;
- void verify_constantvalue(int constantvalue_index, int signature_index, TRAPS);
- void verify_legal_utf8(const unsigned char* buffer, int length, TRAPS);
- void verify_legal_class_name(Symbol* name, TRAPS);
- void verify_legal_field_name(Symbol* name, TRAPS);
- void verify_legal_method_name(Symbol* name, TRAPS);
- void verify_legal_field_signature(Symbol* fieldname, Symbol* signature, TRAPS);
- int verify_legal_method_signature(Symbol* methodname, Symbol* signature, TRAPS);
- void verify_legal_class_modifiers(jint flags, TRAPS);
- void verify_legal_field_modifiers(jint flags, bool is_interface, TRAPS);
- void verify_legal_method_modifiers(jint flags, bool is_interface, Symbol* name, TRAPS);
- bool verify_unqualified_name(char* name, unsigned int length, int type);
- char* skip_over_field_name(char* name, bool slash_ok, unsigned int length);
- char* skip_over_field_signature(char* signature, bool void_ok, unsigned int length, TRAPS);
+ void verify_legal_field_signature(const Symbol* fieldname,
+ const Symbol* signature,
+ TRAPS) const;
+ int verify_legal_method_signature(const Symbol* methodname,
+ const Symbol* signature,
+ TRAPS) const;
- bool is_anonymous() {
- return _host_klass.not_null();
- }
- bool has_cp_patch_at(int index) {
+ void verify_legal_class_modifiers(jint flags, TRAPS) const;
+ void verify_legal_field_modifiers(jint flags, bool is_interface, TRAPS) const;
+ void verify_legal_method_modifiers(jint flags,
+ bool is_interface,
+ const Symbol* name,
+ TRAPS) const;
+
+ const char* skip_over_field_signature(const char* signature,
+ bool void_ok,
+ unsigned int length,
+ TRAPS) const;
+
+ bool has_cp_patch_at(int index) const {
assert(index >= 0, "oob");
return (_cp_patches != NULL
&& index < _cp_patches->length()
&& _cp_patches->adr_at(index)->not_null());
}
- Handle cp_patch_at(int index) {
+
+ Handle cp_patch_at(int index) const {
assert(has_cp_patch_at(index), "oob");
return _cp_patches->at(index);
}
+
Handle clear_cp_patch_at(int index) {
Handle patch = cp_patch_at(index);
_cp_patches->at_put(index, Handle());
assert(!has_cp_patch_at(index), "");
return patch;
}
- void patch_constant_pool(const constantPoolHandle& cp, int index, Handle patch, TRAPS);
+
+ void patch_constant_pool(ConstantPool* cp,
+ int index,
+ Handle patch,
+ TRAPS);
// Wrapper for constantTag.is_klass_[or_]reference.
// In older versions of the VM, Klass*s cannot sneak into early phases of
// constant pool construction, but in later versions they can.
// %%% Let's phase out the old is_klass_reference.
- bool valid_klass_reference_at(int index) {
- return _cp->is_within_bounds(index) && _cp->tag_at(index).is_klass_or_reference();
+ bool valid_klass_reference_at(int index) const {
+ return _cp->is_within_bounds(index) &&
+ _cp->tag_at(index).is_klass_or_reference();
}
// Checks that the cpool index is in range and is a utf8
- bool valid_symbol_at(int cpool_index) {
- return (_cp->is_within_bounds(cpool_index) &&
- _cp->tag_at(cpool_index).is_utf8());
+ bool valid_symbol_at(int cpool_index) const {
+ return _cp->is_within_bounds(cpool_index) &&
+ _cp->tag_at(cpool_index).is_utf8();
}
- void copy_localvariable_table(ConstMethod* cm, int lvt_cnt,
- u2* localvariable_table_length,
- u2** localvariable_table_start,
+ void copy_localvariable_table(const ConstMethod* cm,
+ int lvt_cnt,
+ u2* const localvariable_table_length,
+ const u2**const localvariable_table_start,
int lvtt_cnt,
- u2* localvariable_type_table_length,
- u2** localvariable_type_table_start,
+ u2* const localvariable_type_table_length,
+ const u2** const localvariable_type_table_start,
TRAPS);
void copy_method_annotations(ConstMethod* cm,
- u1* runtime_visible_annotations,
+ const u1* runtime_visible_annotations,
int runtime_visible_annotations_length,
- u1* runtime_invisible_annotations,
+ const u1* runtime_invisible_annotations,
int runtime_invisible_annotations_length,
- u1* runtime_visible_parameter_annotations,
+ const u1* runtime_visible_parameter_annotations,
int runtime_visible_parameter_annotations_length,
- u1* runtime_invisible_parameter_annotations,
+ const u1* runtime_invisible_parameter_annotations,
int runtime_invisible_parameter_annotations_length,
- u1* runtime_visible_type_annotations,
+ const u1* runtime_visible_type_annotations,
int runtime_visible_type_annotations_length,
- u1* runtime_invisible_type_annotations,
+ const u1* runtime_invisible_type_annotations,
int runtime_invisible_type_annotations_length,
- u1* annotation_default,
+ const u1* annotation_default,
int annotation_default_length,
TRAPS);
// lays out fields in class and returns the total oopmap count
- void layout_fields(Handle class_loader, FieldAllocationCount* fac,
- ClassAnnotationCollector* parsed_annotations,
- FieldLayoutInfo* info, TRAPS);
+ void layout_fields(ConstantPool* cp,
+ const FieldAllocationCount* fac,
+ const ClassAnnotationCollector* parsed_annotations,
+ FieldLayoutInfo* info,
+ TRAPS);
public:
- // Constructor
- ClassFileParser(ClassFileStream* st) { set_stream(st); }
+ ClassFileParser(ClassFileStream* stream,
+ Symbol* name,
+ ClassLoaderData* loader_data,
+ Handle protection_domain,
+ TempNewSymbol* parsed_name,
+ const Klass* host_klass,
+ GrowableArray<Handle>* cp_patches,
+ Publicity pub_level,
+ TRAPS);
+
~ClassFileParser();
- // Parse .class file and return new Klass*. The Klass* is not hooked up
- // to the system dictionary or any other structures, so a .class file can
- // be loaded several times if desired.
- // The system dictionary hookup is done by the caller.
- //
- // "parsed_name" is updated by this method, and is the name found
- // while parsing the stream.
- instanceKlassHandle parseClassFile(Symbol* name,
- ClassLoaderData* loader_data,
- Handle protection_domain,
- TempNewSymbol& parsed_name,
- bool verify,
- TRAPS) {
- KlassHandle no_host_klass;
- return parseClassFile(name, loader_data, protection_domain, no_host_klass, NULL, parsed_name, verify, THREAD);
- }
- instanceKlassHandle parseClassFile(Symbol* name,
- ClassLoaderData* loader_data,
- Handle protection_domain,
- KlassHandle host_klass,
- GrowableArray<Handle>* cp_patches,
- TempNewSymbol& parsed_name,
- bool verify,
- TRAPS);
+ InstanceKlass* create_instance_klass(TRAPS);
+
+ const ClassFileStream* clone_stream() const;
+
+ void set_klass_to_deallocate(InstanceKlass* klass);
+
+ int static_field_size() const;
+ int total_oop_map_count() const;
+ jint layout_size() const;
+
+ int vtable_size() const { return _vtable_size; }
+ int itable_size() const { return _itable_size; }
- // Verifier checks
- static void check_super_class_access(instanceKlassHandle this_klass, TRAPS);
- static void check_super_interface_access(instanceKlassHandle this_klass, TRAPS);
- static void check_final_method_override(instanceKlassHandle this_klass, TRAPS);
- static void check_illegal_static_method(instanceKlassHandle this_klass, TRAPS);
+ u2 this_class_index() const { return _this_class_index; }
+ u2 super_class_index() const { return _super_class_index; }
+
+ bool is_anonymous() const { return _host_klass != NULL; }
+ bool is_interface() const { return _access_flags.is_interface(); }
+
+ const Klass* host_klass() const { return _host_klass; }
+ const GrowableArray<Handle>* cp_patches() const { return _cp_patches; }
+ ClassLoaderData* loader_data() const { return _loader_data; }
+ const Symbol* class_name() const { return _class_name; }
+ const Klass* super_klass() const { return _super_klass; }
+
+ ReferenceType reference_type() const { return _rt; }
+ AccessFlags access_flags() const { return _access_flags; }
+
+ bool is_internal() const { return INTERNAL == _pub_level; }
+
};
#endif // SHARE_VM_CLASSFILE_CLASSFILEPARSER_HPP
--- a/hotspot/src/share/vm/classfile/classFileStream.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/classFileStream.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,19 +26,51 @@
#include "classfile/classFileStream.hpp"
#include "classfile/vmSymbols.hpp"
-void ClassFileStream::truncated_file_error(TRAPS) {
+const bool ClassFileStream::verify = true;
+const bool ClassFileStream::no_verification = false;
+
+void ClassFileStream::truncated_file_error(TRAPS) const {
THROW_MSG(vmSymbols::java_lang_ClassFormatError(), "Truncated class file");
}
-ClassFileStream::ClassFileStream(u1* buffer, int length, const char* source) {
- _buffer_start = buffer;
- _buffer_end = buffer + length;
- _current = buffer;
- _source = source;
- _need_verify = false;
+ClassFileStream::ClassFileStream(const u1* buffer,
+ int length,
+ const char* source,
+ bool verify_stream) :
+ _buffer_start(buffer),
+ _buffer_end(buffer + length),
+ _current(buffer),
+ _source(source),
+ _need_verify(verify_stream) {}
+
+const u1* ClassFileStream::clone_buffer() const {
+ u1* const new_buffer_start = NEW_RESOURCE_ARRAY(u1, length());
+ memcpy(new_buffer_start, _buffer_start, length());
+ return new_buffer_start;
}
-u1 ClassFileStream::get_u1(TRAPS) {
+const char* const ClassFileStream::clone_source() const {
+ const char* const src = source();
+ char* source_copy = NULL;
+ if (src != NULL) {
+ size_t source_len = strlen(src);
+ source_copy = NEW_RESOURCE_ARRAY(char, source_len + 1);
+ strncpy(source_copy, src, source_len + 1);
+ }
+ return source_copy;
+}
+
+// Caller responsible for ResourceMark
+// clone stream with a rewound position
+const ClassFileStream* ClassFileStream::clone() const {
+ const u1* const new_buffer_start = clone_buffer();
+ return new ClassFileStream(new_buffer_start,
+ length(),
+ clone_source(),
+ need_verify());
+}
+
+u1 ClassFileStream::get_u1(TRAPS) const {
if (_need_verify) {
guarantee_more(1, CHECK_0);
} else {
@@ -47,54 +79,54 @@
return *_current++;
}
-u2 ClassFileStream::get_u2(TRAPS) {
+u2 ClassFileStream::get_u2(TRAPS) const {
if (_need_verify) {
guarantee_more(2, CHECK_0);
} else {
assert(2 <= _buffer_end - _current, "buffer overflow");
}
- u1* tmp = _current;
+ const u1* tmp = _current;
_current += 2;
- return Bytes::get_Java_u2(tmp);
+ return Bytes::get_Java_u2((address)tmp);
}
-u4 ClassFileStream::get_u4(TRAPS) {
+u4 ClassFileStream::get_u4(TRAPS) const {
if (_need_verify) {
guarantee_more(4, CHECK_0);
} else {
assert(4 <= _buffer_end - _current, "buffer overflow");
}
- u1* tmp = _current;
+ const u1* tmp = _current;
_current += 4;
- return Bytes::get_Java_u4(tmp);
+ return Bytes::get_Java_u4((address)tmp);
}
-u8 ClassFileStream::get_u8(TRAPS) {
+u8 ClassFileStream::get_u8(TRAPS) const {
if (_need_verify) {
guarantee_more(8, CHECK_0);
} else {
assert(8 <= _buffer_end - _current, "buffer overflow");
}
- u1* tmp = _current;
+ const u1* tmp = _current;
_current += 8;
- return Bytes::get_Java_u8(tmp);
+ return Bytes::get_Java_u8((address)tmp);
}
-void ClassFileStream::skip_u1(int length, TRAPS) {
+void ClassFileStream::skip_u1(int length, TRAPS) const {
if (_need_verify) {
guarantee_more(length, CHECK);
}
_current += length;
}
-void ClassFileStream::skip_u2(int length, TRAPS) {
+void ClassFileStream::skip_u2(int length, TRAPS) const {
if (_need_verify) {
guarantee_more(length * 2, CHECK);
}
_current += length * 2;
}
-void ClassFileStream::skip_u4(int length, TRAPS) {
+void ClassFileStream::skip_u4(int length, TRAPS) const {
if (_need_verify) {
guarantee_more(length * 4, CHECK);
}
--- a/hotspot/src/share/vm/classfile/classFileStream.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/classFileStream.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,65 +34,88 @@
// The caller is responsible for deallocating the buffer and for using
// ResourceMarks appropriately when constructing streams.
+class ClassPathEntry;
+
class ClassFileStream: public ResourceObj {
private:
- u1* _buffer_start; // Buffer bottom
- u1* _buffer_end; // Buffer top (one past last element)
- u1* _current; // Current buffer position
- const char* _source; // Source of stream (directory name, ZIP/JAR archive name)
- bool _need_verify; // True if verification is on for the class file
+ const u1* const _buffer_start; // Buffer bottom
+ const u1* const _buffer_end; // Buffer top (one past last element)
+ mutable const u1* _current; // Current buffer position
+ const char* const _source; // Source of stream (directory name, ZIP/JAR archive name)
+ bool _need_verify; // True if verification is on for the class file
+
+ void truncated_file_error(TRAPS) const ;
- void truncated_file_error(TRAPS);
+ protected:
+ const u1* clone_buffer() const;
+ const char* const clone_source() const;
+
public:
- // Constructor
- ClassFileStream(u1* buffer, int length, const char* source);
+ static const bool no_verification;
+ static const bool verify;
+
+ ClassFileStream(const u1* buffer,
+ int length,
+ const char* source,
+ bool verify_stream = verify); // to be verified by default
+
+ virtual const ClassFileStream* clone() const;
// Buffer access
- u1* buffer() const { return _buffer_start; }
- int length() const { return _buffer_end - _buffer_start; }
- u1* current() const { return _current; }
- void set_current(u1* pos) { _current = pos; }
- const char* source() const { return _source; }
- void set_verify(bool flag) { _need_verify = flag; }
+ const u1* buffer() const { return _buffer_start; }
+ int length() const { return _buffer_end - _buffer_start; }
+ const u1* current() const { return _current; }
+ void set_current(const u1* pos) const {
+ assert(pos >= _buffer_start && pos <= _buffer_end, "invariant");
+ _current = pos;
+ }
- void check_truncated_file(bool b, TRAPS) {
+ // for relative positioning
+ juint current_offset() const {
+ return (juint)(_current - _buffer_start);
+ }
+ const char* source() const { return _source; }
+ bool need_verify() const { return _need_verify; }
+ void set_verify(bool flag) { _need_verify = flag; }
+
+ void check_truncated_file(bool b, TRAPS) const {
if (b) {
truncated_file_error(THREAD);
}
}
- void guarantee_more(int size, TRAPS) {
+ void guarantee_more(int size, TRAPS) const {
size_t remaining = (size_t)(_buffer_end - _current);
unsigned int usize = (unsigned int)size;
check_truncated_file(usize > remaining, CHECK);
}
// Read u1 from stream
- u1 get_u1(TRAPS);
- u1 get_u1_fast() {
+ u1 get_u1(TRAPS) const;
+ u1 get_u1_fast() const {
return *_current++;
}
// Read u2 from stream
- u2 get_u2(TRAPS);
- u2 get_u2_fast() {
- u2 res = Bytes::get_Java_u2(_current);
+ u2 get_u2(TRAPS) const;
+ u2 get_u2_fast() const {
+ u2 res = Bytes::get_Java_u2((address)_current);
_current += 2;
return res;
}
// Read u4 from stream
- u4 get_u4(TRAPS);
- u4 get_u4_fast() {
- u4 res = Bytes::get_Java_u4(_current);
+ u4 get_u4(TRAPS) const;
+ u4 get_u4_fast() const {
+ u4 res = Bytes::get_Java_u4((address)_current);
_current += 4;
return res;
}
// Read u8 from stream
- u8 get_u8(TRAPS);
- u8 get_u8_fast() {
- u8 res = Bytes::get_Java_u8(_current);
+ u8 get_u8(TRAPS) const;
+ u8 get_u8_fast() const {
+ u8 res = Bytes::get_Java_u8((address)_current);
_current += 8;
return res;
}
@@ -100,32 +123,32 @@
// Get direct pointer into stream at current position.
// Returns NULL if length elements are not remaining. The caller is
// responsible for calling skip below if buffer contents is used.
- u1* get_u1_buffer() {
+ const u1* get_u1_buffer() const {
return _current;
}
- u2* get_u2_buffer() {
- return (u2*) _current;
+ const u2* get_u2_buffer() const {
+ return (const u2*) _current;
}
// Skip length u1 or u2 elements from stream
- void skip_u1(int length, TRAPS);
- void skip_u1_fast(int length) {
+ void skip_u1(int length, TRAPS) const;
+ void skip_u1_fast(int length) const {
_current += length;
}
- void skip_u2(int length, TRAPS);
- void skip_u2_fast(int length) {
+ void skip_u2(int length, TRAPS) const;
+ void skip_u2_fast(int length) const {
_current += 2 * length;
}
- void skip_u4(int length, TRAPS);
- void skip_u4_fast(int length) {
+ void skip_u4(int length, TRAPS) const;
+ void skip_u4_fast(int length) const {
_current += 4 * length;
}
// Tells whether eos is reached
- bool at_eos() const { return _current == _buffer_end; }
+ bool at_eos() const { return _current == _buffer_end; }
};
#endif // SHARE_VM_CLASSFILE_CLASSFILESTREAM_HPP
--- a/hotspot/src/share/vm/classfile/classLoader.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -23,13 +23,13 @@
*/
#include "precompiled.hpp"
-#include "classfile/classFileParser.hpp"
#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/classLoaderExt.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/jimage.hpp"
+#include "classfile/klassFactory.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "compiler/compileBroker.hpp"
@@ -170,17 +170,13 @@
}
-ClassPathEntry::ClassPathEntry() {
- set_next(NULL);
-}
-
-
ClassPathDirEntry::ClassPathDirEntry(const char* dir) : ClassPathEntry() {
char* copy = NEW_C_HEAP_ARRAY(char, strlen(dir)+1, mtClass);
strcpy(copy, dir);
_dir = copy;
}
+
ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) {
// construct full path name
char path[JVM_MAXPATHLEN];
@@ -211,14 +207,17 @@
if (UsePerfData) {
ClassLoader::perf_sys_classfile_bytes_read()->inc(num_read);
}
- return new ClassFileStream(buffer, st.st_size, _dir); // Resource allocated
+ // Resource allocated
+ return new ClassFileStream(buffer,
+ st.st_size,
+ _dir,
+ ClassFileStream::verify);
}
}
}
return NULL;
}
-
ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name) : ClassPathEntry() {
_zip = zip;
char *copy = NEW_C_HEAP_ARRAY(char, strlen(zip_name)+1, mtClass);
@@ -269,14 +268,18 @@
ClassFileStream* ClassPathZipEntry::open_stream(const char* name, TRAPS) {
jint filesize;
- u1* buffer = open_entry(name, &filesize, false, CHECK_NULL);
+ const u1* buffer = open_entry(name, &filesize, false, CHECK_NULL);
if (buffer == NULL) {
return NULL;
}
if (UsePerfData) {
ClassLoader::perf_sys_classfile_bytes_read()->inc(filesize);
}
- return new ClassFileStream(buffer, filesize, _zip_name); // Resource allocated
+ // Resource allocated
+ return new ClassFileStream(buffer,
+ filesize,
+ _zip_name,
+ ClassFileStream::verify);
}
// invoke function for each entry in the zip file
@@ -366,7 +369,11 @@
}
char* data = NEW_RESOURCE_ARRAY(char, size);
(*JImageGetResource)(_jimage, location, data, size);
- return new ClassFileStream((u1*)data, (int)size, _name); // Resource allocated
+ // Resource allocated
+ return new ClassFileStream((u1*)data,
+ (int)size,
+ _name,
+ ClassFileStream::verify);
}
return NULL;
@@ -996,74 +1003,94 @@
return result();
}
+// caller needs ResourceMark
+const char* ClassLoader::file_name_for_class_name(const char* class_name,
+ int class_name_len) {
+ assert(class_name != NULL, "invariant");
+ assert((int)strlen(class_name) == class_name_len, "invariant");
-instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) {
- ResourceMark rm(THREAD);
- const char* class_name = h_name->as_C_string();
+ static const char class_suffix[] = ".class";
+
+ char* const file_name = NEW_RESOURCE_ARRAY(char,
+ class_name_len +
+ sizeof(class_suffix)); // includes term NULL
+
+ strncpy(file_name, class_name, class_name_len);
+ strncpy(&file_name[class_name_len], class_suffix, sizeof(class_suffix));
+
+ return file_name;
+}
+
+instanceKlassHandle ClassLoader::load_class(Symbol* name, TRAPS) {
+
+ assert(name != NULL, "invariant");
+ assert(THREAD->is_Java_thread(), "must be a JavaThread");
+
+ ResourceMark rm;
+ HandleMark hm;
+
+ const char* const class_name = name->as_C_string();
+
EventMark m("loading class %s", class_name);
ThreadProfilerMark tpm(ThreadProfilerMark::classLoaderRegion);
- stringStream st;
- // st.print() uses too much stack space while handling a StackOverflowError
- // st.print("%s.class", h_name->as_utf8());
- st.print_raw(h_name->as_utf8());
- st.print_raw(".class");
- const char* file_name = st.as_string();
+ const char* const file_name = file_name_for_class_name(class_name,
+ name->utf8_length());
+ assert(file_name != NULL, "invariant");
+
ClassLoaderExt::Context context(class_name, file_name, THREAD);
- // Lookup stream for parsing .class file
+ // Lookup stream
ClassFileStream* stream = NULL;
int classpath_index = 0;
- ClassPathEntry* e = NULL;
- instanceKlassHandle h;
+ ClassPathEntry* e = _first_entry;
{
PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(),
- ((JavaThread*) THREAD)->get_thread_stat()->perf_timers_addr(),
- PerfClassTraceTime::CLASS_LOAD);
- e = _first_entry;
- while (e != NULL) {
+ ((JavaThread*)THREAD)->get_thread_stat()->perf_timers_addr(),
+ PerfClassTraceTime::CLASS_LOAD);
+
+ for (; e != NULL; e = e->next(), ++classpath_index) {
stream = e->open_stream(file_name, CHECK_NULL);
+ if (NULL == stream) {
+ continue;
+ }
if (!context.check(stream, classpath_index)) {
- return h; // NULL
+ return NULL;
}
- if (stream != NULL) {
- break;
- }
- e = e->next();
- ++classpath_index;
+ break;
}
}
- if (stream != NULL) {
- // class file found, parse it
- ClassFileParser parser(stream);
- ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
- Handle protection_domain;
- TempNewSymbol parsed_name = NULL;
- instanceKlassHandle result = parser.parseClassFile(h_name,
- loader_data,
- protection_domain,
- parsed_name,
- context.should_verify(classpath_index),
- THREAD);
- if (HAS_PENDING_EXCEPTION) {
- ResourceMark rm;
- if (DumpSharedSpaces) {
- tty->print_cr("Preload Error: Failed to load %s", class_name);
- }
- return h;
- }
- h = context.record_result(classpath_index, e, result, THREAD);
- } else {
+ if (NULL == stream) {
if (DumpSharedSpaces) {
tty->print_cr("Preload Warning: Cannot find %s", class_name);
}
+ return NULL;
}
- return h;
+ stream->set_verify(context.should_verify(classpath_index));
+
+ ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
+ Handle protection_domain;
+
+ instanceKlassHandle result = KlassFactory::create_from_stream(stream,
+ name,
+ loader_data,
+ protection_domain,
+ NULL, // host_klass
+ NULL, // cp_patches
+ NULL, // parsed_name
+ THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ if (DumpSharedSpaces) {
+ tty->print_cr("Preload Error: Failed to load %s", class_name);
+ }
+ return NULL;
+ }
+
+ return context.record_result(classpath_index, e, result, THREAD);
}
-
void ClassLoader::create_package_info_table(HashtableBucket<mtClass> *t, int length,
int number_of_entries) {
assert(_package_hash_table == NULL, "One package info table allowed.");
--- a/hotspot/src/share/vm/classfile/classLoader.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/classLoader.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -25,8 +25,9 @@
#ifndef SHARE_VM_CLASSFILE_CLASSLOADER_HPP
#define SHARE_VM_CLASSFILE_CLASSLOADER_HPP
-#include "classfile/classFileParser.hpp"
+#include "runtime/orderAccess.hpp"
#include "runtime/perfData.hpp"
+#include "utilities/exceptions.hpp"
#include "utilities/macros.hpp"
// The VM class loader.
@@ -35,41 +36,39 @@
// Name of boot module image
#define BOOT_IMAGE_NAME "bootmodules.jimage"
-// Class path entry (directory or zip file)
-
class JImageFile;
+class ClassFileStream;
-class ClassPathEntry: public CHeapObj<mtClass> {
- private:
+class ClassPathEntry : public CHeapObj<mtClass> {
+private:
ClassPathEntry* _next;
- public:
+public:
// Next entry in class path
- ClassPathEntry* next() { return _next; }
+ ClassPathEntry* next() const { return _next; }
void set_next(ClassPathEntry* next) {
// may have unlocked readers, so write atomically.
OrderAccess::release_store_ptr(&_next, next);
}
- virtual bool is_jar_file() = 0;
- virtual const char* name() = 0;
- virtual JImageFile* jimage() = 0;
+ virtual bool is_jar_file() const = 0;
+ virtual const char* name() const = 0;
+ virtual JImageFile* jimage() const = 0;
// Constructor
- ClassPathEntry();
+ ClassPathEntry() : _next(NULL) {}
// Attempt to locate file_name through this class path entry.
// Returns a class file parsing stream if successfull.
virtual ClassFileStream* open_stream(const char* name, TRAPS) = 0;
// Debugging
NOT_PRODUCT(virtual void compile_the_world(Handle loader, TRAPS) = 0;)
- NOT_PRODUCT(virtual bool is_jrt() = 0;)
+ NOT_PRODUCT(virtual bool is_jrt() = 0;)
};
-
class ClassPathDirEntry: public ClassPathEntry {
private:
const char* _dir; // Name of directory
public:
- bool is_jar_file() { return false; }
- const char* name() { return _dir; }
- JImageFile* jimage() { return NULL; }
+ bool is_jar_file() const { return false; }
+ const char* name() const { return _dir; }
+ JImageFile* jimage() const { return NULL; }
ClassPathDirEntry(const char* dir);
ClassFileStream* open_stream(const char* name, TRAPS);
// Debugging
@@ -97,9 +96,9 @@
jzfile* _zip; // The zip archive
const char* _zip_name; // Name of zip archive
public:
- bool is_jar_file() { return true; }
- const char* name() { return _zip_name; }
- JImageFile* jimage() { return NULL; }
+ bool is_jar_file() const { return true; }
+ const char* name() const { return _zip_name; }
+ JImageFile* jimage() const { return NULL; }
ClassPathZipEntry(jzfile* zip, const char* zip_name);
~ClassPathZipEntry();
u1* open_entry(const char* name, jint* filesize, bool nul_terminate, TRAPS);
@@ -117,10 +116,10 @@
JImageFile* _jimage;
const char* _name;
public:
- bool is_jar_file() { return false; }
- bool is_open() { return _jimage != NULL; }
- const char* name() { return _name == NULL ? "" : _name; }
- JImageFile* jimage() { return _jimage; }
+ bool is_jar_file() const { return false; }
+ bool is_open() const { return _jimage != NULL; }
+ const char* name() const { return _name == NULL ? "" : _name; }
+ JImageFile* jimage() const { return _jimage; }
ClassPathImageEntry(JImageFile* jimage, const char* name);
~ClassPathImageEntry();
static void name_to_package(const char* name, char* buffer, int length);
@@ -212,6 +211,10 @@
// Canonicalizes path names, so strcmp will work properly. This is mainly
// to avoid confusing the zip library
static bool get_canonical_path(const char* orig, char* out, int len);
+
+ static const char* file_name_for_class_name(const char* class_name,
+ int class_name_len);
+
public:
static jboolean decompress(void *in, u8 inSize, void *out, u8 outSize, char **pmsg);
static int crc32(int crc, const char* buf, int len);
@@ -282,7 +285,7 @@
}
// Load individual .class file
- static instanceKlassHandle load_classfile(Symbol* h_name, TRAPS);
+ static instanceKlassHandle load_class(Symbol* class_name, TRAPS);
// If the specified package has been loaded by the system, then returns
// the name of the directory or ZIP file that the package was loaded from.
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -166,7 +166,9 @@
}
}
-void ClassLoaderData::record_dependency(Klass* k, TRAPS) {
+void ClassLoaderData::record_dependency(const Klass* k, TRAPS) {
+ assert(k != NULL, "invariant");
+
ClassLoaderData * const from_cld = this;
ClassLoaderData * const to_cld = k->class_loader_data();
@@ -273,16 +275,18 @@
}
}
-void ClassLoaderData::add_class(Klass* k) {
- MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
- Klass* old_value = _klasses;
- k->set_next_link(old_value);
- // Make sure linked class is stable, since the class list is walked without a lock
- OrderAccess::storestore();
- // link the new item into the list
- _klasses = k;
+void ClassLoaderData::add_class(Klass* k, bool publicize /* true */) {
+ {
+ MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
+ Klass* old_value = _klasses;
+ k->set_next_link(old_value);
+ // Make sure linked class is stable, since the class list is walked without a lock
+ OrderAccess::storestore();
+ // link the new item into the list
+ _klasses = k;
+ }
- if (TraceClassLoaderData && Verbose && k->class_loader_data() != NULL) {
+ if (publicize && TraceClassLoaderData && Verbose && k->class_loader_data() != NULL) {
ResourceMark rm;
tty->print_cr("[TraceClassLoaderData] Adding k: " PTR_FORMAT " %s to CLD: "
PTR_FORMAT " loader: " PTR_FORMAT " %s",
--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -275,7 +275,7 @@
// Used to make sure that this CLD is not unloaded.
void set_keep_alive(bool value) { _keep_alive = value; }
- unsigned int identity_hash() {
+ unsigned int identity_hash() const {
return _class_loader == NULL ? 0 : _class_loader->identity_hash();
}
@@ -294,10 +294,10 @@
const char* loader_name();
jobject add_handle(Handle h);
- void add_class(Klass* k);
+ void add_class(Klass* k, bool publicize = true);
void remove_class(Klass* k);
bool contains_klass(Klass* k);
- void record_dependency(Klass* to, TRAPS);
+ void record_dependency(const Klass* to, TRAPS);
void init_dependencies(TRAPS);
void add_to_deallocate_list(Metadata* m);
@@ -312,7 +312,7 @@
Metaspace* rw_metaspace();
void initialize_shared_metaspaces();
- int shared_class_loader_id() {
+ int shared_class_loader_id() const {
return _shared_class_loader_id;
}
void set_shared_class_loader_id(int id) {
--- a/hotspot/src/share/vm/classfile/classLoaderExt.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/classLoaderExt.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -41,7 +41,7 @@
_file_name = file_name;
}
- bool check(ClassFileStream* stream, const int classpath_index) {
+ bool check(const ClassFileStream* stream, const int classpath_index) {
return true;
}
@@ -50,7 +50,8 @@
}
instanceKlassHandle record_result(const int classpath_index,
- ClassPathEntry* e, instanceKlassHandle result, TRAPS) {
+ const ClassPathEntry* e,
+ instanceKlassHandle result, TRAPS) {
if (ClassLoader::add_package(_file_name, classpath_index, THREAD)) {
if (DumpSharedSpaces) {
result->set_shared_classpath_index(classpath_index);
--- a/hotspot/src/share/vm/classfile/compactHashtable.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/compactHashtable.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "classfile/compactHashtable.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "memory/metaspaceShared.hpp"
#include "prims/jvm.h"
--- a/hotspot/src/share/vm/classfile/compactHashtable.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/compactHashtable.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -27,8 +27,6 @@
#include "classfile/stringTable.hpp"
#include "classfile/symbolTable.hpp"
-#include "memory/allocation.inline.hpp"
-#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "services/diagnosticCommand.hpp"
#include "utilities/hashtable.hpp"
@@ -117,13 +115,8 @@
return _required_bytes;
}
- void add(unsigned int hash, Symbol* symbol) {
- add(hash, new Entry(hash, symbol));
- }
-
- void add(unsigned int hash, oop string) {
- add(hash, new Entry(hash, string));
- }
+ inline void add(unsigned int hash, Symbol* symbol);
+ inline void add(unsigned int hash, oop string);
private:
void add(unsigned int hash, Entry* entry);
@@ -219,27 +212,10 @@
juint* _buckets;
inline Symbol* lookup_entry(CompactHashtable<Symbol*, char>* const t,
- juint* addr, const char* name, int len) {
- Symbol* sym = (Symbol*)((void*)(_base_address + *addr));
- if (sym->equals(name, len)) {
- assert(sym->refcount() == -1, "must be shared");
- return sym;
- }
-
- return NULL;
- }
+ juint* addr, const char* name, int len);
inline oop lookup_entry(CompactHashtable<oop, char>* const t,
- juint* addr, const char* name, int len) {
- narrowOop obj = (narrowOop)(*addr);
- oop string = oopDesc::decode_heap_oop(obj);
- if (java_lang_String::equals(string, (jchar*)name, len)) {
- return string;
- }
-
- return NULL;
- }
-
+ juint* addr, const char* name, int len);
public:
CompactHashtable() {
_entry_count = 0;
@@ -257,41 +233,7 @@
}
// Lookup an entry from the compact table
- inline T lookup(const N* name, unsigned int hash, int len) {
- if (_entry_count > 0) {
- assert(!DumpSharedSpaces, "run-time only");
- int index = hash % _bucket_count;
- juint bucket_info = _buckets[index];
- juint bucket_offset = BUCKET_OFFSET(bucket_info);
- int bucket_type = BUCKET_TYPE(bucket_info);
- juint* bucket = _buckets + bucket_offset;
- juint* bucket_end = _buckets;
-
- if (bucket_type == COMPACT_BUCKET_TYPE) {
- // the compact bucket has one entry with entry offset only
- T res = lookup_entry(this, &bucket[0], name, len);
- if (res != NULL) {
- return res;
- }
- } else {
- // This is a regular bucket, which has more than one
- // entries. Each entry is a pair of entry (hash, offset).
- // Seek until the end of the bucket.
- bucket_end += BUCKET_OFFSET(_buckets[index + 1]);
- while (bucket < bucket_end) {
- unsigned int h = (unsigned int)(bucket[0]);
- if (h == hash) {
- T res = lookup_entry(this, &bucket[1], name, len);
- if (res != NULL) {
- return res;
- }
- }
- bucket += 2;
- }
- }
- }
- return NULL;
- }
+ inline T lookup(const N* name, unsigned int hash, int len);
// iterate over symbols
void symbols_do(SymbolClosure *cl);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/compactHashtable.inline.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_CLASSFILE_COMPACTHASHTABLE_INLINE_HPP
+#define SHARE_VM_CLASSFILE_COMPACTHASHTABLE_INLINE_HPP
+
+#include "classfile/compactHashtable.hpp"
+#include "memory/allocation.inline.hpp"
+#include "oops/oop.inline.hpp"
+
+template <class T, class N>
+inline Symbol* CompactHashtable<T, N>::lookup_entry(CompactHashtable<Symbol*, char>* const t,
+ juint* addr, const char* name, int len) {
+ Symbol* sym = (Symbol*)((void*)(_base_address + *addr));
+ if (sym->equals(name, len)) {
+ assert(sym->refcount() == -1, "must be shared");
+ return sym;
+ }
+
+ return NULL;
+}
+
+template <class T, class N>
+inline oop CompactHashtable<T, N>::lookup_entry(CompactHashtable<oop, char>* const t,
+ juint* addr, const char* name, int len) {
+ narrowOop obj = (narrowOop)(*addr);
+ oop string = oopDesc::decode_heap_oop(obj);
+ if (java_lang_String::equals(string, (jchar*)name, len)) {
+ return string;
+ }
+
+ return NULL;
+}
+
+template <class T, class N>
+inline T CompactHashtable<T,N>::lookup(const N* name, unsigned int hash, int len) {
+ if (_entry_count > 0) {
+ assert(!DumpSharedSpaces, "run-time only");
+ int index = hash % _bucket_count;
+ juint bucket_info = _buckets[index];
+ juint bucket_offset = BUCKET_OFFSET(bucket_info);
+ int bucket_type = BUCKET_TYPE(bucket_info);
+ juint* bucket = _buckets + bucket_offset;
+ juint* bucket_end = _buckets;
+
+ if (bucket_type == COMPACT_BUCKET_TYPE) {
+ // the compact bucket has one entry with entry offset only
+ T res = lookup_entry(this, &bucket[0], name, len);
+ if (res != NULL) {
+ return res;
+ }
+ } else {
+ // This is a regular bucket, which has more than one
+ // entries. Each entry is a pair of entry (hash, offset).
+ // Seek until the end of the bucket.
+ bucket_end += BUCKET_OFFSET(_buckets[index + 1]);
+ while (bucket < bucket_end) {
+ unsigned int h = (unsigned int)(bucket[0]);
+ if (h == hash) {
+ T res = lookup_entry(this, &bucket[1], name, len);
+ if (res != NULL) {
+ return res;
+ }
+ }
+ bucket += 2;
+ }
+ }
+ }
+ return NULL;
+}
+
+inline void CompactHashtableWriter::add(unsigned int hash, Symbol* symbol) {
+ add(hash, new Entry(hash, symbol));
+}
+
+inline void CompactHashtableWriter::add(unsigned int hash, oop string) {
+ add(hash, new Entry(hash, string));
+}
+
+
+#endif // SHARE_VM_CLASSFILE_COMPACTHASHTABLE_INLINE_HPP
--- a/hotspot/src/share/vm/classfile/defaultMethods.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/defaultMethods.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -30,6 +30,7 @@
#include "memory/allocation.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/resourceArea.hpp"
+#include "runtime/handles.inline.hpp"
#include "runtime/signature.hpp"
#include "runtime/thread.hpp"
#include "oops/instanceKlass.hpp"
@@ -606,7 +607,7 @@
}
static GrowableArray<EmptyVtableSlot*>* find_empty_vtable_slots(
- InstanceKlass* klass, GrowableArray<Method*>* mirandas, TRAPS) {
+ InstanceKlass* klass, const GrowableArray<Method*>* mirandas, TRAPS) {
assert(klass != NULL, "Must be valid class");
@@ -777,7 +778,8 @@
// candidate). These methods are then added to the class's method list.
// The JVM does not create bridges nor handle generic signatures here.
void DefaultMethods::generate_default_methods(
- InstanceKlass* klass, GrowableArray<Method*>* mirandas, TRAPS) {
+ InstanceKlass* klass, const GrowableArray<Method*>* mirandas, TRAPS) {
+ assert(klass != NULL, "invariant");
// This resource mark is the bound for all memory allocation that takes
// place during default method processing. After this goes out of scope,
@@ -787,6 +789,7 @@
ResourceMark rm(THREAD);
// Keep entire hierarchy alive for the duration of the computation
+ constantPoolHandle cp(THREAD, klass->constants());
KeepAliveRegistrar keepAlive(THREAD);
KeepAliveVisitor loadKeepAlive(&keepAlive);
loadKeepAlive.run(klass);
--- a/hotspot/src/share/vm/classfile/defaultMethods.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/defaultMethods.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -43,6 +43,6 @@
// default method. Overpass methods are added to the methods lists for
// the class.
static void generate_default_methods(
- InstanceKlass* klass, GrowableArray<Method*>* mirandas, TRAPS);
+ InstanceKlass* klass, const GrowableArray<Method*>* mirandas, TRAPS);
};
#endif // SHARE_VM_CLASSFILE_DEFAULTMETHODS_HPP
--- a/hotspot/src/share/vm/classfile/dictionary.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/dictionary.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -54,7 +54,7 @@
Symbol* name, ClassLoaderData* loader_data);
protected:
- DictionaryEntry* bucket(int i) {
+ DictionaryEntry* bucket(int i) const {
return (DictionaryEntry*)Hashtable<Klass*, mtClass>::bucket(i);
}
@@ -323,7 +323,7 @@
}
}
- bool equals(Symbol* class_name, ClassLoaderData* loader_data) const {
+ bool equals(const Symbol* class_name, ClassLoaderData* loader_data) const {
Klass* klass = (Klass*)literal();
return (klass->name() == class_name && _loader_data == loader_data);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/klassFactory.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -0,0 +1,140 @@
+/*
+* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*
+*/
+
+#include "precompiled.hpp"
+#include "classfile/classFileParser.hpp"
+#include "classfile/classFileStream.hpp"
+#include "classfile/classLoaderData.hpp"
+#include "classfile/klassFactory.hpp"
+#include "memory/resourceArea.hpp"
+#include "prims/jvmtiEnvBase.hpp"
+
+static ClassFileStream* prologue(ClassFileStream* stream,
+ Symbol* name,
+ ClassLoaderData* loader_data,
+ Handle protection_domain,
+ JvmtiCachedClassFileData** cached_class_file,
+ TRAPS) {
+
+ assert(stream != NULL, "invariant");
+
+ if (JvmtiExport::should_post_class_file_load_hook()) {
+ assert(THREAD->is_Java_thread(), "must be a JavaThread");
+ const JavaThread* jt = (JavaThread*)THREAD;
+
+ Handle class_loader(THREAD, loader_data->class_loader());
+
+ // Get the cached class file bytes (if any) from the class that
+ // is being redefined or retransformed. We use jvmti_thread_state()
+ // instead of JvmtiThreadState::state_for(jt) so we don't allocate
+ // a JvmtiThreadState any earlier than necessary. This will help
+ // avoid the bug described by 7126851.
+
+ JvmtiThreadState* state = jt->jvmti_thread_state();
+
+ if (state != NULL) {
+ KlassHandle* h_class_being_redefined =
+ state->get_class_being_redefined();
+
+ if (h_class_being_redefined != NULL) {
+ instanceKlassHandle ikh_class_being_redefined =
+ instanceKlassHandle(THREAD, (*h_class_being_redefined)());
+
+ *cached_class_file = ikh_class_being_redefined->get_cached_class_file();
+ }
+ }
+
+ unsigned char* ptr = const_cast<unsigned char*>(stream->buffer());
+ unsigned char* end_ptr = ptr + stream->length();
+
+ JvmtiExport::post_class_file_load_hook(name,
+ class_loader,
+ protection_domain,
+ &ptr,
+ &end_ptr,
+ cached_class_file);
+
+ if (ptr != stream->buffer()) {
+ // JVMTI agent has modified class file data.
+ // Set new class file stream using JVMTI agent modified class file data.
+ stream = new ClassFileStream(ptr,
+ end_ptr - ptr,
+ stream->source(),
+ stream->need_verify());
+ }
+ }
+
+ return stream;
+}
+
+
+instanceKlassHandle KlassFactory::create_from_stream(ClassFileStream* stream,
+ Symbol* name,
+ ClassLoaderData* loader_data,
+ Handle protection_domain,
+ const Klass* host_klass,
+ GrowableArray<Handle>* cp_patches,
+ TempNewSymbol* parsed_name,
+ TRAPS) {
+
+ assert(stream != NULL, "invariant");
+ assert(loader_data != NULL, "invariant");
+ assert(THREAD->is_Java_thread(), "must be a JavaThread");
+
+ ResourceMark rm;
+ HandleMark hm;
+
+ JvmtiCachedClassFileData* cached_class_file = NULL;
+
+ stream = prologue(stream,
+ name,
+ loader_data,
+ protection_domain,
+ &cached_class_file,
+ CHECK_NULL);
+
+ ClassFileParser parser(stream,
+ name,
+ loader_data,
+ protection_domain,
+ parsed_name,
+ host_klass,
+ cp_patches,
+ ClassFileParser::BROADCAST, // publicity level
+ CHECK_NULL);
+
+ instanceKlassHandle result = parser.create_instance_klass(CHECK_NULL);
+ assert(result == parser.create_instance_klass(THREAD), "invariant");
+
+ if (result.is_null()) {
+ return NULL;
+ }
+
+ if (cached_class_file != NULL) {
+ // JVMTI: we have an InstanceKlass now, tell it about the cached bytes
+ result->set_cached_class_file(cached_class_file);
+ }
+
+ return result;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/src/share/vm/classfile/klassFactory.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -0,0 +1,81 @@
+/*
+* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+*
+* This code is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 only, as
+* published by the Free Software Foundation.
+*
+* This code is distributed in the hope that it will be useful, but WITHOUT
+* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+* version 2 for more details (a copy is included in the LICENSE file that
+* accompanied this code).
+*
+* You should have received a copy of the GNU General Public License version
+* 2 along with this work; if not, write to the Free Software Foundation,
+* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+*
+* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+* or visit www.oracle.com if you need additional information or have any
+* questions.
+*
+*/
+
+#ifndef SHARE_VM_CLASSFILE_KLASSFACTORY_HPP
+#define SHARE_VM_CLASSFILE_KLASSFACTORY_HPP
+
+#include "memory/allocation.inline.hpp"
+#include "runtime/handles.hpp"
+
+class ClassFileStream;
+class ClassLoaderData;
+template <typename>
+class GrowableArray;
+class Klass;
+class Symbol;
+class TempNewSymbol;
+
+/*
+ * KlassFactory is an interface to implementations of the following mapping/function:
+ *
+ * Summary: create a VM internal runtime representation ("Klass")
+ from a bytestream (classfile).
+ *
+ * Input: a named bytestream in the Java class file format (see JVMS, chapter 4).
+ * Output: a VM runtime representation of a Java class
+ *
+ * Pre-conditions:
+ * a non-NULL ClassFileStream* // the classfile bytestream
+ * a non-NULL Symbol* // the name of the class
+ * a non-NULL ClassLoaderData* // the metaspace allocator
+ * (no pending exceptions)
+ *
+ * Returns:
+ * if the returned value is non-NULL, that value is an indirection (pointer/handle)
+ * to a Klass. The caller will not have a pending exception.
+ *
+ * On broken invariants and/or runtime errors the returned value will be
+ * NULL (or a NULL handle) and the caller *might* now have a pending exception.
+ *
+ */
+
+class KlassFactory : AllStatic {
+
+ // approved clients
+ friend class ClassLoader;
+ friend class ClassLoaderExt;
+ friend class SystemDictionary;
+
+ private:
+ static instanceKlassHandle create_from_stream(ClassFileStream* stream,
+ Symbol* name,
+ ClassLoaderData* loader_data,
+ Handle protection_domain,
+ const Klass* host_klass,
+ GrowableArray<Handle>* cp_patches,
+ TempNewSymbol* parsed_name,
+ TRAPS);
+};
+
+#endif // SHARE_VM_CLASSFILE_KLASSFACTORY_HPP
--- a/hotspot/src/share/vm/classfile/stringTable.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/stringTable.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "classfile/altHashing.hpp"
-#include "classfile/compactHashtable.hpp"
+#include "classfile/compactHashtable.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/systemDictionary.hpp"
--- a/hotspot/src/share/vm/classfile/symbolTable.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/symbolTable.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "classfile/altHashing.hpp"
-#include "classfile/compactHashtable.hpp"
+#include "classfile/compactHashtable.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -23,9 +23,14 @@
*/
#include "precompiled.hpp"
+#include "classfile/classFileParser.hpp"
+#include "classfile/classFileStream.hpp"
+#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
+#include "classfile/classLoaderExt.hpp"
#include "classfile/dictionary.hpp"
#include "classfile/javaClasses.inline.hpp"
+#include "classfile/klassFactory.hpp"
#include "classfile/loaderConstraints.hpp"
#include "classfile/placeholders.hpp"
#include "classfile/resolutionErrors.hpp"
@@ -616,6 +621,25 @@
return (nh);
}
+// utility function for class load event
+static void post_class_load_event(const Ticks& start_time,
+ instanceKlassHandle k,
+ Handle initiating_loader) {
+#if INCLUDE_TRACE
+ EventClassLoad event(UNTIMED);
+ if (event.should_commit()) {
+ event.set_starttime(start_time);
+ event.set_loadedClass(k());
+ oop defining_class_loader = k->class_loader();
+ event.set_definingClassLoader(defining_class_loader != NULL ?
+ defining_class_loader->klass() : (Klass*)NULL);
+ oop class_loader = initiating_loader.is_null() ? (oop)NULL : initiating_loader();
+ event.set_initiatingClassLoader(class_loader != NULL ?
+ class_loader->klass() : (Klass*)NULL);
+ event.commit();
+ }
+#endif // INCLUDE_TRACE
+}
Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
Handle class_loader,
@@ -984,42 +1008,42 @@
Handle class_loader,
Handle protection_domain,
ClassFileStream* st,
- KlassHandle host_klass,
+ const Klass* host_klass,
GrowableArray<Handle>* cp_patches,
TRAPS) {
- TempNewSymbol parsed_name = NULL;
Ticks class_load_start_time = Ticks::now();
ClassLoaderData* loader_data;
- if (host_klass.not_null()) {
+ if (host_klass != NULL) {
// Create a new CLD for anonymous class, that uses the same class loader
// as the host_klass
guarantee(host_klass->class_loader() == class_loader(), "should be the same");
guarantee(!DumpSharedSpaces, "must not create anonymous classes when dumping");
loader_data = ClassLoaderData::anonymous_class_loader_data(class_loader(), CHECK_NULL);
- loader_data->record_dependency(host_klass(), CHECK_NULL);
+ loader_data->record_dependency(host_klass, CHECK_NULL);
} else {
loader_data = ClassLoaderData::class_loader_data(class_loader());
}
- // Parse the stream. Note that we do this even though this klass might
+ assert(st != NULL, "invariant");
+ assert(st->need_verify(), "invariant");
+
+ // Parse stream and create a klass.
+ // Note that we do this even though this klass might
// already be present in the SystemDictionary, otherwise we would not
// throw potential ClassFormatErrors.
- //
- // Note: "name" is updated.
- instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name,
- loader_data,
- protection_domain,
- host_klass,
- cp_patches,
- parsed_name,
- true,
- THREAD);
+ instanceKlassHandle k = KlassFactory::create_from_stream(st,
+ class_name,
+ loader_data,
+ protection_domain,
+ host_klass,
+ cp_patches,
+ NULL, // parsed_name
+ THREAD);
-
- if (host_klass.not_null() && k.not_null()) {
+ if (host_klass != NULL && k.not_null()) {
// If it's anonymous, initialize it now, since nobody else will.
{
@@ -1050,7 +1074,7 @@
post_class_load_event(class_load_start_time, k, class_loader);
}
- assert(host_klass.not_null() || cp_patches == NULL,
+ assert(host_klass != NULL || NULL == cp_patches,
"cp_patches only found with host_klass");
return k();
@@ -1065,7 +1089,6 @@
Handle class_loader,
Handle protection_domain,
ClassFileStream* st,
- bool verify,
TRAPS) {
// Classloaders that support parallelism, e.g. bootstrap classloader,
@@ -1082,22 +1105,23 @@
check_loader_lock_contention(lockObject, THREAD);
ObjectLocker ol(lockObject, THREAD, DoObjectLock);
- TempNewSymbol parsed_name = NULL;
+ assert(st != NULL, "invariant");
- // Parse the stream. Note that we do this even though this klass might
+ // Parse the stream and create a klass.
+ // Note that we do this even though this klass might
// already be present in the SystemDictionary, otherwise we would not
// throw potential ClassFormatErrors.
//
- // Note: "name" is updated.
+ // Note: "parsed_name" is updated.
+ TempNewSymbol parsed_name = NULL;
- instanceKlassHandle k;
+ instanceKlassHandle k;
#if INCLUDE_CDS
k = SystemDictionaryShared::lookup_from_stream(class_name,
class_loader,
protection_domain,
st,
- verify,
CHECK_NULL);
#endif
@@ -1107,12 +1131,14 @@
if (st->buffer() == NULL) {
return NULL;
}
- k = ClassFileParser(st).parseClassFile(class_name,
- loader_data,
- protection_domain,
- parsed_name,
- verify,
- THREAD);
+ k = KlassFactory::create_from_stream(st,
+ class_name,
+ loader_data,
+ protection_domain,
+ NULL, // host_klass
+ NULL, // cp_patches
+ &parsed_name,
+ THREAD);
}
const char* pkg = "java/";
@@ -1319,7 +1345,7 @@
if (k.is_null()) {
// Use VM class loader
PerfTraceTime vmtimer(ClassLoader::perf_sys_classload_time());
- k = ClassLoader::load_classfile(class_name, CHECK_(nh));
+ k = ClassLoader::load_class(class_name, CHECK_(nh));
}
// find_or_define_instance_class may return a different InstanceKlass
@@ -2704,23 +2730,14 @@
constraints()->verify(dictionary(), placeholders());
}
-// utility function for class load event
-void SystemDictionary::post_class_load_event(const Ticks& start_time,
- instanceKlassHandle k,
- Handle initiating_loader) {
-#if INCLUDE_TRACE
- EventClassLoad event(UNTIMED);
- if (event.should_commit()) {
- event.set_starttime(start_time);
- event.set_loadedClass(k());
- oop defining_class_loader = k->class_loader();
- event.set_definingClassLoader(defining_class_loader != NULL ?
- defining_class_loader->klass() : (Klass*)NULL);
- oop class_loader = initiating_loader.is_null() ? (oop)NULL : initiating_loader();
- event.set_initiatingClassLoader(class_loader != NULL ?
- class_loader->klass() : (Klass*)NULL);
- event.commit();
- }
-#endif // INCLUDE_TRACE
+// caller needs ResourceMark
+const char* SystemDictionary::loader_name(const oop loader) {
+ return ((loader) == NULL ? "<bootloader>" :
+ InstanceKlass::cast((loader)->klass())->name()->as_C_string());
}
+// caller needs ResourceMark
+const char* SystemDictionary::loader_name(const ClassLoaderData* loader_data) {
+ return (loader_data->class_loader() == NULL ? "<bootloader>" :
+ InstanceKlass::cast((loader_data->class_loader())->klass())->name()->as_C_string());
+}
--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -25,17 +25,15 @@
#ifndef SHARE_VM_CLASSFILE_SYSTEMDICTIONARY_HPP
#define SHARE_VM_CLASSFILE_SYSTEMDICTIONARY_HPP
-#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary_ext.hpp"
+#include "jvmci/systemDictionary_jvmci.hpp"
#include "oops/objArrayOop.hpp"
#include "oops/symbol.hpp"
#include "runtime/java.hpp"
#include "runtime/reflectionUtils.hpp"
#include "utilities/hashtable.hpp"
#include "utilities/hashtable.inline.hpp"
-#include "jvmci/systemDictionary_jvmci.hpp"
-
// The system dictionary stores all loaded classes and maps:
//
@@ -73,13 +71,13 @@
// of placeholders must hold the SystemDictionary_lock.
//
+class ClassFileStream;
class Dictionary;
class PlaceholderTable;
class LoaderConstraintTable;
template <MEMFLAGS F> class HashtableBucket;
class ResolutionErrorTable;
class SymbolPropertyTable;
-class Ticks;
// Certain classes are preloaded, such as java.lang.Object and java.lang.String.
// They are all "well-known", in the sense that no class loader is allowed
@@ -272,34 +270,41 @@
// parse_interfaces, resolve_instance_class_or_null, load_shared_class
// "child_name" is the class whose super class or interface is being resolved.
static Klass* resolve_super_or_fail(Symbol* child_name,
- Symbol* class_name,
- Handle class_loader,
- Handle protection_domain,
- bool is_superclass,
- TRAPS);
+ Symbol* class_name,
+ Handle class_loader,
+ Handle protection_domain,
+ bool is_superclass,
+ TRAPS);
// Parse new stream. This won't update the system dictionary or
// class hierarchy, simply parse the stream. Used by JVMTI RedefineClasses.
static Klass* parse_stream(Symbol* class_name,
- Handle class_loader,
- Handle protection_domain,
- ClassFileStream* st,
- TRAPS) {
- KlassHandle nullHandle;
- return parse_stream(class_name, class_loader, protection_domain, st, nullHandle, NULL, THREAD);
+ Handle class_loader,
+ Handle protection_domain,
+ ClassFileStream* st,
+ TRAPS) {
+ return parse_stream(class_name,
+ class_loader,
+ protection_domain,
+ st,
+ NULL, // host klass
+ NULL, // cp_patches
+ THREAD);
}
static Klass* parse_stream(Symbol* class_name,
- Handle class_loader,
- Handle protection_domain,
- ClassFileStream* st,
- KlassHandle host_klass,
- GrowableArray<Handle>* cp_patches,
- TRAPS);
+ Handle class_loader,
+ Handle protection_domain,
+ ClassFileStream* st,
+ const Klass* host_klass,
+ GrowableArray<Handle>* cp_patches,
+ TRAPS);
// Resolve from stream (called by jni_DefineClass and JVM_DefineClass)
- static Klass* resolve_from_stream(Symbol* class_name, Handle class_loader,
- Handle protection_domain,
- ClassFileStream* st, bool verify, TRAPS);
+ static Klass* resolve_from_stream(Symbol* class_name,
+ Handle class_loader,
+ Handle protection_domain,
+ ClassFileStream* st,
+ TRAPS);
// Lookup an already loaded class. If not found NULL is returned.
static Klass* find(Symbol* class_name, Handle class_loader, Handle protection_domain, TRAPS);
@@ -546,14 +551,8 @@
TRAPS);
// Utility for printing loader "name" as part of tracing constraints
- static const char* loader_name(oop loader) {
- return ((loader) == NULL ? "<bootloader>" :
- InstanceKlass::cast((loader)->klass())->name()->as_C_string() );
- }
- static const char* loader_name(ClassLoaderData* loader_data) {
- return (loader_data->class_loader() == NULL ? "<bootloader>" :
- InstanceKlass::cast((loader_data->class_loader())->klass())->name()->as_C_string() );
- }
+ static const char* loader_name(const oop loader);
+ static const char* loader_name(const ClassLoaderData* loader_data);
// Record the error when the first attempt to resolve a reference from a constant
// pool entry to a class fails.
@@ -663,9 +662,6 @@
// Setup link to hierarchy
static void add_to_hierarchy(instanceKlassHandle k, TRAPS);
- // event based tracing
- static void post_class_load_event(const Ticks& start_time, instanceKlassHandle k,
- Handle initiating_loader);
// We pass in the hashtable index so we can calculate it outside of
// the SystemDictionary_lock.
--- a/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/systemDictionaryShared.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -63,8 +63,7 @@
static InstanceKlass* lookup_from_stream(Symbol* class_name,
Handle class_loader,
Handle protection_domain,
- ClassFileStream* st,
- bool verify,
+ const ClassFileStream* st,
TRAPS) {
return NULL;
}
--- a/hotspot/src/share/vm/classfile/vmSymbols.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/vmSymbols.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -34,7 +34,7 @@
Symbol* vmSymbols::_type_signatures[T_VOID+1] = { NULL /*, NULL...*/ };
-inline int compare_symbol(Symbol* a, Symbol* b) {
+inline int compare_symbol(const Symbol* a, const Symbol* b) {
if (a == b) return 0;
// follow the natural address order:
return (address)a > (address)b ? +1 : -1;
@@ -43,8 +43,8 @@
static vmSymbols::SID vm_symbol_index[vmSymbols::SID_LIMIT];
extern "C" {
static int compare_vmsymbol_sid(const void* void_a, const void* void_b) {
- Symbol* a = vmSymbols::symbol_at(*((vmSymbols::SID*) void_a));
- Symbol* b = vmSymbols::symbol_at(*((vmSymbols::SID*) void_b));
+ const Symbol* a = vmSymbols::symbol_at(*((vmSymbols::SID*) void_a));
+ const Symbol* b = vmSymbols::symbol_at(*((vmSymbols::SID*) void_b));
return compare_symbol(a, b);
}
}
@@ -188,7 +188,7 @@
}
-BasicType vmSymbols::signature_type(Symbol* s) {
+BasicType vmSymbols::signature_type(const Symbol* s) {
assert(s != NULL, "checking");
for (int i = T_BOOLEAN; i < T_VOID+1; i++) {
if (s == _type_signatures[i]) {
@@ -206,7 +206,7 @@
// (Typical counts are calls=7000 and probes=17000.)
#endif
-vmSymbols::SID vmSymbols::find_sid(Symbol* symbol) {
+vmSymbols::SID vmSymbols::find_sid(const Symbol* symbol) {
// Handle the majority of misses by a bounds check.
// Then, use a binary search over the index.
// Expected trip count is less than log2_SID_LIMIT, about eight.
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -1367,7 +1367,7 @@
return _type_signatures[t];
}
// inverse of type_signature; returns T_OBJECT if s is not recognized
- static BasicType signature_type(Symbol* s);
+ static BasicType signature_type(const Symbol* s);
static Symbol* symbol_at(SID id) {
assert(id >= FIRST_SID && id < SID_LIMIT, "oob");
@@ -1376,7 +1376,7 @@
}
// Returns symbol's SID if one is assigned, else NO_SID.
- static SID find_sid(Symbol* symbol);
+ static SID find_sid(const Symbol* symbol);
static SID find_sid(const char* symbol_name);
#ifndef PRODUCT
--- a/hotspot/src/share/vm/compiler/compilerDirectives.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/compiler/compilerDirectives.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,6 @@
#include "ci/ciUtilities.hpp"
#include "compiler/methodMatcher.hpp"
#include "compiler/compilerOracle.hpp"
-#include "oops/oop.inline.hpp"
#include "utilities/exceptions.hpp"
// Directives flag name, type, default value, compile command name
--- a/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/cms/concurrentMarkSweepGeneration.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "classfile/classLoaderData.hpp"
#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "gc/cms/cmsCollectorPolicy.hpp"
--- a/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/dirtyCardQueue.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -112,7 +112,7 @@
fl_owner);
set_buffer_size(G1UpdateBufferSize);
_shared_dirty_card_queue.set_lock(lock);
- _free_ids = new FreeIdSet((int) num_par_ids(), _cbl_mon);
+ _free_ids = new FreeIdSet(num_par_ids(), _cbl_mon);
}
void DirtyCardQueueSet::handle_zero_index_for_thread(JavaThread* t) {
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
#include "gc/g1/bufferingOopClosure.hpp"
@@ -3265,11 +3266,11 @@
// Print the per-region information.
st->cr();
- st->print_cr("Heap Regions: (E=young(eden), S=young(survivor), O=old, "
+ st->print_cr("Heap Regions: E=young(eden), S=young(survivor), O=old, "
"HS=humongous(starts), HC=humongous(continues), "
"CS=collection set, F=free, A=archive, TS=gc time stamp, "
- "PTAMS=previous top-at-mark-start, "
- "NTAMS=next top-at-mark-start)");
+ "AC=allocation context, "
+ "TAMS=top-at-mark-start (previous, next)");
PrintRegionClosure blk(st);
heap_region_iterate(&blk);
}
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -573,6 +573,9 @@
void register_old_region_with_cset(HeapRegion* r) {
_in_cset_fast_test.set_in_old(r->hrm_index());
}
+ inline void register_ext_region_with_cset(HeapRegion* r) {
+ _in_cset_fast_test.set_ext(r->hrm_index());
+ }
void clear_in_cset(const HeapRegion* hr) {
_in_cset_fast_test.clear(hr);
}
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -191,6 +191,7 @@
_recent_prev_end_times_for_all_gcs_sec->add(os::elapsedTime());
_prev_collection_pause_end_ms = os::elapsedTime() * 1000.0;
+ clear_ratio_check_data();
_phase_times = new G1GCPhaseTimes(_parallel_gc_threads);
@@ -1080,6 +1081,14 @@
_recent_avg_pause_time_ratio = 1.0;
}
}
+
+ // Compute the ratio of just this last pause time to the entire time range stored
+ // in the vectors. Comparing this pause to the entire range, rather than only the
+ // most recent interval, has the effect of smoothing over a possible transient 'burst'
+ // of more frequent pauses that don't really reflect a change in heap occupancy.
+ // This reduces the likelihood of a needless heap expansion being triggered.
+ _last_pause_time_ratio =
+ (pause_time_ms * _recent_prev_end_times_for_all_gcs_sec->num()) / interval_ms;
}
bool new_in_marking_window = collector_state()->in_marking_window();
@@ -1597,41 +1606,124 @@
_prev_collection_pause_end_ms = end_time_sec * 1000.0;
}
-size_t G1CollectorPolicy::expansion_amount() const {
+void G1CollectorPolicy::clear_ratio_check_data() {
+ _ratio_over_threshold_count = 0;
+ _ratio_over_threshold_sum = 0.0;
+ _pauses_since_start = 0;
+}
+
+size_t G1CollectorPolicy::expansion_amount() {
double recent_gc_overhead = recent_avg_pause_time_ratio() * 100.0;
+ double last_gc_overhead = _last_pause_time_ratio * 100.0;
double threshold = _gc_overhead_perc;
- if (recent_gc_overhead > threshold) {
- // We will double the existing space, or take
- // G1ExpandByPercentOfAvailable % of the available expansion
- // space, whichever is smaller, bounded below by a minimum
- // expansion (unless that's all that's left.)
- const size_t min_expand_bytes = 1*M;
+ size_t expand_bytes = 0;
+
+ // If the heap is at less than half its maximum size, scale the threshold down,
+ // to a limit of 1. Thus the smaller the heap is, the more likely it is to expand,
+ // though the scaling code will likely keep the increase small.
+ if (_g1->capacity() <= _g1->max_capacity() / 2) {
+ threshold *= (double)_g1->capacity() / (double)(_g1->max_capacity() / 2);
+ threshold = MAX2(threshold, 1.0);
+ }
+
+ // If the last GC time ratio is over the threshold, increment the count of
+ // times it has been exceeded, and add this ratio to the sum of exceeded
+ // ratios.
+ if (last_gc_overhead > threshold) {
+ _ratio_over_threshold_count++;
+ _ratio_over_threshold_sum += last_gc_overhead;
+ }
+
+ // Check if we've had enough GC time ratio checks that were over the
+ // threshold to trigger an expansion. We'll also expand if we've
+ // reached the end of the history buffer and the average of all entries
+ // is still over the threshold. This indicates a smaller number of GCs were
+ // long enough to make the average exceed the threshold.
+ bool filled_history_buffer = _pauses_since_start == NumPrevPausesForHeuristics;
+ if ((_ratio_over_threshold_count == MinOverThresholdForGrowth) ||
+ (filled_history_buffer && (recent_gc_overhead > threshold))) {
+ size_t min_expand_bytes = HeapRegion::GrainBytes;
size_t reserved_bytes = _g1->max_capacity();
size_t committed_bytes = _g1->capacity();
size_t uncommitted_bytes = reserved_bytes - committed_bytes;
- size_t expand_bytes;
size_t expand_bytes_via_pct =
uncommitted_bytes * G1ExpandByPercentOfAvailable / 100;
- expand_bytes = MIN2(expand_bytes_via_pct, committed_bytes);
- expand_bytes = MAX2(expand_bytes, min_expand_bytes);
- expand_bytes = MIN2(expand_bytes, uncommitted_bytes);
+ double scale_factor = 1.0;
+
+ // If the current size is less than 1/4 of the Initial heap size, expand
+ // by half of the delta between the current and Initial sizes. IE, grow
+ // back quickly.
+ //
+ // Otherwise, take the current size, or G1ExpandByPercentOfAvailable % of
+ // the available expansion space, whichever is smaller, as the base
+ // expansion size. Then possibly scale this size according to how much the
+ // threshold has (on average) been exceeded by. If the delta is small
+ // (less than the StartScaleDownAt value), scale the size down linearly, but
+ // not by less than MinScaleDownFactor. If the delta is large (greater than
+ // the StartScaleUpAt value), scale up, but adding no more than MaxScaleUpFactor
+ // times the base size. The scaling will be linear in the range from
+ // StartScaleUpAt to (StartScaleUpAt + ScaleUpRange). In other words,
+ // ScaleUpRange sets the rate of scaling up.
+ if (committed_bytes < InitialHeapSize / 4) {
+ expand_bytes = (InitialHeapSize - committed_bytes) / 2;
+ } else {
+ double const MinScaleDownFactor = 0.2;
+ double const MaxScaleUpFactor = 2;
+ double const StartScaleDownAt = _gc_overhead_perc;
+ double const StartScaleUpAt = _gc_overhead_perc * 1.5;
+ double const ScaleUpRange = _gc_overhead_perc * 2.0;
+
+ double ratio_delta;
+ if (filled_history_buffer) {
+ ratio_delta = recent_gc_overhead - threshold;
+ } else {
+ ratio_delta = (_ratio_over_threshold_sum/_ratio_over_threshold_count) - threshold;
+ }
+
+ expand_bytes = MIN2(expand_bytes_via_pct, committed_bytes);
+ if (ratio_delta < StartScaleDownAt) {
+ scale_factor = ratio_delta / StartScaleDownAt;
+ scale_factor = MAX2(scale_factor, MinScaleDownFactor);
+ } else if (ratio_delta > StartScaleUpAt) {
+ scale_factor = 1 + ((ratio_delta - StartScaleUpAt) / ScaleUpRange);
+ scale_factor = MIN2(scale_factor, MaxScaleUpFactor);
+ }
+ }
ergo_verbose5(ErgoHeapSizing,
"attempt heap expansion",
ergo_format_reason("recent GC overhead higher than "
"threshold after GC")
ergo_format_perc("recent GC overhead")
- ergo_format_perc("threshold")
+ ergo_format_perc("current threshold")
ergo_format_byte("uncommitted")
- ergo_format_byte_perc("calculated expansion amount"),
+ ergo_format_byte_perc("base expansion amount and scale"),
recent_gc_overhead, threshold,
uncommitted_bytes,
- expand_bytes_via_pct, (double) G1ExpandByPercentOfAvailable);
+ expand_bytes, scale_factor * 100);
+
+ expand_bytes = static_cast<size_t>(expand_bytes * scale_factor);
+
+ // Ensure the expansion size is at least the minimum growth amount
+ // and at most the remaining uncommitted byte size.
+ expand_bytes = MAX2(expand_bytes, min_expand_bytes);
+ expand_bytes = MIN2(expand_bytes, uncommitted_bytes);
- return expand_bytes;
+ clear_ratio_check_data();
} else {
- return 0;
+ // An expansion was not triggered. If we've started counting, increment
+ // the number of checks we've made in the current window. If we've
+ // reached the end of the window without resizing, clear the counters to
+ // start again the next time we see a ratio above the threshold.
+ if (_ratio_over_threshold_count > 0) {
+ _pauses_since_start++;
+ if (_pauses_since_start > NumPrevPausesForHeuristics) {
+ clear_ratio_check_data();
+ }
+ }
}
+
+ return expand_bytes;
}
void G1CollectorPolicy::print_tracing_info() const {
--- a/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1CollectorPolicy.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -201,6 +201,11 @@
TruncatedSeq* _concurrent_mark_remark_times_ms;
TruncatedSeq* _concurrent_mark_cleanup_times_ms;
+ // Ratio check data for determining if heap growth is necessary.
+ uint _ratio_over_threshold_count;
+ double _ratio_over_threshold_sum;
+ uint _pauses_since_start;
+
TraceYoungGenTimeData _trace_young_gen_time_data;
TraceOldGenTimeData _trace_old_gen_time_data;
@@ -224,7 +229,11 @@
enum PredictionConstants {
TruncatedSeqLength = 10,
- NumPrevPausesForHeuristics = 10
+ NumPrevPausesForHeuristics = 10,
+ // MinOverThresholdForGrowth must be less than NumPrevPausesForHeuristics,
+ // representing the minimum number of pause time ratios that exceed
+ // GCTimeRatio before a heap expansion will be triggered.
+ MinOverThresholdForGrowth = 4
};
TruncatedSeq* _alloc_rate_ms_seq;
@@ -483,8 +492,10 @@
G1GCPhaseTimes* _phase_times;
- // The ratio of gc time to elapsed time, computed over recent pauses.
+ // The ratio of gc time to elapsed time, computed over recent pauses,
+ // and the ratio for just the last pause.
double _recent_avg_pause_time_ratio;
+ double _last_pause_time_ratio;
double recent_avg_pause_time_ratio() const {
return _recent_avg_pause_time_ratio;
@@ -760,7 +771,10 @@
// If an expansion would be appropriate, because recent GC overhead had
// exceeded the desired limit, return an amount to expand by.
- virtual size_t expansion_amount() const;
+ virtual size_t expansion_amount();
+
+ // Clear ratio tracking data used by expansion_amount().
+ void clear_ratio_check_data();
// Print tracing information.
void print_tracing_info() const;
--- a/hotspot/src/share/vm/gc/g1/g1InCSetState.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1InCSetState.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -53,8 +53,12 @@
// frequency of the checks.
// The most common check is whether the region is in the collection set or not,
// this encoding allows us to use an > 0 check.
- // The other values are simply encoded in increasing generation order, which
- // makes getting the next generation fast by a simple increment.
+ // The positive values are encoded in increasing generation order, which
+ // makes getting the next generation fast by a simple increment. They are also
+ // used to index into arrays.
+ // The negative values are used for objects requiring various special cases,
+ // for example eager reclamation of humongous objects.
+ Ext = -2, // Extension point
Humongous = -1, // The region is humongous
NotInCSet = 0, // The region is not in the collection set.
Young = 1, // The region is in the collection set and a young region.
@@ -76,10 +80,11 @@
bool is_humongous() const { return _value == Humongous; }
bool is_young() const { return _value == Young; }
bool is_old() const { return _value == Old; }
+ bool is_ext() const { return _value == Ext; }
#ifdef ASSERT
- bool is_default() const { return !is_in_cset_or_humongous(); }
- bool is_valid() const { return (_value >= Humongous) && (_value < Num); }
+ bool is_default() const { return _value == NotInCSet; }
+ bool is_valid() const { return (_value >= Ext) && (_value < Num); }
bool is_valid_gen() const { return (_value >= Young && _value <= Old); }
#endif
};
@@ -105,6 +110,12 @@
set_by_index(index, InCSetState::Humongous);
}
+ void set_ext(uintptr_t index) {
+ assert(get_by_index(index).is_default(),
+ "State at index " INTPTR_FORMAT " should be default but is " CSETSTATE_FORMAT, index, get_by_index(index).value());
+ set_by_index(index, InCSetState::Ext);
+ }
+
void clear_humongous(uintptr_t index) {
set_by_index(index, InCSetState::NotInCSet);
}
--- a/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -121,7 +121,7 @@
G1MarkPromotedFromRoot
};
-template <G1Barrier barrier, G1Mark do_mark_object>
+template <G1Barrier barrier, G1Mark do_mark_object, bool use_ext>
class G1ParCopyClosure : public G1ParCopyHelper {
public:
G1ParCopyClosure(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) :
--- a/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1OopClosures.inline.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -90,6 +90,8 @@
} else {
if (state.is_humongous()) {
_g1->set_humongous_is_live(obj);
+ } else if (state.is_ext()) {
+ _par_scan_state->do_oop_ext(p);
}
_par_scan_state->update_rs(_from, p, obj);
}
@@ -102,12 +104,15 @@
if (!oopDesc::is_null(heap_oop)) {
oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
- if (_g1->is_in_cset_or_humongous(obj)) {
+ const InCSetState state = _g1->in_cset_state(obj);
+ if (state.is_in_cset_or_humongous()) {
Prefetch::write(obj->mark_addr(), 0);
Prefetch::read(obj->mark_addr(), (HeapWordSize*2));
// Place on the references queue
_par_scan_state->push_on_queue(p);
+ } else if (state.is_ext()) {
+ _par_scan_state->do_oop_ext(p);
} else {
assert(!_g1->obj_in_cs(obj), "checking");
}
@@ -249,9 +254,9 @@
_cm->grayRoot(to_obj, (size_t) from_obj->size(), _worker_id);
}
-template <G1Barrier barrier, G1Mark do_mark_object>
+template <G1Barrier barrier, G1Mark do_mark_object, bool use_ext>
template <class T>
-void G1ParCopyClosure<barrier, do_mark_object>::do_oop_nv(T* p) {
+void G1ParCopyClosure<barrier, do_mark_object, use_ext>::do_oop_nv(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (oopDesc::is_null(heap_oop)) {
@@ -286,6 +291,10 @@
if (state.is_humongous()) {
_g1->set_humongous_is_live(obj);
}
+
+ if (use_ext && state.is_ext()) {
+ _par_scan_state->do_oop_ext(p);
+ }
// The object is not in collection set. If we're a root scanning
// closure during an initial mark pause then attempt to mark the object.
if (do_mark_object == G1MarkFromRoot) {
--- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -96,6 +96,7 @@
bool verify_task(StarTask ref) const;
#endif // ASSERT
+ template <class T> void do_oop_ext(T* ref);
template <class T> void push_on_queue(T* ref);
template <class T> void update_rs(HeapRegion* from, T* p, oop o) {
--- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState.inline.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -50,8 +50,8 @@
} else if (in_cset_state.is_humongous()) {
_g1h->set_humongous_is_live(obj);
} else {
- assert(!in_cset_state.is_in_cset_or_humongous(),
- "In_cset_state must be NotInCSet here, but is " CSETSTATE_FORMAT, in_cset_state.value());
+ assert(in_cset_state.is_default() || in_cset_state.is_ext(),
+ "In_cset_state must be NotInCSet or Ext here, but is " CSETSTATE_FORMAT, in_cset_state.value());
}
assert(obj != NULL, "Must be");
--- a/hotspot/src/share/vm/gc/g1/g1ParScanThreadState_ext.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1ParScanThreadState_ext.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -29,3 +29,10 @@
G1ParScanThreadState* G1ParScanThreadStateSet::new_par_scan_state(uint worker_id, size_t young_cset_length) {
return new G1ParScanThreadState(_g1h, worker_id, young_cset_length);
}
+
+template <typename T>
+void G1ParScanThreadState::do_oop_ext(T* ref) {
+}
+
+template void G1ParScanThreadState::do_oop_ext<oop>(oop* ref);
+template void G1ParScanThreadState::do_oop_ext<narrowOop>(narrowOop* ref);
--- a/hotspot/src/share/vm/gc/g1/g1SharedClosures.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1SharedClosures.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -31,15 +31,15 @@
class G1ParScanThreadState;
// Simple holder object for a complete set of closures used by the G1 evacuation code.
-template <G1Mark Mark>
+template <G1Mark Mark, bool use_ext = false>
class G1SharedClosures VALUE_OBJ_CLASS_SPEC {
public:
- G1ParCopyClosure<G1BarrierNone, Mark> _oops;
- G1ParCopyClosure<G1BarrierKlass, Mark> _oop_in_klass;
- G1KlassScanClosure _klass_in_cld_closure;
- CLDToKlassAndOopClosure _clds;
- G1CodeBlobClosure _codeblobs;
- BufferingOopClosure _buffered_oops;
+ G1ParCopyClosure<G1BarrierNone, Mark, use_ext> _oops;
+ G1ParCopyClosure<G1BarrierKlass, Mark, use_ext> _oop_in_klass;
+ G1KlassScanClosure _klass_in_cld_closure;
+ CLDToKlassAndOopClosure _clds;
+ G1CodeBlobClosure _codeblobs;
+ BufferingOopClosure _buffered_oops;
G1SharedClosures(G1CollectedHeap* g1h, G1ParScanThreadState* pss, bool process_only_dirty_klasses, bool must_claim_cld) :
_oops(g1h, pss),
--- a/hotspot/src/share/vm/gc/g1/g1_globals.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/g1_globals.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -157,6 +157,7 @@
"Each time the rset update queue increases by this amount " \
"activate the next refinement thread if available. " \
"Will be selected ergonomically by default.") \
+ range(0, max_jint) \
\
product(intx, G1RSetUpdatingPauseTimePercent, 10, \
"A target percentage of time that is allowed to be spend on " \
@@ -300,6 +301,7 @@
\
product(uintx, G1MixedGCCountTarget, 8, \
"The target number of mixed GCs after a marking cycle.") \
+ range(0, max_uintx) \
\
experimental(bool, G1EagerReclaimHumongousObjects, true, \
"Try to reclaim dead large objects at every young GC.") \
--- a/hotspot/src/share/vm/gc/g1/heapRegion.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/g1/heapRegion.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -592,17 +592,20 @@
void HeapRegion::print() const { print_on(gclog_or_tty); }
void HeapRegion::print_on(outputStream* st) const {
- st->print("AC%4u", allocation_context());
-
- st->print(" %2s", get_short_type_str());
- if (in_collection_set())
- st->print(" CS");
- else
- st->print(" ");
- st->print(" TS %5d", _gc_time_stamp);
- st->print(" PTAMS " PTR_FORMAT " NTAMS " PTR_FORMAT,
- p2i(prev_top_at_mark_start()), p2i(next_top_at_mark_start()));
- G1OffsetTableContigSpace::print_on(st);
+ st->print("|%4u", this->_hrm_index);
+ st->print("|" PTR_FORMAT ", " PTR_FORMAT ", " PTR_FORMAT,
+ p2i(bottom()), p2i(top()), p2i(end()));
+ st->print("|%3d%%", (int) ((double) used() * 100 / capacity()));
+ st->print("|%2s", get_short_type_str());
+ if (in_collection_set()) {
+ st->print("|CS");
+ } else {
+ st->print("| ");
+ }
+ st->print("|TS%3u", _gc_time_stamp);
+ st->print("|AC%3u", allocation_context());
+ st->print_cr("|TAMS " PTR_FORMAT ", " PTR_FORMAT "|",
+ p2i(prev_top_at_mark_start()), p2i(next_top_at_mark_start()));
}
class VerifyLiveClosure: public OopClosure {
--- a/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/parallel/psMarkSweep.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "gc/parallel/parallelScavengeHeap.hpp"
--- a/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/parallel/psParallelCompact.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "gc/parallel/gcTaskManager.hpp"
--- a/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/serial/genMarkSweep.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/codeCache.hpp"
--- a/hotspot/src/share/vm/gc/shared/workgroup.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/shared/workgroup.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -500,122 +500,42 @@
return false;
}
-bool FreeIdSet::_stat_init = false;
-FreeIdSet* FreeIdSet::_sets[NSets];
-bool FreeIdSet::_safepoint;
-
-FreeIdSet::FreeIdSet(int sz, Monitor* mon) :
- _sz(sz), _mon(mon), _hd(0), _waiters(0), _index(-1), _claimed(0)
+FreeIdSet::FreeIdSet(uint size, Monitor* mon) :
+ _size(size), _mon(mon), _hd(0), _waiters(0), _claimed(0)
{
- _ids = NEW_C_HEAP_ARRAY(int, sz, mtInternal);
- for (int i = 0; i < sz; i++) _ids[i] = i+1;
- _ids[sz-1] = end_of_list; // end of list.
- if (_stat_init) {
- for (int j = 0; j < NSets; j++) _sets[j] = NULL;
- _stat_init = true;
+ guarantee(size != 0, "must be");
+ _ids = NEW_C_HEAP_ARRAY(uint, size, mtGC);
+ for (uint i = 0; i < size - 1; i++) {
+ _ids[i] = i+1;
}
- // Add to sets. (This should happen while the system is still single-threaded.)
- for (int j = 0; j < NSets; j++) {
- if (_sets[j] == NULL) {
- _sets[j] = this;
- _index = j;
- break;
- }
- }
- guarantee(_index != -1, "Too many FreeIdSets in use!");
+ _ids[size-1] = end_of_list; // end of list.
}
FreeIdSet::~FreeIdSet() {
- _sets[_index] = NULL;
- FREE_C_HEAP_ARRAY(int, _ids);
+ FREE_C_HEAP_ARRAY(uint, _ids);
}
-void FreeIdSet::set_safepoint(bool b) {
- _safepoint = b;
- if (b) {
- for (int j = 0; j < NSets; j++) {
- if (_sets[j] != NULL && _sets[j]->_waiters > 0) {
- Monitor* mon = _sets[j]->_mon;
- mon->lock_without_safepoint_check();
- mon->notify_all();
- mon->unlock();
- }
- }
- }
-}
-
-#define FID_STATS 0
-
-int FreeIdSet::claim_par_id() {
-#if FID_STATS
- thread_t tslf = thr_self();
- tty->print("claim_par_id[%d]: sz = %d, claimed = %d\n", tslf, _sz, _claimed);
-#endif
+uint FreeIdSet::claim_par_id() {
MutexLockerEx x(_mon, Mutex::_no_safepoint_check_flag);
- while (!_safepoint && _hd == end_of_list) {
+ while (_hd == end_of_list) {
_waiters++;
-#if FID_STATS
- if (_waiters > 5) {
- tty->print("claim_par_id waiting[%d]: %d waiters, %d claimed.\n",
- tslf, _waiters, _claimed);
- }
-#endif
_mon->wait(Mutex::_no_safepoint_check_flag);
_waiters--;
}
- if (_hd == end_of_list) {
-#if FID_STATS
- tty->print("claim_par_id[%d]: returning EOL.\n", tslf);
-#endif
- return -1;
- } else {
- int res = _hd;
- _hd = _ids[res];
- _ids[res] = claimed; // For debugging.
- _claimed++;
-#if FID_STATS
- tty->print("claim_par_id[%d]: returning %d, claimed = %d.\n",
- tslf, res, _claimed);
-#endif
- return res;
- }
+ uint res = _hd;
+ _hd = _ids[res];
+ _ids[res] = claimed; // For debugging.
+ _claimed++;
+ return res;
}
-bool FreeIdSet::claim_perm_id(int i) {
- assert(0 <= i && i < _sz, "Out of range.");
- MutexLockerEx x(_mon, Mutex::_no_safepoint_check_flag);
- int prev = end_of_list;
- int cur = _hd;
- while (cur != end_of_list) {
- if (cur == i) {
- if (prev == end_of_list) {
- _hd = _ids[cur];
- } else {
- _ids[prev] = _ids[cur];
- }
- _ids[cur] = claimed;
- _claimed++;
- return true;
- } else {
- prev = cur;
- cur = _ids[cur];
- }
- }
- return false;
-
-}
-
-void FreeIdSet::release_par_id(int id) {
+void FreeIdSet::release_par_id(uint id) {
MutexLockerEx x(_mon, Mutex::_no_safepoint_check_flag);
assert(_ids[id] == claimed, "Precondition.");
_ids[id] = _hd;
_hd = id;
_claimed--;
-#if FID_STATS
- tty->print("[%d] release_par_id(%d), waiters =%d, claimed = %d.\n",
- thr_self(), id, _waiters, _claimed);
-#endif
- if (_waiters > 0)
- // Notify all would be safer, but this is OK, right?
+ if (_waiters > 0) {
_mon->notify_all();
+ }
}
--- a/hotspot/src/share/vm/gc/shared/workgroup.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/gc/shared/workgroup.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -379,42 +379,29 @@
};
// Represents a set of free small integer ids.
-class FreeIdSet : public CHeapObj<mtInternal> {
+class FreeIdSet : public CHeapObj<mtGC> {
enum {
- end_of_list = -1,
- claimed = -2
+ end_of_list = UINT_MAX,
+ claimed = UINT_MAX - 1
};
- int _sz;
+ uint _size;
Monitor* _mon;
- int* _ids;
- int _hd;
- int _waiters;
- int _claimed;
-
- static bool _safepoint;
- typedef FreeIdSet* FreeIdSetPtr;
- static const int NSets = 10;
- static FreeIdSetPtr _sets[NSets];
- static bool _stat_init;
- int _index;
+ uint* _ids;
+ uint _hd;
+ uint _waiters;
+ uint _claimed;
public:
- FreeIdSet(int sz, Monitor* mon);
+ FreeIdSet(uint size, Monitor* mon);
~FreeIdSet();
- static void set_safepoint(bool b);
-
- // Attempt to claim the given id permanently. Returns "true" iff
- // successful.
- bool claim_perm_id(int i);
+ // Returns an unclaimed parallel id (waiting for one to be released if
+ // necessary).
+ uint claim_par_id();
- // Returns an unclaimed parallel id (waiting for one to be released if
- // necessary). Returns "-1" if a GC wakes up a wait for an id.
- int claim_par_id();
-
- void release_par_id(int id);
+ void release_par_id(uint id);
};
#endif // SHARE_VM_GC_SHARED_WORKGROUP_HPP
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/interpreter/linkResolver.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/defaultMethods.hpp"
+#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "compiler/compileBroker.hpp"
--- a/hotspot/src/share/vm/memory/filemap.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/memory/filemap.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/classLoader.hpp"
+#include "classfile/compactHashtable.inline.hpp"
#include "classfile/sharedClassUtil.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionaryShared.hpp"
--- a/hotspot/src/share/vm/oops/arrayKlass.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/arrayKlass.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -71,7 +71,9 @@
return super()->find_field(name, sig, fd);
}
-Method* ArrayKlass::uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const {
+Method* ArrayKlass::uncached_lookup_method(const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode) const {
// There are no methods in an array klass but the super class (Object) has some
assert(super(), "super klass must be present");
// Always ignore overpass methods in superclasses, although technically the
@@ -80,19 +82,18 @@
return super()->uncached_lookup_method(name, signature, Klass::skip_overpass);
}
-ArrayKlass::ArrayKlass(Symbol* name) {
- set_name(name);
-
- set_super(Universe::is_bootstrapping() ? (Klass*)NULL : SystemDictionary::Object_klass());
- set_layout_helper(Klass::_lh_neutral_value);
- set_dimension(1);
- set_higher_dimension(NULL);
- set_lower_dimension(NULL);
+ArrayKlass::ArrayKlass(Symbol* name) :
+ _dimension(1),
+ _higher_dimension(NULL),
+ _lower_dimension(NULL),
// Arrays don't add any new methods, so their vtable is the same size as
// the vtable of klass Object.
- int vtable_size = Universe::base_vtable_size();
- set_vtable_length(vtable_size);
- set_is_cloneable(); // All arrays are considered to be cloneable (See JLS 20.1.5)
+ _vtable_len(Universe::base_vtable_size()) {
+ set_name(name);
+ set_super(Universe::is_bootstrapping() ? (Klass*)NULL : SystemDictionary::Object_klass());
+ set_layout_helper(Klass::_lh_neutral_value);
+ set_is_cloneable(); // All arrays are considered to be cloneable (See JLS 20.1.5)
+ TRACE_INIT_ID(this);
}
--- a/hotspot/src/share/vm/oops/arrayKlass.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/arrayKlass.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -82,12 +82,17 @@
Klass* find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const;
// Lookup operations
- Method* uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const;
+ Method* uncached_lookup_method(const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode) const;
- // Casting from Klass*
static ArrayKlass* cast(Klass* k) {
+ return const_cast<ArrayKlass*>(cast(const_cast<const Klass*>(k)));
+ }
+
+ static const ArrayKlass* cast(const Klass* k) {
assert(k->is_array_klass(), "cast to ArrayKlass");
- return static_cast<ArrayKlass*>(k);
+ return static_cast<const ArrayKlass*>(k);
}
GrowableArray<Klass*>* compute_secondary_supers(int num_extra_slots);
--- a/hotspot/src/share/vm/oops/constantPool.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/constantPool.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -60,25 +60,33 @@
return new (loader_data, size, false, MetaspaceObj::ConstantPoolType, THREAD) ConstantPool(tags);
}
-ConstantPool::ConstantPool(Array<u1>* tags) {
- set_length(tags->length());
- set_tags(NULL);
- set_cache(NULL);
- set_reference_map(NULL);
- set_resolved_references(NULL);
- set_operands(NULL);
- set_pool_holder(NULL);
- set_flags(0);
+#ifdef ASSERT
- // only set to non-zero if constant pool is merged by RedefineClasses
- set_version(0);
+// MetaspaceObj allocation invariant is calloc equivalent memory
+// simple verification of this here (JVM_CONSTANT_Invalid == 0 )
+static bool tag_array_is_zero_initialized(Array<u1>* tags) {
+ assert(tags != NULL, "invariant");
+ const int length = tags->length();
+ for (int index = 0; index < length; ++index) {
+ if (JVM_CONSTANT_Invalid != tags->at(index)) {
+ return false;
+ }
+ }
+ return true;
+}
- // initialize tag array
- int length = tags->length();
- for (int index = 0; index < length; index++) {
- tags->at_put(index, JVM_CONSTANT_Invalid);
- }
- set_tags(tags);
+#endif
+
+ConstantPool::ConstantPool(Array<u1>* tags) :
+ _tags(tags),
+ _length(tags->length()) {
+
+ assert(_tags != NULL, "invariant");
+ assert(tags->length() == _length, "invariant");
+ assert(tag_array_is_zero_initialized(tags), "invariant");
+ assert(0 == _flags, "invariant");
+ assert(0 == version(), "invariant");
+ assert(NULL == _pool_holder, "invariant");
}
void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) {
@@ -466,7 +474,7 @@
}
-Symbol* ConstantPool::klass_name_at(int which) {
+Symbol* ConstantPool::klass_name_at(int which) const {
assert(tag_at(which).is_unresolved_klass() || tag_at(which).is_klass(),
"Corrupted constant pool");
// A resolved constantPool entry will contain a Klass*, otherwise a Symbol*.
@@ -497,7 +505,7 @@
return unresolved_string_at(which)->as_C_string();
}
-BasicType ConstantPool::basic_type_for_signature_at(int which) {
+BasicType ConstantPool::basic_type_for_signature_at(int which) const {
return FieldType::basic_type(symbol_at(which));
}
--- a/hotspot/src/share/vm/oops/constantPool.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/constantPool.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -116,7 +116,7 @@
private:
intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(ConstantPool)); }
- CPSlot slot_at(int which) {
+ CPSlot slot_at(int which) const {
assert(is_within_bounds(which), "index out of bounds");
// Uses volatile because the klass slot changes without a lock.
volatile intptr_t adr = (intptr_t)OrderAccess::load_ptr_acquire(obj_at_addr_raw(which));
@@ -349,7 +349,7 @@
return klass_at_impl(h_this, which, false, THREAD);
}
- Symbol* klass_name_at(int which); // Returns the name, w/o resolving.
+ Symbol* klass_name_at(int which) const; // Returns the name, w/o resolving.
Klass* resolved_klass_at(int which) const { // Used by Compiler
guarantee(tag_at(which).is_klass(), "Corrupted constant pool");
@@ -384,7 +384,7 @@
return *((jdouble*)&tmp);
}
- Symbol* symbol_at(int which) {
+ Symbol* symbol_at(int which) const {
assert(tag_at(which).is_utf8(), "Corrupted constant pool");
return *symbol_at_addr(which);
}
@@ -668,7 +668,7 @@
int name_ref_index_at(int which_nt); // == low-order jshort of name_and_type_at(which_nt)
int signature_ref_index_at(int which_nt); // == high-order jshort of name_and_type_at(which_nt)
- BasicType basic_type_for_signature_at(int which);
+ BasicType basic_type_for_signature_at(int which) const;
// Resolve string constants (to prevent allocation during compilation)
void resolve_string_constants(TRAPS) {
--- a/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/instanceClassLoaderKlass.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -29,6 +29,8 @@
#include "oops/instanceKlass.hpp"
#include "utilities/macros.hpp"
+class ClassFileParser;
+
// An InstanceClassLoaderKlass is a specialization of the InstanceKlass. It does
// not add any field. It is added to walk the dependencies for the class loader
// key that this class loader points to. This is how the loader_data graph is
@@ -38,11 +40,8 @@
class InstanceClassLoaderKlass: public InstanceKlass {
friend class VMStructs;
friend class InstanceKlass;
-
- // Constructor
- InstanceClassLoaderKlass(int vtable_len, int itable_len, int static_field_size, int nonstatic_oop_map_size, ReferenceType rt, AccessFlags access_flags, bool is_anonymous)
- : InstanceKlass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_size,
- InstanceKlass::_misc_kind_class_loader, rt, access_flags, is_anonymous) {}
+ private:
+ InstanceClassLoaderKlass(const ClassFileParser& parser) : InstanceKlass(parser, InstanceKlass::_misc_kind_class_loader) {}
public:
InstanceClassLoaderKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); }
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "classfile/classFileParser.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/verifier.hpp"
@@ -114,47 +115,57 @@
volatile int InstanceKlass::_total_instanceKlass_count = 0;
-InstanceKlass* InstanceKlass::allocate_instance_klass(
- ClassLoaderData* loader_data,
- int vtable_len,
- int itable_len,
- int static_field_size,
- int nonstatic_oop_map_size,
- ReferenceType rt,
- AccessFlags access_flags,
- Symbol* name,
- Klass* super_klass,
- bool is_anonymous,
- TRAPS) {
-
- int size = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size,
- access_flags.is_interface(), is_anonymous);
+static inline bool is_class_loader(const Symbol* class_name,
+ const ClassFileParser& parser) {
+ assert(class_name != NULL, "invariant");
+
+ if (class_name == vmSymbols::java_lang_ClassLoader()) {
+ return true;
+ }
+
+ if (SystemDictionary::ClassLoader_klass_loaded()) {
+ const Klass* const super_klass = parser.super_klass();
+ if (super_klass != NULL) {
+ if (super_klass->is_subtype_of(SystemDictionary::ClassLoader_klass())) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+InstanceKlass* InstanceKlass::allocate_instance_klass(const ClassFileParser& parser, TRAPS) {
+ const int size = InstanceKlass::size(parser.vtable_size(),
+ parser.itable_size(),
+ nonstatic_oop_map_size(parser.total_oop_map_count()),
+ parser.is_interface(),
+ parser.is_anonymous());
+
+ const Symbol* const class_name = parser.class_name();
+ assert(class_name != NULL, "invariant");
+ ClassLoaderData* loader_data = parser.loader_data();
+ assert(loader_data != NULL, "invariant");
+
+ InstanceKlass* ik;
// Allocation
- InstanceKlass* ik;
- if (rt == REF_NONE) {
- if (name == vmSymbols::java_lang_Class()) {
- ik = new (loader_data, size, THREAD) InstanceMirrorKlass(
- vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt,
- access_flags, is_anonymous);
- } else if (name == vmSymbols::java_lang_ClassLoader() ||
- (SystemDictionary::ClassLoader_klass_loaded() &&
- super_klass != NULL &&
- super_klass->is_subtype_of(SystemDictionary::ClassLoader_klass()))) {
- ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(
- vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt,
- access_flags, is_anonymous);
- } else {
- // normal class
- ik = new (loader_data, size, THREAD) InstanceKlass(
- vtable_len, itable_len, static_field_size, nonstatic_oop_map_size,
- InstanceKlass::_misc_kind_other, rt, access_flags, is_anonymous);
+ if (REF_NONE == parser.reference_type()) {
+ if (class_name == vmSymbols::java_lang_Class()) {
+ // mirror
+ ik = new (loader_data, size, THREAD) InstanceMirrorKlass(parser);
+ }
+ else if (is_class_loader(class_name, parser)) {
+ // class loader
+ ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(parser);
}
- } else {
- // reference klass
- ik = new (loader_data, size, THREAD) InstanceRefKlass(
- vtable_len, itable_len, static_field_size, nonstatic_oop_map_size, rt,
- access_flags, is_anonymous);
+ else {
+ // normal
+ ik = new (loader_data, size, THREAD) InstanceKlass(parser, InstanceKlass::_misc_kind_other);
+ }
+ }
+ else {
+ // reference
+ ik = new (loader_data, size, THREAD) InstanceRefKlass(parser);
}
// Check for pending exception before adding to the loader data and incrementing
@@ -163,17 +174,21 @@
return NULL;
}
+ assert(ik != NULL, "invariant");
+
+ const bool publicize = !parser.is_internal();
+
// Add all classes to our internal class loader list here,
// including classes in the bootstrap (NULL) class loader.
- loader_data->add_class(ik);
-
+ loader_data->add_class(ik, publicize);
Atomic::inc(&_total_instanceKlass_count);
+
return ik;
}
// copy method ordering from resource area to Metaspace
-void InstanceKlass::copy_method_ordering(intArray* m, TRAPS) {
+void InstanceKlass::copy_method_ordering(const intArray* m, TRAPS) {
if (m != NULL) {
// allocate a new array and copy contents (memcpy?)
_method_ordering = MetadataFactory::new_array<int>(class_loader_data(), m->length(), CHECK);
@@ -193,79 +208,23 @@
return vtable_indices;
}
-InstanceKlass::InstanceKlass(int vtable_len,
- int itable_len,
- int static_field_size,
- int nonstatic_oop_map_size,
- unsigned kind,
- ReferenceType rt,
- AccessFlags access_flags,
- bool is_anonymous) {
- No_Safepoint_Verifier no_safepoint; // until k becomes parsable
-
- int iksize = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size,
- access_flags.is_interface(), is_anonymous);
- set_vtable_length(vtable_len);
- set_itable_length(itable_len);
- set_static_field_size(static_field_size);
- set_nonstatic_oop_map_size(nonstatic_oop_map_size);
- set_access_flags(access_flags);
- _misc_flags = 0; // initialize to zero
- set_kind(kind);
- set_is_anonymous(is_anonymous);
- assert(size() == iksize, "wrong size for object");
-
- set_array_klasses(NULL);
- set_methods(NULL);
- set_method_ordering(NULL);
- set_default_methods(NULL);
- set_default_vtable_indices(NULL);
- set_local_interfaces(NULL);
- set_transitive_interfaces(NULL);
- init_implementor();
- set_fields(NULL, 0);
- set_constants(NULL);
- set_class_loader_data(NULL);
- set_source_file_name_index(0);
- set_source_debug_extension(NULL, 0);
- set_array_name(NULL);
- set_inner_classes(NULL);
- set_static_oop_field_count(0);
- set_nonstatic_field_size(0);
- set_is_marked_dependent(false);
- _dep_context = DependencyContext::EMPTY;
- set_init_state(InstanceKlass::allocated);
- set_init_thread(NULL);
- set_reference_type(rt);
- set_oop_map_cache(NULL);
- set_jni_ids(NULL);
- set_osr_nmethods_head(NULL);
- set_breakpoints(NULL);
- init_previous_versions();
- set_generic_signature_index(0);
- release_set_methods_jmethod_ids(NULL);
- set_annotations(NULL);
- set_jvmti_cached_class_field_map(NULL);
- set_initial_method_idnum(0);
- set_jvmti_cached_class_field_map(NULL);
- set_cached_class_file(NULL);
- set_initial_method_idnum(0);
- set_minor_version(0);
- set_major_version(0);
- NOT_PRODUCT(_verify_count = 0;)
-
- // initialize the non-header words to zero
- intptr_t* p = (intptr_t*)this;
- for (int index = InstanceKlass::header_size(); index < iksize; index++) {
- p[index] = NULL_WORD;
- }
-
- // Set temporary value until parseClassFile updates it with the real instance
- // size.
- set_layout_helper(Klass::instance_layout_helper(0, true));
+InstanceKlass::InstanceKlass(const ClassFileParser& parser, unsigned kind) :
+ _static_field_size(parser.static_field_size()),
+ _nonstatic_oop_map_size(nonstatic_oop_map_size(parser.total_oop_map_count())),
+ _vtable_len(parser.vtable_size()),
+ _itable_len(parser.itable_size()),
+ _reference_type(parser.reference_type()) {
+ set_kind(kind);
+ set_access_flags(parser.access_flags());
+ set_is_anonymous(parser.is_anonymous());
+ set_layout_helper(Klass::instance_layout_helper(parser.layout_size(),
+ false));
+
+ assert(NULL == _methods, "underlying memory not zeroed?");
+ assert(is_instance_klass(), "is layout incorrect?");
+ assert(size_helper() == parser.layout_size(), "incorrect size_helper?");
}
-
void InstanceKlass::deallocate_methods(ClassLoaderData* loader_data,
Array<Method*>* methods) {
if (methods != NULL && methods != Universe::the_empty_method_array() &&
@@ -283,7 +242,7 @@
}
void InstanceKlass::deallocate_interfaces(ClassLoaderData* loader_data,
- Klass* super_klass,
+ const Klass* super_klass,
Array<Klass*>* local_interfaces,
Array<Klass*>* transitive_interfaces) {
// Only deallocate transitive interfaces if not empty, same as super class
@@ -1349,10 +1308,12 @@
}
#ifdef ASSERT
-static int linear_search(Array<Method*>* methods, Symbol* name, Symbol* signature) {
- int len = methods->length();
+static int linear_search(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature) {
+ const int len = methods->length();
for (int index = 0; index < len; index++) {
- Method* m = methods->at(index);
+ const Method* const m = methods->at(index);
assert(m->is_method(), "must be method");
if (m->signature() == signature && m->name() == name) {
return index;
@@ -1362,7 +1323,7 @@
}
#endif
-static int binary_search(Array<Method*>* methods, Symbol* name) {
+static int binary_search(const Array<Method*>* methods, const Symbol* name) {
int len = methods->length();
// methods are sorted, so do binary search
int l = 0;
@@ -1384,31 +1345,44 @@
}
// find_method looks up the name/signature in the local methods array
-Method* InstanceKlass::find_method(Symbol* name, Symbol* signature) const {
+Method* InstanceKlass::find_method(const Symbol* name,
+ const Symbol* signature) const {
return find_method_impl(name, signature, find_overpass, find_static, find_private);
}
-Method* InstanceKlass::find_method_impl(Symbol* name, Symbol* signature,
+Method* InstanceKlass::find_method_impl(const Symbol* name,
+ const Symbol* signature,
OverpassLookupMode overpass_mode,
StaticLookupMode static_mode,
PrivateLookupMode private_mode) const {
- return InstanceKlass::find_method_impl(methods(), name, signature, overpass_mode, static_mode, private_mode);
+ return InstanceKlass::find_method_impl(methods(),
+ name,
+ signature,
+ overpass_mode,
+ static_mode,
+ private_mode);
}
// find_instance_method looks up the name/signature in the local methods array
// and skips over static methods
-Method* InstanceKlass::find_instance_method(
- Array<Method*>* methods, Symbol* name, Symbol* signature) {
- Method* meth = InstanceKlass::find_method_impl(methods, name, signature,
- find_overpass, skip_static, find_private);
- assert(((meth == NULL) || !meth->is_static()), "find_instance_method should have skipped statics");
+Method* InstanceKlass::find_instance_method(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature) {
+ Method* const meth = InstanceKlass::find_method_impl(methods,
+ name,
+ signature,
+ find_overpass,
+ skip_static,
+ find_private);
+ assert(((meth == NULL) || !meth->is_static()),
+ "find_instance_method should have skipped statics");
return meth;
}
// find_instance_method looks up the name/signature in the local methods array
// and skips over static methods
-Method* InstanceKlass::find_instance_method(Symbol* name, Symbol* signature) {
- return InstanceKlass::find_instance_method(methods(), name, signature);
+Method* InstanceKlass::find_instance_method(const Symbol* name, const Symbol* signature) const {
+ return InstanceKlass::find_instance_method(methods(), name, signature);
}
// Find looks up the name/signature in the local methods array
@@ -1416,11 +1390,17 @@
// This returns the first one found
// note that the local methods array can have up to one overpass, one static
// and one instance (private or not) with the same name/signature
-Method* InstanceKlass::find_local_method(Symbol* name, Symbol* signature,
- OverpassLookupMode overpass_mode,
- StaticLookupMode static_mode,
- PrivateLookupMode private_mode) const {
- return InstanceKlass::find_method_impl(methods(), name, signature, overpass_mode, static_mode, private_mode);
+Method* InstanceKlass::find_local_method(const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode,
+ StaticLookupMode static_mode,
+ PrivateLookupMode private_mode) const {
+ return InstanceKlass::find_method_impl(methods(),
+ name,
+ signature,
+ overpass_mode,
+ static_mode,
+ private_mode);
}
// Find looks up the name/signature in the local methods array
@@ -1428,34 +1408,51 @@
// This returns the first one found
// note that the local methods array can have up to one overpass, one static
// and one instance (private or not) with the same name/signature
-Method* InstanceKlass::find_local_method(Array<Method*>* methods,
- Symbol* name, Symbol* signature,
+Method* InstanceKlass::find_local_method(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode,
+ StaticLookupMode static_mode,
+ PrivateLookupMode private_mode) {
+ return InstanceKlass::find_method_impl(methods,
+ name,
+ signature,
+ overpass_mode,
+ static_mode,
+ private_mode);
+}
+
+Method* InstanceKlass::find_method(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature) {
+ return InstanceKlass::find_method_impl(methods,
+ name,
+ signature,
+ find_overpass,
+ find_static,
+ find_private);
+}
+
+Method* InstanceKlass::find_method_impl(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature,
OverpassLookupMode overpass_mode,
StaticLookupMode static_mode,
PrivateLookupMode private_mode) {
- return InstanceKlass::find_method_impl(methods, name, signature, overpass_mode, static_mode, private_mode);
-}
-
-
-// find_method looks up the name/signature in the local methods array
-Method* InstanceKlass::find_method(
- Array<Method*>* methods, Symbol* name, Symbol* signature) {
- return InstanceKlass::find_method_impl(methods, name, signature, find_overpass, find_static, find_private);
-}
-
-Method* InstanceKlass::find_method_impl(
- Array<Method*>* methods, Symbol* name, Symbol* signature,
- OverpassLookupMode overpass_mode, StaticLookupMode static_mode,
- PrivateLookupMode private_mode) {
int hit = find_method_index(methods, name, signature, overpass_mode, static_mode, private_mode);
return hit >= 0 ? methods->at(hit): NULL;
}
-bool InstanceKlass::method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static, bool skipping_private) {
- return ((m->signature() == signature) &&
- (!skipping_overpass || !m->is_overpass()) &&
- (!skipping_static || !m->is_static()) &&
- (!skipping_private || !m->is_private()));
+// true if method matches signature and conforms to skipping_X conditions.
+static bool method_matches(const Method* m,
+ const Symbol* signature,
+ bool skipping_overpass,
+ bool skipping_static,
+ bool skipping_private) {
+ return ((m->signature() == signature) &&
+ (!skipping_overpass || !m->is_overpass()) &&
+ (!skipping_static || !m->is_static()) &&
+ (!skipping_private || !m->is_private()));
}
// Used directly for default_methods to find the index into the
@@ -1470,50 +1467,65 @@
// To correctly catch a given method, the search criteria may need
// to explicitly skip the other two. For local instance methods, it
// is often necessary to skip private methods
-int InstanceKlass::find_method_index(
- Array<Method*>* methods, Symbol* name, Symbol* signature,
- OverpassLookupMode overpass_mode, StaticLookupMode static_mode,
- PrivateLookupMode private_mode) {
- bool skipping_overpass = (overpass_mode == skip_overpass);
- bool skipping_static = (static_mode == skip_static);
- bool skipping_private = (private_mode == skip_private);
- int hit = binary_search(methods, name);
+int InstanceKlass::find_method_index(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode,
+ StaticLookupMode static_mode,
+ PrivateLookupMode private_mode) {
+ const bool skipping_overpass = (overpass_mode == skip_overpass);
+ const bool skipping_static = (static_mode == skip_static);
+ const bool skipping_private = (private_mode == skip_private);
+ const int hit = binary_search(methods, name);
if (hit != -1) {
- Method* m = methods->at(hit);
+ const Method* const m = methods->at(hit);
// Do linear search to find matching signature. First, quick check
// for common case, ignoring overpasses if requested.
- if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) return hit;
+ if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) {
+ return hit;
+ }
// search downwards through overloaded methods
int i;
for (i = hit - 1; i >= 0; --i) {
- Method* m = methods->at(i);
+ const Method* const m = methods->at(i);
assert(m->is_method(), "must be method");
- if (m->name() != name) break;
- if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) return i;
+ if (m->name() != name) {
+ break;
+ }
+ if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) {
+ return i;
+ }
}
// search upwards
for (i = hit + 1; i < methods->length(); ++i) {
- Method* m = methods->at(i);
+ const Method* const m = methods->at(i);
assert(m->is_method(), "must be method");
- if (m->name() != name) break;
- if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) return i;
+ if (m->name() != name) {
+ break;
+ }
+ if (method_matches(m, signature, skipping_overpass, skipping_static, skipping_private)) {
+ return i;
+ }
}
// not found
#ifdef ASSERT
- int index = (skipping_overpass || skipping_static || skipping_private) ? -1 : linear_search(methods, name, signature);
- assert(index == -1, "binary search should have found entry %d", index);
+ const int index = (skipping_overpass || skipping_static || skipping_private) ? -1 :
+ linear_search(methods, name, signature);
+ assert(-1 == index, "binary search should have found entry %d", index);
#endif
}
return -1;
}
-int InstanceKlass::find_method_by_name(Symbol* name, int* end) {
+
+int InstanceKlass::find_method_by_name(const Symbol* name, int* end) const {
return find_method_by_name(methods(), name, end);
}
-int InstanceKlass::find_method_by_name(
- Array<Method*>* methods, Symbol* name, int* end_ptr) {
+int InstanceKlass::find_method_by_name(const Array<Method*>* methods,
+ const Symbol* name,
+ int* end_ptr) {
assert(end_ptr != NULL, "just checking");
int start = binary_search(methods, name);
int end = start + 1;
@@ -1528,11 +1540,17 @@
// uncached_lookup_method searches both the local class methods array and all
// superclasses methods arrays, skipping any overpass methods in superclasses.
-Method* InstanceKlass::uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const {
+Method* InstanceKlass::uncached_lookup_method(const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode) const {
OverpassLookupMode overpass_local_mode = overpass_mode;
- Klass* klass = const_cast<InstanceKlass*>(this);
+ const Klass* klass = this;
while (klass != NULL) {
- Method* method = InstanceKlass::cast(klass)->find_method_impl(name, signature, overpass_local_mode, find_static, find_private);
+ Method* const method = InstanceKlass::cast(klass)->find_method_impl(name,
+ signature,
+ overpass_local_mode,
+ find_static,
+ find_private);
if (method != NULL) {
return method;
}
@@ -1545,8 +1563,8 @@
#ifdef ASSERT
// search through class hierarchy and return true if this class or
// one of the superclasses was redefined
-bool InstanceKlass::has_redefined_this_or_super() {
- Klass* klass = this;
+bool InstanceKlass::has_redefined_this_or_super() const {
+ const Klass* klass = this;
while (klass != NULL) {
if (InstanceKlass::cast(klass)->has_been_redefined()) {
return true;
@@ -1615,19 +1633,18 @@
return probe;
}
-u2 InstanceKlass::enclosing_method_data(int offset) {
- Array<jushort>* inner_class_list = inner_classes();
+u2 InstanceKlass::enclosing_method_data(int offset) const {
+ const Array<jushort>* const inner_class_list = inner_classes();
if (inner_class_list == NULL) {
return 0;
}
- int length = inner_class_list->length();
+ const int length = inner_class_list->length();
if (length % inner_class_next_offset == 0) {
return 0;
- } else {
- int index = length - enclosing_method_attribute_size;
- assert(offset < enclosing_method_attribute_size, "invalid offset");
- return inner_class_list->at(index + offset);
}
+ const int index = length - enclosing_method_attribute_size;
+ assert(offset < enclosing_method_attribute_size, "invalid offset");
+ return inner_class_list->at(index + offset);
}
void InstanceKlass::set_enclosing_method_indices(u2 class_index,
@@ -2103,7 +2120,7 @@
Atomic::dec(&_total_instanceKlass_count);
}
-void InstanceKlass::set_source_debug_extension(char* array, int length) {
+void InstanceKlass::set_source_debug_extension(const char* array, int length) {
if (array == NULL) {
_source_debug_extension = NULL;
} else {
@@ -2164,26 +2181,42 @@
}
// different verisons of is_same_class_package
-bool InstanceKlass::is_same_class_package(Klass* class2) {
+bool InstanceKlass::is_same_class_package(const Klass* class2) const {
+ const Klass* const class1 = (const Klass* const)this;
+ oop classloader1 = InstanceKlass::cast(class1)->class_loader();
+ const Symbol* const classname1 = class1->name();
+
if (class2->is_objArray_klass()) {
class2 = ObjArrayKlass::cast(class2)->bottom_klass();
}
- oop classloader2 = class2->class_loader();
- Symbol* classname2 = class2->name();
-
- return InstanceKlass::is_same_class_package(class_loader(), name(),
+ oop classloader2;
+ if (class2->is_instance_klass()) {
+ classloader2 = InstanceKlass::cast(class2)->class_loader();
+ } else {
+ assert(class2->is_typeArray_klass(), "should be type array");
+ classloader2 = NULL;
+ }
+ const Symbol* classname2 = class2->name();
+
+ return InstanceKlass::is_same_class_package(classloader1, classname1,
classloader2, classname2);
}
-bool InstanceKlass::is_same_class_package(oop classloader2, Symbol* classname2) {
- return InstanceKlass::is_same_class_package(class_loader(), name(),
- classloader2, classname2);
+bool InstanceKlass::is_same_class_package(oop other_class_loader,
+ const Symbol* other_class_name) const {
+ oop this_class_loader = class_loader();
+ const Symbol* const this_class_name = name();
+
+ return InstanceKlass::is_same_class_package(this_class_loader,
+ this_class_name,
+ other_class_loader,
+ other_class_name);
}
// return true if two classes are in the same package, classloader
// and classname information is enough to determine a class's package
-bool InstanceKlass::is_same_class_package(oop class_loader1, Symbol* class_name1,
- oop class_loader2, Symbol* class_name2) {
+bool InstanceKlass::is_same_class_package(oop class_loader1, const Symbol* class_name1,
+ oop class_loader2, const Symbol* class_name2) {
if (class_loader1 != class_loader2) {
return false;
} else if (class_name1 == class_name2) {
@@ -2262,11 +2295,11 @@
*/
// tell if two classes have the same enclosing class (at package level)
-bool InstanceKlass::is_same_package_member_impl(instanceKlassHandle class1,
- Klass* class2_oop, TRAPS) {
- if (class2_oop == class1()) return true;
- if (!class2_oop->is_instance_klass()) return false;
- instanceKlassHandle class2(THREAD, class2_oop);
+bool InstanceKlass::is_same_package_member_impl(const InstanceKlass* class1,
+ const Klass* class2,
+ TRAPS) {
+ if (class2 == class1) return true;
+ if (!class2->is_instance_klass()) return false;
// must be in same package before we try anything else
if (!class1->is_same_class_package(class2->class_loader(), class2->name()))
@@ -2274,30 +2307,30 @@
// As long as there is an outer1.getEnclosingClass,
// shift the search outward.
- instanceKlassHandle outer1 = class1;
+ const InstanceKlass* outer1 = class1;
for (;;) {
// As we walk along, look for equalities between outer1 and class2.
// Eventually, the walks will terminate as outer1 stops
// at the top-level class around the original class.
bool ignore_inner_is_member;
- Klass* next = outer1->compute_enclosing_class(&ignore_inner_is_member,
- CHECK_false);
+ const Klass* next = outer1->compute_enclosing_class(&ignore_inner_is_member,
+ CHECK_false);
if (next == NULL) break;
- if (next == class2()) return true;
- outer1 = instanceKlassHandle(THREAD, next);
+ if (next == class2) return true;
+ outer1 = InstanceKlass::cast(next);
}
// Now do the same for class2.
- instanceKlassHandle outer2 = class2;
+ const InstanceKlass* outer2 = InstanceKlass::cast(class2);
for (;;) {
bool ignore_inner_is_member;
Klass* next = outer2->compute_enclosing_class(&ignore_inner_is_member,
CHECK_false);
if (next == NULL) break;
// Might as well check the new outer against all available values.
- if (next == class1()) return true;
- if (next == outer1()) return true;
- outer2 = instanceKlassHandle(THREAD, next);
+ if (next == class1) return true;
+ if (next == outer1) return true;
+ outer2 = InstanceKlass::cast(next);
}
// If by this point we have not found an equality between the
@@ -2325,36 +2358,38 @@
return false;
}
-Klass* InstanceKlass::compute_enclosing_class_impl(instanceKlassHandle k, bool* inner_is_member, TRAPS) {
- instanceKlassHandle outer_klass;
+InstanceKlass* InstanceKlass::compute_enclosing_class_impl(const InstanceKlass* k,
+ bool* inner_is_member,
+ TRAPS) {
+ InstanceKlass* outer_klass = NULL;
*inner_is_member = false;
int ooff = 0, noff = 0;
if (find_inner_classes_attr(k, &ooff, &noff, THREAD)) {
constantPoolHandle i_cp(THREAD, k->constants());
if (ooff != 0) {
Klass* ok = i_cp->klass_at(ooff, CHECK_NULL);
- outer_klass = instanceKlassHandle(THREAD, ok);
+ outer_klass = InstanceKlass::cast(ok);
*inner_is_member = true;
}
- if (outer_klass.is_null()) {
+ if (NULL == outer_klass) {
// It may be anonymous; try for that.
int encl_method_class_idx = k->enclosing_method_class_index();
if (encl_method_class_idx != 0) {
Klass* ok = i_cp->klass_at(encl_method_class_idx, CHECK_NULL);
- outer_klass = instanceKlassHandle(THREAD, ok);
+ outer_klass = InstanceKlass::cast(ok);
*inner_is_member = false;
}
}
}
// If no inner class attribute found for this class.
- if (outer_klass.is_null()) return NULL;
+ if (NULL == outer_klass) return NULL;
// Throws an exception if outer klass has not declared k as an inner klass
// We need evidence that each klass knows about the other, or else
// the system could allow a spoof of an inner class to gain access rights.
Reflection::check_for_inner_class(outer_klass, k, *inner_is_member, CHECK_NULL);
- return outer_klass();
+ return outer_klass;
}
jint InstanceKlass::compute_modifier_flags(TRAPS) const {
--- a/hotspot/src/share/vm/oops/instanceKlass.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/instanceKlass.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -54,6 +54,7 @@
// forward declaration for class -- see below for definition
class BreakpointInfo;
+class ClassFileParser;
class DepChange;
class DependencyContext;
class fieldDescriptor;
@@ -112,29 +113,9 @@
friend class CompileReplay;
protected:
- // Constructor
- InstanceKlass(int vtable_len,
- int itable_len,
- int static_field_size,
- int nonstatic_oop_map_size,
- unsigned kind,
- ReferenceType rt,
- AccessFlags access_flags,
- bool is_anonymous);
+ InstanceKlass(const ClassFileParser& parser, unsigned kind);
+
public:
- static InstanceKlass* allocate_instance_klass(
- ClassLoaderData* loader_data,
- int vtable_len,
- int itable_len,
- int static_field_size,
- int nonstatic_oop_map_size,
- ReferenceType rt,
- AccessFlags access_flags,
- Symbol* name,
- Klass* super_klass,
- bool is_anonymous,
- TRAPS);
-
InstanceKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); }
// See "The Java Virtual Machine Specification" section 2.16.2-5 for a detailed description
@@ -152,6 +133,7 @@
private:
static volatile int _total_instanceKlass_count;
+ static InstanceKlass* allocate_instance_klass(const ClassFileParser& parser, TRAPS);
protected:
// Annotations for this class
@@ -176,7 +158,7 @@
// the source debug extension for this klass, NULL if not specified.
// Specified as UTF-8 string without terminating zero byte in the classfile,
// it is stored in the instanceklass as a NULL-terminated UTF-8 string
- char* _source_debug_extension;
+ const char* _source_debug_extension;
// Array name derived from this class which needs unreferencing
// if this class is unloaded.
Symbol* _array_name;
@@ -350,7 +332,7 @@
// method ordering
Array<int>* method_ordering() const { return _method_ordering; }
void set_method_ordering(Array<int>* m) { _method_ordering = m; }
- void copy_method_ordering(intArray* m, TRAPS);
+ void copy_method_ordering(const intArray* m, TRAPS);
// default_methods
Array<Method*>* default_methods() const { return _default_methods; }
@@ -416,29 +398,32 @@
bool is_override(const methodHandle& super_method, Handle targetclassloader, Symbol* targetclassname, TRAPS);
// package
- bool is_same_class_package(Klass* class2);
- bool is_same_class_package(oop classloader2, Symbol* classname2);
- static bool is_same_class_package(oop class_loader1, Symbol* class_name1, oop class_loader2, Symbol* class_name2);
+ bool is_same_class_package(const Klass* class2) const;
+ bool is_same_class_package(oop classloader2, const Symbol* classname2) const;
+ static bool is_same_class_package(oop class_loader1,
+ const Symbol* class_name1,
+ oop class_loader2,
+ const Symbol* class_name2);
// find an enclosing class
- Klass* compute_enclosing_class(bool* inner_is_member, TRAPS) {
- instanceKlassHandle self(THREAD, this);
- return compute_enclosing_class_impl(self, inner_is_member, THREAD);
+ InstanceKlass* compute_enclosing_class(bool* inner_is_member, TRAPS) const {
+ return compute_enclosing_class_impl(this, inner_is_member, THREAD);
}
- static Klass* compute_enclosing_class_impl(instanceKlassHandle self,
- bool* inner_is_member, TRAPS);
+ static InstanceKlass* compute_enclosing_class_impl(const InstanceKlass* self,
+ bool* inner_is_member,
+ TRAPS);
// Find InnerClasses attribute for k and return outer_class_info_index & inner_name_index.
static bool find_inner_classes_attr(instanceKlassHandle k,
int* ooff, int* noff, TRAPS);
// tell if two classes have the same enclosing class (at package level)
- bool is_same_package_member(Klass* class2, TRAPS) {
- instanceKlassHandle self(THREAD, this);
- return is_same_package_member_impl(self, class2, THREAD);
+ bool is_same_package_member(const Klass* class2, TRAPS) const {
+ return is_same_package_member_impl(this, class2, THREAD);
}
- static bool is_same_package_member_impl(instanceKlassHandle self,
- Klass* class2, TRAPS);
+ static bool is_same_package_member_impl(const InstanceKlass* self,
+ const Klass* class2,
+ TRAPS);
// initialization state
bool is_loaded() const { return _init_state >= loaded; }
@@ -507,38 +492,44 @@
bool find_field_from_offset(int offset, bool is_static, fieldDescriptor* fd) const;
// find a local method (returns NULL if not found)
- Method* find_method(Symbol* name, Symbol* signature) const;
- static Method* find_method(Array<Method*>* methods, Symbol* name, Symbol* signature);
+ Method* find_method(const Symbol* name, const Symbol* signature) const;
+ static Method* find_method(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature);
// find a local method, but skip static methods
- Method* find_instance_method(Symbol* name, Symbol* signature);
- static Method* find_instance_method(Array<Method*>* methods, Symbol* name, Symbol* signature);
+ Method* find_instance_method(const Symbol* name, const Symbol* signature) const;
+ static Method* find_instance_method(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature);
// find a local method (returns NULL if not found)
- Method* find_local_method(Symbol* name, Symbol* signature,
- OverpassLookupMode overpass_mode,
- StaticLookupMode static_mode,
- PrivateLookupMode private_mode) const;
+ Method* find_local_method(const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode,
+ StaticLookupMode static_mode,
+ PrivateLookupMode private_mode) const;
// find a local method from given methods array (returns NULL if not found)
- static Method* find_local_method(Array<Method*>* methods,
- Symbol* name, Symbol* signature,
- OverpassLookupMode overpass_mode,
- StaticLookupMode static_mode,
- PrivateLookupMode private_mode);
-
- // true if method matches signature and conforms to skipping_X conditions.
- static bool method_matches(Method* m, Symbol* signature, bool skipping_overpass, bool skipping_static, bool skipping_private);
+ static Method* find_local_method(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode,
+ StaticLookupMode static_mode,
+ PrivateLookupMode private_mode);
// find a local method index in methods or default_methods (returns -1 if not found)
- static int find_method_index(Array<Method*>* methods,
- Symbol* name, Symbol* signature,
+ static int find_method_index(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature,
OverpassLookupMode overpass_mode,
StaticLookupMode static_mode,
PrivateLookupMode private_mode);
// lookup operation (returns NULL if not found)
- Method* uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const;
+ Method* uncached_lookup_method(const Symbol* name,
+ const Symbol* signature,
+ OverpassLookupMode overpass_mode) const;
// lookup a method in all the interfaces that this class implements
// (returns NULL if not found)
@@ -552,8 +543,9 @@
// found the index to the first method is returned, and 'end' is filled in
// with the index of first non-name-matching method. If no method is found
// -1 is returned.
- int find_method_by_name(Symbol* name, int* end);
- static int find_method_by_name(Array<Method*>* methods, Symbol* name, int* end);
+ int find_method_by_name(const Symbol* name, int* end) const;
+ static int find_method_by_name(const Array<Method*>* methods,
+ const Symbol* name, int* end);
// constant pool
ConstantPool* constants() const { return _constants; }
@@ -575,9 +567,9 @@
return *hk;
}
}
- void set_host_klass(Klass* host) {
+ void set_host_klass(const Klass* host) {
assert(is_anonymous(), "not anonymous");
- Klass** addr = (Klass**)adr_host_klass();
+ const Klass** addr = (const Klass**)adr_host_klass();
assert(addr != NULL, "no reversed space");
if (addr != NULL) {
*addr = host;
@@ -630,8 +622,8 @@
void set_major_version(u2 major_version) { _major_version = major_version; }
// source debug extension
- char* source_debug_extension() const { return _source_debug_extension; }
- void set_source_debug_extension(char* array, int length);
+ const char* source_debug_extension() const { return _source_debug_extension; }
+ void set_source_debug_extension(const char* array, int length);
// symbol unloading support (refcount already added)
Symbol* array_name() { return _array_name; }
@@ -764,8 +756,8 @@
_generic_signature_index = sig_index;
}
- u2 enclosing_method_data(int offset);
- u2 enclosing_method_class_index() {
+ u2 enclosing_method_data(int offset) const;
+ u2 enclosing_method_class_index() const {
return enclosing_method_data(enclosing_method_class_index_offset);
}
u2 enclosing_method_method_index() {
@@ -859,7 +851,7 @@
#ifdef ASSERT
// check whether this class or one of its superclasses was redefined
- bool has_redefined_this_or_super();
+ bool has_redefined_this_or_super() const;
#endif
// Access to the implementor of an interface.
@@ -919,11 +911,14 @@
void array_klasses_do(void f(Klass* k, TRAPS), TRAPS);
bool super_types_do(SuperTypeClosure* blk);
- // Casting from Klass*
static InstanceKlass* cast(Klass* k) {
+ return const_cast<InstanceKlass*>(cast(const_cast<const Klass*>(k)));
+ }
+
+ static const InstanceKlass* cast(const Klass* k) {
assert(k != NULL, "k should not be null");
assert(k->is_instance_klass(), "cast to InstanceKlass");
- return static_cast<InstanceKlass*>(k);
+ return static_cast<const InstanceKlass*>(k);
}
InstanceKlass* java_super() const {
@@ -1032,7 +1027,7 @@
static void deallocate_methods(ClassLoaderData* loader_data,
Array<Method*>* methods);
void static deallocate_interfaces(ClassLoaderData* loader_data,
- Klass* super_klass,
+ const Klass* super_klass,
Array<Klass*>* local_interfaces,
Array<Klass*>* transitive_interfaces);
@@ -1203,12 +1198,15 @@
Klass* array_klass_impl(bool or_null, TRAPS);
// find a local method (returns NULL if not found)
- Method* find_method_impl(Symbol* name, Symbol* signature,
+ Method* find_method_impl(const Symbol* name,
+ const Symbol* signature,
OverpassLookupMode overpass_mode,
StaticLookupMode static_mode,
PrivateLookupMode private_mode) const;
- static Method* find_method_impl(Array<Method*>* methods,
- Symbol* name, Symbol* signature,
+
+ static Method* find_method_impl(const Array<Method*>* methods,
+ const Symbol* name,
+ const Symbol* signature,
OverpassLookupMode overpass_mode,
StaticLookupMode static_mode,
PrivateLookupMode private_mode);
--- a/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/instanceMirrorKlass.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -31,6 +31,8 @@
#include "runtime/handles.hpp"
#include "utilities/macros.hpp"
+class ClassFileParser;
+
// An InstanceMirrorKlass is a specialized InstanceKlass for
// java.lang.Class instances. These instances are special because
// they contain the static fields of the class in addition to the
@@ -46,10 +48,7 @@
private:
static int _offset_of_static_fields;
- // Constructor
- InstanceMirrorKlass(int vtable_len, int itable_len, int static_field_size, int nonstatic_oop_map_size, ReferenceType rt, AccessFlags access_flags, bool is_anonymous)
- : InstanceKlass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_size,
- InstanceKlass::_misc_kind_mirror, rt, access_flags, is_anonymous) {}
+ InstanceMirrorKlass(const ClassFileParser& parser) : InstanceKlass(parser, InstanceKlass::_misc_kind_mirror) {}
public:
InstanceMirrorKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); }
--- a/hotspot/src/share/vm/oops/instanceRefKlass.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/instanceRefKlass.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -29,6 +29,8 @@
#include "oops/instanceKlass.hpp"
#include "utilities/macros.hpp"
+class ClassFileParser;
+
// An InstanceRefKlass is a specialized InstanceKlass for Java
// classes that are subclasses of java/lang/ref/Reference.
//
@@ -48,11 +50,8 @@
class InstanceRefKlass: public InstanceKlass {
friend class InstanceKlass;
-
- // Constructor
- InstanceRefKlass(int vtable_len, int itable_len, int static_field_size, int nonstatic_oop_map_size, ReferenceType rt, AccessFlags access_flags, bool is_anonymous)
- : InstanceKlass(vtable_len, itable_len, static_field_size, nonstatic_oop_map_size,
- InstanceKlass::_misc_kind_reference, rt, access_flags, is_anonymous) {}
+ private:
+ InstanceRefKlass(const ClassFileParser& parser) : InstanceKlass(parser, InstanceKlass::_misc_kind_reference) {}
public:
InstanceRefKlass() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); }
--- a/hotspot/src/share/vm/oops/klass.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/klass.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -136,7 +136,7 @@
return NULL;
}
-Method* Klass::uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const {
+Method* Klass::uncached_lookup_method(const Symbol* name, const Symbol* signature, OverpassLookupMode overpass_mode) const {
#ifdef ASSERT
tty->print_cr("Error: uncached_lookup_method called on a klass oop."
" Likely error: reflection method does not correctly"
@@ -151,45 +151,18 @@
MetaspaceObj::ClassType, THREAD);
}
-Klass::Klass() {
- Klass* k = this;
-
- // Preinitialize supertype information.
- // A later call to initialize_supers() may update these settings:
- set_super(NULL);
- for (juint i = 0; i < Klass::primary_super_limit(); i++) {
- _primary_supers[i] = NULL;
- }
- set_secondary_supers(NULL);
- set_secondary_super_cache(NULL);
- _primary_supers[0] = k;
- set_super_check_offset(in_bytes(primary_supers_offset()));
-
- // The constructor is used from init_self_patching_vtbl_list,
- // which doesn't zero out the memory before calling the constructor.
- // Need to set the field explicitly to not hit an assert that the field
- // should be NULL before setting it.
- _java_mirror = NULL;
+// "Normal" instantiation is preceeded by a MetaspaceObj allocation
+// which zeros out memory - calloc equivalent.
+// The constructor is also used from init_self_patching_vtbl_list,
+// which doesn't zero out the memory before calling the constructor.
+// Need to set the _java_mirror field explicitly to not hit an assert that the field
+// should be NULL before setting it.
+Klass::Klass() : _prototype_header(markOopDesc::prototype()),
+ _shared_class_path_index(-1),
+ _java_mirror(NULL) {
- set_modifier_flags(0);
- set_layout_helper(Klass::_lh_neutral_value);
- set_name(NULL);
- AccessFlags af;
- af.set_flags(0);
- set_access_flags(af);
- set_subklass(NULL);
- set_next_sibling(NULL);
- set_next_link(NULL);
- TRACE_INIT_ID(this);
-
- set_prototype_header(markOopDesc::prototype());
- set_biased_lock_revocation_count(0);
- set_last_biased_lock_bulk_revocation_time(0);
-
- // The klass doesn't have any references at this point.
- clear_modified_oops();
- clear_accumulated_modified_oops();
- _shared_class_path_index = -1;
+ _primary_supers[0] = this;
+ set_super_check_offset(in_bytes(primary_supers_offset()));
}
jint Klass::array_layout_helper(BasicType etype) {
--- a/hotspot/src/share/vm/oops/klass.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/klass.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -410,9 +410,9 @@
// lookup operation for MethodLookupCache
friend class MethodLookupCache;
virtual Klass* find_field(Symbol* name, Symbol* signature, fieldDescriptor* fd) const;
- virtual Method* uncached_lookup_method(Symbol* name, Symbol* signature, OverpassLookupMode overpass_mode) const;
+ virtual Method* uncached_lookup_method(const Symbol* name, const Symbol* signature, OverpassLookupMode overpass_mode) const;
public:
- Method* lookup_method(Symbol* name, Symbol* signature) const {
+ Method* lookup_method(const Symbol* name, const Symbol* signature) const {
return uncached_lookup_method(name, signature, find_overpass);
}
--- a/hotspot/src/share/vm/oops/klassVtable.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/klassVtable.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -54,7 +54,7 @@
// treated as any other public method in C for method over-ride purposes.
void klassVtable::compute_vtable_size_and_num_mirandas(
int* vtable_length_ret, int* num_new_mirandas,
- GrowableArray<Method*>* all_mirandas, Klass* super,
+ GrowableArray<Method*>* all_mirandas, const Klass* super,
Array<Method*>* methods, AccessFlags class_flags,
Handle classloader, Symbol* classname, Array<Klass*>* local_interfaces,
TRAPS) {
@@ -548,7 +548,7 @@
// However, the vtable entries are filled in at link time, and therefore
// the superclass' vtable may not yet have been filled in.
bool klassVtable::needs_new_vtable_entry(methodHandle target_method,
- Klass* super,
+ const Klass* super,
Handle classloader,
Symbol* classname,
AccessFlags class_flags,
@@ -605,7 +605,7 @@
ResourceMark rm;
Symbol* name = target_method()->name();
Symbol* signature = target_method()->signature();
- Klass* k = super;
+ const Klass* k = super;
Method* super_method = NULL;
InstanceKlass *holder = NULL;
Method* recheck_method = NULL;
@@ -640,7 +640,7 @@
// miranda method in the super, whose entry it should re-use.
// Actually, to handle cases that javac would not generate, we need
// this check for all access permissions.
- InstanceKlass *sk = InstanceKlass::cast(super);
+ const InstanceKlass *sk = InstanceKlass::cast(super);
if (sk->has_miranda_methods()) {
if (sk->lookup_method_in_all_interfaces(name, signature, Klass::find_defaults) != NULL) {
return false; // found a matching miranda; we do not need a new entry
@@ -734,7 +734,7 @@
// Part of the Miranda Rights in the US mean that if you do not have
// an attorney one will be appointed for you.
bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods,
- Array<Method*>* default_methods, Klass* super) {
+ Array<Method*>* default_methods, const Klass* super) {
if (m->is_static() || m->is_private() || m->is_overpass()) {
return false;
}
@@ -760,7 +760,7 @@
// Overpasses may or may not exist for supers for pass 1,
// they should have been created for pass 2 and later.
- for (Klass* cursuper = super; cursuper != NULL; cursuper = cursuper->super())
+ for (const Klass* cursuper = super; cursuper != NULL; cursuper = cursuper->super())
{
if (InstanceKlass::cast(cursuper)->find_local_method(name, signature,
Klass::find_overpass, Klass::skip_static, Klass::skip_private) != NULL) {
@@ -782,7 +782,7 @@
void klassVtable::add_new_mirandas_to_lists(
GrowableArray<Method*>* new_mirandas, GrowableArray<Method*>* all_mirandas,
Array<Method*>* current_interface_methods, Array<Method*>* class_methods,
- Array<Method*>* default_methods, Klass* super) {
+ Array<Method*>* default_methods, const Klass* super) {
// iterate thru the current interface's method to see if it a miranda
int num_methods = current_interface_methods->length();
@@ -802,7 +802,7 @@
if (!is_duplicate) { // we don't want duplicate miranda entries in the vtable
if (is_miranda(im, class_methods, default_methods, super)) { // is it a miranda at all?
- InstanceKlass *sk = InstanceKlass::cast(super);
+ const InstanceKlass *sk = InstanceKlass::cast(super);
// check if it is a duplicate of a super's miranda
if (sk->lookup_method_in_all_interfaces(im->name(), im->signature(), Klass::find_defaults) == NULL) {
new_mirandas->append(im);
@@ -817,7 +817,8 @@
void klassVtable::get_mirandas(GrowableArray<Method*>* new_mirandas,
GrowableArray<Method*>* all_mirandas,
- Klass* super, Array<Method*>* class_methods,
+ const Klass* super,
+ Array<Method*>* class_methods,
Array<Method*>* default_methods,
Array<Klass*>* local_interfaces) {
assert((new_mirandas->length() == 0) , "current mirandas must be 0");
--- a/hotspot/src/share/vm/oops/klassVtable.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/klassVtable.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -84,11 +84,16 @@
bool is_initialized();
// computes vtable length (in words) and the number of miranda methods
- static void compute_vtable_size_and_num_mirandas(
- int* vtable_length, int* num_new_mirandas,
- GrowableArray<Method*>* all_mirandas, Klass* super,
- Array<Method*>* methods, AccessFlags class_flags, Handle classloader,
- Symbol* classname, Array<Klass*>* local_interfaces, TRAPS);
+ static void compute_vtable_size_and_num_mirandas(int* vtable_length,
+ int* num_new_mirandas,
+ GrowableArray<Method*>* all_mirandas,
+ const Klass* super,
+ Array<Method*>* methods,
+ AccessFlags class_flags,
+ Handle classloader,
+ Symbol* classname,
+ Array<Klass*>* local_interfaces,
+ TRAPS);
#if INCLUDE_JVMTI
// RedefineClasses() API support:
@@ -116,7 +121,12 @@
int initialize_from_super(KlassHandle super);
int index_of(Method* m, int len) const; // same as index_of, but search only up to len
void put_method_at(Method* m, int index);
- static bool needs_new_vtable_entry(methodHandle m, Klass* super, Handle classloader, Symbol* classname, AccessFlags access_flags, TRAPS);
+ static bool needs_new_vtable_entry(methodHandle m,
+ const Klass* super,
+ Handle classloader,
+ Symbol* classname,
+ AccessFlags access_flags,
+ TRAPS);
bool update_inherited_vtable(InstanceKlass* klass, methodHandle target_method, int super_vtable_len, int default_index, bool checkconstraints, TRAPS);
InstanceKlass* find_transitive_override(InstanceKlass* initialsuper, methodHandle target_method, int vtable_index,
@@ -126,17 +136,18 @@
bool is_miranda_entry_at(int i);
int fill_in_mirandas(int initialized);
static bool is_miranda(Method* m, Array<Method*>* class_methods,
- Array<Method*>* default_methods, Klass* super);
+ Array<Method*>* default_methods, const Klass* super);
static void add_new_mirandas_to_lists(
GrowableArray<Method*>* new_mirandas,
GrowableArray<Method*>* all_mirandas,
Array<Method*>* current_interface_methods,
Array<Method*>* class_methods,
Array<Method*>* default_methods,
- Klass* super);
+ const Klass* super);
static void get_mirandas(
GrowableArray<Method*>* new_mirandas,
- GrowableArray<Method*>* all_mirandas, Klass* super,
+ GrowableArray<Method*>* all_mirandas,
+ const Klass* super,
Array<Method*>* class_methods,
Array<Method*>* default_methods,
Array<Klass*>* local_interfaces);
--- a/hotspot/src/share/vm/oops/method.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/method.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -1320,12 +1320,12 @@
return newm;
}
-vmSymbols::SID Method::klass_id_for_intrinsics(Klass* holder) {
+vmSymbols::SID Method::klass_id_for_intrinsics(const Klass* holder) {
// if loader is not the default loader (i.e., != NULL), we can't know the intrinsics
// because we are not loading from core libraries
// exception: the AES intrinsics come from lib/ext/sunjce_provider.jar
// which does not use the class default class loader so we check for its loader here
- InstanceKlass* ik = InstanceKlass::cast(holder);
+ const InstanceKlass* ik = InstanceKlass::cast(holder);
if ((ik->class_loader() != NULL) && !SystemDictionary::is_ext_class_loader(ik->class_loader())) {
return vmSymbols::NO_SID; // regardless of name, no intrinsics here
}
--- a/hotspot/src/share/vm/oops/method.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/method.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -84,7 +84,7 @@
_running_emcp = 1 << 6,
_intrinsic_candidate = 1 << 7
};
- u1 _flags;
+ mutable u1 _flags;
#ifndef PRODUCT
int _compiled_invocation_count; // Number of nmethod invocations so far (for perf. debugging)
@@ -784,12 +784,12 @@
// Helper routines for intrinsic_id() and vmIntrinsics::method().
void init_intrinsic_id(); // updates from _none if a match
- static vmSymbols::SID klass_id_for_intrinsics(Klass* holder);
+ static vmSymbols::SID klass_id_for_intrinsics(const Klass* holder);
- bool jfr_towrite() {
+ bool jfr_towrite() const {
return (_flags & _jfr_towrite) != 0;
}
- void set_jfr_towrite(bool x) {
+ void set_jfr_towrite(bool x) const {
_flags = x ? (_flags | _jfr_towrite) : (_flags & ~_jfr_towrite);
}
--- a/hotspot/src/share/vm/oops/objArrayKlass.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/objArrayKlass.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -89,10 +89,14 @@
virtual Klass* array_klass_impl(bool or_null, TRAPS);
public:
- // Casting from Klass*
+
static ObjArrayKlass* cast(Klass* k) {
+ return const_cast<ObjArrayKlass*>(cast(const_cast<const Klass*>(k)));
+ }
+
+ static const ObjArrayKlass* cast(const Klass* k) {
assert(k->is_objArray_klass(), "cast to ObjArrayKlass");
- return static_cast<ObjArrayKlass*>(k);
+ return static_cast<const ObjArrayKlass*>(k);
}
// Sizing
--- a/hotspot/src/share/vm/oops/symbol.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/symbol.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -148,8 +148,8 @@
int size() { return size(utf8_length()); }
// Returns the largest size symbol we can safely hold.
- static int max_length() { return max_symbol_length; }
- unsigned identity_hash() {
+ static int max_length() { return max_symbol_length; }
+ unsigned identity_hash() const {
unsigned addr_bits = (unsigned)((uintptr_t)this >> (LogMinObjAlignmentInBytes + 3));
return ((unsigned)_identity_hash & 0xffff) |
((addr_bits ^ (_length << 8) ^ (( _body[0] << 8) | _body[1])) << 16);
@@ -197,7 +197,7 @@
// Three-way compare for sorting; returns -1/0/1 if receiver is </==/> than arg
// note that the ordering is not alfabetical
- inline int fast_compare(Symbol* other) const;
+ inline int fast_compare(const Symbol* other) const;
// Returns receiver converted to null-terminated UTF-8 string; string is
// allocated in resource area, or in the char buffer provided by caller.
@@ -246,7 +246,7 @@
// what order it defines, as long as it is a total, time-invariant order
// Since Symbol*s are in C_HEAP, their relative order in memory never changes,
// so use address comparison for speed
-int Symbol::fast_compare(Symbol* other) const {
+int Symbol::fast_compare(const Symbol* other) const {
return (((uintptr_t)this < (uintptr_t)other) ? -1
: ((uintptr_t)this == (uintptr_t) other) ? 0 : 1);
}
--- a/hotspot/src/share/vm/oops/typeArrayKlass.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/oops/typeArrayKlass.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -120,10 +120,13 @@
virtual Klass* array_klass_impl(bool or_null, TRAPS);
public:
- // Casting from Klass*
static TypeArrayKlass* cast(Klass* k) {
+ return const_cast<TypeArrayKlass*>(cast(const_cast<const Klass*>(k)));
+ }
+
+ static const TypeArrayKlass* cast(const Klass* k) {
assert(k->is_typeArray_klass(), "cast to TypeArrayKlass");
- return static_cast<TypeArrayKlass*>(k);
+ return static_cast<const TypeArrayKlass*>(k);
}
// Naming
--- a/hotspot/src/share/vm/prims/jni.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/prims/jni.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -26,6 +26,7 @@
#include "precompiled.hpp"
#include "ci/ciReplay.hpp"
#include "classfile/altHashing.hpp"
+#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/symbolTable.hpp"
@@ -326,7 +327,7 @@
class_name = SymbolTable::new_symbol(name, CHECK_NULL);
}
ResourceMark rm(THREAD);
- ClassFileStream st((u1*) buf, bufLen, NULL);
+ ClassFileStream st((u1*)buf, bufLen, NULL, ClassFileStream::verify);
Handle class_loader (THREAD, JNIHandles::resolve(loaderRef));
if (UsePerfData && !class_loader.is_null()) {
@@ -338,9 +339,11 @@
ClassLoader::sync_JNIDefineClassLockFreeCounter()->inc();
}
}
- Klass* k = SystemDictionary::resolve_from_stream(class_name, class_loader,
- Handle(), &st, true,
- CHECK_NULL);
+ Klass* k = SystemDictionary::resolve_from_stream(class_name,
+ class_loader,
+ Handle(),
+ &st,
+ CHECK_NULL);
if (TraceClassResolution && k != NULL) {
trace_class_resolution(k);
--- a/hotspot/src/share/vm/prims/jvm.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/prims/jvm.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/javaAssertions.hpp"
#include "classfile/javaClasses.inline.hpp"
@@ -965,7 +966,7 @@
}
ResourceMark rm(THREAD);
- ClassFileStream st((u1*) buf, len, (char *)source);
+ ClassFileStream st((u1*)buf, len, source, ClassFileStream::verify);
Handle class_loader (THREAD, JNIHandles::resolve(loader));
if (UsePerfData) {
is_lock_held_by_thread(class_loader,
@@ -973,9 +974,11 @@
THREAD);
}
Handle protection_domain (THREAD, JNIHandles::resolve(pd));
- Klass* k = SystemDictionary::resolve_from_stream(class_name, class_loader,
- protection_domain, &st,
- true, CHECK_NULL);
+ Klass* k = SystemDictionary::resolve_from_stream(class_name,
+ class_loader,
+ protection_domain,
+ &st,
+ CHECK_NULL);
if (TraceClassResolution && k != NULL) {
trace_class_resolution(k);
@@ -3723,4 +3726,3 @@
JVM_ENTRY_NO_ENV(jint, JVM_FindSignal(const char *name))
return os::get_signal_number(name);
JVM_END
-
--- a/hotspot/src/share/vm/prims/jvmtiEnv.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/prims/jvmtiEnv.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -2577,7 +2577,7 @@
if (!k->is_instance_klass()) {
return JVMTI_ERROR_ABSENT_INFORMATION;
}
- char* sde = InstanceKlass::cast(k)->source_debug_extension();
+ const char* sde = InstanceKlass::cast(k)->source_debug_extension();
NULL_CHECK(sde, JVMTI_ERROR_ABSENT_INFORMATION);
{
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "classfile/classFileStream.hpp"
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/verifier.hpp"
@@ -977,8 +978,10 @@
the_class->external_name(), _class_load_kind,
os::available_memory() >> 10));
- ClassFileStream st((u1*) _class_defs[i].class_bytes,
- _class_defs[i].class_byte_count, (char *)"__VM_RedefineClasses__");
+ ClassFileStream st((u1*)_class_defs[i].class_bytes,
+ _class_defs[i].class_byte_count,
+ "__VM_RedefineClasses__",
+ ClassFileStream::verify);
// Parse the stream.
Handle the_class_loader(THREAD, the_class->class_loader());
--- a/hotspot/src/share/vm/prims/unsafe.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/prims/unsafe.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "classfile/classFileStream.hpp"
#include "classfile/vmSymbols.hpp"
#include "memory/allocation.inline.hpp"
#include "oops/objArrayOop.inline.hpp"
@@ -997,7 +998,9 @@
cp_patches_h = objArrayHandle(THREAD, (objArrayOop)p);
}
- KlassHandle host_klass(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(host_class)));
+ const Klass* host_klass = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(host_class));
+ assert(host_klass != NULL, "invariant");
+
const char* host_source = host_klass->external_name();
Handle host_loader(THREAD, host_klass->class_loader());
Handle host_domain(THREAD, host_klass->protection_domain());
@@ -1016,15 +1019,21 @@
}
}
- ClassFileStream st(class_bytes, class_bytes_length, (char*) host_source);
+ ClassFileStream st(class_bytes,
+ class_bytes_length,
+ host_source,
+ ClassFileStream::verify);
instanceKlassHandle anon_klass;
{
Symbol* no_class_name = NULL;
Klass* anonk = SystemDictionary::parse_stream(no_class_name,
- host_loader, host_domain,
- &st, host_klass, cp_patches,
- CHECK_NULL);
+ host_loader,
+ host_domain,
+ &st,
+ host_klass,
+ cp_patches,
+ CHECK_NULL);
if (anonk == NULL) return NULL;
anon_klass = instanceKlassHandle(THREAD, anonk);
}
--- a/hotspot/src/share/vm/runtime/arguments.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -1308,18 +1308,20 @@
PropertyList_unique_add(&_system_properties, key, value, true);
} else {
if (strcmp(key, "sun.java.command") == 0) {
- if (_java_command != NULL) {
- os::free(_java_command);
+ char *old_java_command = _java_command;
+ _java_command = os::strdup_check_oom(value, mtInternal);
+ if (old_java_command != NULL) {
+ os::free(old_java_command);
}
- _java_command = os::strdup_check_oom(value, mtInternal);
} else if (strcmp(key, "java.vendor.url.bug") == 0) {
- if (_java_vendor_url_bug != DEFAULT_VENDOR_URL_BUG) {
- assert(_java_vendor_url_bug != NULL, "_java_vendor_url_bug is NULL");
- os::free((void *)_java_vendor_url_bug);
- }
+ const char* old_java_vendor_url_bug = _java_vendor_url_bug;
// save it in _java_vendor_url_bug, so JVM fatal error handler can access
// its value without going through the property list or making a Java call.
_java_vendor_url_bug = os::strdup_check_oom(value, mtInternal);
+ if (old_java_vendor_url_bug != DEFAULT_VENDOR_URL_BUG) {
+ assert(old_java_vendor_url_bug != NULL, "_java_vendor_url_bug is NULL");
+ os::free((void *)old_java_vendor_url_bug);
+ }
}
// Create new property and add at the end of the list
@@ -1949,12 +1951,9 @@
if (FLAG_IS_DEFAULT(GCTimeRatio) || GCTimeRatio == 0) {
// In G1, we want the default GC overhead goal to be higher than
- // say in PS. So we set it here to 10%. Otherwise the heap might
- // be expanded more aggressively than we would like it to. In
- // fact, even 10% seems to not be high enough in some cases
- // (especially small GC stress tests that the main thing they do
- // is allocation). We might consider increase it further.
- FLAG_SET_DEFAULT(GCTimeRatio, 9);
+ // it is for PS, or the heap might be expanded too aggressively.
+ // We set it here to ~8%.
+ FLAG_SET_DEFAULT(GCTimeRatio, 12);
}
if (PrintGCDetails && Verbose) {
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintList.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -223,7 +223,7 @@
#define EMIT_CONSTRAINT_CHECK(func, type) , func, CommandLineFlagConstraint::type
// the "name" argument must be a string literal
-#define INITIAL_CONSTRAINTS_SIZE 69
+#define INITIAL_CONSTRAINTS_SIZE 72
GrowableArray<CommandLineFlagConstraint*>* CommandLineFlagConstraintList::_constraints = NULL;
CommandLineFlagConstraint::ConstraintType CommandLineFlagConstraintList::_validating_type = CommandLineFlagConstraint::AtParse;
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -31,6 +31,7 @@
#include "runtime/commandLineFlagRangeList.hpp"
#include "runtime/globals.hpp"
#include "runtime/globals_extension.hpp"
+#include "runtime/thread.inline.hpp"
#include "utilities/defaultStream.hpp"
#if INCLUDE_ALL_GCS
@@ -506,6 +507,19 @@
return Flag::SUCCESS;
}
+// To avoid an overflow by 'align_size_up(value, alignment)'.
+static Flag::Error MaxSizeForAlignment(const char* name, size_t value, size_t alignment, bool verbose) {
+ size_t aligned_max = ((max_uintx - alignment) & ~(alignment-1));
+ if (value > aligned_max) {
+ CommandLineError::print(verbose,
+ "%s (" SIZE_FORMAT ") must be "
+ "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n",
+ name, value, aligned_max);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ return Flag::SUCCESS;
+}
+
static Flag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool verbose) {
// For G1 GC, we don't know until G1CollectorPolicy is created.
size_t heap_alignment;
@@ -519,16 +533,7 @@
heap_alignment = CollectorPolicy::compute_heap_alignment();
}
- // Not to overflow 'align_size_up(value, _heap_alignment) used from CollectorPolicy::initialize_flags()'.
- size_t aligned_max = ((max_uintx - heap_alignment) & ~(heap_alignment-1));
- if (value > aligned_max) {
- CommandLineError::print(verbose,
- "%s (" SIZE_FORMAT ") must be "
- "less than or equal to aligned maximum value (" SIZE_FORMAT ")\n",
- name, value, aligned_max);
- return Flag::VIOLATES_CONSTRAINT;
- }
- return Flag::SUCCESS;
+ return MaxSizeForAlignment(name, value, heap_alignment, verbose);
}
Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose) {
@@ -544,6 +549,29 @@
return status;
}
+Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose) {
+ // If an overflow happened in Arguments::set_heap_size(), MaxHeapSize will have too large a value.
+ // Check for this by ensuring that MaxHeapSize plus the requested min base address still fit within max_uintx.
+ if (UseCompressedOops && FLAG_IS_ERGO(MaxHeapSize) && (value > (max_uintx - MaxHeapSize))) {
+ CommandLineError::print(verbose,
+ "HeapBaseMinAddress (" SIZE_FORMAT ") or MaxHeapSize (" SIZE_FORMAT ") is too large. "
+ "Sum of them must be less than or equal to maximum of size_t (" SIZE_FORMAT ")\n",
+ value, MaxHeapSize, max_uintx);
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+
+ return MaxSizeForHeapAlignment("HeapBaseMinAddress", value, verbose);
+}
+
+Flag::Error NUMAInterleaveGranularityConstraintFunc(size_t value, bool verbose) {
+ if (UseNUMA && UseNUMAInterleaving) {
+ size_t min_interleave_granularity = UseLargePages ? os::large_page_size() : os::vm_allocation_granularity();
+ return MaxSizeForAlignment("NUMAInterleaveGranularity", value, min_interleave_granularity, verbose);
+ } else {
+ return Flag::SUCCESS;
+ }
+}
+
Flag::Error NewSizeConstraintFunc(size_t value, bool verbose) {
#ifdef _LP64
#if INCLUDE_ALL_GCS
@@ -596,6 +624,24 @@
return Flag::SUCCESS;
}
+// We will protect overflow from ThreadLocalAllocBuffer::record_slow_allocation(),
+// so AfterMemoryInit type is enough to check.
+Flag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose) {
+ if (UseTLAB) {
+ size_t refill_waste_limit = Thread::current()->tlab().refill_waste_limit();
+
+ // Compare with 'max_uintx' as ThreadLocalAllocBuffer::_refill_waste_limit is 'size_t'.
+ if (refill_waste_limit > (max_uintx - value)) {
+ CommandLineError::print(verbose,
+ "TLABWasteIncrement (" UINTX_FORMAT ") must be "
+ "less than or equal to ergonomic TLAB waste increment maximum size(" SIZE_FORMAT ")\n",
+ value, (max_uintx - refill_waste_limit));
+ return Flag::VIOLATES_CONSTRAINT;
+ }
+ }
+ return Flag::SUCCESS;
+}
+
Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose) {
if (FLAG_IS_CMDLINE(SurvivorRatio) &&
(value > (MaxHeapSize / Universe::heap()->collector_policy()->space_alignment()))) {
--- a/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/runtime/commandLineFlagConstraintsGC.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -67,9 +67,12 @@
Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool verbose);
Flag::Error InitialHeapSizeConstraintFunc(size_t value, bool verbose);
Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose);
+Flag::Error HeapBaseMinAddressConstraintFunc(size_t value, bool verbose);
+Flag::Error NUMAInterleaveGranularityConstraintFunc(size_t value, bool verbose);
Flag::Error NewSizeConstraintFunc(size_t value, bool verbose);
Flag::Error MinTLABSizeConstraintFunc(size_t value, bool verbose);
Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose);
+Flag::Error TLABWasteIncrementConstraintFunc(uintx value, bool verbose);
Flag::Error SurvivorRatioConstraintFunc(uintx value, bool verbose);
Flag::Error MetaspaceSizeConstraintFunc(size_t value, bool verbose);
Flag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose);
--- a/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/runtime/commandLineFlagRangeList.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -250,6 +250,9 @@
void emit_range_intx(const char* name, intx min, intx max) {
CommandLineFlagRangeList::add(new CommandLineFlagRange_intx(name, min, max));
}
+void emit_range_uint(const char* name, uint min, uint max) {
+ CommandLineFlagRangeList::add(new CommandLineFlagRange_uint(name, min, max));
+}
void emit_range_uintx(const char* name, uintx min, uintx max) {
CommandLineFlagRangeList::add(new CommandLineFlagRange_uintx(name, min, max));
}
@@ -279,7 +282,7 @@
// Generate func argument to pass into emit_range_xxx functions
#define EMIT_RANGE_CHECK(a, b) , a, b
-#define INITIAL_RANGES_SIZE 320
+#define INITIAL_RANGES_SIZE 379
GrowableArray<CommandLineFlagRange*>* CommandLineFlagRangeList::_ranges = NULL;
// Check the ranges of all flags that have them
--- a/hotspot/src/share/vm/runtime/globals.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/runtime/globals.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -25,7 +25,6 @@
#ifndef SHARE_VM_RUNTIME_GLOBALS_HPP
#define SHARE_VM_RUNTIME_GLOBALS_HPP
-#include <float.h>
#include "utilities/debug.hpp"
#include <float.h> // for DBL_MAX
@@ -625,9 +624,6 @@
notproduct(bool, CheckCompressedOops, true, \
"Generate checks in encoding/decoding code in debug VM") \
\
- product_pd(size_t, HeapBaseMinAddress, \
- "OS specific low limit for heap base address") \
- \
product(uintx, HeapSearchSteps, 3 PPC64_ONLY(+17), \
"Heap allocation steps through preferred address regions to find" \
" where it can allocate the heap. Number of steps to take per " \
@@ -692,6 +688,8 @@
\
product(size_t, NUMAInterleaveGranularity, 2*M, \
"Granularity to use for NUMA interleaving on Windows OS") \
+ range(os::vm_allocation_granularity(), max_uintx) \
+ constraint(NUMAInterleaveGranularityConstraintFunc,AfterErgo) \
\
product(bool, ForceNUMA, false, \
"Force NUMA optimizations on single-node/UMA systems") \
@@ -704,6 +702,7 @@
\
product(size_t, NUMASpaceResizeRate, 1*G, \
"Do not reallocate more than this amount per collection") \
+ range(0, max_uintx) \
\
product(bool, UseAdaptiveNUMAChunkSizing, true, \
"Enable adaptive chunk sizing for NUMA") \
@@ -713,6 +712,7 @@
\
product(uintx, NUMAPageScanRate, 256, \
"Maximum number of pages to include in the page scan procedure") \
+ range(0, max_uintx) \
\
product_pd(bool, NeedsDeoptSuspend, \
"True for register window machines (sparc/ia64)") \
@@ -733,9 +733,11 @@
\
product(size_t, LargePageSizeInBytes, 0, \
"Large page size (0 to let VM choose the page size)") \
+ range(0, max_uintx) \
\
product(size_t, LargePageHeapSizeThreshold, 128*M, \
"Use large pages if maximum heap is at least this big") \
+ range(0, max_uintx) \
\
product(bool, ForceTimeHighResolution, false, \
"Using high time resolution (for Win32 only)") \
@@ -1421,6 +1423,13 @@
range(500, max_intx) \
constraint(BiasedLockingDecayTimeFunc,AfterErgo) \
\
+ product(bool, ExitOnOutOfMemoryError, false, \
+ "JVM exits on the first occurrence of an out-of-memory error") \
+ \
+ product(bool, CrashOnOutOfMemoryError, false, \
+ "JVM aborts, producing an error log and core/mini dump, on the " \
+ "first occurrence of an out-of-memory error") \
+ \
/* tracing */ \
\
develop(bool, StressRewriter, false, \
@@ -1526,9 +1535,11 @@
product(uintx, HeapMaximumCompactionInterval, 20, \
"How often should we maximally compact the heap (not allowing " \
"any dead space)") \
+ range(0, max_uintx) \
\
product(uintx, HeapFirstMaximumCompactionCount, 3, \
"The collection count for the first maximum compaction") \
+ range(0, max_uintx) \
\
product(bool, UseMaximumCompactionOnSystemGC, true, \
"Use maximum compaction in the Parallel Old garbage collector " \
@@ -1610,6 +1621,7 @@
diagnostic(uintx, GCLockerRetryAllocationCount, 2, \
"Number of times to retry allocations when " \
"blocked by the GC locker") \
+ range(0, max_uintx) \
\
product(bool, UseCMSBestFit, true, \
"Use CMS best fit allocation strategy") \
@@ -1664,6 +1676,7 @@
\
product(uintx, ParGCDesiredObjsFromOverflowList, 20, \
"The desired number of objects to claim from the overflow list") \
+ range(0, max_uintx) \
\
diagnostic(uintx, ParGCStridesPerThread, 2, \
"The number of strides per worker thread that we divide up the " \
@@ -1717,6 +1730,7 @@
product(uintx, CMSOldPLABReactivityFactor, 2, \
"The gain in the feedback loop for on-the-fly PLAB resizing " \
"during a scavenge") \
+ range(1, max_uintx) \
\
product(bool, AlwaysPreTouch, false, \
"Force all freshly committed pages to be pre-touched") \
@@ -1745,6 +1759,7 @@
product(uintx, CMS_FLSPadding, 1, \
"The multiple of deviation from mean to use for buffering " \
"against volatility in free list demand") \
+ range(0, max_juint) \
\
product(uintx, FLSCoalescePolicy, 2, \
"CMS: aggressiveness level for coalescing, increasing " \
@@ -1793,10 +1808,12 @@
product(uintx, CMS_SweepPadding, 1, \
"The multiple of deviation from mean to use for buffering " \
"against volatility in inter-sweep duration") \
+ range(0, max_juint) \
\
product(uintx, CMS_SweepTimerThresholdMillis, 10, \
"Skip block flux-rate sampling for an epoch unless inter-sweep " \
"duration exceeds this threshold in milliseconds") \
+ range(0, max_uintx) \
\
product(bool, CMSClassUnloadingEnabled, true, \
"Whether class unloading enabled when using CMS GC") \
@@ -1804,6 +1821,7 @@
product(uintx, CMSClassUnloadingMaxInterval, 0, \
"When CMS class unloading is enabled, the maximum CMS cycle " \
"count for which classes may not be unloaded") \
+ range(0, max_uintx) \
\
product(uintx, CMSIndexedFreeListReplenish, 4, \
"Replenish an indexed free list with this number of chunks") \
@@ -1837,6 +1855,7 @@
\
product(uintx, CMSMaxAbortablePrecleanLoops, 0, \
"Maximum number of abortable preclean iterations, if > 0") \
+ range(0, max_uintx) \
\
product(intx, CMSMaxAbortablePrecleanTime, 5000, \
"Maximum time in abortable preclean (in milliseconds)") \
@@ -1844,6 +1863,7 @@
\
product(uintx, CMSAbortablePrecleanMinWorkPerIteration, 100, \
"Nominal minimum work per abortable preclean iteration") \
+ range(0, max_uintx) \
\
manageable(intx, CMSAbortablePrecleanWaitMillis, 100, \
"Time that we sleep between iterations when not given " \
@@ -1931,6 +1951,7 @@
\
product(size_t, CMSScheduleRemarkEdenSizeThreshold, 2*M, \
"If Eden size is below this, do not try to schedule remark") \
+ range(0, max_uintx) \
\
product(uintx, CMSScheduleRemarkEdenPenetration, 50, \
"The Eden occupancy percentage (0-100) at which " \
@@ -1960,6 +1981,7 @@
\
manageable(intx, CMSWaitDuration, 2000, \
"Time in milliseconds that CMS thread waits for young GC") \
+ range(min_jint, max_jint) \
\
develop(uintx, CMSCheckInterval, 1000, \
"Interval in milliseconds that CMS thread checks if it " \
@@ -2161,6 +2183,7 @@
product(size_t, ErgoHeapSizeLimit, 0, \
"Maximum ergonomically set heap size (in bytes); zero means use " \
"MaxRAM / MaxRAMFraction") \
+ range(0, max_uintx) \
\
product(uintx, MaxRAMFraction, 4, \
"Maximum fraction (1/n) of real memory used for maximum heap " \
@@ -2185,6 +2208,7 @@
\
product(uintx, AutoGCSelectPauseMillis, 5000, \
"Automatic GC selection pause threshold in milliseconds") \
+ range(0, max_uintx) \
\
product(bool, UseAdaptiveSizePolicy, true, \
"Use adaptive generation sizing policies") \
@@ -2217,12 +2241,14 @@
\
product(uintx, AdaptiveSizePolicyInitializingSteps, 20, \
"Number of steps where heuristics is used before data is used") \
+ range(0, max_uintx) \
\
develop(uintx, AdaptiveSizePolicyReadyThreshold, 5, \
"Number of collections before the adaptive sizing is started") \
\
product(uintx, AdaptiveSizePolicyOutputInterval, 0, \
"Collection interval for printing information; zero means never") \
+ range(0, max_uintx) \
\
product(bool, UseAdaptiveSizePolicyFootprintGoal, true, \
"Use adaptive minimum footprint as a goal") \
@@ -2237,12 +2263,15 @@
\
product(uintx, PausePadding, 1, \
"How much buffer to keep for pause time") \
+ range(0, max_juint) \
\
product(uintx, PromotedPadding, 3, \
"How much buffer to keep for promotion failure") \
+ range(0, max_juint) \
\
product(uintx, SurvivorPadding, 3, \
"How much buffer to keep for survivor overflow") \
+ range(0, max_juint) \
\
product(uintx, ThresholdTolerance, 10, \
"Allowed collection cost difference between generations") \
@@ -2251,6 +2280,7 @@
product(uintx, AdaptiveSizePolicyCollectionCostMargin, 50, \
"If collection costs are within margin, reduce both by full " \
"delta") \
+ range(0, 100) \
\
product(uintx, YoungGenerationSizeIncrement, 20, \
"Adaptive size percentage change in young generation") \
@@ -2289,9 +2319,11 @@
product(uintx, MaxGCMinorPauseMillis, max_uintx, \
"Adaptive size policy maximum GC minor pause time goal " \
"in millisecond") \
+ range(0, max_uintx) \
\
product(uintx, GCTimeRatio, 99, \
"Adaptive size policy application time to GC time ratio") \
+ range(0, max_juint) \
\
product(uintx, AdaptiveSizeDecrementScaleFactor, 4, \
"Adaptive size scale down factor for shrinking") \
@@ -2302,6 +2334,7 @@
\
product(uintx, AdaptiveSizeMajorGCDecayTimeScale, 10, \
"Time scale over which major costs decay") \
+ range(0, max_uintx) \
\
product(uintx, MinSurvivorRatio, 3, \
"Minimum ratio of young generation/survivor space size") \
@@ -2309,9 +2342,11 @@
\
product(uintx, InitialSurvivorRatio, 8, \
"Initial ratio of young generation/survivor space size") \
+ range(0, max_uintx) \
\
product(size_t, BaseFootPrintEstimate, 256*M, \
"Estimate of footprint other than Java Heap") \
+ range(0, max_uintx) \
\
product(bool, UseGCOverheadLimit, true, \
"Use policy to limit of proportion of time spent in GC " \
@@ -2336,12 +2371,15 @@
\
product(intx, PrefetchCopyIntervalInBytes, -1, \
"How far ahead to prefetch destination area (<= 0 means off)") \
+ range(-1, max_jint) \
\
product(intx, PrefetchScanIntervalInBytes, -1, \
"How far ahead to prefetch scan area (<= 0 means off)") \
+ range(-1, max_jint) \
\
product(intx, PrefetchFieldsAhead, -1, \
"How many fields ahead to prefetch in oop scan (<= 0 means off)") \
+ range(-1, max_jint) \
\
diagnostic(bool, VerifySilently, false, \
"Do not print the verification progress") \
@@ -2389,6 +2427,7 @@
\
diagnostic(uintx, CPUForCMSThread, 0, \
"When BindCMSThreadToCPU is true, the CPU to bind CMS thread to") \
+ range(0, max_juint) \
\
product(bool, BindGCTaskThreadsToCPUs, false, \
"Bind GCTaskThreads to CPUs if possible") \
@@ -2398,14 +2437,17 @@
\
product(uintx, ProcessDistributionStride, 4, \
"Stride through processors when distributing processes") \
+ range(0, max_juint) \
\
product(uintx, CMSCoordinatorYieldSleepCount, 10, \
"Number of times the coordinator GC thread will sleep while " \
"yielding before giving up and resuming GC") \
+ range(0, max_juint) \
\
product(uintx, CMSYieldSleepCount, 0, \
"Number of times a GC thread (minus the coordinator) " \
"will sleep while yielding before giving up and resuming GC") \
+ range(0, max_juint) \
\
/* gc tracing */ \
manageable(bool, PrintGC, false, \
@@ -2554,10 +2596,12 @@
product(uintx, NumberOfGCLogFiles, 0, \
"Number of gclog files in rotation " \
"(default: 0, no rotation)") \
+ range(0, max_uintx) \
\
product(size_t, GCLogFileSize, 8*K, \
"GC log file size, requires UseGCLogFileRotation. " \
"Set to 0 to only trigger rotation via jcmd") \
+ range(0, max_uintx) \
\
/* JVMTI heap profiling */ \
\
@@ -3325,6 +3369,7 @@
\
product(size_t, OldSize, ScaleForWordSize(4*M), \
"Initial tenured generation size (in bytes)") \
+ range(0, max_uintx) \
\
product(size_t, NewSize, ScaleForWordSize(1*M), \
"Initial new generation size (in bytes)") \
@@ -3333,10 +3378,16 @@
product(size_t, MaxNewSize, max_uintx, \
"Maximum new generation size (in bytes), max_uintx means set " \
"ergonomically") \
+ range(0, max_uintx) \
+ \
+ product_pd(size_t, HeapBaseMinAddress, \
+ "OS specific low limit for heap base address") \
+ constraint(HeapBaseMinAddressConstraintFunc,AfterErgo) \
\
product(size_t, PretenureSizeThreshold, 0, \
"Maximum size in bytes of objects allocated in DefNew " \
"generation; zero means no maximum") \
+ range(0, max_uintx) \
\
product(size_t, MinTLABSize, 2*K, \
"Minimum allowed TLAB size (in bytes)") \
@@ -3368,10 +3419,12 @@
\
product(uintx, TLABRefillWasteFraction, 64, \
"Maximum TLAB waste at a refill (internal fragmentation)") \
- range(1, max_uintx) \
+ range(1, max_juint) \
\
product(uintx, TLABWasteIncrement, 4, \
"Increment allowed waste at slow allocation") \
+ range(0, max_jint) \
+ constraint(TLABWasteIncrementConstraintFunc,AfterMemoryInit) \
\
product(uintx, SurvivorRatio, 8, \
"Ratio of eden/survivor space size") \
@@ -3385,6 +3438,7 @@
product_pd(size_t, NewSizeThreadIncrease, \
"Additional size added to desired new generation size per " \
"non-daemon thread (in bytes)") \
+ range(0, max_uintx) \
\
product_pd(size_t, MetaspaceSize, \
"Initial size of Metaspaces (in bytes)") \
@@ -3420,9 +3474,11 @@
\
product(size_t, MinHeapDeltaBytes, ScaleForWordSize(128*K), \
"The minimum change in heap space due to GC (in bytes)") \
+ range(0, max_uintx) \
\
product(size_t, MinMetaspaceExpansion, ScaleForWordSize(256*K), \
"The minimum expansion of Metaspace (in bytes)") \
+ range(0, max_uintx) \
\
product(uintx, MaxMetaspaceFreeRatio, 70, \
"The maximum percentage of Metaspace free after GC to avoid " \
@@ -3438,13 +3494,16 @@
\
product(size_t, MaxMetaspaceExpansion, ScaleForWordSize(4*M), \
"The maximum expansion of Metaspace without full GC (in bytes)") \
+ range(0, max_uintx) \
\
product(uintx, QueuedAllocationWarningCount, 0, \
"Number of times an allocation that queues behind a GC " \
"will retry before printing a warning") \
+ range(0, max_uintx) \
\
diagnostic(uintx, VerifyGCStartAt, 0, \
"GC invoke count where +VerifyBefore/AfterGC kicks in") \
+ range(0, max_uintx) \
\
diagnostic(intx, VerifyGCLevel, 0, \
"Generation level at which to start +VerifyBefore/AfterGC") \
@@ -3482,15 +3541,18 @@
\
product(intx, PrintCMSStatistics, 0, \
"Statistics for CMS") \
+ range(0, 2) \
\
product(bool, PrintCMSInitiationStatistics, false, \
"Statistics for initiating a CMS collection") \
\
product(intx, PrintFLSStatistics, 0, \
"Statistics for CMS' FreeListSpace") \
+ range(0, 2) \
\
product(intx, PrintFLSCensus, 0, \
"Census for CMS' FreeListSpace") \
+ range(0, 1) \
\
develop(uintx, GCExpandToAllocateDelayMillis, 0, \
"Delay between expansion and allocation (in milliseconds)") \
@@ -3517,6 +3579,7 @@
product(uintx, GCDrainStackTargetSize, 64, \
"Number of entries we will try to leave on the stack " \
"during parallel gc") \
+ range(0, max_juint) \
\
/* stack parameters */ \
product_pd(intx, StackYellowPages, \
--- a/hotspot/src/share/vm/runtime/init.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/runtime/init.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
#include "code/codeCacheExtensions.hpp"
#include "code/icBuffer.hpp"
#include "gc/shared/collectedHeap.hpp"
--- a/hotspot/src/share/vm/runtime/os.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/runtime/os.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -315,6 +315,10 @@
// We need to initialize large page support here because ergonomics takes some
// decisions depending on large page support and the calculated large page size.
large_page_init();
+
+ // VM version initialization identifies some characteristics of the
+ // the platform that are used during ergonomic decisions.
+ VM_Version::init_before_ergo();
}
void os::signal_init() {
--- a/hotspot/src/share/vm/runtime/reflection.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/runtime/reflection.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -46,7 +46,7 @@
#include "runtime/signature.hpp"
#include "runtime/vframe.hpp"
-static void trace_class_resolution(Klass* to_class) {
+static void trace_class_resolution(const Klass* to_class) {
ResourceMark rm;
int line_number = -1;
const char * source_file = NULL;
@@ -300,23 +300,23 @@
}
}
-
-Klass* Reflection::basic_type_mirror_to_arrayklass(oop basic_type_mirror, TRAPS) {
+static Klass* basic_type_mirror_to_arrayklass(oop basic_type_mirror, TRAPS) {
assert(java_lang_Class::is_primitive(basic_type_mirror), "just checking");
BasicType type = java_lang_Class::primitive_type(basic_type_mirror);
if (type == T_VOID) {
THROW_0(vmSymbols::java_lang_IllegalArgumentException());
- } else {
+ }
+ else {
return Universe::typeArrayKlassObj(type);
}
}
-
-oop Reflection:: basic_type_arrayklass_to_mirror(Klass* basic_type_arrayklass, TRAPS) {
+#ifdef ASSERT
+static oop basic_type_arrayklass_to_mirror(Klass* basic_type_arrayklass, TRAPS) {
BasicType type = TypeArrayKlass::cast(basic_type_arrayklass)->element_type();
return Universe::java_mirror(type);
}
-
+#endif
arrayOop Reflection::reflect_new_array(oop element_mirror, jint length, TRAPS) {
if (element_mirror == NULL) {
@@ -410,8 +410,51 @@
return result;
}
+static bool under_host_klass(const InstanceKlass* ik, const Klass* host_klass) {
+ DEBUG_ONLY(int inf_loop_check = 1000 * 1000 * 1000);
+ for (;;) {
+ const Klass* hc = (const Klass*)ik->host_klass();
+ if (hc == NULL) return false;
+ if (hc == host_klass) return true;
+ ik = InstanceKlass::cast(hc);
-bool Reflection::verify_class_access(Klass* current_class, Klass* new_class, bool classloader_only) {
+ // There's no way to make a host class loop short of patching memory.
+ // Therefore there cannot be a loop here unless there's another bug.
+ // Still, let's check for it.
+ assert(--inf_loop_check > 0, "no host_klass loop");
+ }
+}
+
+static bool can_relax_access_check_for(const Klass* accessor,
+ const Klass* accessee,
+ bool classloader_only) {
+
+ const InstanceKlass* accessor_ik = InstanceKlass::cast(accessor);
+ const InstanceKlass* accessee_ik = InstanceKlass::cast(accessee);
+
+ // If either is on the other's host_klass chain, access is OK,
+ // because one is inside the other.
+ if (under_host_klass(accessor_ik, accessee) ||
+ under_host_klass(accessee_ik, accessor))
+ return true;
+
+ if ((RelaxAccessControlCheck &&
+ accessor_ik->major_version() < Verifier::NO_RELAX_ACCESS_CTRL_CHECK_VERSION &&
+ accessee_ik->major_version() < Verifier::NO_RELAX_ACCESS_CTRL_CHECK_VERSION) ||
+ (accessor_ik->major_version() < Verifier::STRICTER_ACCESS_CTRL_CHECK_VERSION &&
+ accessee_ik->major_version() < Verifier::STRICTER_ACCESS_CTRL_CHECK_VERSION)) {
+ return classloader_only &&
+ Verifier::relax_verify_for(accessor_ik->class_loader()) &&
+ accessor_ik->protection_domain() == accessee_ik->protection_domain() &&
+ accessor_ik->class_loader() == accessee_ik->class_loader();
+ }
+
+ return false;
+}
+
+bool Reflection::verify_class_access(const Klass* current_class,
+ const Klass* new_class,
+ bool classloader_only) {
// Verify that current_class can access new_class. If the classloader_only
// flag is set, we automatically allow any accesses in which current_class
// doesn't have a classloader.
@@ -430,49 +473,9 @@
return can_relax_access_check_for(current_class, new_class, classloader_only);
}
-static bool under_host_klass(InstanceKlass* ik, Klass* host_klass) {
- DEBUG_ONLY(int inf_loop_check = 1000 * 1000 * 1000);
- for (;;) {
- Klass* hc = (Klass*) ik->host_klass();
- if (hc == NULL) return false;
- if (hc == host_klass) return true;
- ik = InstanceKlass::cast(hc);
-
- // There's no way to make a host class loop short of patching memory.
- // Therefore there cannot be a loop here unless there's another bug.
- // Still, let's check for it.
- assert(--inf_loop_check > 0, "no host_klass loop");
- }
-}
-
-bool Reflection::can_relax_access_check_for(
- Klass* accessor, Klass* accessee, bool classloader_only) {
- InstanceKlass* accessor_ik = InstanceKlass::cast(accessor);
- InstanceKlass* accessee_ik = InstanceKlass::cast(accessee);
-
- // If either is on the other's host_klass chain, access is OK,
- // because one is inside the other.
- if (under_host_klass(accessor_ik, accessee) ||
- under_host_klass(accessee_ik, accessor))
- return true;
-
- if ((RelaxAccessControlCheck &&
- accessor_ik->major_version() < Verifier::NO_RELAX_ACCESS_CTRL_CHECK_VERSION &&
- accessee_ik->major_version() < Verifier::NO_RELAX_ACCESS_CTRL_CHECK_VERSION) ||
- (accessor_ik->major_version() < Verifier::STRICTER_ACCESS_CTRL_CHECK_VERSION &&
- accessee_ik->major_version() < Verifier::STRICTER_ACCESS_CTRL_CHECK_VERSION)) {
- return classloader_only &&
- Verifier::relax_verify_for(accessor_ik->class_loader()) &&
- accessor_ik->protection_domain() == accessee_ik->protection_domain() &&
- accessor_ik->class_loader() == accessee_ik->class_loader();
- } else {
- return false;
- }
-}
-
-bool Reflection::verify_field_access(Klass* current_class,
- Klass* resolved_class,
- Klass* field_class,
+bool Reflection::verify_field_access(const Klass* current_class,
+ const Klass* resolved_class,
+ const Klass* field_class,
AccessFlags access,
bool classloader_only,
bool protected_restriction) {
@@ -494,10 +497,10 @@
return true;
}
- Klass* host_class = current_class;
+ const Klass* host_class = current_class;
while (host_class->is_instance_klass() &&
InstanceKlass::cast(host_class)->is_anonymous()) {
- Klass* next_host_class = InstanceKlass::cast(host_class)->host_klass();
+ const Klass* next_host_class = InstanceKlass::cast(host_class)->host_klass();
if (next_host_class == NULL) break;
host_class = next_host_class;
}
@@ -535,16 +538,10 @@
current_class, field_class, classloader_only);
}
-
-bool Reflection::is_same_class_package(Klass* class1, Klass* class2) {
+bool Reflection::is_same_class_package(const Klass* class1, const Klass* class2) {
return InstanceKlass::cast(class1)->is_same_class_package(class2);
}
-bool Reflection::is_same_package_member(Klass* class1, Klass* class2, TRAPS) {
- return InstanceKlass::cast(class1)->is_same_package_member(class2, THREAD);
-}
-
-
// Checks that the 'outer' klass has declared 'inner' as being an inner klass. If not,
// throw an incompatible class change exception
// If inner_is_member, require the inner to be a member of the outer.
@@ -588,38 +585,43 @@
}
// Utility method converting a single SignatureStream element into java.lang.Class instance
+static oop get_mirror_from_signature(methodHandle method,
+ SignatureStream* ss,
+ TRAPS) {
-oop get_mirror_from_signature(methodHandle method, SignatureStream* ss, TRAPS) {
- switch (ss->type()) {
- default:
- assert(ss->type() != T_VOID || ss->at_return_type(), "T_VOID should only appear as return type");
- return java_lang_Class::primitive_mirror(ss->type());
- case T_OBJECT:
- case T_ARRAY:
- Symbol* name = ss->as_symbol(CHECK_NULL);
- oop loader = method->method_holder()->class_loader();
- oop protection_domain = method->method_holder()->protection_domain();
- Klass* k = SystemDictionary::resolve_or_fail(
- name,
- Handle(THREAD, loader),
- Handle(THREAD, protection_domain),
- true, CHECK_NULL);
- if (TraceClassResolution) {
- trace_class_resolution(k);
- }
- return k->java_mirror();
- };
+
+ if (T_OBJECT == ss->type() || T_ARRAY == ss->type()) {
+ Symbol* name = ss->as_symbol(CHECK_NULL);
+ oop loader = method->method_holder()->class_loader();
+ oop protection_domain = method->method_holder()->protection_domain();
+ const Klass* k = SystemDictionary::resolve_or_fail(name,
+ Handle(THREAD, loader),
+ Handle(THREAD, protection_domain),
+ true,
+ CHECK_NULL);
+ if (TraceClassResolution) {
+ trace_class_resolution(k);
+ }
+ return k->java_mirror();
+ }
+
+ assert(ss->type() != T_VOID || ss->at_return_type(),
+ "T_VOID should only appear as return type");
+
+ return java_lang_Class::primitive_mirror(ss->type());
}
-
-objArrayHandle Reflection::get_parameter_types(const methodHandle& method, int parameter_count, oop* return_type, TRAPS) {
+static objArrayHandle get_parameter_types(methodHandle method,
+ int parameter_count,
+ oop* return_type,
+ TRAPS) {
// Allocate array holding parameter types (java.lang.Class instances)
objArrayOop m = oopFactory::new_objArray(SystemDictionary::Class_klass(), parameter_count, CHECK_(objArrayHandle()));
- objArrayHandle mirrors (THREAD, m);
+ objArrayHandle mirrors(THREAD, m);
int index = 0;
// Collect parameter types
ResourceMark rm(THREAD);
- Symbol* signature = method->signature();
+ Symbol* signature = method->signature();
SignatureStream ss(signature);
while (!ss.at_return_type()) {
oop mirror = get_mirror_from_signature(method, &ss, CHECK_(objArrayHandle()));
@@ -635,22 +637,22 @@
return mirrors;
}
-objArrayHandle Reflection::get_exception_types(const methodHandle& method, TRAPS) {
+static objArrayHandle get_exception_types(methodHandle method, TRAPS) {
return method->resolved_checked_exceptions(THREAD);
}
-
-Handle Reflection::new_type(Symbol* signature, KlassHandle k, TRAPS) {
+static Handle new_type(Symbol* signature, KlassHandle k, TRAPS) {
// Basic types
BasicType type = vmSymbols::signature_type(signature);
if (type != T_OBJECT) {
return Handle(THREAD, Universe::java_mirror(type));
}
- Klass* result = SystemDictionary::resolve_or_fail(signature,
- Handle(THREAD, k->class_loader()),
- Handle(THREAD, k->protection_domain()),
- true, CHECK_(Handle()));
+ Klass* result =
+ SystemDictionary::resolve_or_fail(signature,
+ Handle(THREAD, k->class_loader()),
+ Handle(THREAD, k->protection_domain()),
+ true, CHECK_(Handle()));
if (TraceClassResolution) {
trace_class_resolution(result);
@@ -686,7 +688,7 @@
Handle name = Handle(THREAD, name_oop);
if (name == NULL) return NULL;
- int modifiers = method->access_flags().as_int() & JVM_RECOGNIZED_METHOD_MODIFIERS;
+ const int modifiers = method->access_flags().as_int() & JVM_RECOGNIZED_METHOD_MODIFIERS;
Handle mh = java_lang_reflect_Method::create(CHECK_NULL);
@@ -738,7 +740,7 @@
objArrayHandle exception_types = get_exception_types(method, CHECK_NULL);
if (exception_types.is_null()) return NULL;
- int modifiers = method->access_flags().as_int() & JVM_RECOGNIZED_METHOD_MODIFIERS;
+ const int modifiers = method->access_flags().as_int() & JVM_RECOGNIZED_METHOD_MODIFIERS;
Handle ch = java_lang_reflect_Constructor::create(CHECK_NULL);
@@ -822,8 +824,12 @@
}
-methodHandle Reflection::resolve_interface_call(instanceKlassHandle klass, const methodHandle& method,
- KlassHandle recv_klass, Handle receiver, TRAPS) {
+static methodHandle resolve_interface_call(instanceKlassHandle klass,
+ const methodHandle& method,
+ KlassHandle recv_klass,
+ Handle receiver,
+ TRAPS) {
+
assert(!method.is_null() , "method should not be null");
CallInfo info;
@@ -836,10 +842,48 @@
return info.selected_method();
}
+// Conversion
+static BasicType basic_type_mirror_to_basic_type(oop basic_type_mirror, TRAPS) {
+ assert(java_lang_Class::is_primitive(basic_type_mirror),
+ "just checking");
+ return java_lang_Class::primitive_type(basic_type_mirror);
+}
-oop Reflection::invoke(instanceKlassHandle klass, const methodHandle& reflected_method,
- Handle receiver, bool override, objArrayHandle ptypes,
- BasicType rtype, objArrayHandle args, bool is_method_invoke, TRAPS) {
+// Narrowing of basic types. Used to create correct jvalues for
+// boolean, byte, char and short return return values from interpreter
+// which are returned as ints. Throws IllegalArgumentException.
+static void narrow(jvalue* value, BasicType narrow_type, TRAPS) {
+ switch (narrow_type) {
+ case T_BOOLEAN:
+ value->z = (jboolean)value->i;
+ return;
+ case T_BYTE:
+ value->b = (jbyte)value->i;
+ return;
+ case T_CHAR:
+ value->c = (jchar)value->i;
+ return;
+ case T_SHORT:
+ value->s = (jshort)value->i;
+ return;
+ default:
+ break; // fail
+ }
+ THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch");
+}
+
+
+// Method call (shared by invoke_method and invoke_constructor)
+static oop invoke(instanceKlassHandle klass,
+ methodHandle reflected_method,
+ Handle receiver,
+ bool override,
+ objArrayHandle ptypes,
+ BasicType rtype,
+ objArrayHandle args,
+ bool is_method_invoke,
+ TRAPS) {
+
ResourceMark rm(THREAD);
methodHandle method; // actual method to invoke
@@ -876,18 +920,18 @@
// Linktime resolution & IllegalAccessCheck already done by Class.getMethod()
method = resolve_interface_call(klass, reflected_method, target_klass, receiver, THREAD);
if (HAS_PENDING_EXCEPTION) {
- // Method resolution threw an exception; wrap it in an InvocationTargetException
+ // Method resolution threw an exception; wrap it in an InvocationTargetException
oop resolution_exception = PENDING_EXCEPTION;
CLEAR_PENDING_EXCEPTION;
// JVMTI has already reported the pending exception
// JVMTI internal flag reset is needed in order to report InvocationTargetException
if (THREAD->is_Java_thread()) {
- JvmtiExport::clear_detected_exception((JavaThread*) THREAD);
+ JvmtiExport::clear_detected_exception((JavaThread*)THREAD);
}
JavaCallArguments args(Handle(THREAD, resolution_exception));
THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
- vmSymbols::throwable_void_signature(),
- &args);
+ vmSymbols::throwable_void_signature(),
+ &args);
}
} else {
// if the method can be overridden, we resolve using the vtable index.
@@ -906,10 +950,10 @@
// new default: 6531596
ResourceMark rm(THREAD);
Handle h_origexception = Exceptions::new_exception(THREAD,
- vmSymbols::java_lang_AbstractMethodError(),
- Method::name_and_sig_as_C_string(target_klass(),
- method->name(),
- method->signature()));
+ vmSymbols::java_lang_AbstractMethodError(),
+ Method::name_and_sig_as_C_string(target_klass(),
+ method->name(),
+ method->signature()));
JavaCallArguments args(h_origexception);
THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(),
vmSymbols::throwable_void_signature(),
@@ -926,15 +970,16 @@
ResourceMark rm(THREAD);
THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(),
Method::name_and_sig_as_C_string(klass(),
- reflected_method->name(),
- reflected_method->signature()));
+ reflected_method->name(),
+ reflected_method->signature()));
}
assert(ptypes->is_objArray(), "just checking");
int args_len = args.is_null() ? 0 : args->length();
// Check number of arguments
if (ptypes->length() != args_len) {
- THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "wrong number of arguments");
+ THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
+ "wrong number of arguments");
}
// Create object to contain parameters for the JavaCall
@@ -950,9 +995,9 @@
if (java_lang_Class::is_primitive(type_mirror)) {
jvalue value;
BasicType ptype = basic_type_mirror_to_basic_type(type_mirror, CHECK_NULL);
- BasicType atype = unbox_for_primitive(arg, &value, CHECK_NULL);
+ BasicType atype = Reflection::unbox_for_primitive(arg, &value, CHECK_NULL);
if (ptype != atype) {
- widen(&value, atype, ptype, CHECK_NULL);
+ Reflection::widen(&value, atype, ptype, CHECK_NULL);
}
switch (ptype) {
case T_BOOLEAN: java_args.push_int(value.z); break;
@@ -970,7 +1015,8 @@
if (arg != NULL) {
Klass* k = java_lang_Class::as_Klass(type_mirror);
if (!arg->is_a(k)) {
- THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch");
+ THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
+ "argument type mismatch");
}
}
Handle arg_handle(THREAD, arg); // Create handle for argument
@@ -978,7 +1024,8 @@
}
}
- assert(java_args.size_of_parameters() == method->size_of_parameters(), "just checking");
+ assert(java_args.size_of_parameters() == method->size_of_parameters(),
+ "just checking");
// All oops (including receiver) is passed in as Handles. An potential oop is returned as an
// oop (i.e., NOT as an handle)
@@ -992,7 +1039,7 @@
// JVMTI has already reported the pending exception
// JVMTI internal flag reset is needed in order to report InvocationTargetException
if (THREAD->is_Java_thread()) {
- JvmtiExport::clear_detected_exception((JavaThread*) THREAD);
+ JvmtiExport::clear_detected_exception((JavaThread*)THREAD);
}
JavaCallArguments args(Handle(THREAD, target_exception));
@@ -1001,39 +1048,12 @@
&args);
} else {
if (rtype == T_BOOLEAN || rtype == T_BYTE || rtype == T_CHAR || rtype == T_SHORT) {
- narrow((jvalue*) result.get_value_addr(), rtype, CHECK_NULL);
+ narrow((jvalue*)result.get_value_addr(), rtype, CHECK_NULL);
}
- return box((jvalue*) result.get_value_addr(), rtype, THREAD);
+ return Reflection::box((jvalue*)result.get_value_addr(), rtype, THREAD);
}
}
-
-void Reflection::narrow(jvalue* value, BasicType narrow_type, TRAPS) {
- switch (narrow_type) {
- case T_BOOLEAN:
- value->z = (jboolean) value->i;
- return;
- case T_BYTE:
- value->b = (jbyte) value->i;
- return;
- case T_CHAR:
- value->c = (jchar) value->i;
- return;
- case T_SHORT:
- value->s = (jshort) value->i;
- return;
- default:
- break; // fail
- }
- THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "argument type mismatch");
-}
-
-
-BasicType Reflection::basic_type_mirror_to_basic_type(oop basic_type_mirror, TRAPS) {
- assert(java_lang_Class::is_primitive(basic_type_mirror), "just checking");
- return java_lang_Class::primitive_type(basic_type_mirror);
-}
-
// This would be nicer if, say, java.lang.reflect.Method was a subclass
// of java.lang.reflect.Constructor
--- a/hotspot/src/share/vm/runtime/reflection.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/runtime/reflection.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -43,16 +43,6 @@
class FieldStream;
class Reflection: public AllStatic {
- private:
- // Conversion
- static Klass* basic_type_mirror_to_arrayklass(oop basic_type_mirror, TRAPS);
- static oop basic_type_arrayklass_to_mirror(Klass* basic_type_arrayklass, TRAPS);
-
- static objArrayHandle get_parameter_types(const methodHandle& method, int parameter_count, oop* return_type, TRAPS);
- static objArrayHandle get_exception_types(const methodHandle& method, TRAPS);
- // Creating new java.lang.reflect.xxx wrappers
- static Handle new_type(Symbol* signature, KlassHandle k, TRAPS);
-
public:
// Constants defined by java reflection api classes
enum SomeConstants {
@@ -83,27 +73,27 @@
static arrayOop reflect_new_multi_array(oop element_mirror, typeArrayOop dimensions, TRAPS);
// Verification
- static bool verify_class_access(Klass* current_class, Klass* new_class, bool classloader_only);
+ static bool verify_class_access(const Klass* current_class,
+ const Klass* new_class,
+ bool classloader_only);
- static bool verify_field_access(Klass* current_class,
- Klass* resolved_class,
- Klass* field_class,
+ static bool verify_field_access(const Klass* current_class,
+ const Klass* resolved_class,
+ const Klass* field_class,
AccessFlags access,
bool classloader_only,
bool protected_restriction = false);
- static bool is_same_class_package(Klass* class1, Klass* class2);
- static bool is_same_package_member(Klass* class1, Klass* class2, TRAPS);
-
- static bool can_relax_access_check_for(
- Klass* accessor, Klass* accesee, bool classloader_only);
+ static bool is_same_class_package(const Klass* class1, const Klass* class2);
// inner class reflection
// raise an ICCE unless the required relationship can be proven to hold
// If inner_is_member, require the inner to be a member of the outer.
// If !inner_is_member, require the inner to be anonymous (a non-member).
// Caller is responsible for figuring out in advance which case must be true.
- static void check_for_inner_class(instanceKlassHandle outer, instanceKlassHandle inner,
- bool inner_is_member, TRAPS);
+ static void check_for_inner_class(instanceKlassHandle outer,
+ instanceKlassHandle inner,
+ bool inner_is_member,
+ TRAPS);
//
// Support for reflection based on dynamic bytecode generation (JDK 1.4)
@@ -119,31 +109,11 @@
// MethodParameterElement
static oop new_parameter(Handle method, int index, Symbol* sym,
int flags, TRAPS);
-
-private:
- // method resolution for invoke
- static methodHandle resolve_interface_call(instanceKlassHandle klass, const methodHandle& method, KlassHandle recv_klass, Handle receiver, TRAPS);
- // Method call (shared by invoke_method and invoke_constructor)
- static oop invoke(instanceKlassHandle klass,
- const methodHandle& method,
- Handle receiver,
- bool override,
- objArrayHandle ptypes,
- BasicType rtype,
- objArrayHandle args,
- bool is_method_invoke, TRAPS);
-
- // Narrowing of basic types. Used to create correct jvalues for
- // boolean, byte, char and short return return values from interpreter
- // which are returned as ints. Throws IllegalArgumentException.
- static void narrow(jvalue* value, BasicType narrow_type, TRAPS);
-
- // Conversion
- static BasicType basic_type_mirror_to_basic_type(oop basic_type_mirror, TRAPS);
-
-public:
// Method invocation through java.lang.reflect.Method
- static oop invoke_method(oop method_mirror, Handle receiver, objArrayHandle args, TRAPS);
+ static oop invoke_method(oop method_mirror,
+ Handle receiver,
+ objArrayHandle args,
+ TRAPS);
// Method invocation through java.lang.reflect.Constructor
static oop invoke_constructor(oop method_mirror, objArrayHandle args, TRAPS);
--- a/hotspot/src/share/vm/runtime/safepoint.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/runtime/safepoint.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/stringTable.hpp"
+#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "code/icBuffer.hpp"
--- a/hotspot/src/share/vm/runtime/thread.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/runtime/thread.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -272,7 +272,7 @@
jlong _allocated_bytes; // Cumulative number of bytes allocated on
// the Java heap
- TRACE_DATA _trace_data; // Thread-local data for tracing
+ mutable TRACE_DATA _trace_data; // Thread-local data for tracing
ThreadExt _ext;
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -320,7 +320,7 @@
nonstatic_field(InstanceKlass, _constants, ConstantPool*) \
nonstatic_field(InstanceKlass, _class_loader_data, ClassLoaderData*) \
nonstatic_field(InstanceKlass, _source_file_name_index, u2) \
- nonstatic_field(InstanceKlass, _source_debug_extension, char*) \
+ nonstatic_field(InstanceKlass, _source_debug_extension, const char*) \
nonstatic_field(InstanceKlass, _inner_classes, Array<jushort>*) \
nonstatic_field(InstanceKlass, _nonstatic_field_size, int) \
nonstatic_field(InstanceKlass, _static_field_size, int) \
--- a/hotspot/src/share/vm/runtime/vm_version.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/runtime/vm_version.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -56,6 +56,12 @@
unsigned int dem,
unsigned int switch_pt);
public:
+ // Called as part of the runtime services initialization which is
+ // called from the management module initialization (via init_globals())
+ // after argument parsing and attaching of the main thread has
+ // occurred. Examines a variety of the hardware capabilities of
+ // the platform to determine which features can be used to execute the
+ // program.
static void initialize();
// This allows for early initialization of VM_Version information
@@ -65,6 +71,11 @@
// need to specialize this define VM_Version::early_initialize().
static void early_initialize() { }
+ // Called to initialize VM variables needing initialization
+ // after command line parsing. Platforms that need to specialize
+ // this should define VM_Version::init_before_ergo().
+ static void init_before_ergo() {}
+
// Name
static const char* vm_name();
// Vendor
--- a/hotspot/src/share/vm/utilities/accessFlags.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/utilities/accessFlags.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -100,6 +100,9 @@
jint _flags;
public:
+ AccessFlags() : _flags(0) {}
+ explicit AccessFlags(jint flags) : _flags(flags) {}
+
// Java access flags
bool is_public () const { return (_flags & JVM_ACC_PUBLIC ) != 0; }
bool is_private () const { return (_flags & JVM_ACC_PRIVATE ) != 0; }
--- a/hotspot/src/share/vm/utilities/debug.cpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/utilities/debug.cpp Thu Dec 10 18:55:58 2015 +0000
@@ -305,6 +305,16 @@
if (OnOutOfMemoryError && OnOutOfMemoryError[0]) {
VMError::report_java_out_of_memory(message);
}
+
+ if (CrashOnOutOfMemoryError) {
+ tty->print_cr("Aborting due to java.lang.OutOfMemoryError: %s", message);
+ fatal("OutOfMemory encountered: %s", message);
+ }
+
+ if (ExitOnOutOfMemoryError) {
+ tty->print_cr("Terminating due to java.lang.OutOfMemoryError: %s", message);
+ os::exit(3);
+ }
}
}
--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -949,7 +949,6 @@
// (in order to reduce interface dependencies & reduce
// number of unnecessary compilations after changes)
-class symbolTable;
class ClassFileStream;
class Event;
--- a/hotspot/src/share/vm/utilities/hashtable.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/utilities/hashtable.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -151,7 +151,7 @@
void copy_table(char** top, char* end);
// Bucket handling
- int hash_to_index(unsigned int full_hash) {
+ int hash_to_index(unsigned int full_hash) const {
int h = full_hash % _table_size;
assert(h >= 0 && h < _table_size, "Illegal hash value");
return h;
@@ -173,8 +173,8 @@
protected:
#ifdef ASSERT
- int _lookup_count;
- int _lookup_length;
+ mutable int _lookup_count;
+ mutable int _lookup_length;
void verify_lookup_length(double load);
#endif
@@ -184,7 +184,7 @@
int entry_size() const { return _entry_size; }
// The following method is MT-safe and may be used with caution.
- BasicHashtableEntry<F>* bucket(int i);
+ BasicHashtableEntry<F>* bucket(int i) const;
// The following method is not MT-safe and must be done under lock.
BasicHashtableEntry<F>** bucket_addr(int i) { return _buckets[i].entry_addr(); }
@@ -263,7 +263,7 @@
HashtableEntry<T, F>* new_entry(unsigned int hashValue, T obj);
// The following method is MT-safe and may be used with caution.
- HashtableEntry<T, F>* bucket(int i) {
+ HashtableEntry<T, F>* bucket(int i) const {
return (HashtableEntry<T, F>*)BasicHashtable<F>::bucket(i);
}
@@ -329,7 +329,7 @@
: Hashtable<T, F>(table_size, entry_size, t, number_of_entries) {}
public:
- unsigned int compute_hash(Symbol* name, ClassLoaderData* loader_data) {
+ unsigned int compute_hash(const Symbol* name, const ClassLoaderData* loader_data) const {
unsigned int name_hash = name->identity_hash();
// loader is null with CDS
assert(loader_data != NULL || UseSharedSpaces || DumpSharedSpaces,
--- a/hotspot/src/share/vm/utilities/hashtable.inline.hpp Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/src/share/vm/utilities/hashtable.inline.hpp Thu Dec 10 18:55:58 2015 +0000
@@ -72,7 +72,7 @@
// The following method is MT-safe and may be used with caution.
-template <MEMFLAGS F> inline BasicHashtableEntry<F>* BasicHashtable<F>::bucket(int i) {
+template <MEMFLAGS F> inline BasicHashtableEntry<F>* BasicHashtable<F>::bucket(int i) const {
return _buckets[i].get_entry();
}
--- a/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java Thu Dec 10 18:55:58 2015 +0000
@@ -29,7 +29,7 @@
* java.management
* jdk.attach
* jdk.management/sun.tools.attach
- * @run main/othervm/timeout=780 TestOptionsWithRanges
+ * @run main/othervm/timeout=900 TestOptionsWithRanges
*/
import java.util.ArrayList;
@@ -116,11 +116,26 @@
* Exclude below options as their maximum value would consume too much memory
* and would affect other tests that run in parallel.
*/
+ excludeTestMaxRange("ConcGCThreads");
excludeTestMaxRange("G1ConcRefinementThreads");
excludeTestMaxRange("G1RSetRegionEntries");
excludeTestMaxRange("G1RSetSparseRegionEntries");
excludeTestMaxRange("G1UpdateBufferSize");
excludeTestMaxRange("InitialBootClassLoaderMetaspaceSize");
+ excludeTestMaxRange("InitialHeapSize");
+ excludeTestMaxRange("MaxHeapSize");
+ excludeTestMaxRange("MaxRAM");
+ excludeTestMaxRange("NewSize");
+ excludeTestMaxRange("OldSize");
+ excludeTestMaxRange("ParallelGCThreads");
+
+ excludeTestMaxRange("VMThreadStackSize");
+
+ /*
+ * JDK-8145027
+ * Temporarily exclude as current range/constraint is not enough for some option combinations.
+ */
+ excludeTestRange("NUMAInterleaveGranularity");
/*
* Remove parameters controlling the code cache. As these
--- a/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java Thu Dec 10 13:38:18 2015 -0500
+++ b/hotspot/test/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java Thu Dec 10 18:55:58 2015 +0000
@@ -168,6 +168,10 @@
option.addPrepend("-Xshare:dump");
}
+ if (name.startsWith("NUMA")) {
+ option.addPrepend("-XX:+UseNUMA");
+ }
+
switch (name) {
case "MinHeapFreeRatio":
option.addPrepend("-XX:MaxHeapFreeRatio=100");
@@ -196,6 +200,19 @@
case "InitialTenuringThreshold":
option.addPrepend("-XX:MaxTenuringThreshold=" + option.getMax());
break;
+ case "NUMAInterleaveGranularity":
+ option.addPrepend("-XX:+UseNUMAInterleaving");
+ break;
+ case "CPUForCMSThread":
+ option.addPrepend("-XX:+BindCMSThreadToCPU");
+ break;
+ case "VerifyGCStartAt":
+ option.addPrepend("-XX:+VerifyBeforeGC");
+ option.addPrepend("-XX:+VerifyAfterGC");
+ break;
+ case "NewSizeThreadIncrease":
+ option.addPrepend("-XX:+UseSerialGC");
+ break;
default:
/* Do nothing */
break;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ErrorHandling/TestCrashOnOutOfMemoryError.java Thu Dec 10 18:55:58 2015 +0000
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test TestCrashOnOutOfMemoryError
+ * @summary Test using -XX:+CrashOnOutOfMemoryError
+ * @library /testlibrary
+ * @build jdk.test.lib.*
+ * @run driver TestCrashOnOutOfMemoryError
+ * @bug 8138745
+ */
+
+import jdk.test.lib.OutputAnalyzer;
+import jdk.test.lib.ProcessTools;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+
+public class TestCrashOnOutOfMemoryError {
+
+ public static void main(String[] args) throws Exception {
+ if (args.length == 1) {
+ // This should guarantee to throw:
+ // java.lang.OutOfMemoryError: Requested array size exceeds VM limit
+ try {
+ Object[] oa = new Object[Integer.MAX_VALUE];
+ throw new Error("OOME not triggered");
+ } catch (OutOfMemoryError err) {
+ throw new Error("OOME didn't abort JVM!");
+ }
+ }
+ // else this is the main test
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+CrashOnOutOfMemoryError",
+ "-XX:-CreateCoredumpOnCrash", "-Xmx64m", TestCrashOnOutOfMemoryError.class.getName(),"throwOOME");
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ int exitValue = output.getExitValue();
+ if (0 == exitValue) {
+ //expecting a non zero value
+ throw new Error("Expected to get non zero exit value");
+ }
+
+ /* Output should look something like this. The actual text will depend on the OS and its core dump processing.
+ Aborting due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit
+ # To suppress the following error report, specify this argument
+ # after -XX: or in .hotspotrc: SuppressErrorAt=/debug.cpp:303
+ #
+ # A fatal error has been detected by the Java Runtime Environment:
+ #
+ # Internal Error (/home/cheleswer/Desktop/jdk9/dev/hotspot/src/share/vm/utilities/debug.cpp:303), pid=6212, tid=6213
+ # fatal error: OutOfMemory encountered: Requested array size exceeds VM limit
+ #
+ # JRE version: OpenJDK Runtime Environment (9.0) (build 1.9.0-internal-debug-cheleswer_2015_10_20_14_32-b00)
+ # Java VM: OpenJDK 64-Bit Server VM (1.9.0-internal-debug-cheleswer_2015_10_20_14_32-b00, mixed mode, tiered, compressed oops, serial gc, linux-amd64)
+ # Core dump will be written. Default location: Core dumps may be processed with "/usr/share/apport/apport %p %s %c %P" (or dumping to
+ /home/cheleswer/Desktop/core.6212)
+ #
+ # An error report file with more information is saved as:
+ # /home/cheleswer/Desktop/hs_err_pid6212.log
+ #
+ # If you would like to submit a bug report, please visit:
+ # http://bugreport.java.com/bugreport/crash.jsp
+ #
+ Current thread is 6213
+ Dumping core ...
+ Aborted (core dumped)
+ */
+ output.shouldContain("Aborting due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit");
+ // extract hs-err file
+ String hs_err_file = output.firstMatch("# *(\\S*hs_err_pid\\d+\\.log)", 1);
+ if (hs_err_file == null) {
+ throw new Error("Did not find hs-err file in output.\n");
+ }
+
+ /*
+ * Check if hs_err files exist or not
+ */
+ File f = new File(hs_err_file);
+ if (!f.exists()) {
+ throw new Error("hs-err file missing at "+ f.getAbsolutePath() + ".\n");
+ }
+
+ /*
+ * Checking the completness of hs_err file. If last line of hs_err file is "END"
+ * then it proves that file is complete.
+ */
+ try (FileInputStream fis = new FileInputStream(f);
+ BufferedReader br = new BufferedReader(new InputStreamReader(fis))) {
+ String line = null;
+ String lastLine = null;
+ while ((line = br.readLine()) != null) {
+ lastLine = line;
+ }
+ if (!lastLine.equals("END.")) {
+ throw new Error("hs-err file incomplete (missing END marker.)");
+ } else {
+ System.out.println("End marker found.");
+ }
+ }
+ System.out.println("PASSED");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ErrorHandling/TestExitOnOutOfMemoryError.java Thu Dec 10 18:55:58 2015 +0000
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test TestExitOnOutOfMemoryError
+ * @summary Test using -XX:ExitOnOutOfMemoryError
+ * @library /testlibrary
+ * @build jdk.test.lib.*
+ * @run driver TestExitOnOutOfMemoryError
+ * @bug 8138745
+ */
+
+import jdk.test.lib.ProcessTools;
+import jdk.test.lib.OutputAnalyzer;
+
+public class TestExitOnOutOfMemoryError {
+
+ public static void main(String[] args) throws Exception {
+ if (args.length == 1) {
+ // This should guarantee to throw:
+ // java.lang.OutOfMemoryError: Requested array size exceeds VM limit
+ try {
+ Object[] oa = new Object[Integer.MAX_VALUE];
+ throw new Error("OOME not triggered");
+ } catch (OutOfMemoryError err) {
+ throw new Error("OOME didn't terminate JVM!");
+ }
+ }
+
+ // else this is the main test
+ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+ExitOnOutOfMemoryError",
+ "-Xmx64m", TestExitOnOutOfMemoryError.class.getName(), "throwOOME");
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+ /*
+ * Actual output should look like this:
+ * Terminating due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit
+ */
+ output.shouldHaveExitValue(3);
+ output.stdoutShouldNotBeEmpty();
+ output.shouldContain("Terminating due to java.lang.OutOfMemoryError: Requested array size exceeds VM limit");
+ System.out.println("PASSED");
+ }
+}