提交 9d513174 编写于 作者: N never

Merge

......@@ -35,7 +35,6 @@ import sun.jvm.hotspot.utilities.*;
public class NMethod extends CodeBlob {
private static long pcDescSize;
private static CIntegerField zombieInstructionSizeField;
private static sun.jvm.hotspot.types.OopField methodField;
/** != InvocationEntryBci if this nmethod is an on-stack replacement method */
private static CIntegerField entryBCIField;
......@@ -88,7 +87,6 @@ public class NMethod extends CodeBlob {
private static void initialize(TypeDataBase db) {
Type type = db.lookupType("nmethod");
zombieInstructionSizeField = type.getCIntegerField("_zombie_instruction_size");
methodField = type.getOopField("_method");
entryBCIField = type.getCIntegerField("_entry_bci");
osrLinkField = type.getAddressField("_osr_link");
......
......@@ -376,10 +376,17 @@ public:
static bool is_amd() { assert_is_initialized(); return _cpuid_info.std_vendor_name_0 == 0x68747541; } // 'htuA'
static bool is_intel() { assert_is_initialized(); return _cpuid_info.std_vendor_name_0 == 0x756e6547; } // 'uneG'
static bool supports_processor_topology() {
return (_cpuid_info.std_max_function >= 0xB) &&
// eax[4:0] | ebx[0:15] == 0 indicates invalid topology level.
// Some cpus have max cpuid >= 0xB but do not support processor topology.
((_cpuid_info.tpl_cpuidB0_eax & 0x1f | _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus) != 0);
}
static uint cores_per_cpu() {
uint result = 1;
if (is_intel()) {
if (_cpuid_info.std_max_function >= 0xB) {
if (supports_processor_topology()) {
result = _cpuid_info.tpl_cpuidB1_ebx.bits.logical_cpus /
_cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus;
} else {
......@@ -393,7 +400,7 @@ public:
static uint threads_per_core() {
uint result = 1;
if (is_intel() && _cpuid_info.std_max_function >= 0xB) {
if (is_intel() && supports_processor_topology()) {
result = _cpuid_info.tpl_cpuidB0_ebx.bits.logical_cpus;
} else if (_cpuid_info.std_cpuid1_edx.bits.ht != 0) {
result = _cpuid_info.std_cpuid1_ebx.bits.threads_per_cpu /
......
/*
* Copyright (c) 1999, 2007, 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 "incls/_precompiled.incl"
#include "incls/_vtune_linux.cpp.incl"
// empty implementation
void VTune::start_GC() {}
void VTune::end_GC() {}
void VTune::start_class_load() {}
void VTune::end_class_load() {}
void VTune::exit() {}
void VTune::register_stub(const char* name, address start, address end) {}
void VTune::create_nmethod(nmethod* nm) {}
void VTune::delete_nmethod(nmethod* nm) {}
void vtune_init() {}
// Reconciliation History
// vtune_solaris.cpp 1.8 99/07/12 23:54:21
// End
/*
* Copyright (c) 1998, 2007, 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 "incls/_precompiled.incl"
#include "incls/_vtune_solaris.cpp.incl"
// empty implementation
void VTune::start_GC() {}
void VTune::end_GC() {}
void VTune::start_class_load() {}
void VTune::end_class_load() {}
void VTune::exit() {}
void VTune::register_stub(const char* name, address start, address end) {}
void VTune::create_nmethod(nmethod* nm) {}
void VTune::delete_nmethod(nmethod* nm) {}
void vtune_init() {}
/*
* Copyright (c) 1998, 2007, 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 "incls/_precompiled.incl"
#include "incls/_vtune_windows.cpp.incl"
static int current_method_ID = 0;
// ------------- iJITProf.h -------------------
// defined by Intel -- do not change
#include "windows.h"
extern "C" {
enum iJITP_Event {
ExceptionOccurred_S, // Java exception
ExceptionOccurred_IDS,
Shutdown, // VM exit
ThreadCreate, // threads
ThreadDestroy,
ThreadSwitch,
ClassLoadStart, // class loading
ClassLoadEnd,
GCStart, // GC
GCEnd,
NMethodCreate = 13, // nmethod creation
NMethodDelete
// rest of event types omitted (call profiling not supported yet)
};
// version number -- 0 if VTune not installed
int WINAPI iJitP_VersionNumber();
enum iJITP_ModeFlags {
NoNotification = 0x0, // don't call vtune
NotifyNMethodCreate = 0x1, // notify NMethod_Create
NotifyNMethodDelete = 0x2, // notify NMethod_Create
NotifyMethodEnter = 0x4, // method entry
NotifyMethodExit = 0x8, // method exit
NotifyShutdown = 0x10, // VM exit
NotifyGC = 0x20, // GC
};
// call back function type
typedef void (WINAPI *ModeChangedFn)(iJITP_ModeFlags flags);
// ------------- VTune method interfaces ----------------------
typedef void (WINAPI *RegisterCallbackFn)(ModeChangedFn fn); // register callback
typedef int (WINAPI *NotifyEventFn)(iJITP_Event, void* event_data);
// specific event data structures
// data for NMethodCreate
struct VTuneObj { // base class for allocation
// (can't use CHeapObj -- has vtable ptr)
void* operator new(size_t size) { return os::malloc(size); }
void operator delete(void* p) { fatal("never delete VTune data"); }
};
struct LineNumberInfo : VTuneObj { // PC-to-line number mapping
unsigned long offset; // byte offset from start of method
unsigned long line_num; // corresponding line number
};
struct MethodLoadInfo : VTuneObj {
unsigned long methodID; // unique method ID
const char* name; // method name
unsigned long instr_start; // start address
unsigned long instr_size; // length in bytes
unsigned long line_number_size; // size of line number table
LineNumberInfo* line_number_table; // line number mapping
unsigned long classID; // unique class ID
char* class_file_name; // fully qualified class file name
char* source_file_name; // fully qualified source file name
MethodLoadInfo(nmethod* nm); // for real nmethods
MethodLoadInfo(const char* vm_name, address start, address end);
// for "nmethods" like stubs, interpreter, etc
};
// data for NMethodDelete
struct MethodInfo : VTuneObj {
unsigned long methodID; // unique method ID
unsigned long classID; // (added for convenience -- not part of Intel interface)
MethodInfo(methodOop m);
};
};
MethodInfo::MethodInfo(methodOop m) {
// just give it a new ID -- we're not compiling methods twice (usually)
// (and even if we did, one might want to see the two versions separately)
methodID = ++current_method_ID;
}
MethodLoadInfo::MethodLoadInfo(const char* vm_name, address start, address end) {
classID = 0;
methodID = ++current_method_ID;
name = vm_name;
instr_start = (unsigned long)start;
instr_size = end - start;
line_number_size = 0;
line_number_table = NULL;
class_file_name = source_file_name = "HotSpot JVM";
}
MethodLoadInfo::MethodLoadInfo(nmethod* nm) {
methodOop m = nm->method();
MethodInfo info(m);
classID = info.classID;
methodID = info.methodID;
name = strdup(m->name()->as_C_string());
instr_start = (unsigned long)nm->instructions_begin();
instr_size = nm->code_size();
line_number_size = 0;
line_number_table = NULL;
klassOop kl = m->method_holder();
char* class_name = Klass::cast(kl)->name()->as_C_string();
char* file_name = NEW_C_HEAP_ARRAY(char, strlen(class_name) + 1);
strcpy(file_name, class_name);
class_file_name = file_name;
char* src_name = NEW_C_HEAP_ARRAY(char, strlen(class_name) + strlen(".java") + 1);
strcpy(src_name, class_name);
strcat(src_name, ".java");
source_file_name = src_name;
}
// --------------------- DLL loading functions ------------------------
#define DLLNAME "iJitProf.dll"
static HINSTANCE load_lib(char* name) {
HINSTANCE lib = NULL;
HKEY hk;
// try to get VTune directory from the registry
if (RegOpenKey(HKEY_CURRENT_USER, "Software\\VB and VBA Program Settings\\VTune\\StartUp", &hk) == ERROR_SUCCESS) {
for (int i = 0; true; i++) {
char szName[MAX_PATH + 1];
char szVal [MAX_PATH + 1];
DWORD cbName, cbVal;
cbName = cbVal = MAX_PATH + 1;
if (RegEnumValue(hk, i, szName, &cbName, NULL, NULL, (LPBYTE)szVal, &cbVal) == ERROR_SUCCESS) {
// get VTune directory
if (!strcmp(szName, name)) {
char*p = szVal;
while (*p == ' ') p++; // trim
char* q = p + strlen(p) - 1;
while (*q == ' ') *(q--) = '\0';
// chdir to the VTune dir
GetCurrentDirectory(MAX_PATH + 1, szName);
SetCurrentDirectory(p);
// load lib
lib = LoadLibrary(strcat(strcat(p, "\\"), DLLNAME));
if (lib != NULL && WizardMode) tty->print_cr("*loaded VTune DLL %s", p);
// restore current dir
SetCurrentDirectory(szName);
break;
}
} else {
break;
}
}
}
return lib;
}
static RegisterCallbackFn iJIT_RegisterCallback = NULL;
static NotifyEventFn iJIT_NotifyEvent = NULL;
static bool load_iJIT_funcs() {
// first try to load from PATH
HINSTANCE lib = LoadLibrary(DLLNAME);
if (lib != NULL && WizardMode) tty->print_cr("*loaded VTune DLL %s via PATH", DLLNAME);
// if not successful, try to look in the VTUNE directory
if (lib == NULL) lib = load_lib("VTUNEDIR30");
if (lib == NULL) lib = load_lib("VTUNEDIR25");
if (lib == NULL) lib = load_lib("VTUNEDIR");
if (lib == NULL) return false; // unsuccessful
// try to load the functions
iJIT_RegisterCallback = (RegisterCallbackFn)GetProcAddress(lib, "iJIT_RegisterCallback");
iJIT_NotifyEvent = (NotifyEventFn) GetProcAddress(lib, "iJIT_NotifyEvent");
if (!iJIT_RegisterCallback) tty->print_cr("*couldn't find VTune entry point iJIT_RegisterCallback");
if (!iJIT_NotifyEvent) tty->print_cr("*couldn't find VTune entry point iJIT_NotifyEvent");
return iJIT_RegisterCallback != NULL && iJIT_NotifyEvent != NULL;
}
// --------------------- VTune class ------------------------
static bool active = false;
static int flags = 0;
void VTune::start_GC() {
if (active && (flags & NotifyGC)) iJIT_NotifyEvent(GCStart, NULL);
}
void VTune::end_GC() {
if (active && (flags & NotifyGC)) iJIT_NotifyEvent(GCEnd, NULL);
}
void VTune::start_class_load() {
// not yet implemented in VTune
}
void VTune::end_class_load() {
// not yet implemented in VTune
}
void VTune::exit() {
if (active && (flags & NotifyShutdown)) iJIT_NotifyEvent(Shutdown, NULL);
}
void VTune::register_stub(const char* name, address start, address end) {
if (flags & NotifyNMethodCreate) {
MethodLoadInfo* info = new MethodLoadInfo(name, start, end);
if (PrintMiscellaneous && WizardMode && Verbose) {
tty->print_cr("NMethodCreate %s (%d): %#x..%#x", info->name, info->methodID,
info->instr_start, info->instr_start + info->instr_size);
}
iJIT_NotifyEvent(NMethodCreate, info);
}
}
void VTune::create_nmethod(nmethod* nm) {
if (flags & NotifyNMethodCreate) {
MethodLoadInfo* info = new MethodLoadInfo(nm);
if (PrintMiscellaneous && WizardMode && Verbose) {
tty->print_cr("NMethodCreate %s (%d): %#x..%#x", info->name, info->methodID,
info->instr_start, info->instr_start + info->instr_size);
}
iJIT_NotifyEvent(NMethodCreate, info);
}
}
void VTune::delete_nmethod(nmethod* nm) {
if (flags & NotifyNMethodDelete) {
MethodInfo* info = new MethodInfo(nm->method());
iJIT_NotifyEvent(NMethodDelete, info);
}
}
static void set_flags(int new_flags) {
flags = new_flags;
// if (WizardMode) tty->print_cr("*new VTune flags: %#x", flags);
}
void vtune_init() {
if (!UseVTune) return;
active = load_iJIT_funcs();
if (active) {
iJIT_RegisterCallback((ModeChangedFn)set_flags);
} else {
assert(flags == 0, "flags shouldn't be set");
}
}
......@@ -106,7 +106,7 @@ public:
void BCEscapeAnalyzer::set_returned(ArgumentMap vars) {
for (int i = 0; i < _arg_size; i++) {
if (vars.contains(i))
_arg_returned.set_bit(i);
_arg_returned.set(i);
}
_return_local = _return_local && !(vars.contains_unknown() || vars.contains_allocated());
_return_allocated = _return_allocated && vars.contains_allocated() && !(vars.contains_unknown() || vars.contains_vars());
......@@ -126,16 +126,16 @@ bool BCEscapeAnalyzer::is_arg_stack(ArgumentMap vars){
if (_conservative)
return true;
for (int i = 0; i < _arg_size; i++) {
if (vars.contains(i) && _arg_stack.at(i))
if (vars.contains(i) && _arg_stack.test(i))
return true;
}
return false;
}
void BCEscapeAnalyzer::clear_bits(ArgumentMap vars, BitMap &bm) {
void BCEscapeAnalyzer::clear_bits(ArgumentMap vars, VectorSet &bm) {
for (int i = 0; i < _arg_size; i++) {
if (vars.contains(i)) {
bm.clear_bit(i);
bm >>= i;
}
}
}
......@@ -1157,15 +1157,15 @@ void BCEscapeAnalyzer::initialize() {
ciSignature* sig = method()->signature();
int j = 0;
if (!method()->is_static()) {
_arg_local.set_bit(0);
_arg_stack.set_bit(0);
_arg_local.set(0);
_arg_stack.set(0);
j++;
}
for (i = 0; i < sig->count(); i++) {
ciType* t = sig->type_at(i);
if (!t->is_primitive_type()) {
_arg_local.set_bit(j);
_arg_stack.set_bit(j);
_arg_local.set(j);
_arg_stack.set(j);
}
j += t->size();
}
......@@ -1198,9 +1198,9 @@ void BCEscapeAnalyzer::clear_escape_info() {
set_modified(var, OFFSET_ANY, 4);
set_global_escape(var);
}
_arg_local.clear();
_arg_stack.clear();
_arg_returned.clear();
_arg_local.Clear();
_arg_stack.Clear();
_arg_returned.Clear();
_return_local = false;
_return_allocated = false;
_allocated_escapes = true;
......@@ -1254,7 +1254,7 @@ void BCEscapeAnalyzer::compute_escape_info() {
// Do not scan method if it has no object parameters and
// does not returns an object (_return_allocated is set in initialize()).
if (_arg_local.is_empty() && !_return_allocated) {
if (_arg_local.Size() == 0 && !_return_allocated) {
// Clear all info since method's bytecode was not analysed and
// set pessimistic escape information.
clear_escape_info();
......@@ -1275,14 +1275,14 @@ void BCEscapeAnalyzer::compute_escape_info() {
//
if (!has_dependencies() && !methodData()->is_empty()) {
for (i = 0; i < _arg_size; i++) {
if (_arg_local.at(i)) {
assert(_arg_stack.at(i), "inconsistent escape info");
if (_arg_local.test(i)) {
assert(_arg_stack.test(i), "inconsistent escape info");
methodData()->set_arg_local(i);
methodData()->set_arg_stack(i);
} else if (_arg_stack.at(i)) {
} else if (_arg_stack.test(i)) {
methodData()->set_arg_stack(i);
}
if (_arg_returned.at(i)) {
if (_arg_returned.test(i)) {
methodData()->set_arg_returned(i);
}
methodData()->set_arg_modified(i, _arg_modified[i]);
......@@ -1308,9 +1308,12 @@ void BCEscapeAnalyzer::read_escape_info() {
// read escape information from method descriptor
for (int i = 0; i < _arg_size; i++) {
_arg_local.at_put(i, methodData()->is_arg_local(i));
_arg_stack.at_put(i, methodData()->is_arg_stack(i));
_arg_returned.at_put(i, methodData()->is_arg_returned(i));
if (methodData()->is_arg_local(i))
_arg_local.set(i);
if (methodData()->is_arg_stack(i))
_arg_stack.set(i);
if (methodData()->is_arg_returned(i))
_arg_returned.set(i);
_arg_modified[i] = methodData()->arg_modified(i);
}
_return_local = methodData()->eflag_set(methodDataOopDesc::return_local);
......@@ -1358,26 +1361,26 @@ void BCEscapeAnalyzer::dump() {
BCEscapeAnalyzer::BCEscapeAnalyzer(ciMethod* method, BCEscapeAnalyzer* parent)
: _conservative(method == NULL || !EstimateArgEscape)
, _arena(CURRENT_ENV->arena())
, _method(method)
, _methodData(method ? method->method_data() : NULL)
, _arg_size(method ? method->arg_size() : 0)
, _stack()
, _arg_local(_arg_size)
, _arg_stack(_arg_size)
, _arg_returned(_arg_size)
, _dirty(_arg_size)
, _arg_local(_arena)
, _arg_stack(_arena)
, _arg_returned(_arena)
, _dirty(_arena)
, _return_local(false)
, _return_allocated(false)
, _allocated_escapes(false)
, _unknown_modified(false)
, _dependencies()
, _dependencies(_arena, 4, 0, NULL)
, _parent(parent)
, _level(parent == NULL ? 0 : parent->level() + 1) {
if (!_conservative) {
_arg_local.clear();
_arg_stack.clear();
_arg_returned.clear();
_dirty.clear();
_arg_local.Clear();
_arg_stack.Clear();
_arg_returned.Clear();
_dirty.Clear();
Arena* arena = CURRENT_ENV->arena();
_arg_modified = (uint *) arena->Amalloc(_arg_size * sizeof(uint));
Copy::zero_to_bytes(_arg_modified, _arg_size * sizeof(uint));
......@@ -1414,8 +1417,8 @@ void BCEscapeAnalyzer::copy_dependencies(Dependencies *deps) {
deps->assert_evol_method(method());
}
for (int i = 0; i < _dependencies.length(); i+=2) {
ciKlass *k = _dependencies[i]->as_klass();
ciMethod *m = _dependencies[i+1]->as_method();
ciKlass *k = _dependencies.at(i)->as_klass();
ciMethod *m = _dependencies.at(i+1)->as_method();
deps->assert_unique_concrete_method(k, m);
}
}
......@@ -22,9 +22,6 @@
*
*/
define_array(ciObjectArray, ciObject*);
define_stack(ciObjectList, ciObjectArray);
// This class implements a fast, conservative analysis of effect of methods
// on the escape state of their arguments. The analysis is at the bytecode
// level.
......@@ -34,18 +31,17 @@ class ciBlock;
class BCEscapeAnalyzer : public ResourceObj {
private:
Arena* _arena; // ciEnv arena
bool _conservative; // If true, return maximally
// conservative results.
ciMethod* _method;
ciMethodData* _methodData;
int _arg_size;
intStack _stack;
BitMap _arg_local;
BitMap _arg_stack;
BitMap _arg_returned;
BitMap _dirty;
VectorSet _arg_local;
VectorSet _arg_stack;
VectorSet _arg_returned;
VectorSet _dirty;
enum{ ARG_OFFSET_MAX = 31};
uint *_arg_modified;
......@@ -54,7 +50,7 @@ class BCEscapeAnalyzer : public ResourceObj {
bool _allocated_escapes;
bool _unknown_modified;
ciObjectList _dependencies;
GrowableArray<ciObject *> _dependencies;
ciMethodBlocks *_methodBlocks;
......@@ -68,20 +64,10 @@ class BCEscapeAnalyzer : public ResourceObj {
private:
// helper functions
bool is_argument(int i) { return i >= 0 && i < _arg_size; }
void raw_push(int i) { _stack.push(i); }
int raw_pop() { return _stack.is_empty() ? -1 : _stack.pop(); }
void apush(int i) { raw_push(i); }
void spush() { raw_push(-1); }
void lpush() { spush(); spush(); }
int apop() { return raw_pop(); }
void spop() { assert(_stack.is_empty() || _stack.top() == -1, ""); raw_pop(); }
void lpop() { spop(); spop(); }
void set_returned(ArgumentMap vars);
bool is_argument(ArgumentMap vars);
bool is_arg_stack(ArgumentMap vars);
void clear_bits(ArgumentMap vars, BitMap &bs);
void clear_bits(ArgumentMap vars, VectorSet &bs);
void set_method_escape(ArgumentMap vars);
void set_global_escape(ArgumentMap vars);
void set_dirty(ArgumentMap vars);
......@@ -116,25 +102,25 @@ class BCEscapeAnalyzer : public ResourceObj {
ciMethodData* methodData() const { return _methodData; }
BCEscapeAnalyzer* parent() const { return _parent; }
int level() const { return _level; }
ciObjectList* dependencies() { return &_dependencies; }
GrowableArray<ciObject *>* dependencies() { return &_dependencies; }
bool has_dependencies() const { return !_dependencies.is_empty(); }
// retrieval of interprocedural escape information
// The given argument does not escape the callee.
bool is_arg_local(int i) const {
return !_conservative && _arg_local.at(i);
return !_conservative && _arg_local.test(i);
}
// The given argument escapes the callee, but does not become globally
// reachable.
bool is_arg_stack(int i) const {
return !_conservative && _arg_stack.at(i);
return !_conservative && _arg_stack.test(i);
}
// The given argument does not escape globally, and may be returned.
bool is_arg_returned(int i) const {
return !_conservative && _arg_returned.at(i); }
return !_conservative && _arg_returned.test(i); }
// True iff only input arguments are returned.
bool is_return_local() const {
......
/*
* Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2010, 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
......@@ -44,9 +44,7 @@ ciInstanceKlass::ciInstanceKlass(KlassHandle h_k) :
_flags = ciFlags(access_flags);
_has_finalizer = access_flags.has_finalizer();
_has_subklass = ik->subklass() != NULL;
_is_initialized = ik->is_initialized();
// Next line must follow and use the result of the previous line:
_is_linked = _is_initialized || ik->is_linked();
_init_state = (instanceKlass::ClassState)ik->get_init_state();
_nonstatic_field_size = ik->nonstatic_field_size();
_has_nonstatic_fields = ik->has_nonstatic_fields();
_nonstatic_fields = NULL; // initialized lazily by compute_nonstatic_fields:
......@@ -91,8 +89,7 @@ ciInstanceKlass::ciInstanceKlass(ciSymbol* name,
: ciKlass(name, ciInstanceKlassKlass::make())
{
assert(name->byte_at(0) != '[', "not an instance klass");
_is_initialized = false;
_is_linked = false;
_init_state = (instanceKlass::ClassState)0;
_nonstatic_field_size = -1;
_has_nonstatic_fields = false;
_nonstatic_fields = NULL;
......@@ -109,21 +106,10 @@ ciInstanceKlass::ciInstanceKlass(ciSymbol* name,
// ------------------------------------------------------------------
// ciInstanceKlass::compute_shared_is_initialized
bool ciInstanceKlass::compute_shared_is_initialized() {
void ciInstanceKlass::compute_shared_init_state() {
GUARDED_VM_ENTRY(
instanceKlass* ik = get_instanceKlass();
_is_initialized = ik->is_initialized();
return _is_initialized;
)
}
// ------------------------------------------------------------------
// ciInstanceKlass::compute_shared_is_linked
bool ciInstanceKlass::compute_shared_is_linked() {
GUARDED_VM_ENTRY(
instanceKlass* ik = get_instanceKlass();
_is_linked = ik->is_linked();
return _is_linked;
_init_state = (instanceKlass::ClassState)ik->get_init_state();
)
}
......
/*
* Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2010, 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
......@@ -39,9 +39,8 @@ private:
jobject _loader;
jobject _protection_domain;
instanceKlass::ClassState _init_state; // state of class
bool _is_shared;
bool _is_initialized;
bool _is_linked;
bool _has_finalizer;
bool _has_subklass;
bool _has_nonstatic_fields;
......@@ -87,27 +86,34 @@ protected:
bool is_shared() { return _is_shared; }
bool compute_shared_is_initialized();
bool compute_shared_is_linked();
void compute_shared_init_state();
bool compute_shared_has_subklass();
int compute_shared_nof_implementors();
int compute_nonstatic_fields();
GrowableArray<ciField*>* compute_nonstatic_fields_impl(GrowableArray<ciField*>* super_fields);
// Update the init_state for shared klasses
void update_if_shared(instanceKlass::ClassState expected) {
if (_is_shared && _init_state != expected) {
if (is_loaded()) compute_shared_init_state();
}
}
public:
// Has this klass been initialized?
bool is_initialized() {
if (_is_shared && !_is_initialized) {
return is_loaded() && compute_shared_is_initialized();
}
return _is_initialized;
update_if_shared(instanceKlass::fully_initialized);
return _init_state == instanceKlass::fully_initialized;
}
// Is this klass being initialized?
bool is_being_initialized() {
update_if_shared(instanceKlass::being_initialized);
return _init_state == instanceKlass::being_initialized;
}
// Has this klass been linked?
bool is_linked() {
if (_is_shared && !_is_linked) {
return is_loaded() && compute_shared_is_linked();
}
return _is_linked;
update_if_shared(instanceKlass::linked);
return _init_state >= instanceKlass::linked;
}
// General klass information.
......
......@@ -54,10 +54,10 @@ ciMethod::ciMethod(methodHandle h_m) : ciObject(h_m) {
_code = NULL;
_exception_handlers = NULL;
_liveness = NULL;
_bcea = NULL;
_method_blocks = NULL;
#ifdef COMPILER2
_flow = NULL;
_bcea = NULL;
#endif // COMPILER2
ciEnv *env = CURRENT_ENV;
......@@ -121,11 +121,11 @@ ciMethod::ciMethod(ciInstanceKlass* holder,
_intrinsic_id = vmIntrinsics::_none;
_liveness = NULL;
_can_be_statically_bound = false;
_bcea = NULL;
_method_blocks = NULL;
_method_data = NULL;
#ifdef COMPILER2
_flow = NULL;
_bcea = NULL;
#endif // COMPILER2
}
......@@ -1033,10 +1033,15 @@ bool ciMethod::is_accessor () const { FETCH_FLAG_FROM_VM(is_accessor)
bool ciMethod::is_initializer () const { FETCH_FLAG_FROM_VM(is_initializer); }
BCEscapeAnalyzer *ciMethod::get_bcea() {
#ifdef COMPILER2
if (_bcea == NULL) {
_bcea = new (CURRENT_ENV->arena()) BCEscapeAnalyzer(this, NULL);
}
return _bcea;
#else // COMPILER2
ShouldNotReachHere();
return NULL;
#endif // COMPILER2
}
ciMethodBlocks *ciMethod::get_method_blocks() {
......
......@@ -48,7 +48,6 @@ class ciMethod : public ciObject {
ciInstanceKlass* _holder;
ciSignature* _signature;
ciMethodData* _method_data;
BCEscapeAnalyzer* _bcea;
ciMethodBlocks* _method_blocks;
// Code attributes.
......@@ -72,7 +71,8 @@ class ciMethod : public ciObject {
// Optional liveness analyzer.
MethodLiveness* _liveness;
#ifdef COMPILER2
ciTypeFlow* _flow;
ciTypeFlow* _flow;
BCEscapeAnalyzer* _bcea;
#endif
ciMethod(methodHandle h_m);
......
/*
* Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2010, 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
......@@ -832,7 +832,6 @@ objArrayOop ClassLoader::get_system_packages(TRAPS) {
instanceKlassHandle ClassLoader::load_classfile(symbolHandle h_name, TRAPS) {
VTuneClassLoadMarker clm;
ResourceMark rm(THREAD);
EventMark m("loading class " INTPTR_FORMAT, (address)h_name());
ThreadProfilerMark tpm(ThreadProfilerMark::classLoaderRegion);
......
......@@ -210,6 +210,7 @@ AdapterBlob* AdapterBlob::create(CodeBuffer* cb) {
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
blob = new (size) AdapterBlob(size, cb);
CodeCache::commit(blob);
}
// Track memory usage statistic after releasing CodeCache_lock
MemoryService::track_code_cache_memory_usage();
......@@ -281,7 +282,6 @@ RuntimeStub* RuntimeStub::new_runtime_stub(const char* stub_name,
tty->print_cr("Decoding %s " INTPTR_FORMAT, stub_id, stub);
Disassembler::decode(stub->instructions_begin(), stub->instructions_end());
}
VTune::register_stub(stub_id, stub->instructions_begin(), stub->instructions_end());
Forte::register_stub(stub_id, stub->instructions_begin(), stub->instructions_end());
if (JvmtiExport::should_post_dynamic_code_generated()) {
......@@ -356,7 +356,6 @@ DeoptimizationBlob* DeoptimizationBlob::create(
tty->print_cr("Decoding %s " INTPTR_FORMAT, blob_id, blob);
Disassembler::decode(blob->instructions_begin(), blob->instructions_end());
}
VTune::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end());
Forte::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end());
if (JvmtiExport::should_post_dynamic_code_generated()) {
......@@ -414,7 +413,6 @@ UncommonTrapBlob* UncommonTrapBlob::create(
tty->print_cr("Decoding %s " INTPTR_FORMAT, blob_id, blob);
Disassembler::decode(blob->instructions_begin(), blob->instructions_end());
}
VTune::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end());
Forte::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end());
if (JvmtiExport::should_post_dynamic_code_generated()) {
......@@ -474,7 +472,6 @@ ExceptionBlob* ExceptionBlob::create(
tty->print_cr("Decoding %s " INTPTR_FORMAT, blob_id, blob);
Disassembler::decode(blob->instructions_begin(), blob->instructions_end());
}
VTune::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end());
Forte::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end());
if (JvmtiExport::should_post_dynamic_code_generated()) {
......@@ -533,7 +530,6 @@ SafepointBlob* SafepointBlob::create(
tty->print_cr("Decoding %s " INTPTR_FORMAT, blob_id, blob);
Disassembler::decode(blob->instructions_begin(), blob->instructions_end());
}
VTune::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end());
Forte::register_stub(blob_id, blob->instructions_begin(), blob->instructions_end());
if (JvmtiExport::should_post_dynamic_code_generated()) {
......
......@@ -93,6 +93,8 @@ class CodeBlob_sizes {
CodeHeap * CodeCache::_heap = new CodeHeap();
int CodeCache::_number_of_blobs = 0;
int CodeCache::_number_of_adapters = 0;
int CodeCache::_number_of_nmethods = 0;
int CodeCache::_number_of_nmethods_with_dependencies = 0;
bool CodeCache::_needs_cache_clean = false;
nmethod* CodeCache::_scavenge_root_nmethods = NULL;
......@@ -176,8 +178,14 @@ void CodeCache::free(CodeBlob* cb) {
verify_if_often();
print_trace("free", cb);
if (cb->is_nmethod() && ((nmethod *)cb)->has_dependencies()) {
_number_of_nmethods_with_dependencies--;
if (cb->is_nmethod()) {
_number_of_nmethods--;
if (((nmethod *)cb)->has_dependencies()) {
_number_of_nmethods_with_dependencies--;
}
}
if (cb->is_adapter_blob()) {
_number_of_adapters--;
}
_number_of_blobs--;
......@@ -191,9 +199,16 @@ void CodeCache::free(CodeBlob* cb) {
void CodeCache::commit(CodeBlob* cb) {
// this is called by nmethod::nmethod, which must already own CodeCache_lock
assert_locked_or_safepoint(CodeCache_lock);
if (cb->is_nmethod() && ((nmethod *)cb)->has_dependencies()) {
_number_of_nmethods_with_dependencies++;
if (cb->is_nmethod()) {
_number_of_nmethods++;
if (((nmethod *)cb)->has_dependencies()) {
_number_of_nmethods_with_dependencies++;
}
}
if (cb->is_adapter_blob()) {
_number_of_adapters++;
}
// flush the hardware I-cache
ICache::invalidate_range(cb->instructions_begin(), cb->instructions_size());
}
......
/*
* Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2010, 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
......@@ -43,6 +43,8 @@ class CodeCache : AllStatic {
// 4422213 or 4436291 for details.
static CodeHeap * _heap;
static int _number_of_blobs;
static int _number_of_adapters;
static int _number_of_nmethods;
static int _number_of_nmethods_with_dependencies;
static bool _needs_cache_clean;
static nmethod* _scavenge_root_nmethods; // linked via nm->scavenge_root_link()
......@@ -105,6 +107,8 @@ class CodeCache : AllStatic {
static nmethod* first_nmethod();
static nmethod* next_nmethod (CodeBlob* cb);
static int nof_blobs() { return _number_of_blobs; }
static int nof_adapters() { return _number_of_adapters; }
static int nof_nmethods() { return _number_of_nmethods; }
// GC support
static void gc_epilogue();
......
......@@ -397,11 +397,6 @@ void nmethod::add_handler_for_exception_and_pc(Handle exception, address pc, add
//-------------end of code for ExceptionCache--------------
void nmFlags::clear() {
assert(sizeof(nmFlags) == sizeof(int), "using more than one word for nmFlags");
*(jint*)this = 0;
}
int nmethod::total_size() const {
return
code_size() +
......@@ -419,8 +414,32 @@ const char* nmethod::compile_kind() const {
return NULL;
}
// %%% This variable is no longer used?
int nmethod::_zombie_instruction_size = NativeJump::instruction_size;
// Fill in default values for various flag fields
void nmethod::init_defaults() {
_state = alive;
_marked_for_reclamation = 0;
_has_flushed_dependencies = 0;
_speculatively_disconnected = 0;
_has_unsafe_access = 0;
_has_method_handle_invokes = 0;
_marked_for_deoptimization = 0;
_lock_count = 0;
_stack_traversal_mark = 0;
_unload_reported = false; // jvmti state
NOT_PRODUCT(_has_debug_info = false);
_oops_do_mark_link = NULL;
_jmethod_id = NULL;
_osr_link = NULL;
_scavenge_root_link = NULL;
_scavenge_root_state = 0;
_saved_nmethod_link = NULL;
_compiler = NULL;
#ifdef HAVE_DTRACE_H
_trap_offset = 0;
#endif // def HAVE_DTRACE_H
}
nmethod* nmethod::new_native_nmethod(methodHandle method,
......@@ -580,25 +599,16 @@ nmethod::nmethod(
debug_only(No_Safepoint_Verifier nsv;)
assert_locked_or_safepoint(CodeCache_lock);
NOT_PRODUCT(_has_debug_info = false);
_oops_do_mark_link = NULL;
init_defaults();
_method = method;
_entry_bci = InvocationEntryBci;
_jmethod_id = NULL;
_osr_link = NULL;
_scavenge_root_link = NULL;
_scavenge_root_state = 0;
_saved_nmethod_link = NULL;
_compiler = NULL;
// We have no exception handler or deopt handler make the
// values something that will never match a pc like the nmethod vtable entry
_exception_offset = 0;
_deoptimize_offset = 0;
_deoptimize_mh_offset = 0;
_orig_pc_offset = 0;
#ifdef HAVE_DTRACE_H
_trap_offset = 0;
#endif // def HAVE_DTRACE_H
_stub_offset = data_offset();
_consts_offset = data_offset();
_oops_offset = data_offset();
......@@ -616,17 +626,9 @@ nmethod::nmethod(
_exception_cache = NULL;
_pc_desc_cache.reset_to(NULL);
flags.clear();
flags.state = alive;
_markedForDeoptimization = 0;
_lock_count = 0;
_stack_traversal_mark = 0;
code_buffer->copy_oops_to(this);
debug_only(verify_scavenge_root_oops());
CodeCache::commit(this);
VTune::create_nmethod(this);
}
if (PrintNativeNMethods || PrintDebugInfo || PrintRelocations || PrintDependencies) {
......@@ -674,15 +676,9 @@ nmethod::nmethod(
debug_only(No_Safepoint_Verifier nsv;)
assert_locked_or_safepoint(CodeCache_lock);
NOT_PRODUCT(_has_debug_info = false);
_oops_do_mark_link = NULL;
init_defaults();
_method = method;
_entry_bci = InvocationEntryBci;
_jmethod_id = NULL;
_osr_link = NULL;
_scavenge_root_link = NULL;
_scavenge_root_state = 0;
_compiler = NULL;
// We have no exception handler or deopt handler make the
// values something that will never match a pc like the nmethod vtable entry
_exception_offset = 0;
......@@ -708,17 +704,9 @@ nmethod::nmethod(
_exception_cache = NULL;
_pc_desc_cache.reset_to(NULL);
flags.clear();
flags.state = alive;
_markedForDeoptimization = 0;
_lock_count = 0;
_stack_traversal_mark = 0;
code_buffer->copy_oops_to(this);
debug_only(verify_scavenge_root_oops());
CodeCache::commit(this);
VTune::create_nmethod(this);
}
if (PrintNMethods || PrintDebugInfo || PrintRelocations || PrintDependencies) {
......@@ -783,21 +771,13 @@ nmethod::nmethod(
debug_only(No_Safepoint_Verifier nsv;)
assert_locked_or_safepoint(CodeCache_lock);
NOT_PRODUCT(_has_debug_info = false);
_oops_do_mark_link = NULL;
init_defaults();
_method = method;
_jmethod_id = NULL;
_entry_bci = entry_bci;
_compile_id = compile_id;
_comp_level = comp_level;
_entry_bci = entry_bci;
_osr_link = NULL;
_scavenge_root_link = NULL;
_scavenge_root_state = 0;
_compiler = compiler;
_orig_pc_offset = orig_pc_offset;
#ifdef HAVE_DTRACE_H
_trap_offset = 0;
#endif // def HAVE_DTRACE_H
_stub_offset = instructions_offset() + code_buffer->total_offset_of(code_buffer->stubs()->start());
// Exception handler and deopt handler are in the stub section
......@@ -824,15 +804,6 @@ nmethod::nmethod(
_exception_cache = NULL;
_pc_desc_cache.reset_to(scopes_pcs_begin());
flags.clear();
flags.state = alive;
_markedForDeoptimization = 0;
_unload_reported = false; // jvmti state
_lock_count = 0;
_stack_traversal_mark = 0;
// Copy contents of ScopeDescRecorder to nmethod
code_buffer->copy_oops_to(this);
debug_info->copy_to(this);
......@@ -844,8 +815,6 @@ nmethod::nmethod(
CodeCache::commit(this);
VTune::create_nmethod(this);
// Copy contents of ExceptionHandlerTable to nmethod
handler_table->copy_to(this);
nul_chk_table->copy_to(this);
......@@ -991,11 +960,6 @@ void nmethod::print_nmethod(bool printmethod) {
}
void nmethod::set_version(int v) {
flags.version = v;
}
// Promote one word from an assembly-time handle to a live embedded oop.
inline void nmethod::initialize_immediate_oop(oop* dest, jobject handle) {
if (handle == NULL ||
......@@ -1142,6 +1106,8 @@ void nmethod::cleanup_inline_caches() {
// This is a private interface with the sweeper.
void nmethod::mark_as_seen_on_stack() {
assert(is_not_entrant(), "must be a non-entrant method");
// Set the traversal mark to ensure that the sweeper does 2
// cleaning passes before moving to zombie.
set_stack_traversal_mark(NMethodSweeper::traversal_count());
}
......@@ -1210,7 +1176,7 @@ void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) {
// for later on.
CodeCache::set_needs_cache_clean(true);
}
flags.state = unloaded;
_state = unloaded;
// Log the unloading.
log_state_change();
......@@ -1236,21 +1202,21 @@ void nmethod::log_state_change() const {
if (LogCompilation) {
if (xtty != NULL) {
ttyLocker ttyl; // keep the following output all in one block
if (flags.state == unloaded) {
if (_state == unloaded) {
xtty->begin_elem("make_unloaded thread='" UINTX_FORMAT "'",
os::current_thread_id());
} else {
xtty->begin_elem("make_not_entrant thread='" UINTX_FORMAT "'%s",
os::current_thread_id(),
(flags.state == zombie ? " zombie='1'" : ""));
(_state == zombie ? " zombie='1'" : ""));
}
log_identity(xtty);
xtty->stamp();
xtty->end_elem();
}
}
if (PrintCompilation && flags.state != unloaded) {
print_on(tty, flags.state == zombie ? "made zombie " : "made not entrant ");
if (PrintCompilation && _state != unloaded) {
print_on(tty, _state == zombie ? "made zombie " : "made not entrant ");
tty->cr();
}
}
......@@ -1261,8 +1227,9 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
bool was_alive = false;
// Make sure the nmethod is not flushed in case of a safepoint in code below.
// Make sure neither the nmethod nor the method is flushed in case of a safepoint in code below.
nmethodLocker nml(this);
methodHandle the_method(method());
{
// If the method is already zombie there is nothing to do
......@@ -1282,7 +1249,7 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
// Enter critical section. Does not block for safepoint.
MutexLockerEx pl(Patching_lock, Mutex::_no_safepoint_check_flag);
if (flags.state == state) {
if (_state == state) {
// another thread already performed this transition so nothing
// to do, but return false to indicate this.
return false;
......@@ -1293,17 +1260,37 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
if (!is_osr_method() && !is_not_entrant()) {
NativeJump::patch_verified_entry(entry_point(), verified_entry_point(),
SharedRuntime::get_handle_wrong_method_stub());
assert (NativeJump::instruction_size == nmethod::_zombie_instruction_size, "");
}
was_alive = is_in_use(); // Read state under lock
if (is_in_use()) {
// It's a true state change, so mark the method as decompiled.
// Do it only for transition from alive.
inc_decompile_count();
}
// Change state
flags.state = state;
_state = state;
// Log the transition once
log_state_change();
// Remove nmethod from method.
// We need to check if both the _code and _from_compiled_code_entry_point
// refer to this nmethod because there is a race in setting these two fields
// in methodOop as seen in bugid 4947125.
// If the vep() points to the zombie nmethod, the memory for the nmethod
// could be flushed and the compiler and vtable stubs could still call
// through it.
if (method() != NULL && (method()->code() == this ||
method()->from_compiled_entry() == verified_entry_point())) {
HandleMark hm;
method()->clear_code();
}
if (state == not_entrant) {
mark_as_seen_on_stack();
}
} // leave critical region under Patching_lock
// When the nmethod becomes zombie it is no longer alive so the
......@@ -1311,18 +1298,17 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
// state will be flushed later when the transition to zombie
// happens or they get unloaded.
if (state == zombie) {
// zombie only - if a JVMTI agent has enabled the CompiledMethodUnload event
// and it hasn't already been reported for this nmethod then report it now.
// (the event may have been reported earilier if the GC marked it for unloading).
post_compiled_method_unload();
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
flush_dependencies(NULL);
} else {
assert(state == not_entrant, "other cases may need to be handled differently");
}
if (state == not_entrant) {
Events::log("Make nmethod not entrant " INTPTR_FORMAT, this);
} else {
Events::log("Make nmethod zombie " INTPTR_FORMAT, this);
}
if (TraceCreateZombies) {
tty->print_cr("nmethod <" INTPTR_FORMAT "> code made %s", this, (state == not_entrant) ? "not entrant" : "zombie");
}
......@@ -1330,47 +1316,6 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
// Make sweeper aware that there is a zombie method that needs to be removed
NMethodSweeper::notify(this);
// not_entrant only stuff
if (state == not_entrant) {
mark_as_seen_on_stack();
}
if (was_alive) {
// It's a true state change, so mark the method as decompiled.
// Do it only for transition from alive.
inc_decompile_count();
}
// zombie only - if a JVMTI agent has enabled the CompiledMethodUnload event
// and it hasn't already been reported for this nmethod then report it now.
// (the event may have been reported earilier if the GC marked it for unloading).
if (state == zombie) {
post_compiled_method_unload();
}
// Zombie only stuff
if (state == zombie) {
VTune::delete_nmethod(this);
}
// Check whether method got unloaded at a safepoint before this,
// if so we can skip the flushing steps below
if (method() == NULL) return true;
// Remove nmethod from method.
// We need to check if both the _code and _from_compiled_code_entry_point
// refer to this nmethod because there is a race in setting these two fields
// in methodOop as seen in bugid 4947125.
// If the vep() points to the zombie nmethod, the memory for the nmethod
// could be flushed and the compiler and vtable stubs could still call
// through it.
if (method()->code() == this ||
method()->from_compiled_entry() == verified_entry_point()) {
HandleMark hm;
method()->clear_code();
}
return true;
}
......@@ -2109,7 +2054,6 @@ address nmethod::continuation_for_implicit_exception(address pc) {
void nmethod_init() {
// make sure you didn't forget to adjust the filler fields
assert(sizeof(nmFlags) <= 4, "nmFlags occupies more than a word");
assert(sizeof(nmethod) % oopSize == 0, "nmethod size must be multiple of a word");
}
......@@ -2345,7 +2289,6 @@ void nmethod::print() const {
tty->print("((nmethod*) "INTPTR_FORMAT ") ", this);
tty->print(" for method " INTPTR_FORMAT , (address)method());
tty->print(" { ");
if (version()) tty->print("v%d ", version());
if (is_in_use()) tty->print("in_use ");
if (is_not_entrant()) tty->print("not_entrant ");
if (is_zombie()) tty->print("zombie ");
......
......@@ -78,29 +78,8 @@ class PcDescCache VALUE_OBJ_CLASS_SPEC {
// nmethods (native methods) are the compiled code versions of Java methods.
struct nmFlags {
friend class VMStructs;
unsigned int version:8; // version number (0 = first version)
unsigned int age:4; // age (in # of sweep steps)
unsigned int state:2; // {alive, zombie, unloaded)
unsigned int isUncommonRecompiled:1; // recompiled because of uncommon trap?
unsigned int isToBeRecompiled:1; // to be recompiled as soon as it matures
unsigned int hasFlushedDependencies:1; // Used for maintenance of dependencies
unsigned int markedForReclamation:1; // Used by NMethodSweeper
unsigned int has_unsafe_access:1; // May fault due to unsafe access.
unsigned int has_method_handle_invokes:1; // Has this method MethodHandle invokes?
unsigned int speculatively_disconnected:1; // Marked for potential unload
void clear();
};
// A nmethod contains:
//
// An nmethod contains:
// - header (the nmethod structure)
// [Relocation]
// - relocation information
......@@ -131,8 +110,6 @@ class nmethod : public CodeBlob {
friend class CodeCache; // non-perm oops
private:
// Shared fields for all nmethod's
static int _zombie_instruction_size;
methodOop _method;
int _entry_bci; // != InvocationEntryBci if this nmethod is an on-stack replacement method
jmethodID _jmethod_id; // Cache of method()->jmethod_id()
......@@ -147,6 +124,11 @@ class nmethod : public CodeBlob {
AbstractCompiler* _compiler; // The compiler which compiled this nmethod
// offsets for entry points
address _entry_point; // entry point with class check
address _verified_entry_point; // entry point without class check
address _osr_entry_point; // entry point for on stack replacement
// Offsets for different nmethod parts
int _exception_offset;
// All deoptee's will resume execution at this location described by
......@@ -175,23 +157,31 @@ class nmethod : public CodeBlob {
// pc during a deopt.
int _orig_pc_offset;
int _compile_id; // which compilation made this nmethod
int _comp_level; // compilation level
int _compile_id; // which compilation made this nmethod
int _comp_level; // compilation level
// offsets for entry points
address _entry_point; // entry point with class check
address _verified_entry_point; // entry point without class check
address _osr_entry_point; // entry point for on stack replacement
// protected by CodeCache_lock
bool _has_flushed_dependencies; // Used for maintenance of dependencies (CodeCache_lock)
bool _speculatively_disconnected; // Marked for potential unload
bool _marked_for_reclamation; // Used by NMethodSweeper (set only by sweeper)
bool _marked_for_deoptimization; // Used for stack deoptimization
// used by jvmti to track if an unload event has been posted for this nmethod.
bool _unload_reported;
// set during construction
unsigned int _has_unsafe_access:1; // May fault due to unsafe access.
unsigned int _has_method_handle_invokes:1; // Has this method MethodHandle invokes?
// Protected by Patching_lock
unsigned char _state; // {alive, not_entrant, zombie, unloaded)
nmFlags flags; // various flags to keep track of nmethod state
bool _markedForDeoptimization; // Used for stack deoptimization
enum { alive = 0,
not_entrant = 1, // uncommon trap has happened but activations may still exist
zombie = 2,
unloaded = 3 };
// used by jvmti to track if an unload event has been posted for this nmethod.
bool _unload_reported;
jbyte _scavenge_root_state;
......@@ -270,15 +260,15 @@ class nmethod : public CodeBlob {
bool make_not_entrant_or_zombie(unsigned int state);
void inc_decompile_count();
// used to check that writes to nmFlags are done consistently.
static void check_safepoint() PRODUCT_RETURN;
// Used to manipulate the exception cache
void add_exception_cache_entry(ExceptionCache* new_entry);
ExceptionCache* exception_cache_entry_for_exception(Handle exception);
// Inform external interfaces that a compiled method has been unloaded
inline void post_compiled_method_unload();
void post_compiled_method_unload();
// Initailize fields to their default values
void init_defaults();
public:
// create nmethod with entry_bci
......@@ -393,11 +383,11 @@ class nmethod : public CodeBlob {
address verified_entry_point() const { return _verified_entry_point; } // if klass is correct
// flag accessing and manipulation
bool is_in_use() const { return flags.state == alive; }
bool is_alive() const { return flags.state == alive || flags.state == not_entrant; }
bool is_not_entrant() const { return flags.state == not_entrant; }
bool is_zombie() const { return flags.state == zombie; }
bool is_unloaded() const { return flags.state == unloaded; }
bool is_in_use() const { return _state == alive; }
bool is_alive() const { return _state == alive || _state == not_entrant; }
bool is_not_entrant() const { return _state == not_entrant; }
bool is_zombie() const { return _state == zombie; }
bool is_unloaded() const { return _state == unloaded; }
// Make the nmethod non entrant. The nmethod will continue to be
// alive. It is used when an uncommon trap happens. Returns true
......@@ -410,37 +400,33 @@ class nmethod : public CodeBlob {
bool unload_reported() { return _unload_reported; }
void set_unload_reported() { _unload_reported = true; }
bool is_marked_for_deoptimization() const { return _markedForDeoptimization; }
void mark_for_deoptimization() { _markedForDeoptimization = true; }
bool is_marked_for_deoptimization() const { return _marked_for_deoptimization; }
void mark_for_deoptimization() { _marked_for_deoptimization = true; }
void make_unloaded(BoolObjectClosure* is_alive, oop cause);
bool has_dependencies() { return dependencies_size() != 0; }
void flush_dependencies(BoolObjectClosure* is_alive);
bool has_flushed_dependencies() { return flags.hasFlushedDependencies; }
void set_has_flushed_dependencies() {
bool has_flushed_dependencies() { return _has_flushed_dependencies; }
void set_has_flushed_dependencies() {
assert(!has_flushed_dependencies(), "should only happen once");
flags.hasFlushedDependencies = 1;
_has_flushed_dependencies = 1;
}
bool is_marked_for_reclamation() const { return flags.markedForReclamation; }
void mark_for_reclamation() { flags.markedForReclamation = 1; }
void unmark_for_reclamation() { flags.markedForReclamation = 0; }
bool is_marked_for_reclamation() const { return _marked_for_reclamation; }
void mark_for_reclamation() { _marked_for_reclamation = 1; }
bool has_unsafe_access() const { return flags.has_unsafe_access; }
void set_has_unsafe_access(bool z) { flags.has_unsafe_access = z; }
bool has_unsafe_access() const { return _has_unsafe_access; }
void set_has_unsafe_access(bool z) { _has_unsafe_access = z; }
bool has_method_handle_invokes() const { return flags.has_method_handle_invokes; }
void set_has_method_handle_invokes(bool z) { flags.has_method_handle_invokes = z; }
bool has_method_handle_invokes() const { return _has_method_handle_invokes; }
void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; }
bool is_speculatively_disconnected() const { return flags.speculatively_disconnected; }
void set_speculatively_disconnected(bool z) { flags.speculatively_disconnected = z; }
bool is_speculatively_disconnected() const { return _speculatively_disconnected; }
void set_speculatively_disconnected(bool z) { _speculatively_disconnected = z; }
int comp_level() const { return _comp_level; }
int version() const { return flags.version; }
void set_version(int v);
// Support for oops in scopes and relocs:
// Note: index 0 is reserved for null.
oop oop_at(int index) const { return index == 0 ? (oop) NULL: *oop_addr_at(index); }
......
/*
* Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2010, 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
......@@ -50,7 +50,6 @@ void* VtableStub::operator new(size_t size, int code_size) {
}
_chunk = blob->instructions_begin();
_chunk_end = _chunk + bytes;
VTune::register_stub("vtable stub", _chunk, _chunk_end);
Forte::register_stub("vtable stub", _chunk, _chunk_end);
// Notify JVMTI about this stub. The event will be recorded by the enclosing
// JvmtiDynamicCodeEventCollector and posted when this thread has released
......
......@@ -89,6 +89,21 @@ adlcVMDeps.hpp allocation.hpp
allocation.hpp c2_globals.hpp
bcEscapeAnalyzer.cpp bcEscapeAnalyzer.hpp
bcEscapeAnalyzer.cpp bitMap.inline.hpp
bcEscapeAnalyzer.cpp bytecode.hpp
bcEscapeAnalyzer.cpp ciConstant.hpp
bcEscapeAnalyzer.cpp ciField.hpp
bcEscapeAnalyzer.cpp ciMethodBlocks.hpp
bcEscapeAnalyzer.cpp ciStreams.hpp
bcEscapeAnalyzer.hpp allocation.hpp
bcEscapeAnalyzer.hpp ciMethod.hpp
bcEscapeAnalyzer.hpp ciMethodData.hpp
bcEscapeAnalyzer.hpp dependencies.hpp
bcEscapeAnalyzer.hpp growableArray.hpp
bcEscapeAnalyzer.hpp vectset.hpp
block.cpp allocation.inline.hpp
block.cpp block.hpp
block.cpp cfgnode.hpp
......@@ -239,6 +254,7 @@ chaitin_<os_family>.cpp machnode.hpp
ciEnv.cpp compileLog.hpp
ciEnv.cpp runtime.hpp
ciMethod.cpp bcEscapeAnalyzer.hpp
ciMethod.cpp ciTypeFlow.hpp
ciMethod.cpp methodOop.hpp
......
......@@ -301,20 +301,6 @@ barrierSet.hpp oopsHierarchy.hpp
barrierSet.inline.hpp barrierSet.hpp
barrierSet.inline.hpp cardTableModRefBS.hpp
bcEscapeAnalyzer.cpp bcEscapeAnalyzer.hpp
bcEscapeAnalyzer.cpp bitMap.inline.hpp
bcEscapeAnalyzer.cpp bytecode.hpp
bcEscapeAnalyzer.cpp ciConstant.hpp
bcEscapeAnalyzer.cpp ciField.hpp
bcEscapeAnalyzer.cpp ciMethodBlocks.hpp
bcEscapeAnalyzer.cpp ciStreams.hpp
bcEscapeAnalyzer.hpp allocation.hpp
bcEscapeAnalyzer.hpp ciMethod.hpp
bcEscapeAnalyzer.hpp ciMethodData.hpp
bcEscapeAnalyzer.hpp dependencies.hpp
bcEscapeAnalyzer.hpp growableArray.hpp
biasedLocking.cpp biasedLocking.hpp
biasedLocking.cpp klass.inline.hpp
biasedLocking.cpp markOop.hpp
......@@ -665,7 +651,6 @@ ciKlassKlass.hpp ciSymbol.hpp
ciMethod.cpp abstractCompiler.hpp
ciMethod.cpp allocation.inline.hpp
ciMethod.cpp bcEscapeAnalyzer.hpp
ciMethod.cpp bitMap.inline.hpp
ciMethod.cpp ciCallProfile.hpp
ciMethod.cpp ciExceptionHandler.hpp
......@@ -964,7 +949,6 @@ classLoader.cpp threadService.hpp
classLoader.cpp timer.hpp
classLoader.cpp universe.inline.hpp
classLoader.cpp vmSymbols.hpp
classLoader.cpp vtune.hpp
classLoader.hpp classFileParser.hpp
classLoader.hpp perfData.hpp
......@@ -1004,7 +988,6 @@ codeBlob.cpp relocInfo.hpp
codeBlob.cpp safepoint.hpp
codeBlob.cpp sharedRuntime.hpp
codeBlob.cpp vframe.hpp
codeBlob.cpp vtune.hpp
codeBlob.hpp codeBuffer.hpp
codeBlob.hpp frame.hpp
......@@ -2167,7 +2150,6 @@ interpreter.cpp sharedRuntime.hpp
interpreter.cpp stubRoutines.hpp
interpreter.cpp templateTable.hpp
interpreter.cpp timer.hpp
interpreter.cpp vtune.hpp
interpreter.hpp cppInterpreter.hpp
interpreter.hpp stubs.hpp
......@@ -2323,7 +2305,6 @@ java.cpp universe.hpp
java.cpp vmError.hpp
java.cpp vm_operations.hpp
java.cpp vm_version_<arch>.hpp
java.cpp vtune.hpp
java.hpp os.hpp
......@@ -3050,7 +3031,6 @@ nmethod.cpp nmethod.hpp
nmethod.cpp scopeDesc.hpp
nmethod.cpp sharedRuntime.hpp
nmethod.cpp sweeper.hpp
nmethod.cpp vtune.hpp
nmethod.cpp xmlstream.hpp
nmethod.hpp codeBlob.hpp
......@@ -3773,7 +3753,6 @@ sharedRuntime.cpp vframeArray.hpp
sharedRuntime.cpp vmSymbols.hpp
sharedRuntime.cpp vmreg_<arch>.inline.hpp
sharedRuntime.cpp vtableStubs.hpp
sharedRuntime.cpp vtune.hpp
sharedRuntime.cpp xmlstream.hpp
sharedRuntime.hpp allocation.hpp
......@@ -3937,7 +3916,6 @@ stubCodeGenerator.cpp disassembler.hpp
stubCodeGenerator.cpp forte.hpp
stubCodeGenerator.cpp oop.inline.hpp
stubCodeGenerator.cpp stubCodeGenerator.hpp
stubCodeGenerator.cpp vtune.hpp
stubCodeGenerator.hpp allocation.hpp
stubCodeGenerator.hpp assembler.hpp
......@@ -4458,7 +4436,6 @@ universe.cpp universe.hpp
universe.cpp universe.inline.hpp
universe.cpp vmSymbols.hpp
universe.cpp vm_operations.hpp
universe.cpp vtune.hpp
universe.hpp growableArray.hpp
universe.hpp handles.hpp
......@@ -4721,7 +4698,6 @@ vtableStubs.cpp mutexLocker.hpp
vtableStubs.cpp resourceArea.hpp
vtableStubs.cpp sharedRuntime.hpp
vtableStubs.cpp vtableStubs.hpp
vtableStubs.cpp vtune.hpp
vtableStubs.hpp allocation.hpp
......@@ -4735,11 +4711,6 @@ vtableStubs_<arch_model>.cpp sharedRuntime.hpp
vtableStubs_<arch_model>.cpp vmreg_<arch>.inline.hpp
vtableStubs_<arch_model>.cpp vtableStubs.hpp
vtune.hpp allocation.hpp
vtune_<os_family>.cpp interpreter.hpp
vtune_<os_family>.cpp vtune.hpp
watermark.hpp allocation.hpp
watermark.hpp globalDefinitions.hpp
......
......@@ -99,11 +99,6 @@ void interpreter_init() {
#endif // PRODUCT
// need to hit every safepoint in order to call zapping routine
// register the interpreter
VTune::register_stub(
"Interpreter",
AbstractInterpreter::code()->code_start(),
AbstractInterpreter::code()->code_end()
);
Forte::register_stub(
"Interpreter",
AbstractInterpreter::code()->code_start(),
......
......@@ -343,7 +343,8 @@ bool Parse::can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass* kl
// being initialized. Uncommon-trap for not-initialized static or
// v-calls. Let interface calls happen.
ciInstanceKlass* holder_klass = dest_method->holder();
if (!holder_klass->is_initialized() &&
if (!holder_klass->is_being_initialized() &&
!holder_klass->is_initialized() &&
!holder_klass->is_interface()) {
uncommon_trap(Deoptimization::Reason_uninitialized,
Deoptimization::Action_reinterpret,
......
......@@ -480,6 +480,7 @@ class Parse : public GraphKit {
bool push_constant(ciConstant con, bool require_constant = false);
// implementation of object creation bytecodes
void emit_guard_for_new(ciInstanceKlass* klass);
void do_new();
void do_newarray(BasicType elemtype);
void do_anewarray();
......
/*
* Copyright (c) 1998, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2010, 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
......@@ -197,6 +197,43 @@ void Parse::array_store_check() {
}
void Parse::emit_guard_for_new(ciInstanceKlass* klass) {
// Emit guarded new
// if (klass->_init_thread != current_thread ||
// klass->_init_state != being_initialized)
// uncommon_trap
Node* cur_thread = _gvn.transform( new (C, 1) ThreadLocalNode() );
Node* merge = new (C, 3) RegionNode(3);
_gvn.set_type(merge, Type::CONTROL);
Node* kls = makecon(TypeKlassPtr::make(klass));
Node* init_thread_offset = _gvn.MakeConX(instanceKlass::init_thread_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes());
Node* adr_node = basic_plus_adr(kls, kls, init_thread_offset);
Node* init_thread = make_load(NULL, adr_node, TypeRawPtr::BOTTOM, T_ADDRESS);
Node *tst = Bool( CmpP( init_thread, cur_thread), BoolTest::eq);
IfNode* iff = create_and_map_if(control(), tst, PROB_ALWAYS, COUNT_UNKNOWN);
set_control(IfTrue(iff));
merge->set_req(1, IfFalse(iff));
Node* init_state_offset = _gvn.MakeConX(instanceKlass::init_state_offset_in_bytes() + klassOopDesc::klass_part_offset_in_bytes());
adr_node = basic_plus_adr(kls, kls, init_state_offset);
Node* init_state = make_load(NULL, adr_node, TypeInt::INT, T_INT);
Node* being_init = _gvn.intcon(instanceKlass::being_initialized);
tst = Bool( CmpI( init_state, being_init), BoolTest::eq);
iff = create_and_map_if(control(), tst, PROB_ALWAYS, COUNT_UNKNOWN);
set_control(IfTrue(iff));
merge->set_req(2, IfFalse(iff));
PreserveJVMState pjvms(this);
record_for_igvn(merge);
set_control(merge);
uncommon_trap(Deoptimization::Reason_uninitialized,
Deoptimization::Action_reinterpret,
klass);
}
//------------------------------do_new-----------------------------------------
void Parse::do_new() {
kill_dead_locals();
......@@ -206,7 +243,7 @@ void Parse::do_new() {
assert(will_link, "_new: typeflow responsibility");
// Should initialize, or throw an InstantiationError?
if (!klass->is_initialized() ||
if (!klass->is_initialized() && !klass->is_being_initialized() ||
klass->is_abstract() || klass->is_interface() ||
klass->name() == ciSymbol::java_lang_Class() ||
iter().is_unresolved_klass()) {
......@@ -215,6 +252,9 @@ void Parse::do_new() {
klass);
return;
}
if (klass->is_being_initialized()) {
emit_guard_for_new(klass);
}
Node* kls = makecon(TypeKlassPtr::make(klass));
Node* obj = new_instance(kls);
......
......@@ -118,7 +118,6 @@ void CodeBlobCollector::do_blob(CodeBlob* cb) {
for (int i=0; i<_global_code_blobs->length(); i++) {
JvmtiCodeBlobDesc* scb = _global_code_blobs->at(i);
if (addr == scb->code_begin()) {
ShouldNotReachHere();
return;
}
}
......@@ -206,11 +205,11 @@ jvmtiError JvmtiCodeBlobEvents::generate_compiled_method_load_events(JvmtiEnv* e
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
nmethod* current = CodeCache::first_nmethod();
while (current != NULL) {
// Lock the nmethod so it can't be freed
nmethodLocker nml(current);
// Only notify for live nmethods
if (current->is_alive()) {
// Lock the nmethod so it can't be freed
nmethodLocker nml(current);
// Don't hold the lock over the notify or jmethodID creation
MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
current->get_and_cache_jmethod_id();
......
......@@ -2541,9 +2541,6 @@ class CommandLineFlags {
"Enable String cache capabilities on String.java") \
\
/* statistics */ \
develop(bool, UseVTune, false, \
"enable support for Intel's VTune profiler") \
\
develop(bool, CountCompiledCalls, false, \
"counts method invocations") \
\
......
......@@ -34,7 +34,6 @@ void perfMemory_init();
// Initialization done by Java thread in init_globals()
void management_init();
void vtune_init();
void bytecodes_init();
void classLoader_init();
void codeCache_init();
......@@ -82,7 +81,6 @@ void vm_init_globals() {
jint init_globals() {
HandleMark hm;
management_init();
vtune_init();
bytecodes_init();
classLoader_init();
codeCache_init();
......
/*
* Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2010, 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
......@@ -432,8 +432,6 @@ void before_exit(JavaThread * thread) {
print_statistics();
Universe::heap()->print_tracing_info();
VTune::exit();
{ MutexLocker ml(BeforeExit_lock);
_before_exit_status = BEFORE_EXIT_DONE;
BeforeExit_lock->notify_all();
......
......@@ -2251,7 +2251,6 @@ AdapterHandlerEntry* AdapterHandlerLibrary::get_adapter(methodHandle method) {
B->name(),
fingerprint->as_string(),
B->instructions_begin());
VTune::register_stub(blob_id, B->instructions_begin(), B->instructions_end());
Forte::register_stub(blob_id, B->instructions_begin(), B->instructions_end());
if (JvmtiExport::should_post_dynamic_code_generated()) {
......
/*
* Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2010, 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
......@@ -132,7 +132,6 @@ StubCodeMark::~StubCodeMark() {
_cdesc->set_end(_cgen->assembler()->pc());
assert(StubCodeDesc::_list == _cdesc, "expected order on list");
_cgen->stub_epilog(_cdesc);
VTune::register_stub(_cdesc->name(), _cdesc->begin(), _cdesc->end());
Forte::register_stub(_cdesc->name(), _cdesc->begin(), _cdesc->end());
if (JvmtiExport::should_post_dynamic_code_generated()) {
......
/*
* Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2010, 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
......@@ -27,14 +27,15 @@
long NMethodSweeper::_traversals = 0; // No. of stack traversals performed
nmethod* NMethodSweeper::_current = NULL; // Current nmethod
int NMethodSweeper::_seen = 0 ; // No. of blobs we have currently processed in current pass of CodeCache
int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass
int NMethodSweeper::_seen = 0 ; // No. of nmethods we have currently processed in current pass of CodeCache
volatile int NMethodSweeper::_invocations = 0; // No. of invocations left until we are completed with this pass
volatile int NMethodSweeper::_sweep_started = 0; // Whether a sweep is in progress.
jint NMethodSweeper::_locked_seen = 0;
jint NMethodSweeper::_not_entrant_seen_on_stack = 0;
bool NMethodSweeper::_rescan = false;
bool NMethodSweeper::_do_sweep = false;
jint NMethodSweeper::_sweep_started = 0;
bool NMethodSweeper::_was_full = false;
jint NMethodSweeper::_advise_to_sweep = 0;
jlong NMethodSweeper::_last_was_full = 0;
......@@ -108,23 +109,14 @@ void NMethodSweeper::scan_stacks() {
// code cache is filling up
_last_was_full = os::javaTimeMillis();
if (PrintMethodFlushing) {
tty->print_cr("### sweeper: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes, restarting compiler",
CodeCache::nof_blobs(), CodeCache::unallocated_capacity());
}
if (LogCompilation && (xtty != NULL)) {
ttyLocker ttyl;
xtty->begin_elem("restart_compiler live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
CodeCache::nof_blobs(), CodeCache::unallocated_capacity());
xtty->stamp();
xtty->end_elem();
}
log_sweep("restart_compiler");
}
}
}
}
void NMethodSweeper::possibly_sweep() {
assert(JavaThread::current()->thread_state() == _thread_in_vm, "must run in vm mode");
if ((!MethodFlushing) || (!_do_sweep)) return;
if (_invocations > 0) {
......@@ -133,32 +125,31 @@ void NMethodSweeper::possibly_sweep() {
if (old != 0) {
return;
}
sweep_code_cache();
if (_invocations > 0) {
sweep_code_cache();
_invocations--;
}
_sweep_started = 0;
}
_sweep_started = 0;
}
void NMethodSweeper::sweep_code_cache() {
#ifdef ASSERT
jlong sweep_start;
if(PrintMethodFlushing) {
if (PrintMethodFlushing) {
sweep_start = os::javaTimeMillis();
}
#endif
if (PrintMethodFlushing && Verbose) {
tty->print_cr("### Sweep at %d out of %d. Invocations left: %d", _seen, CodeCache::nof_blobs(), _invocations);
}
// We want to visit all nmethods after NmethodSweepFraction invocations.
// If invocation is 1 we do the rest
int todo = CodeCache::nof_blobs();
if (_invocations > 1) {
todo = (CodeCache::nof_blobs() - _seen) / _invocations;
tty->print_cr("### Sweep at %d out of %d. Invocations left: %d", _seen, CodeCache::nof_nmethods(), _invocations);
}
// Compilers may check to sweep more often than stack scans happen,
// don't keep trying once it is all scanned
_invocations--;
// We want to visit all nmethods after NmethodSweepFraction
// invocations so divide the remaining number of nmethods by the
// remaining number of invocations. This is only an estimate since
// the number of nmethods changes during the sweep so the final
// stage must iterate until it there are no more nmethods.
int todo = (CodeCache::nof_nmethods() - _seen) / _invocations;
assert(!SafepointSynchronize::is_at_safepoint(), "should not be in safepoint when we get here");
assert(!CodeCache_lock->owned_by_self(), "just checking");
......@@ -166,11 +157,12 @@ void NMethodSweeper::sweep_code_cache() {
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
for(int i = 0; i < todo && _current != NULL; i++) {
// The last invocation iterates until there are no more nmethods
for (int i = 0; (i < todo || _invocations == 1) && _current != NULL; i++) {
// Since we will give up the CodeCache_lock, always skip ahead to an nmethod.
// Other blobs can be deleted by other threads
// Read next before we potentially delete current
// Since we will give up the CodeCache_lock, always skip ahead
// to the next nmethod. Other blobs can be deleted by other
// threads but nmethods are only reclaimed by the sweeper.
nmethod* next = CodeCache::next_nmethod(_current);
// Now ready to process nmethod and give up CodeCache_lock
......@@ -183,6 +175,8 @@ void NMethodSweeper::sweep_code_cache() {
}
}
assert(_invocations > 1 || _current == NULL, "must have scanned the whole cache");
if (_current == NULL && !_rescan && (_locked_seen || _not_entrant_seen_on_stack)) {
// we've completed a scan without making progress but there were
// nmethods we were unable to process either because they were
......@@ -201,6 +195,10 @@ void NMethodSweeper::sweep_code_cache() {
tty->print_cr("### sweeper: sweep time(%d): " INT64_FORMAT, _invocations, sweep_end - sweep_start);
}
#endif
if (_invocations == 1) {
log_sweep("finished");
}
}
......@@ -223,7 +221,7 @@ void NMethodSweeper::process_nmethod(nmethod *nm) {
if (nm->is_zombie()) {
// If it is first time, we see nmethod then we mark it. Otherwise,
// we reclame it. When we have seen a zombie method twice, we know that
// there are no inline caches that referes to it.
// there are no inline caches that refer to it.
if (nm->is_marked_for_reclamation()) {
assert(!nm->is_locked_by_vm(), "must not flush locked nmethods");
if (PrintMethodFlushing && Verbose) {
......@@ -320,16 +318,8 @@ void NMethodSweeper::handle_full_code_cache(bool is_full) {
jlong curr_interval = now - _last_was_full;
if (curr_interval < max_interval) {
_rescan = true;
if (PrintMethodFlushing) {
tty->print_cr("### handle full too often, turning off compiler");
}
if (LogCompilation && (xtty != NULL)) {
ttyLocker ttyl;
xtty->begin_elem("disable_compiler flushing_interval='" UINT64_FORMAT "' live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
curr_interval/1000, CodeCache::nof_blobs(), CodeCache::unallocated_capacity());
xtty->stamp();
xtty->end_elem();
}
log_sweep("disable_compiler", "flushing_interval='" UINT64_FORMAT "'",
curr_interval/1000);
return;
}
}
......@@ -349,17 +339,7 @@ void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) {
if ((!was_full()) && (is_full)) {
if (!CodeCache::needs_flushing()) {
if (PrintMethodFlushing) {
tty->print_cr("### sweeper: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes, restarting compiler",
CodeCache::nof_blobs(), CodeCache::unallocated_capacity());
}
if (LogCompilation && (xtty != NULL)) {
ttyLocker ttyl;
xtty->begin_elem("restart_compiler live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
CodeCache::nof_blobs(), CodeCache::unallocated_capacity());
xtty->stamp();
xtty->end_elem();
}
log_sweep("restart_compiler");
CompileBroker::set_should_compile_new_jobs(CompileBroker::run_compilation);
return;
}
......@@ -368,17 +348,7 @@ void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) {
// Traverse the code cache trying to dump the oldest nmethods
uint curr_max_comp_id = CompileBroker::get_compilation_id();
uint flush_target = ((curr_max_comp_id - _highest_marked) >> 1) + _highest_marked;
if (PrintMethodFlushing && Verbose) {
tty->print_cr("### Cleaning code cache: Live blobs:" UINT32_FORMAT "/Free code cache:" SIZE_FORMAT " bytes",
CodeCache::nof_blobs(), CodeCache::unallocated_capacity());
}
if (LogCompilation && (xtty != NULL)) {
ttyLocker ttyl;
xtty->begin_elem("start_cleaning_code_cache live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
CodeCache::nof_blobs(), CodeCache::unallocated_capacity());
xtty->stamp();
xtty->end_elem();
}
log_sweep("start_cleaning");
nmethod* nm = CodeCache::alive_nmethod(CodeCache::first());
jint disconnected = 0;
......@@ -411,13 +381,9 @@ void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) {
nm = CodeCache::alive_nmethod(CodeCache::next(nm));
}
if (LogCompilation && (xtty != NULL)) {
ttyLocker ttyl;
xtty->begin_elem("stop_cleaning_code_cache disconnected='" UINT32_FORMAT "' made_not_entrant='" UINT32_FORMAT "' live_blobs='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
disconnected, made_not_entrant, CodeCache::nof_blobs(), CodeCache::unallocated_capacity());
xtty->stamp();
xtty->end_elem();
}
log_sweep("stop_cleaning",
"disconnected='" UINT32_FORMAT "' made_not_entrant='" UINT32_FORMAT "'",
disconnected, made_not_entrant);
// Shut off compiler. Sweeper will start over with a new stack scan and
// traversal cycle and turn it back on if it clears enough space.
......@@ -435,3 +401,38 @@ void NMethodSweeper::speculative_disconnect_nmethods(bool is_full) {
}
#endif
}
// Print out some state information about the current sweep and the
// state of the code cache if it's requested.
void NMethodSweeper::log_sweep(const char* msg, const char* format, ...) {
if (PrintMethodFlushing) {
ttyLocker ttyl;
tty->print("### sweeper: %s ", msg);
if (format != NULL) {
va_list ap;
va_start(ap, format);
tty->vprint(format, ap);
va_end(ap);
}
tty->print_cr(" total_blobs='" UINT32_FORMAT "' nmethods='" UINT32_FORMAT "'"
" adapters='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
CodeCache::nof_blobs(), CodeCache::nof_nmethods(), CodeCache::nof_adapters(), CodeCache::unallocated_capacity());
}
if (LogCompilation && (xtty != NULL)) {
ttyLocker ttyl;
xtty->begin_elem("sweeper state='%s' traversals='" INTX_FORMAT "' ", msg, (intx)traversal_count());
if (format != NULL) {
va_list ap;
va_start(ap, format);
xtty->vprint(format, ap);
va_end(ap);
}
xtty->print(" total_blobs='" UINT32_FORMAT "' nmethods='" UINT32_FORMAT "'"
" adapters='" UINT32_FORMAT "' free_code_cache='" SIZE_FORMAT "'",
CodeCache::nof_blobs(), CodeCache::nof_nmethods(), CodeCache::nof_adapters(), CodeCache::unallocated_capacity());
xtty->stamp();
xtty->end_elem();
}
}
/*
* Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2010, 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
......@@ -31,12 +31,13 @@ class NMethodSweeper : public AllStatic {
static long _traversals; // Stack traversal count
static nmethod* _current; // Current nmethod
static int _seen; // Nof. nmethod we have currently processed in current pass of CodeCache
static int _invocations; // No. of invocations left until we are completed with this pass
static volatile int _invocations; // No. of invocations left until we are completed with this pass
static volatile int _sweep_started; // Flag to control conc sweeper
static bool _rescan; // Indicates that we should do a full rescan of the
// of the code cache looking for work to do.
static bool _do_sweep; // Flag to skip the conc sweep if no stack scan happened
static jint _sweep_started; // Flag to control conc sweeper
static int _locked_seen; // Number of locked nmethods encountered during the scan
static int _not_entrant_seen_on_stack; // Number of not entrant nmethod were are still on stack
......@@ -47,6 +48,9 @@ class NMethodSweeper : public AllStatic {
static long _was_full_traversal; // trav number at last emergency unloading
static void process_nmethod(nmethod *nm);
static void log_sweep(const char* msg, const char* format = NULL, ...);
public:
static long traversal_count() { return _traversals; }
......
......@@ -614,7 +614,6 @@ static inline uint64_t cast_uint64_t(size_t x)
/* NMethods (NOTE: incomplete, but only a little) */ \
/**************************************************/ \
\
static_field(nmethod, _zombie_instruction_size, int) \
nonstatic_field(nmethod, _method, methodOop) \
nonstatic_field(nmethod, _entry_bci, int) \
nonstatic_field(nmethod, _osr_link, nmethod*) \
......
/*
* Copyright (c) 1998, 2007, 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.
*
*/
// Interface to Intel's VTune profiler.
class VTune : AllStatic {
public:
static void create_nmethod(nmethod* nm); // register newly created nmethod
static void delete_nmethod(nmethod* nm); // unregister nmethod before discarding it
static void register_stub(const char* name, address start, address end);
// register internal VM stub
static void start_GC(); // start/end of GC or scavenge
static void end_GC();
static void start_class_load(); // start/end of class loading
static void end_class_load();
static void exit(); // VM exit
};
// helper objects
class VTuneGCMarker : StackObj {
public:
VTuneGCMarker() { VTune::start_GC(); }
~VTuneGCMarker() { VTune::end_GC(); }
};
class VTuneClassLoadMarker : StackObj {
public:
VTuneClassLoadMarker() { VTune::start_class_load(); }
~VTuneClassLoadMarker() { VTune::end_class_load(); }
};
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册