Merge
This commit is contained in:
commit
79e18f084b
@ -223,9 +223,12 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_at
|
||||
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);
|
||||
|
@ -86,7 +86,7 @@ typedef int bool;
|
||||
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);
|
||||
|
@ -215,9 +215,12 @@ static bool ptrace_waitpid(pid_t pid) {
|
||||
}
|
||||
|
||||
// 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 @@ static ps_prochandle_ops process_ops = {
|
||||
};
|
||||
|
||||
// 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 @@ struct ps_prochandle* Pgrab(pid_t pid) {
|
||||
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;
|
||||
|
@ -1446,7 +1446,7 @@ public class CommandProcessor {
|
||||
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 @@ public class CommandProcessor {
|
||||
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 @@ public class CommandProcessor {
|
||||
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 @@ public class CommandProcessor {
|
||||
for (JavaThread thread = threads.first(); thread != null; thread = thread.next()) {
|
||||
thread.printThreadIDOn(out);
|
||||
out.println(" " + thread.getThreadName());
|
||||
thread.printInfoOn(out);
|
||||
out.println("\n...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,10 +125,14 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
|
||||
}
|
||||
}
|
||||
|
||||
// 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 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
|
||||
|
||||
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 @@ public class HSDB implements ObjectHistogramPanel.Listener, SAListener {
|
||||
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));
|
||||
|
@ -416,7 +416,7 @@ public class JavaThread extends Thread {
|
||||
} 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());
|
||||
|
@ -1921,6 +1921,15 @@ public class HTMLGenerator implements /* imports */ ClassConstants {
|
||||
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");
|
||||
}
|
||||
|
@ -261,7 +261,11 @@ endif
|
||||
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
|
||||
|
@ -1973,7 +1973,7 @@ class StubGenerator: public StubCodeGenerator {
|
||||
// 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 @@ class StubGenerator: public StubCodeGenerator {
|
||||
__ 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);
|
||||
|
@ -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::verify() {
|
||||
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -1651,6 +1651,7 @@ uint MachSpillCopyNode::implementation( CodeBuffer *cbuf,
|
||||
#endif // !_LP64
|
||||
|
||||
Unimplemented();
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
|
@ -35,7 +35,10 @@ const char* VM_Version::_features_str = "";
|
||||
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 @@ void VM_Version::initialize() {
|
||||
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();
|
||||
|
@ -127,6 +127,8 @@ public:
|
||||
// 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; }
|
||||
|
@ -3431,8 +3431,12 @@ void os::Aix::check_signal_handler(int sig) {
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
|
@ -3382,8 +3382,12 @@ void os::Bsd::check_signal_handler(int sig) {
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
|
@ -4533,8 +4533,12 @@ void os::Linux::check_signal_handler(int sig) {
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
|
@ -736,12 +736,12 @@ bool os::Posix::is_valid_signal(int sig) {
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
@ -4058,8 +4058,12 @@ void os::Solaris::check_signal_handler(int sig) {
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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 @@ address os::Linux::ucontext_get_pc(ucontext_t* uc) {
|
||||
}
|
||||
|
||||
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 @@ JVM_handle_linux_signal(int sig,
|
||||
VMError::report_and_die(t, sig, pc, info, ucVoid);
|
||||
|
||||
ShouldNotReachHere();
|
||||
return false;
|
||||
}
|
||||
|
||||
void os::Linux::init_thread_fpu_state(void) {
|
||||
|
@ -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"
|
||||
|
@ -551,6 +551,7 @@ JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
|
||||
VMError::report_and_die(t, sig, pc, info, ucVoid);
|
||||
|
||||
ShouldNotReachHere();
|
||||
return false;
|
||||
}
|
||||
|
||||
void os::print_context(outputStream *st, void *context) {
|
||||
|
@ -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"
|
||||
|
@ -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) {
|
||||
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) 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, 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,
|
||||
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, 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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
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);
|
||||
|
||||
const InstanceKlass* parse_super_class(ConstantPool* const cp,
|
||||
const int super_class_index,
|
||||
const bool need_verify,
|
||||
TRAPS);
|
||||
|
||||
instanceKlassHandle parse_super_class(int super_class_index, 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);
|
||||
|
||||
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_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);
|
||||
|
||||
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 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
#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 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
#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 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
|
||||
}
|
||||
}
|
||||
|
||||
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_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_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;
|
||||
|
||||
bool is_anonymous() {
|
||||
return _host_klass.not_null();
|
||||
}
|
||||
bool has_cp_patch_at(int index) {
|
||||
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;
|
||||
|
||||
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; }
|
||||
|
||||
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; }
|
||||
|
||||
// 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);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_CLASSFILE_CLASSFILEPARSER_HPP
|
||||
|
@ -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 @@ u1 ClassFileStream::get_u1(TRAPS) {
|
||||
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);
|
||||
}
|
||||
|
@ -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 ;
|
||||
|
||||
protected:
|
||||
const u1* clone_buffer() const;
|
||||
const char* const clone_source() const;
|
||||
|
||||
void truncated_file_error(TRAPS);
|
||||
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 @@ class ClassFileStream: public ResourceObj {
|
||||
// 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
|
||||
|
@ -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 @@ bool string_ends_with(const char* str, const char* str_to_find) {
|
||||
}
|
||||
|
||||
|
||||
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 @@ ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) {
|
||||
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 @@ u1* ClassPathZipEntry::open_entry(const char* name, jint* filesize, bool nul_ter
|
||||
|
||||
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 @@ ClassFileStream* ClassPathImageEntry::open_stream(const char* name, TRAPS) {
|
||||
}
|
||||
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,73 +1003,93 @@ objArrayOop ClassLoader::get_system_packages(TRAPS) {
|
||||
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");
|
||||
|
||||
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();
|
||||
|
||||
instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) {
|
||||
ResourceMark rm(THREAD);
|
||||
const char* class_name = h_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) {
|
||||
|
@ -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 @@ class ClassPathZipEntry: public ClassPathEntry {
|
||||
jzfile* _zip; // The zip archive
|
||||
const char* _zip_name; // Name of zip archive
|
||||
public:
|
||||
bool is_jar_file() { return true; }
|
||||
const char* name() { return _zip_name; }
|
||||
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 @@ private:
|
||||
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 @@ class ClassLoader: AllStatic {
|
||||
// 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 @@ class ClassLoader: AllStatic {
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
@ -166,7 +166,9 @@ void ClassLoaderData::classes_do(void f(InstanceKlass*)) {
|
||||
}
|
||||
}
|
||||
|
||||
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 ClassLoaderDataGraph::clear_claimed_marks() {
|
||||
}
|
||||
}
|
||||
|
||||
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",
|
||||
|
@ -275,7 +275,7 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
// 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 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
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 @@ class ClassLoaderData : public CHeapObj<mtClass> {
|
||||
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) {
|
||||
|
@ -41,7 +41,7 @@ public:
|
||||
_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 @@ public:
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/compactHashtable.inline.hpp"
|
||||
#include "classfile/javaClasses.hpp"
|
||||
#include "memory/metaspaceShared.hpp"
|
||||
#include "prims/jvm.h"
|
||||
|
@ -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 @@ public:
|
||||
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 @@ private:
|
||||
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 @@ public:
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
102
hotspot/src/share/vm/classfile/compactHashtable.inline.hpp
Normal file
102
hotspot/src/share/vm/classfile/compactHashtable.inline.hpp
Normal file
@ -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
|
@ -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 bool already_in_vtable_slots(GrowableArray<EmptyVtableSlot*>* slots, Meth
|
||||
}
|
||||
|
||||
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 @@ static void create_default_methods( InstanceKlass* klass,
|
||||
// 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 @@ void DefaultMethods::generate_default_methods(
|
||||
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);
|
||||
|
@ -43,6 +43,6 @@ class DefaultMethods : AllStatic {
|
||||
// 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
|
||||
|
@ -54,7 +54,7 @@ private:
|
||||
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 @@ class DictionaryEntry : public HashtableEntry<Klass*, mtClass> {
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
140
hotspot/src/share/vm/classfile/klassFactory.cpp
Normal file
140
hotspot/src/share/vm/classfile/klassFactory.cpp
Normal file
@ -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;
|
||||
}
|
81
hotspot/src/share/vm/classfile/klassFactory.hpp
Normal file
81
hotspot/src/share/vm/classfile/klassFactory.hpp
Normal file
@ -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
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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 @@ instanceKlassHandle SystemDictionary::handle_parallel_super_load(
|
||||
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 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
|
||||
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 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
|
||||
|
||||
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 @@ Klass* SystemDictionary::resolve_from_stream(Symbol* class_name,
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
ClassFileStream* st,
|
||||
bool verify,
|
||||
TRAPS) {
|
||||
|
||||
// Classloaders that support parallelism, e.g. bootstrap classloader,
|
||||
@ -1082,22 +1105,23 @@ Klass* SystemDictionary::resolve_from_stream(Symbol* class_name,
|
||||
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 @@ Klass* SystemDictionary::resolve_from_stream(Symbol* class_name,
|
||||
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 @@ instanceKlassHandle SystemDictionary::load_instance_class(Symbol* class_name, Ha
|
||||
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 @@ void SystemDictionary::verify() {
|
||||
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());
|
||||
}
|
||||
|
@ -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 @@ public:
|
||||
// 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 @@ public:
|
||||
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 @@ protected:
|
||||
// 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.
|
||||
|
||||
|
@ -63,8 +63,7 @@ public:
|
||||
static InstanceKlass* lookup_from_stream(Symbol* class_name,
|
||||
Handle class_loader,
|
||||
Handle protection_domain,
|
||||
ClassFileStream* st,
|
||||
bool verify,
|
||||
const ClassFileStream* st,
|
||||
TRAPS) {
|
||||
return NULL;
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ Symbol* vmSymbols::_symbols[vmSymbols::SID_LIMIT];
|
||||
|
||||
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 @@ inline int compare_symbol(Symbol* a, Symbol* b) {
|
||||
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 @@ void vmSymbols::serialize(SerializeClosure* soc) {
|
||||
}
|
||||
|
||||
|
||||
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 @@ static int find_sid_calls, find_sid_probes;
|
||||
// (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.
|
||||
|
@ -1367,7 +1367,7 @@ class vmSymbols: AllStatic {
|
||||
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 @@ class vmSymbols: AllStatic {
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -112,7 +112,7 @@ void DirtyCardQueueSet::initialize(CardTableEntryClosure* cl,
|
||||
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) {
|
||||
|
@ -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 @@ void G1CollectedHeap::print_extended_on(outputStream* st) const {
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
@ -573,6 +573,9 @@ public:
|
||||
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);
|
||||
}
|
||||
|
@ -191,6 +191,7 @@ G1CollectorPolicy::G1CollectorPolicy() :
|
||||
|
||||
_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 @@ void G1CollectorPolicy::record_collection_pause_end(double pause_time_ms, size_t
|
||||
_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 @@ void G1CollectorPolicy::update_recent_gc_times(double end_time_sec,
|
||||
_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);
|
||||
|
||||
return expand_bytes;
|
||||
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);
|
||||
|
||||
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 {
|
||||
|
@ -201,6 +201,11 @@ class G1CollectorPolicy: public CollectorPolicy {
|
||||
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 @@ class G1CollectorPolicy: public CollectorPolicy {
|
||||
|
||||
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 @@ private:
|
||||
|
||||
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 @@ public:
|
||||
|
||||
// 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;
|
||||
|
@ -53,8 +53,12 @@ struct InCSetState {
|
||||
// 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 @@ struct InCSetState {
|
||||
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 @@ class G1InCSetStateFastTestBiasedMappedArray : public G1BiasedMappedArray<InCSet
|
||||
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);
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ enum G1Mark {
|
||||
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) :
|
||||
|
@ -90,6 +90,8 @@ inline void G1ParScanClosure::do_oop_nv(T* p) {
|
||||
} 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 @@ inline void G1ParPushHeapRSClosure::do_oop_nv(T* p) {
|
||||
|
||||
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 @@ void G1ParCopyHelper::mark_forwarded_object(oop from_obj, oop to_obj) {
|
||||
_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 @@ void G1ParCopyClosure<barrier, do_mark_object>::do_oop_nv(T* p) {
|
||||
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) {
|
||||
|
@ -96,6 +96,7 @@ class G1ParScanThreadState : public CHeapObj<mtGC> {
|
||||
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) {
|
||||
|
@ -50,8 +50,8 @@ template <class T> void G1ParScanThreadState::do_oop_evac(T* p, HeapRegion* from
|
||||
} 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");
|
||||
|
@ -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);
|
||||
|
@ -31,15 +31,15 @@ class G1CollectedHeap;
|
||||
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),
|
||||
|
@ -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.") \
|
||||
|
@ -592,17 +592,20 @@ void HeapRegion::verify_strong_code_roots(VerifyOption vo, bool* failures) const
|
||||
|
||||
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 {
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -500,122 +500,42 @@ bool SequentialSubTasksDone::all_tasks_completed() {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -379,42 +379,29 @@ public:
|
||||
};
|
||||
|
||||
// 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). Returns "-1" if a GC wakes up a wait for an id.
|
||||
int claim_par_id();
|
||||
// necessary).
|
||||
uint claim_par_id();
|
||||
|
||||
void release_par_id(int id);
|
||||
void release_par_id(uint id);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_GC_SHARED_WORKGROUP_HPP
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -71,7 +71,9 @@ Klass* ArrayKlass::find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) co
|
||||
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 @@ Method* ArrayKlass::uncached_lookup_method(Symbol* name, Symbol* signature, Over
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -82,12 +82,17 @@ class ArrayKlass: public Klass {
|
||||
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);
|
||||
|
@ -60,25 +60,33 @@ ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, T
|
||||
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);
|
||||
|
||||
// initialize tag array
|
||||
int length = tags->length();
|
||||
for (int index = 0; index < length; index++) {
|
||||
tags->at_put(index, JVM_CONSTANT_Invalid);
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
set_tags(tags);
|
||||
return true;
|
||||
}
|
||||
|
||||
#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 @@ Klass* ConstantPool::klass_ref_at(int which, TRAPS) {
|
||||
}
|
||||
|
||||
|
||||
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 @@ char* ConstantPool::string_at_noresolve(int which) {
|
||||
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));
|
||||
}
|
||||
|
||||
|
@ -116,7 +116,7 @@ class ConstantPool : public Metadata {
|
||||
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 @@ class ConstantPool : public Metadata {
|
||||
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 @@ class ConstantPool : public Metadata {
|
||||
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 @@ class ConstantPool : public Metadata {
|
||||
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) {
|
||||
|
@ -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"); }
|
||||
|
@ -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) {
|
||||
static inline bool is_class_loader(const Symbol* class_name,
|
||||
const ClassFileParser& parser) {
|
||||
assert(class_name != NULL, "invariant");
|
||||
|
||||
int size = InstanceKlass::size(vtable_len, itable_len, nonstatic_oop_map_size,
|
||||
access_flags.is_interface(), is_anonymous);
|
||||
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 {
|
||||
// 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 if (is_class_loader(class_name, parser)) {
|
||||
// class loader
|
||||
ik = new (loader_data, size, THREAD) InstanceClassLoaderKlass(parser);
|
||||
}
|
||||
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 @@ InstanceKlass* InstanceKlass::allocate_instance_klass(
|
||||
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 @@ Array<int>* InstanceKlass::create_new_default_vtable_indices(int len, TRAPS) {
|
||||
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
|
||||
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));
|
||||
|
||||
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));
|
||||
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_methods(ClassLoaderData* loader_data,
|
||||
}
|
||||
|
||||
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 @@ void InstanceKlass::array_klasses_do(void f(Klass* k)) {
|
||||
}
|
||||
|
||||
#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 @@ static int linear_search(Array<Method*>* methods, Symbol* name, Symbol* signatur
|
||||
}
|
||||
#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 @@ static int binary_search(Array<Method*>* methods, Symbol* name) {
|
||||
}
|
||||
|
||||
// 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 @@ Method* InstanceKlass::find_instance_method(Symbol* name, Symbol* signature) {
|
||||
// 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 @@ Method* InstanceKlass::find_local_method(Symbol* name, Symbol* signature,
|
||||
// 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 @@ bool InstanceKlass::method_matches(Method* m, Symbol* signature, bool skipping_o
|
||||
// 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 @@ int InstanceKlass::find_method_by_name(
|
||||
|
||||
// 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 @@ Method* InstanceKlass::uncached_lookup_method(Symbol* name, Symbol* signature, O
|
||||
#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 @@ JNIid* InstanceKlass::jni_id_for(int offset) {
|
||||
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 @@ void InstanceKlass::release_C_heap_structures() {
|
||||
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 @@ const char* InstanceKlass::signature_name() const {
|
||||
}
|
||||
|
||||
// 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();
|
||||
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(class_loader(), 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 @@ Klass* InstanceKlass::compute_enclosing_class_impl(instanceKlassHandle self,
|
||||
*/
|
||||
|
||||
// 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 @@ bool InstanceKlass::is_same_package_member_impl(instanceKlassHandle class1,
|
||||
|
||||
// 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 @@ bool InstanceKlass::find_inner_classes_attr(instanceKlassHandle k, int* ooff, in
|
||||
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 {
|
||||
|
@ -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 @@ class InstanceKlass: public Klass {
|
||||
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);
|
||||
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(const ClassFileParser& parser, unsigned kind);
|
||||
|
||||
public:
|
||||
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 @@ class InstanceKlass: public Klass {
|
||||
|
||||
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 @@ class InstanceKlass: public Klass {
|
||||
// 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 @@ class InstanceKlass: public Klass {
|
||||
// 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 @@ class InstanceKlass: public Klass {
|
||||
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 @@ class InstanceKlass: public Klass {
|
||||
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 @@ class InstanceKlass: public Klass {
|
||||
// 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 @@ class InstanceKlass: public Klass {
|
||||
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 @@ class InstanceKlass: public Klass {
|
||||
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 @@ public:
|
||||
_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 @@ public:
|
||||
|
||||
#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 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ private:
|
||||
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);
|
||||
|
@ -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 @@ class InstanceMirrorKlass: public InstanceKlass {
|
||||
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"); }
|
||||
|
@ -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"); }
|
||||
|
@ -136,7 +136,7 @@ Klass* Klass::find_field(Symbol* name, Symbol* sig, fieldDescriptor* fd) const {
|
||||
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 @@ void* Klass::operator new(size_t size, ClassLoaderData* loader_data, size_t word
|
||||
MetaspaceObj::ClassType, THREAD);
|
||||
}
|
||||
|
||||
Klass::Klass() {
|
||||
Klass* k = this;
|
||||
// "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) {
|
||||
|
||||
// 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;
|
||||
_primary_supers[0] = this;
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
jint Klass::array_layout_helper(BasicType etype) {
|
||||
|
@ -410,9 +410,9 @@ protected:
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ inline InstanceKlass* klassVtable::ik() const {
|
||||
// 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 @@ void klassVtable::put_method_at(Method* m, int index) {
|
||||
// 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 @@ bool klassVtable::needs_new_vtable_entry(methodHandle target_method,
|
||||
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 @@ bool klassVtable::needs_new_vtable_entry(methodHandle target_method,
|
||||
// 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 @@ bool klassVtable::is_miranda_entry_at(int i) {
|
||||
// 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 @@ bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods,
|
||||
// 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 @@ bool klassVtable::is_miranda(Method* m, Array<Method*>* class_methods,
|
||||
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 @@ void klassVtable::add_new_mirandas_to_lists(
|
||||
|
||||
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::add_new_mirandas_to_lists(
|
||||
|
||||
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");
|
||||
|
@ -84,11 +84,16 @@ class klassVtable : public ResourceObj {
|
||||
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 @@ class klassVtable : public ResourceObj {
|
||||
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 @@ class klassVtable : public ResourceObj {
|
||||
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);
|
||||
|
@ -1320,12 +1320,12 @@ methodHandle Method::clone_with_new_data(methodHandle m, u_char* new_code, int n
|
||||
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
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ class Method : public Metadata {
|
||||
_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 @@ class Method : public Metadata {
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
@ -89,10 +89,14 @@ class ObjArrayKlass : public ArrayKlass {
|
||||
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
|
||||
|
@ -148,8 +148,8 @@ class Symbol : public MetaspaceObj {
|
||||
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 @@ class Symbol : public MetaspaceObj {
|
||||
|
||||
// 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 @@ class Symbol : public MetaspaceObj {
|
||||
// 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);
|
||||
}
|
||||
|
@ -120,10 +120,13 @@ class TypeArrayKlass : public ArrayKlass {
|
||||
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
|
||||
|
@ -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 @@ JNI_ENTRY(jclass, jni_DefineClass(JNIEnv *env, const char *name, jobject loaderR
|
||||
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 @@ JNI_ENTRY(jclass, jni_DefineClass(JNIEnv *env, const char *name, jobject loaderR
|
||||
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);
|
||||
|
@ -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 @@ static jclass jvm_define_class_common(JNIEnv *env, const char *name,
|
||||
}
|
||||
|
||||
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 @@ static jclass jvm_define_class_common(JNIEnv *env, const char *name,
|
||||
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_END
|
||||
JVM_ENTRY_NO_ENV(jint, JVM_FindSignal(const char *name))
|
||||
return os::get_signal_number(name);
|
||||
JVM_END
|
||||
|
||||
|
@ -2577,7 +2577,7 @@ JvmtiEnv::GetSourceDebugExtension(oop k_mirror, char** source_debug_extension_pt
|
||||
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);
|
||||
|
||||
{
|
||||
|
@ -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 @@ jvmtiError VM_RedefineClasses::load_new_class_versions(TRAPS) {
|
||||
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());
|
||||
|
@ -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 @@ Unsafe_DefineAnonymousClass_impl(JNIEnv *env,
|
||||
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 @@ Unsafe_DefineAnonymousClass_impl(JNIEnv *env,
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -1308,18 +1308,20 @@ bool Arguments::add_property(const char* prop) {
|
||||
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);
|
||||
} 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);
|
||||
if (old_java_command != NULL) {
|
||||
os::free(old_java_command);
|
||||
}
|
||||
} else if (strcmp(key, "java.vendor.url.bug") == 0) {
|
||||
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 @@ void Arguments::set_g1_gc_flags() {
|
||||
|
||||
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) {
|
||||
|
@ -223,7 +223,7 @@ void emit_constraint_double(const char* name, CommandLineFlagConstraintFunc_doub
|
||||
#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;
|
||||
|
||||
|
@ -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 @@ Flag::Error InitialBootClassLoaderMetaspaceSizeConstraintFunc(size_t value, bool
|
||||
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 @@ static Flag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool
|
||||
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 @@ Flag::Error MaxHeapSizeConstraintFunc(size_t value, bool verbose) {
|
||||
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 @@ Flag::Error TLABSizeConstraintFunc(size_t value, bool verbose) {
|
||||
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()))) {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user