mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-15 08:34:30 +02:00
Merge
This commit is contained in:
commit
f454e5e02c
44 changed files with 925 additions and 179 deletions
|
@ -1767,7 +1767,7 @@ void MacroAssembler::fast_lock(Register objReg, Register boxReg, Register tmpReg
|
|||
// at [FETCH], below, will never observe a biased encoding (*101b).
|
||||
// If this invariant is not held we risk exclusion (safety) failure.
|
||||
if (UseBiasedLocking && !UseOptoBiasInlining) {
|
||||
biased_locking_enter(boxReg, objReg, tmpReg, scrReg, true, DONE_LABEL, NULL, counters);
|
||||
biased_locking_enter(boxReg, objReg, tmpReg, scrReg, false, DONE_LABEL, NULL, counters);
|
||||
}
|
||||
|
||||
#if INCLUDE_RTM_OPT
|
||||
|
|
|
@ -68,7 +68,10 @@
|
|||
// ciMethod::ciMethod
|
||||
//
|
||||
// Loaded method.
|
||||
ciMethod::ciMethod(methodHandle h_m) : ciMetadata(h_m()) {
|
||||
ciMethod::ciMethod(methodHandle h_m, ciInstanceKlass* holder) :
|
||||
ciMetadata(h_m()),
|
||||
_holder(holder)
|
||||
{
|
||||
assert(h_m() != NULL, "no null method");
|
||||
|
||||
// These fields are always filled in in loaded methods.
|
||||
|
@ -124,7 +127,6 @@ ciMethod::ciMethod(methodHandle h_m) : ciMetadata(h_m()) {
|
|||
// generating _signature may allow GC and therefore move m.
|
||||
// These fields are always filled in.
|
||||
_name = env->get_symbol(h_m()->name());
|
||||
_holder = env->get_instance_klass(h_m()->method_holder());
|
||||
ciSymbol* sig_symbol = env->get_symbol(h_m()->signature());
|
||||
constantPoolHandle cpool = h_m()->constants();
|
||||
_signature = new (env->arena()) ciSignature(_holder, cpool, sig_symbol);
|
||||
|
|
|
@ -91,7 +91,7 @@ class ciMethod : public ciMetadata {
|
|||
BCEscapeAnalyzer* _bcea;
|
||||
#endif
|
||||
|
||||
ciMethod(methodHandle h_m);
|
||||
ciMethod(methodHandle h_m, ciInstanceKlass* holder);
|
||||
ciMethod(ciInstanceKlass* holder, ciSymbol* name, ciSymbol* signature, ciInstanceKlass* accessor);
|
||||
|
||||
Method* get_Method() const {
|
||||
|
|
|
@ -239,7 +239,7 @@ void ciObjectFactory::remove_symbols() {
|
|||
ciObject* ciObjectFactory::get(oop key) {
|
||||
ASSERT_IN_VM;
|
||||
|
||||
assert(key == NULL || Universe::heap()->is_in_reserved(key), "must be");
|
||||
assert(Universe::heap()->is_in_reserved(key), "must be");
|
||||
|
||||
NonPermObject* &bucket = find_non_perm(key);
|
||||
if (bucket != NULL) {
|
||||
|
@ -260,10 +260,10 @@ ciObject* ciObjectFactory::get(oop key) {
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciObjectFactory::get
|
||||
// ciObjectFactory::get_metadata
|
||||
//
|
||||
// Get the ciObject corresponding to some oop. If the ciObject has
|
||||
// already been created, it is returned. Otherwise, a new ciObject
|
||||
// Get the ciMetadata corresponding to some Metadata. If the ciMetadata has
|
||||
// already been created, it is returned. Otherwise, a new ciMetadata
|
||||
// is created.
|
||||
ciMetadata* ciObjectFactory::get_metadata(Metadata* key) {
|
||||
ASSERT_IN_VM;
|
||||
|
@ -290,9 +290,9 @@ ciMetadata* ciObjectFactory::get_metadata(Metadata* key) {
|
|||
}
|
||||
#endif
|
||||
if (!is_found_at(index, key, _ci_metadata)) {
|
||||
// The ciObject does not yet exist. Create it and insert it
|
||||
// The ciMetadata does not yet exist. Create it and insert it
|
||||
// into the cache.
|
||||
ciMetadata* new_object = create_new_object(key);
|
||||
ciMetadata* new_object = create_new_metadata(key);
|
||||
init_ident_of(new_object);
|
||||
assert(new_object->is_metadata(), "must be");
|
||||
|
||||
|
@ -344,15 +344,28 @@ ciObject* ciObjectFactory::create_new_object(oop o) {
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// ciObjectFactory::create_new_object
|
||||
// ciObjectFactory::create_new_metadata
|
||||
//
|
||||
// Create a new ciObject from a Metadata*.
|
||||
// Create a new ciMetadata from a Metadata*.
|
||||
//
|
||||
// Implementation note: this functionality could be virtual behavior
|
||||
// of the oop itself. For now, we explicitly marshal the object.
|
||||
ciMetadata* ciObjectFactory::create_new_object(Metadata* o) {
|
||||
// Implementation note: in order to keep Metadata live, an auxiliary ciObject
|
||||
// is used, which points to it's holder.
|
||||
ciMetadata* ciObjectFactory::create_new_metadata(Metadata* o) {
|
||||
EXCEPTION_CONTEXT;
|
||||
|
||||
// Hold metadata from unloading by keeping it's holder alive.
|
||||
if (_initialized && o->is_klass()) {
|
||||
Klass* holder = ((Klass*)o);
|
||||
if (holder->oop_is_instance() && InstanceKlass::cast(holder)->is_anonymous()) {
|
||||
// Though ciInstanceKlass records class loader oop, it's not enough to keep
|
||||
// VM anonymous classes alive (loader == NULL). Klass holder should be used instead.
|
||||
// It is enough to record a ciObject, since cached elements are never removed
|
||||
// during ciObjectFactory lifetime. ciObjectFactory itself is created for
|
||||
// every compilation and lives for the whole duration of the compilation.
|
||||
ciObject* h = get(holder->klass_holder());
|
||||
}
|
||||
}
|
||||
|
||||
if (o->is_klass()) {
|
||||
KlassHandle h_k(THREAD, (Klass*)o);
|
||||
Klass* k = (Klass*)o;
|
||||
|
@ -365,14 +378,16 @@ ciMetadata* ciObjectFactory::create_new_object(Metadata* o) {
|
|||
}
|
||||
} else if (o->is_method()) {
|
||||
methodHandle h_m(THREAD, (Method*)o);
|
||||
return new (arena()) ciMethod(h_m);
|
||||
ciEnv *env = CURRENT_THREAD_ENV;
|
||||
ciInstanceKlass* holder = env->get_instance_klass(h_m()->method_holder());
|
||||
return new (arena()) ciMethod(h_m, holder);
|
||||
} else if (o->is_methodData()) {
|
||||
// Hold methodHandle alive - might not be necessary ???
|
||||
methodHandle h_m(THREAD, ((MethodData*)o)->method());
|
||||
return new (arena()) ciMethodData((MethodData*)o);
|
||||
}
|
||||
|
||||
// The oop is of some type not supported by the compiler interface.
|
||||
// The Metadata* is of some type not supported by the compiler interface.
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
|
@ -701,7 +716,7 @@ static ciObjectFactory::NonPermObject* emptyBucket = NULL;
|
|||
// If there is no entry in the cache corresponding to this oop, return
|
||||
// the null tail of the bucket into which the oop should be inserted.
|
||||
ciObjectFactory::NonPermObject* &ciObjectFactory::find_non_perm(oop key) {
|
||||
assert(Universe::heap()->is_in_reserved_or_null(key), "must be");
|
||||
assert(Universe::heap()->is_in_reserved(key), "must be");
|
||||
ciMetadata* klass = get_metadata(key->klass());
|
||||
NonPermObject* *bp = &_non_perm_bucket[(unsigned) klass->hash() % NON_PERM_BUCKETS];
|
||||
for (NonPermObject* p; (p = (*bp)) != NULL; bp = &p->next()) {
|
||||
|
|
|
@ -73,7 +73,7 @@ private:
|
|||
void insert(int index, ciMetadata* obj, GrowableArray<ciMetadata*>* objects);
|
||||
|
||||
ciObject* create_new_object(oop o);
|
||||
ciMetadata* create_new_object(Metadata* o);
|
||||
ciMetadata* create_new_metadata(Metadata* o);
|
||||
|
||||
void ensure_metadata_alive(ciMetadata* m);
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
#include "c1/c1_Runtime1.hpp"
|
||||
#endif
|
||||
|
||||
unsigned int align_code_offset(int offset) {
|
||||
unsigned int CodeBlob::align_code_offset(int offset) {
|
||||
// align the size to CodeEntryAlignment
|
||||
return
|
||||
((offset + (int)CodeHeap::header_size() + (CodeEntryAlignment-1)) & ~(CodeEntryAlignment-1))
|
||||
|
|
|
@ -83,6 +83,7 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
|
|||
public:
|
||||
// Returns the space needed for CodeBlob
|
||||
static unsigned int allocation_size(CodeBuffer* cb, int header_size);
|
||||
static unsigned int align_code_offset(int offset);
|
||||
|
||||
// Creation
|
||||
// a) simple CodeBlob
|
||||
|
@ -207,7 +208,7 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
class WhiteBox;
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
// BufferBlob: used to hold non-relocatable machine code such as the interpreter, stubroutines, etc.
|
||||
|
||||
|
@ -215,6 +216,7 @@ class BufferBlob: public CodeBlob {
|
|||
friend class VMStructs;
|
||||
friend class AdapterBlob;
|
||||
friend class MethodHandlesAdapterBlob;
|
||||
friend class WhiteBox;
|
||||
|
||||
private:
|
||||
// Creation support
|
||||
|
|
|
@ -305,7 +305,7 @@ void CodeCache::add_heap(ReservedSpace rs, const char* name, size_t size_initial
|
|||
MemoryService::add_code_heap_memory_pool(heap, name);
|
||||
}
|
||||
|
||||
CodeHeap* CodeCache::get_code_heap(CodeBlob* cb) {
|
||||
CodeHeap* CodeCache::get_code_heap(const CodeBlob* cb) {
|
||||
assert(cb != NULL, "CodeBlob is null");
|
||||
FOR_ALL_HEAPS(heap) {
|
||||
if ((*heap)->contains(cb)) {
|
||||
|
|
|
@ -77,6 +77,7 @@ class DepChange;
|
|||
class CodeCache : AllStatic {
|
||||
friend class VMStructs;
|
||||
friend class NMethodIterator;
|
||||
friend class WhiteBox;
|
||||
private:
|
||||
// CodeHeaps of the cache
|
||||
static GrowableArray<CodeHeap*>* _heaps;
|
||||
|
@ -98,7 +99,7 @@ class CodeCache : AllStatic {
|
|||
static void initialize_heaps(); // Initializes the CodeHeaps
|
||||
// Creates a new heap with the given name and size, containing CodeBlobs of the given type
|
||||
static void add_heap(ReservedSpace rs, const char* name, size_t size_initial, int code_blob_type);
|
||||
static CodeHeap* get_code_heap(CodeBlob* cb); // Returns the CodeHeap for the given CodeBlob
|
||||
static CodeHeap* get_code_heap(const CodeBlob* cb); // Returns the CodeHeap for the given CodeBlob
|
||||
static CodeHeap* get_code_heap(int code_blob_type); // Returns the CodeHeap for the given CodeBlobType
|
||||
// Returns the name of the VM option to set the size of the corresponding CodeHeap
|
||||
static const char* get_code_heap_flag_name(int code_blob_type);
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "oops/method.hpp"
|
||||
#include "oops/oop.inline.hpp"
|
||||
#include "prims/nativeLookup.hpp"
|
||||
#include "prims/whitebox.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/atomic.inline.hpp"
|
||||
#include "runtime/compilationPolicy.hpp"
|
||||
|
@ -1963,6 +1964,12 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
|
|||
if (comp == NULL) {
|
||||
ci_env.record_method_not_compilable("no compiler", !TieredCompilation);
|
||||
} else {
|
||||
if (WhiteBoxAPI && WhiteBox::compilation_locked) {
|
||||
MonitorLockerEx locker(Compilation_lock, Mutex::_no_safepoint_check_flag);
|
||||
while (WhiteBox::compilation_locked) {
|
||||
locker.wait(Mutex::_no_safepoint_check_flag);
|
||||
}
|
||||
}
|
||||
comp->compile_method(&ci_env, target, osr_bci);
|
||||
}
|
||||
|
||||
|
|
|
@ -401,8 +401,10 @@ class Bytecodes: AllStatic {
|
|||
static bool is_astore (Code code) { return (code == _astore || code == _astore_0 || code == _astore_1
|
||||
|| code == _astore_2 || code == _astore_3); }
|
||||
|
||||
static bool is_const (Code code) { return (_aconst_null <= code && code <= _ldc2_w); }
|
||||
static bool is_zero_const (Code code) { return (code == _aconst_null || code == _iconst_0
|
||||
|| code == _fconst_0 || code == _dconst_0); }
|
||||
static bool is_return (Code code) { return (_ireturn <= code && code <= _return); }
|
||||
static bool is_invoke (Code code) { return (_invokevirtual <= code && code <= _invokedynamic); }
|
||||
static bool has_receiver (Code code) { assert(is_invoke(code), ""); return code == _invokevirtual ||
|
||||
code == _invokespecial ||
|
||||
|
|
|
@ -588,6 +588,15 @@ bool Method::is_accessor() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Method::is_constant_getter() const {
|
||||
int last_index = code_size() - 1;
|
||||
// Check if the first 1-3 bytecodes are a constant push
|
||||
// and the last bytecode is a return.
|
||||
return (2 <= code_size() && code_size() <= 4 &&
|
||||
Bytecodes::is_const(java_code_at(0)) &&
|
||||
Bytecodes::length_for(java_code_at(0)) == last_index &&
|
||||
Bytecodes::is_return(java_code_at(last_index)));
|
||||
}
|
||||
|
||||
bool Method::is_initializer() const {
|
||||
return name() == vmSymbols::object_initializer_name() || is_static_initializer();
|
||||
|
|
|
@ -595,6 +595,9 @@ class Method : public Metadata {
|
|||
// returns true if the method is an accessor function (setter/getter).
|
||||
bool is_accessor() const;
|
||||
|
||||
// returns true if the method does nothing but return a constant of primitive type
|
||||
bool is_constant_getter() const;
|
||||
|
||||
// returns true if the method is an initializer (<init> or <clinit>).
|
||||
bool is_initializer() const;
|
||||
|
||||
|
|
|
@ -1134,7 +1134,7 @@ void MethodData::init() {
|
|||
_tenure_traps = 0;
|
||||
_num_loops = 0;
|
||||
_num_blocks = 0;
|
||||
_would_profile = true;
|
||||
_would_profile = unknown;
|
||||
|
||||
#if INCLUDE_RTM_OPT
|
||||
_rtm_state = NoRTM; // No RTM lock eliding by default
|
||||
|
|
|
@ -2096,7 +2096,8 @@ private:
|
|||
short _num_loops;
|
||||
short _num_blocks;
|
||||
// Does this method contain anything worth profiling?
|
||||
bool _would_profile;
|
||||
enum WouldProfile {unknown, no_profile, profile};
|
||||
WouldProfile _would_profile;
|
||||
|
||||
// Size of _data array in bytes. (Excludes header and extra_data fields.)
|
||||
int _data_size;
|
||||
|
@ -2270,8 +2271,8 @@ public:
|
|||
}
|
||||
#endif
|
||||
|
||||
void set_would_profile(bool p) { _would_profile = p; }
|
||||
bool would_profile() const { return _would_profile; }
|
||||
void set_would_profile(bool p) { _would_profile = p ? profile : no_profile; }
|
||||
bool would_profile() const { return _would_profile != no_profile; }
|
||||
|
||||
int num_loops() const { return _num_loops; }
|
||||
void set_num_loops(int n) { _num_loops = n; }
|
||||
|
|
|
@ -794,7 +794,7 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) {
|
|||
Node* ex_klass_node = NULL;
|
||||
if (has_ex_handler() && !ex_type->klass_is_exact()) {
|
||||
Node* p = basic_plus_adr( ex_node, ex_node, oopDesc::klass_offset_in_bytes());
|
||||
ex_klass_node = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) );
|
||||
ex_klass_node = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT));
|
||||
|
||||
// Compute the exception klass a little more cleverly.
|
||||
// Obvious solution is to simple do a LoadKlass from the 'ex_node'.
|
||||
|
@ -812,7 +812,7 @@ void Parse::catch_inline_exceptions(SafePointNode* ex_map) {
|
|||
continue;
|
||||
}
|
||||
Node* p = basic_plus_adr(ex_in, ex_in, oopDesc::klass_offset_in_bytes());
|
||||
Node* k = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) );
|
||||
Node* k = _gvn.transform( LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT));
|
||||
ex_klass_node->init_req( i, k );
|
||||
}
|
||||
_gvn.set_type(ex_klass_node, TypeKlassPtr::OBJECT);
|
||||
|
|
|
@ -1154,7 +1154,7 @@ Node* GraphKit::load_object_klass(Node* obj) {
|
|||
Node* akls = AllocateNode::Ideal_klass(obj, &_gvn);
|
||||
if (akls != NULL) return akls;
|
||||
Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes());
|
||||
return _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), k_adr, TypeInstPtr::KLASS) );
|
||||
return _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), k_adr, TypeInstPtr::KLASS));
|
||||
}
|
||||
|
||||
//-------------------------load_array_length-----------------------------------
|
||||
|
@ -2615,7 +2615,7 @@ Node* Phase::gen_subtype_check(Node* subklass, Node* superklass, Node** ctrl, Me
|
|||
// types load from the super-class display table which is immutable.
|
||||
m = mem->memory_at(C->get_alias_index(gvn->type(p2)->is_ptr()));
|
||||
Node *kmem = might_be_cache ? m : C->immutable_memory();
|
||||
Node *nkls = gvn->transform(LoadKlassNode::make(*gvn, kmem, p2, gvn->type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL));
|
||||
Node *nkls = gvn->transform(LoadKlassNode::make(*gvn, NULL, kmem, p2, gvn->type(p2)->is_ptr(), TypeKlassPtr::OBJECT_OR_NULL));
|
||||
|
||||
// Compile speed common case: ARE a subtype and we canNOT fail
|
||||
if( superklass == nkls )
|
||||
|
|
|
@ -3345,7 +3345,7 @@ Node* LibraryCallKit::load_klass_from_mirror_common(Node* mirror,
|
|||
if (region == NULL) never_see_null = true;
|
||||
Node* p = basic_plus_adr(mirror, offset);
|
||||
const TypeKlassPtr* kls_type = TypeKlassPtr::OBJECT_OR_NULL;
|
||||
Node* kls = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type));
|
||||
Node* kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeRawPtr::BOTTOM, kls_type));
|
||||
Node* null_ctl = top();
|
||||
kls = null_check_oop(kls, &null_ctl, never_see_null);
|
||||
if (region != NULL) {
|
||||
|
@ -3517,7 +3517,7 @@ bool LibraryCallKit::inline_native_Class_query(vmIntrinsics::ID id) {
|
|||
phi->add_req(makecon(TypeInstPtr::make(env()->Object_klass()->java_mirror())));
|
||||
// If we fall through, it's a plain class. Get its _super.
|
||||
p = basic_plus_adr(kls, in_bytes(Klass::super_offset()));
|
||||
kls = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL));
|
||||
kls = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeRawPtr::BOTTOM, TypeKlassPtr::OBJECT_OR_NULL));
|
||||
null_ctl = top();
|
||||
kls = null_check_oop(kls, &null_ctl);
|
||||
if (null_ctl != top()) {
|
||||
|
@ -3671,7 +3671,7 @@ bool LibraryCallKit::inline_native_subtype_check() {
|
|||
args[which_arg] = arg;
|
||||
|
||||
Node* p = basic_plus_adr(arg, class_klass_offset);
|
||||
Node* kls = LoadKlassNode::make(_gvn, immutable_memory(), p, adr_type, kls_type);
|
||||
Node* kls = LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, adr_type, kls_type);
|
||||
klasses[which_arg] = _gvn.transform(kls);
|
||||
}
|
||||
|
||||
|
|
|
@ -2201,7 +2201,7 @@ void PhaseMacroExpand::expand_lock_node(LockNode *lock) {
|
|||
Node* klass_node = AllocateNode::Ideal_klass(obj, &_igvn);
|
||||
if (klass_node == NULL) {
|
||||
Node* k_adr = basic_plus_adr(obj, oopDesc::klass_offset_in_bytes());
|
||||
klass_node = transform_later( LoadKlassNode::make(_igvn, mem, k_adr, _igvn.type(k_adr)->is_ptr()) );
|
||||
klass_node = transform_later(LoadKlassNode::make(_igvn, NULL, mem, k_adr, _igvn.type(k_adr)->is_ptr()));
|
||||
#ifdef _LP64
|
||||
if (UseCompressedClassPointers && klass_node->is_DecodeNKlass()) {
|
||||
assert(klass_node->in(1)->Opcode() == Op_LoadNKlass, "sanity");
|
||||
|
|
|
@ -529,7 +529,7 @@ Node* PhaseMacroExpand::generate_arraycopy(ArrayCopyNode *ac, AllocateArrayNode*
|
|||
// (At this point we can assume disjoint_bases, since types differ.)
|
||||
int ek_offset = in_bytes(ObjArrayKlass::element_klass_offset());
|
||||
Node* p1 = basic_plus_adr(dest_klass, ek_offset);
|
||||
Node* n1 = LoadKlassNode::make(_igvn, C->immutable_memory(), p1, TypeRawPtr::BOTTOM);
|
||||
Node* n1 = LoadKlassNode::make(_igvn, NULL, C->immutable_memory(), p1, TypeRawPtr::BOTTOM);
|
||||
Node* dest_elem_klass = transform_later(n1);
|
||||
Node* cv = generate_checkcast_arraycopy(&local_ctrl, &local_mem,
|
||||
adr_type,
|
||||
|
|
|
@ -861,6 +861,10 @@ Node *MemNode::Ideal_common_DU_postCCP( PhaseCCP *ccp, Node* n, Node* adr ) {
|
|||
|
||||
|
||||
//=============================================================================
|
||||
// Should LoadNode::Ideal() attempt to remove control edges?
|
||||
bool LoadNode::can_remove_control() const {
|
||||
return true;
|
||||
}
|
||||
uint LoadNode::size_of() const { return sizeof(*this); }
|
||||
uint LoadNode::cmp( const Node &n ) const
|
||||
{ return !Type::cmp( _type, ((LoadNode&)n)._type ); }
|
||||
|
@ -1471,7 +1475,7 @@ Node *LoadNode::split_through_phi(PhaseGVN *phase) {
|
|||
}
|
||||
|
||||
//------------------------------Ideal------------------------------------------
|
||||
// If the load is from Field memory and the pointer is non-null, we can
|
||||
// If the load is from Field memory and the pointer is non-null, it might be possible to
|
||||
// zero out the control input.
|
||||
// If the offset is constant and the base is an object allocation,
|
||||
// try to hook me up to the exact initializing store.
|
||||
|
@ -1498,6 +1502,7 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
|||
&& phase->C->get_alias_index(phase->type(address)->is_ptr()) != Compile::AliasIdxRaw) {
|
||||
// Check for useless control edge in some common special cases
|
||||
if (in(MemNode::Control) != NULL
|
||||
&& can_remove_control()
|
||||
&& phase->type(base)->higher_equal(TypePtr::NOTNULL)
|
||||
&& all_controls_dominate(base, phase->C->start())) {
|
||||
// A method-invariant, non-null address (constant or 'this' argument).
|
||||
|
@ -2019,8 +2024,7 @@ const Type* LoadSNode::Value(PhaseTransform *phase) const {
|
|||
//=============================================================================
|
||||
//----------------------------LoadKlassNode::make------------------------------
|
||||
// Polymorphic factory method:
|
||||
Node *LoadKlassNode::make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at, const TypeKlassPtr *tk ) {
|
||||
Node *ctl = NULL;
|
||||
Node* LoadKlassNode::make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypePtr* at, const TypeKlassPtr* tk) {
|
||||
// sanity check the alias category against the created node type
|
||||
const TypePtr *adr_type = adr->bottom_type()->isa_ptr();
|
||||
assert(adr_type != NULL, "expecting TypeKlassPtr");
|
||||
|
@ -2040,6 +2044,12 @@ const Type *LoadKlassNode::Value( PhaseTransform *phase ) const {
|
|||
return klass_value_common(phase);
|
||||
}
|
||||
|
||||
// In most cases, LoadKlassNode does not have the control input set. If the control
|
||||
// input is set, it must not be removed (by LoadNode::Ideal()).
|
||||
bool LoadKlassNode::can_remove_control() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
const Type *LoadNode::klass_value_common( PhaseTransform *phase ) const {
|
||||
// Either input is TOP ==> the result is TOP
|
||||
const Type *t1 = phase->type( in(MemNode::Memory) );
|
||||
|
|
|
@ -148,6 +148,8 @@ private:
|
|||
protected:
|
||||
virtual uint cmp(const Node &n) const;
|
||||
virtual uint size_of() const; // Size is bigger
|
||||
// Should LoadNode::Ideal() attempt to remove control edges?
|
||||
virtual bool can_remove_control() const;
|
||||
const Type* const _type; // What kind of value is loaded?
|
||||
public:
|
||||
|
||||
|
@ -171,8 +173,10 @@ public:
|
|||
// we are equivalent to. We look for Load of a Store.
|
||||
virtual Node *Identity( PhaseTransform *phase );
|
||||
|
||||
// If the load is from Field memory and the pointer is non-null, we can
|
||||
// If the load is from Field memory and the pointer is non-null, it might be possible to
|
||||
// zero out the control input.
|
||||
// If the offset is constant and the base is an object allocation,
|
||||
// try to hook me up to the exact initializing store.
|
||||
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
|
||||
|
||||
// Split instance field load through Phi.
|
||||
|
@ -431,6 +435,10 @@ public:
|
|||
//------------------------------LoadKlassNode----------------------------------
|
||||
// Load a Klass from an object
|
||||
class LoadKlassNode : public LoadPNode {
|
||||
protected:
|
||||
// In most cases, LoadKlassNode does not have the control input set. If the control
|
||||
// input is set, it must not be removed (by LoadNode::Ideal()).
|
||||
virtual bool can_remove_control() const;
|
||||
public:
|
||||
LoadKlassNode(Node *c, Node *mem, Node *adr, const TypePtr *at, const TypeKlassPtr *tk, MemOrd mo)
|
||||
: LoadPNode(c, mem, adr, at, tk, mo) {}
|
||||
|
@ -440,8 +448,8 @@ public:
|
|||
virtual bool depends_only_on_test() const { return true; }
|
||||
|
||||
// Polymorphic factory method:
|
||||
static Node* make( PhaseGVN& gvn, Node *mem, Node *adr, const TypePtr* at,
|
||||
const TypeKlassPtr *tk = TypeKlassPtr::OBJECT );
|
||||
static Node* make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypePtr* at,
|
||||
const TypeKlassPtr* tk = TypeKlassPtr::OBJECT);
|
||||
};
|
||||
|
||||
//------------------------------LoadNKlassNode---------------------------------
|
||||
|
|
|
@ -1987,7 +1987,7 @@ void Parse::call_register_finalizer() {
|
|||
// finalization. In general this will fold up since the concrete
|
||||
// class is often visible so the access flags are constant.
|
||||
Node* klass_addr = basic_plus_adr( receiver, receiver, oopDesc::klass_offset_in_bytes() );
|
||||
Node* klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), klass_addr, TypeInstPtr::KLASS) );
|
||||
Node* klass = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), klass_addr, TypeInstPtr::KLASS));
|
||||
|
||||
Node* access_flags_addr = basic_plus_adr(klass, klass, in_bytes(Klass::access_flags_offset()));
|
||||
Node* access_flags = make_load(NULL, access_flags_addr, TypeInt::INT, T_INT, MemNode::unordered);
|
||||
|
|
|
@ -156,22 +156,43 @@ void Parse::array_store_check() {
|
|||
int klass_offset = oopDesc::klass_offset_in_bytes();
|
||||
Node* p = basic_plus_adr( ary, ary, klass_offset );
|
||||
// p's type is array-of-OOPS plus klass_offset
|
||||
Node* array_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS) );
|
||||
Node* array_klass = _gvn.transform(LoadKlassNode::make(_gvn, NULL, immutable_memory(), p, TypeInstPtr::KLASS));
|
||||
// Get the array klass
|
||||
const TypeKlassPtr *tak = _gvn.type(array_klass)->is_klassptr();
|
||||
|
||||
// array_klass's type is generally INexact array-of-oop. Heroically
|
||||
// cast the array klass to EXACT array and uncommon-trap if the cast
|
||||
// fails.
|
||||
// The type of array_klass is usually INexact array-of-oop. Heroically
|
||||
// cast array_klass to EXACT array and uncommon-trap if the cast fails.
|
||||
// Make constant out of the inexact array klass, but use it only if the cast
|
||||
// succeeds.
|
||||
bool always_see_exact_class = false;
|
||||
if (MonomorphicArrayCheck
|
||||
&& !too_many_traps(Deoptimization::Reason_array_check)) {
|
||||
&& !too_many_traps(Deoptimization::Reason_array_check)
|
||||
&& !tak->klass_is_exact()
|
||||
&& tak != TypeKlassPtr::OBJECT) {
|
||||
// Regarding the fourth condition in the if-statement from above:
|
||||
//
|
||||
// If the compiler has determined that the type of array 'ary' (represented
|
||||
// by 'array_klass') is java/lang/Object, the compiler must not assume that
|
||||
// the array 'ary' is monomorphic.
|
||||
//
|
||||
// If 'ary' were of type java/lang/Object, this arraystore would have to fail,
|
||||
// because it is not possible to perform a arraystore into an object that is not
|
||||
// a "proper" array.
|
||||
//
|
||||
// Therefore, let's obtain at runtime the type of 'ary' and check if we can still
|
||||
// successfully perform the store.
|
||||
//
|
||||
// The implementation reasons for the condition are the following:
|
||||
//
|
||||
// java/lang/Object is the superclass of all arrays, but it is represented by the VM
|
||||
// as an InstanceKlass. The checks generated by gen_checkcast() (see below) expect
|
||||
// 'array_klass' to be ObjArrayKlass, which can result in invalid memory accesses.
|
||||
//
|
||||
// See issue JDK-8057622 for details.
|
||||
|
||||
always_see_exact_class = true;
|
||||
// (If no MDO at all, hope for the best, until a trap actually occurs.)
|
||||
}
|
||||
|
||||
// Is the array klass is exactly its defined type?
|
||||
if (always_see_exact_class && !tak->klass_is_exact()) {
|
||||
// Make a constant out of the inexact array klass
|
||||
const TypeKlassPtr *extak = tak->cast_to_exactness(true)->is_klassptr();
|
||||
Node* con = makecon(extak);
|
||||
|
@ -202,11 +223,15 @@ void Parse::array_store_check() {
|
|||
// Extract the array element class
|
||||
int element_klass_offset = in_bytes(ObjArrayKlass::element_klass_offset());
|
||||
Node *p2 = basic_plus_adr(array_klass, array_klass, element_klass_offset);
|
||||
Node *a_e_klass = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p2, tak) );
|
||||
// We are allowed to use the constant type only if cast succeeded. If always_see_exact_class is true,
|
||||
// we must set a control edge from the IfTrue node created by the uncommon_trap above to the
|
||||
// LoadKlassNode.
|
||||
Node* a_e_klass = _gvn.transform(LoadKlassNode::make(_gvn, always_see_exact_class ? control() : NULL,
|
||||
immutable_memory(), p2, tak));
|
||||
|
||||
// Check (the hard way) and throw if not a subklass.
|
||||
// Result is ignored, we just need the CFG effects.
|
||||
gen_checkcast( obj, a_e_klass );
|
||||
gen_checkcast(obj, a_e_klass);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
#include "precompiled.hpp"
|
||||
|
||||
#include <new>
|
||||
|
||||
#include "code/codeCache.hpp"
|
||||
#include "memory/metadataFactory.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
|
@ -37,9 +39,11 @@
|
|||
|
||||
#include "runtime/thread.hpp"
|
||||
#include "runtime/arguments.hpp"
|
||||
#include "runtime/deoptimization.hpp"
|
||||
#include "runtime/interfaceSupport.hpp"
|
||||
#include "runtime/os.hpp"
|
||||
#include "runtime/vm_version.hpp"
|
||||
#include "runtime/sweeper.hpp"
|
||||
|
||||
#include "utilities/array.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
@ -67,6 +71,7 @@ PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
|
|||
#define SIZE_T_MAX_VALUE ((size_t) -1)
|
||||
|
||||
bool WhiteBox::_used = false;
|
||||
volatile bool WhiteBox::compilation_locked = false;
|
||||
|
||||
WB_ENTRY(jlong, WB_GetObjectAddress(JNIEnv* env, jobject o, jobject obj))
|
||||
return (jlong)(void*)JNIHandles::resolve(obj);
|
||||
|
@ -302,13 +307,12 @@ WB_END
|
|||
WB_ENTRY(jlong, WB_NMTReserveMemory(JNIEnv* env, jobject o, jlong size))
|
||||
jlong addr = 0;
|
||||
|
||||
addr = (jlong)(uintptr_t)os::reserve_memory(size);
|
||||
MemTracker::record_virtual_memory_type((address)addr, mtTest);
|
||||
addr = (jlong)(uintptr_t)os::reserve_memory(size);
|
||||
MemTracker::record_virtual_memory_type((address)addr, mtTest);
|
||||
|
||||
return addr;
|
||||
WB_END
|
||||
|
||||
|
||||
WB_ENTRY(void, WB_NMTCommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size))
|
||||
os::commit_memory((char *)(uintptr_t)addr, size, !ExecMem);
|
||||
MemTracker::record_virtual_memory_type((address)(uintptr_t)addr, mtTest);
|
||||
|
@ -728,6 +732,29 @@ WB_ENTRY(void, WB_SetStringVMFlag(JNIEnv* env, jobject o, jstring name, jstring
|
|||
WB_END
|
||||
|
||||
|
||||
WB_ENTRY(void, WB_LockCompilation(JNIEnv* env, jobject o, jlong timeout))
|
||||
WhiteBox::compilation_locked = true;
|
||||
WB_END
|
||||
|
||||
WB_ENTRY(void, WB_UnlockCompilation(JNIEnv* env, jobject o))
|
||||
MonitorLockerEx mo(Compilation_lock, Mutex::_no_safepoint_check_flag);
|
||||
WhiteBox::compilation_locked = false;
|
||||
mo.notify_all();
|
||||
WB_END
|
||||
|
||||
void WhiteBox::force_sweep() {
|
||||
guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled");
|
||||
{
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
NMethodSweeper::_should_sweep = true;
|
||||
}
|
||||
NMethodSweeper::possibly_sweep();
|
||||
}
|
||||
|
||||
WB_ENTRY(void, WB_ForceNMethodSweep(JNIEnv* env, jobject o))
|
||||
WhiteBox::force_sweep();
|
||||
WB_END
|
||||
|
||||
WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString))
|
||||
ResourceMark rm(THREAD);
|
||||
int len;
|
||||
|
@ -774,6 +801,46 @@ WB_ENTRY(jstring, WB_GetCPUFeatures(JNIEnv* env, jobject o))
|
|||
return features_string;
|
||||
WB_END
|
||||
|
||||
int WhiteBox::get_blob_type(const CodeBlob* code) {
|
||||
guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled");
|
||||
return CodeCache::get_code_heap(code)->code_blob_type();
|
||||
}
|
||||
|
||||
CodeHeap* WhiteBox::get_code_heap(int blob_type) {
|
||||
guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled");
|
||||
return CodeCache::get_code_heap(blob_type);
|
||||
}
|
||||
|
||||
struct CodeBlobStub {
|
||||
CodeBlobStub(const CodeBlob* blob) :
|
||||
name(os::strdup(blob->name())),
|
||||
size(blob->size()),
|
||||
blob_type(WhiteBox::get_blob_type(blob)) { }
|
||||
~CodeBlobStub() { os::free((void*) name); }
|
||||
const char* const name;
|
||||
const int size;
|
||||
const int blob_type;
|
||||
};
|
||||
|
||||
static jobjectArray codeBlob2objectArray(JavaThread* thread, JNIEnv* env, CodeBlobStub* cb) {
|
||||
jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string());
|
||||
CHECK_JNI_EXCEPTION_(env, NULL);
|
||||
jobjectArray result = env->NewObjectArray(3, clazz, NULL);
|
||||
|
||||
jstring name = env->NewStringUTF(cb->name);
|
||||
CHECK_JNI_EXCEPTION_(env, NULL);
|
||||
env->SetObjectArrayElement(result, 0, name);
|
||||
|
||||
jobject obj = integerBox(thread, env, cb->size);
|
||||
CHECK_JNI_EXCEPTION_(env, NULL);
|
||||
env->SetObjectArrayElement(result, 1, obj);
|
||||
|
||||
obj = integerBox(thread, env, cb->blob_type);
|
||||
CHECK_JNI_EXCEPTION_(env, NULL);
|
||||
env->SetObjectArrayElement(result, 2, obj);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jboolean is_osr))
|
||||
ResourceMark rm(THREAD);
|
||||
|
@ -790,27 +857,93 @@ WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jbo
|
|||
ThreadToNativeFromVM ttn(thread);
|
||||
jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string());
|
||||
CHECK_JNI_EXCEPTION_(env, NULL);
|
||||
result = env->NewObjectArray(3, clazz, NULL);
|
||||
result = env->NewObjectArray(4, clazz, NULL);
|
||||
if (result == NULL) {
|
||||
return result;
|
||||
}
|
||||
|
||||
CodeBlobStub stub(code);
|
||||
jobjectArray codeBlob = codeBlob2objectArray(thread, env, &stub);
|
||||
env->SetObjectArrayElement(result, 0, codeBlob);
|
||||
|
||||
jobject level = integerBox(thread, env, code->comp_level());
|
||||
CHECK_JNI_EXCEPTION_(env, NULL);
|
||||
env->SetObjectArrayElement(result, 0, level);
|
||||
env->SetObjectArrayElement(result, 1, level);
|
||||
|
||||
jbyteArray insts = env->NewByteArray(insts_size);
|
||||
CHECK_JNI_EXCEPTION_(env, NULL);
|
||||
env->SetByteArrayRegion(insts, 0, insts_size, (jbyte*) code->insts_begin());
|
||||
env->SetObjectArrayElement(result, 1, insts);
|
||||
env->SetObjectArrayElement(result, 2, insts);
|
||||
|
||||
jobject id = integerBox(thread, env, code->compile_id());
|
||||
CHECK_JNI_EXCEPTION_(env, NULL);
|
||||
env->SetObjectArrayElement(result, 2, id);
|
||||
env->SetObjectArrayElement(result, 3, id);
|
||||
|
||||
return result;
|
||||
WB_END
|
||||
|
||||
CodeBlob* WhiteBox::allocate_code_blob(int size, int blob_type) {
|
||||
guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled");
|
||||
BufferBlob* blob;
|
||||
int full_size = CodeBlob::align_code_offset(sizeof(BufferBlob));
|
||||
if (full_size < size) {
|
||||
full_size += round_to(size - full_size, oopSize);
|
||||
}
|
||||
{
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
blob = (BufferBlob*) CodeCache::allocate(full_size, blob_type);
|
||||
}
|
||||
// Track memory usage statistic after releasing CodeCache_lock
|
||||
MemoryService::track_code_cache_memory_usage();
|
||||
::new (blob) BufferBlob("WB::DummyBlob", full_size);
|
||||
return blob;
|
||||
}
|
||||
|
||||
WB_ENTRY(jlong, WB_AllocateCodeBlob(JNIEnv* env, jobject o, jint size, jint blob_type))
|
||||
return (jlong) WhiteBox::allocate_code_blob(size, blob_type);
|
||||
WB_END
|
||||
|
||||
WB_ENTRY(void, WB_FreeCodeBlob(JNIEnv* env, jobject o, jlong addr))
|
||||
BufferBlob::free((BufferBlob*) addr);
|
||||
WB_END
|
||||
|
||||
WB_ENTRY(jobjectArray, WB_GetCodeHeapEntries(JNIEnv* env, jobject o, jint blob_type))
|
||||
ResourceMark rm;
|
||||
GrowableArray<CodeBlobStub*> blobs;
|
||||
{
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
CodeHeap* heap = WhiteBox::get_code_heap(blob_type);
|
||||
if (heap == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
for (CodeBlob* cb = (CodeBlob*) heap->first();
|
||||
cb != NULL; cb = (CodeBlob*) heap->next(cb)) {
|
||||
CodeBlobStub* stub = NEW_RESOURCE_OBJ(CodeBlobStub);
|
||||
new (stub) CodeBlobStub(cb);
|
||||
blobs.append(stub);
|
||||
}
|
||||
}
|
||||
if (blobs.length() == 0) {
|
||||
return NULL;
|
||||
}
|
||||
ThreadToNativeFromVM ttn(thread);
|
||||
jobjectArray result = NULL;
|
||||
jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string());
|
||||
CHECK_JNI_EXCEPTION_(env, NULL);
|
||||
result = env->NewObjectArray(blobs.length(), clazz, NULL);
|
||||
if (result == NULL) {
|
||||
return result;
|
||||
}
|
||||
int i = 0;
|
||||
for (GrowableArrayIterator<CodeBlobStub*> it = blobs.begin();
|
||||
it != blobs.end(); ++it) {
|
||||
jobjectArray obj = codeBlob2objectArray(thread, env, *it);
|
||||
env->SetObjectArrayElement(result, i, obj);
|
||||
++i;
|
||||
}
|
||||
return result;
|
||||
WB_END
|
||||
|
||||
WB_ENTRY(jlong, WB_GetThreadStackSize(JNIEnv* env, jobject o))
|
||||
return (jlong) Thread::current()->stack_size();
|
||||
WB_END
|
||||
|
@ -1018,6 +1151,8 @@ static JNINativeMethod methods[] = {
|
|||
CC"(Ljava/lang/reflect/Executable;II)Z", (void*)&WB_EnqueueMethodForCompilation},
|
||||
{CC"clearMethodState",
|
||||
CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState},
|
||||
{CC"lockCompilation", CC"()V", (void*)&WB_LockCompilation},
|
||||
{CC"unlockCompilation", CC"()V", (void*)&WB_UnlockCompilation},
|
||||
{CC"isConstantVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsConstantVMFlag},
|
||||
{CC"isLockedVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsLockedVMFlag},
|
||||
{CC"setBooleanVMFlag", CC"(Ljava/lang/String;Z)V",(void*)&WB_SetBooleanVMFlag},
|
||||
|
@ -1055,6 +1190,10 @@ static JNINativeMethod methods[] = {
|
|||
{CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures },
|
||||
{CC"getNMethod", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;",
|
||||
(void*)&WB_GetNMethod },
|
||||
{CC"forceNMethodSweep", CC"()V", (void*)&WB_ForceNMethodSweep },
|
||||
{CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob },
|
||||
{CC"freeCodeBlob", CC"(J)V", (void*)&WB_FreeCodeBlob },
|
||||
{CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries },
|
||||
{CC"getThreadStackSize", CC"()J", (void*)&WB_GetThreadStackSize },
|
||||
{CC"getThreadRemainingStackSize", CC"()J", (void*)&WB_GetThreadRemainingStackSize },
|
||||
};
|
||||
|
|
|
@ -54,17 +54,24 @@
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
class CodeBlob;
|
||||
class CodeHeap;
|
||||
|
||||
class WhiteBox : public AllStatic {
|
||||
private:
|
||||
static bool _used;
|
||||
public:
|
||||
static volatile bool compilation_locked;
|
||||
static bool used() { return _used; }
|
||||
static void set_used() { _used = true; }
|
||||
static int offset_for_field(const char* field_name, oop object,
|
||||
Symbol* signature_symbol);
|
||||
static const char* lookup_jstring(const char* field_name, oop object);
|
||||
static bool lookup_bool(const char* field_name, oop object);
|
||||
|
||||
static void force_sweep();
|
||||
static int get_blob_type(const CodeBlob* code);
|
||||
static CodeHeap* get_code_heap(int blob_type);
|
||||
static CodeBlob* allocate_code_blob(int blob_type, int size);
|
||||
static int array_bytes_to_length(size_t bytes);
|
||||
static void register_methods(JNIEnv* env, jclass wbclass, JavaThread* thread,
|
||||
JNINativeMethod* method_array, int method_count);
|
||||
|
|
|
@ -317,8 +317,8 @@ void AdvancedThresholdPolicy::create_mdo(methodHandle mh, JavaThread* THREAD) {
|
|||
* c. 0 -> (3->2) -> 4.
|
||||
* In this case we enqueue a method for compilation at level 3, but the C1 queue is long enough
|
||||
* to enable the profiling to fully occur at level 0. In this case we change the compilation level
|
||||
* of the method to 2, because it'll allow it to run much faster without full profiling while c2
|
||||
* is compiling.
|
||||
* of the method to 2 while the request is still in-queue, because it'll allow it to run much faster
|
||||
* without full profiling while c2 is compiling.
|
||||
*
|
||||
* d. 0 -> 3 -> 1 or 0 -> 2 -> 1.
|
||||
* After a method was once compiled with C1 it can be identified as trivial and be compiled to
|
||||
|
|
|
@ -87,6 +87,7 @@ Mutex* DerivedPointerTableGC_lock = NULL;
|
|||
Mutex* Compile_lock = NULL;
|
||||
Monitor* MethodCompileQueue_lock = NULL;
|
||||
Monitor* CompileThread_lock = NULL;
|
||||
Monitor* Compilation_lock = NULL;
|
||||
Mutex* CompileTaskAlloc_lock = NULL;
|
||||
Mutex* CompileStatistics_lock = NULL;
|
||||
Mutex* MultiArray_lock = NULL;
|
||||
|
@ -274,7 +275,9 @@ void mutex_init() {
|
|||
def(ProfileVM_lock , Monitor, special, false); // used for profiling of the VMThread
|
||||
def(CompileThread_lock , Monitor, nonleaf+5, false );
|
||||
def(PeriodicTask_lock , Monitor, nonleaf+5, true);
|
||||
|
||||
if (WhiteBoxAPI) {
|
||||
def(Compilation_lock , Monitor, leaf, false );
|
||||
}
|
||||
#ifdef INCLUDE_TRACE
|
||||
def(JfrMsg_lock , Monitor, leaf, true);
|
||||
def(JfrBuffer_lock , Mutex, leaf, true);
|
||||
|
|
|
@ -90,6 +90,7 @@ extern Mutex* EvacFailureStack_lock; // guards the evac failure scan
|
|||
extern Mutex* Compile_lock; // a lock held when Compilation is updating code (used to block CodeCache traversal, CHA updates, etc)
|
||||
extern Monitor* MethodCompileQueue_lock; // a lock held when method compilations are enqueued, dequeued
|
||||
extern Monitor* CompileThread_lock; // a lock held by compile threads during compilation system initialization
|
||||
extern Monitor* Compilation_lock; // a lock used to pause compilation
|
||||
extern Mutex* CompileTaskAlloc_lock; // a lock held when CompileTasks are allocated
|
||||
extern Mutex* CompileStatistics_lock; // a lock held when updating compilation statistics
|
||||
extern Mutex* MultiArray_lock; // a lock used to guard allocation of multi-dim arrays
|
||||
|
|
|
@ -54,13 +54,17 @@ bool SimpleThresholdPolicy::loop_predicate_helper(int i, int b, double scale) {
|
|||
// Simple methods are as good being compiled with C1 as C2.
|
||||
// Determine if a given method is such a case.
|
||||
bool SimpleThresholdPolicy::is_trivial(Method* method) {
|
||||
if (method->is_accessor()) return true;
|
||||
if (method->code() != NULL) {
|
||||
MethodData* mdo = method->method_data();
|
||||
if (mdo != NULL && mdo->num_loops() == 0 &&
|
||||
(method->code_size() < 5 || (mdo->num_blocks() < 4) && (method->code_size() < 15))) {
|
||||
return !mdo->would_profile();
|
||||
}
|
||||
if (method->is_accessor() ||
|
||||
method->is_constant_getter()) {
|
||||
return true;
|
||||
}
|
||||
if (method->has_loops() || method->code_size() >= 15) {
|
||||
return false;
|
||||
}
|
||||
MethodData* mdo = method->method_data();
|
||||
if (mdo != NULL && !mdo->would_profile() &&
|
||||
(method->code_size() < 5 || (mdo->num_blocks() < 4))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#ifndef SHARE_VM_RUNTIME_SWEEPER_HPP
|
||||
#define SHARE_VM_RUNTIME_SWEEPER_HPP
|
||||
|
||||
class WhiteBox;
|
||||
|
||||
#include "utilities/ticks.hpp"
|
||||
// An NmethodSweeper is an incremental cleaner for:
|
||||
// - cleanup inline caches
|
||||
|
@ -52,6 +54,8 @@
|
|||
// nmethod's space is freed.
|
||||
|
||||
class NMethodSweeper : public AllStatic {
|
||||
friend class WhiteBox;
|
||||
private:
|
||||
static long _traversals; // Stack scan count, also sweep ID.
|
||||
static long _total_nof_code_cache_sweeps; // Total number of full sweeps of the code cache
|
||||
static long _time_counter; // Virtual time used to periodically invoke sweeper
|
||||
|
@ -88,7 +92,6 @@ class NMethodSweeper : public AllStatic {
|
|||
static void handle_safepoint_request();
|
||||
static void do_stack_scanning();
|
||||
static void possibly_sweep();
|
||||
|
||||
public:
|
||||
static long traversal_count() { return _traversals; }
|
||||
static int total_nof_methods_reclaimed() { return _total_nof_methods_reclaimed; }
|
||||
|
|
|
@ -426,7 +426,8 @@ hotspot_compiler_2 = \
|
|||
compiler/8005033/Test8005033.java \
|
||||
compiler/8005419/Test8005419.java \
|
||||
compiler/8005956/PolynomialRoot.java \
|
||||
compiler/8007294/Test8007294.java
|
||||
compiler/8007294/Test8007294.java \
|
||||
compiler/EliminateAutoBox/UnsignedLoads.java
|
||||
|
||||
hotspot_compiler_3 = \
|
||||
compiler/8007722/Test8007722.java \
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -26,57 +26,116 @@
|
|||
* @test
|
||||
* @bug 7068051
|
||||
* @summary SIGSEGV in PhaseIdealLoop::build_loop_late_post on T5440
|
||||
* @library /testlibrary
|
||||
*
|
||||
* @run shell/timeout=300 Test7068051.sh
|
||||
* @run main/othervm -showversion -Xbatch Test7068051
|
||||
*/
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
import com.oracle.java.testlibrary.JDKToolLauncher;
|
||||
import com.oracle.java.testlibrary.OutputAnalyzer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
public class Test7068051 {
|
||||
private static final String SELF_NAME = Test7068051.class.getSimpleName();
|
||||
private static final String SELF_FILE_NAME = SELF_NAME + ".java";
|
||||
private static final String JAR_NAME = "foo.jar";
|
||||
private static final String TEST_PATH = System.getProperty("test.src");
|
||||
private static final Path CURRENT_DIR = Paths.get(".");
|
||||
private static final Path TEST_SOURCE_PATH = Paths.get(TEST_PATH, SELF_FILE_NAME);
|
||||
|
||||
public static void main (String[] args) throws Throwable {
|
||||
public static void main (String[] args) throws IOException {
|
||||
createTestJarFile();
|
||||
System.out.println("Running test...");
|
||||
|
||||
ZipFile zf = new ZipFile(args[0]);
|
||||
try (ZipFile zf = new ZipFile(JAR_NAME)) {
|
||||
|
||||
Enumeration<? extends ZipEntry> entries = zf.entries();
|
||||
ArrayList<String> names = new ArrayList<String>();
|
||||
while (entries.hasMoreElements()) {
|
||||
names.add(entries.nextElement().getName());
|
||||
}
|
||||
Enumeration<? extends ZipEntry> entries = zf.entries();
|
||||
ArrayList<String> names = new ArrayList<String>();
|
||||
while (entries.hasMoreElements()) {
|
||||
names.add(entries.nextElement().getName());
|
||||
}
|
||||
|
||||
byte[] bytes = new byte[16];
|
||||
for (String name : names) {
|
||||
ZipEntry e = zf.getEntry(name);
|
||||
byte[] bytes = new byte[16];
|
||||
for (String name : names) {
|
||||
ZipEntry e = zf.getEntry(name);
|
||||
|
||||
if (e.isDirectory())
|
||||
continue;
|
||||
|
||||
final InputStream is = zf.getInputStream(e);
|
||||
|
||||
try {
|
||||
while (is.read(bytes) >= 0) {
|
||||
if (e.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
is.close();
|
||||
|
||||
} catch (IOException x) {
|
||||
System.out.println("..................................");
|
||||
System.out.println(" --> is :" + is);
|
||||
System.out.println(" is.hash :" + is.hashCode());
|
||||
System.out.println();
|
||||
System.out.println(" e.name :" + e.getName());
|
||||
System.out.println(" e.hash :" + e.hashCode());
|
||||
System.out.println(" e.method :" + e.getMethod());
|
||||
System.out.println(" e.size :" + e.getSize());
|
||||
System.out.println(" e.csize :" + e.getCompressedSize());
|
||||
try (final InputStream is = zf.getInputStream(e)) {
|
||||
try {
|
||||
while (is.read(bytes) >= 0) {
|
||||
}
|
||||
} catch (IOException x) {
|
||||
System.out.println("..................................");
|
||||
System.out.println(" --> is :" + is);
|
||||
System.out.println(" is.hash :" + is.hashCode());
|
||||
System.out.println();
|
||||
System.out.println(" e.name :" + e.getName());
|
||||
System.out.println(" e.hash :" + e.hashCode());
|
||||
System.out.println(" e.method :" + e.getMethod());
|
||||
System.out.println(" e.size :" + e.getSize());
|
||||
System.out.println(" e.csize :" + e.getCompressedSize());
|
||||
System.out.println("..................................");
|
||||
|
||||
x.printStackTrace();
|
||||
System.out.println("..................................");
|
||||
System.exit(97);
|
||||
throw new AssertionError("IOException was throwing while read the archive. Test failed.", x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
zf.close();
|
||||
System.out.println("Test passed.");
|
||||
}
|
||||
|
||||
private static void createTestJarFile() {
|
||||
ArrayList<String> jarOptions = new ArrayList<>();
|
||||
|
||||
// jar cf foo.jar *
|
||||
System.out.println("Creating jar file..");
|
||||
jarOptions.add("cf");
|
||||
jarOptions.add(JAR_NAME);
|
||||
try {
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
Path temp = Files.createTempFile(CURRENT_DIR, SELF_NAME, ".java");
|
||||
Files.copy(TEST_SOURCE_PATH, temp, StandardCopyOption.REPLACE_EXISTING);
|
||||
jarOptions.add(temp.toString());
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new AssertionError("TESTBUG: Creating temp files failed.", ex);
|
||||
}
|
||||
runJar(jarOptions);
|
||||
|
||||
// jar -uf0 foo.jar Test7068051.java
|
||||
System.out.println("Adding unpacked file...");
|
||||
jarOptions.clear();
|
||||
jarOptions.add("-uf0");
|
||||
jarOptions.add(JAR_NAME);
|
||||
jarOptions.add(TEST_SOURCE_PATH.toString());
|
||||
runJar(jarOptions);
|
||||
}
|
||||
|
||||
private static void runJar(List<String> params) {
|
||||
JDKToolLauncher jar = JDKToolLauncher.create("jar");
|
||||
for (String p : params) {
|
||||
jar.addToolArg(p);
|
||||
}
|
||||
ProcessBuilder pb = new ProcessBuilder(jar.getCommand());
|
||||
try {
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldHaveExitValue(0);
|
||||
} catch (IOException ex) {
|
||||
throw new AssertionError("TESTBUG: jar failed.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
#
|
||||
## some tests require path to find test source dir
|
||||
if [ "${TESTSRC}" = "" ]
|
||||
then
|
||||
TESTSRC=${PWD}
|
||||
echo "TESTSRC not set. Using "${TESTSRC}" as default"
|
||||
fi
|
||||
echo "TESTSRC=${TESTSRC}"
|
||||
## Adding common setup Variables for running shell tests.
|
||||
. ${TESTSRC}/../../test_env.sh
|
||||
|
||||
set -x
|
||||
|
||||
${COMPILEJAVA}/bin/jar xf ${COMPILEJAVA}/jre/lib/javaws.jar
|
||||
${COMPILEJAVA}/bin/jar cf foo.jar *
|
||||
cp ${TESTSRC}/Test7068051.java ./
|
||||
${COMPILEJAVA}/bin/jar -uf0 foo.jar Test7068051.java
|
||||
|
||||
${COMPILEJAVA}/bin/javac ${TESTJAVACOPTS} -d . Test7068051.java
|
||||
|
||||
${TESTJAVA}/bin/java ${TESTOPTS} -showversion -Xbatch Test7068051 foo.jar
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
/*
|
||||
* @test
|
||||
* @library /testlibrary
|
||||
* @run main/othervm -Xbatch -XX:+EliminateAutoBox
|
||||
* @run main/othervm -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+EliminateAutoBox
|
||||
* -XX:CompileOnly=::valueOf,::byteValue,::shortValue,::testUnsignedByte,::testUnsignedShort
|
||||
* UnsignedLoads
|
||||
*/
|
||||
|
|
128
hotspot/test/compiler/whitebox/AllocationCodeBlobTest.java
Normal file
128
hotspot/test/compiler/whitebox/AllocationCodeBlobTest.java
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.lang.management.MemoryPoolMXBean;
|
||||
import java.util.EnumSet;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import sun.hotspot.WhiteBox;
|
||||
import sun.hotspot.code.BlobType;
|
||||
import com.oracle.java.testlibrary.Asserts;
|
||||
|
||||
/*
|
||||
* @test AllocationCodeBlobTest
|
||||
* @bug 8059624
|
||||
* @library /testlibrary /testlibrary/whitebox
|
||||
* @build AllocationCodeBlobTest
|
||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:-SegmentedCodeCache AllocationCodeBlobTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:+SegmentedCodeCache AllocationCodeBlobTest
|
||||
* @summary testing of WB::allocate/freeCodeBlob()
|
||||
*/
|
||||
public class AllocationCodeBlobTest {
|
||||
private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
|
||||
private static final long CODE_CACHE_SIZE
|
||||
= WHITE_BOX.getUintxVMFlag("ReservedCodeCacheSize");
|
||||
private static final int SIZE = 1;
|
||||
|
||||
public static void main(String[] args) {
|
||||
// check that Sweeper handels dummy blobs correctly
|
||||
new ForcedSweeper(500).start();
|
||||
EnumSet<BlobType> blobTypes = BlobType.getAvailable();
|
||||
for (BlobType type : blobTypes) {
|
||||
new AllocationCodeBlobTest(type).test();
|
||||
}
|
||||
}
|
||||
|
||||
private final BlobType type;
|
||||
private final MemoryPoolMXBean bean;
|
||||
private AllocationCodeBlobTest(BlobType type) {
|
||||
this.type = type;
|
||||
bean = type.getMemoryPool();
|
||||
}
|
||||
|
||||
private void test() {
|
||||
System.out.printf("type %s%n", type);
|
||||
long start = getUsage();
|
||||
long addr = WHITE_BOX.allocateCodeBlob(SIZE, type.id);
|
||||
Asserts.assertNE(0, addr, "allocation failed");
|
||||
|
||||
long firstAllocation = getUsage();
|
||||
Asserts.assertLTE(start + SIZE, firstAllocation,
|
||||
"allocation should increase memory usage: "
|
||||
+ start + " + " + SIZE + " <= " + firstAllocation);
|
||||
|
||||
WHITE_BOX.freeCodeBlob(addr);
|
||||
long firstFree = getUsage();
|
||||
Asserts.assertLTE(firstFree, firstAllocation,
|
||||
"free shouldn't increase memory usage: "
|
||||
+ firstFree + " <= " + firstAllocation);
|
||||
|
||||
addr = WHITE_BOX.allocateCodeBlob(SIZE, type.id);
|
||||
Asserts.assertNE(0, addr, "allocation failed");
|
||||
|
||||
long secondAllocation = getUsage();
|
||||
Asserts.assertEQ(firstAllocation, secondAllocation);
|
||||
|
||||
WHITE_BOX.freeCodeBlob(addr);
|
||||
System.out.println("allocating till possible...");
|
||||
ArrayList<Long> blobs = new ArrayList<>();
|
||||
int size = (int) (CODE_CACHE_SIZE >> 7);
|
||||
while ((addr = WHITE_BOX.allocateCodeBlob(size, type.id)) != 0) {
|
||||
blobs.add(addr);
|
||||
}
|
||||
for (Long blob : blobs) {
|
||||
WHITE_BOX.freeCodeBlob(blob);
|
||||
}
|
||||
}
|
||||
|
||||
private long getUsage() {
|
||||
return bean.getUsage().getUsed();
|
||||
}
|
||||
|
||||
private static class ForcedSweeper extends Thread {
|
||||
private final int millis;
|
||||
public ForcedSweeper(int millis) {
|
||||
super("ForcedSweeper");
|
||||
setDaemon(true);
|
||||
this.millis = millis;
|
||||
}
|
||||
public void run() {
|
||||
try {
|
||||
while (true) {
|
||||
WHITE_BOX.forceNMethodSweep();
|
||||
Thread.sleep(millis);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
95
hotspot/test/compiler/whitebox/GetCodeHeapEntriesTest.java
Normal file
95
hotspot/test/compiler/whitebox/GetCodeHeapEntriesTest.java
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import sun.hotspot.WhiteBox;
|
||||
import sun.hotspot.code.CodeBlob;
|
||||
import sun.hotspot.code.BlobType;
|
||||
import com.oracle.java.testlibrary.Asserts;
|
||||
|
||||
/*
|
||||
* @test GetCodeHeapEntriesTest
|
||||
* @bug 8059624
|
||||
* @library /testlibrary /testlibrary/whitebox
|
||||
* @build GetCodeHeapEntriesTest
|
||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache
|
||||
* GetCodeHeapEntriesTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache
|
||||
* GetCodeHeapEntriesTest
|
||||
* @summary testing of WB::getCodeHeapEntries()
|
||||
*/
|
||||
public class GetCodeHeapEntriesTest {
|
||||
private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
|
||||
private static final int SIZE = 1024;
|
||||
private static final String DUMMY_NAME = "WB::DummyBlob";
|
||||
private static EnumSet<BlobType> SEGMENTED_TYPES
|
||||
= EnumSet.complementOf(EnumSet.of(BlobType.All));
|
||||
|
||||
public static void main(String[] args) {
|
||||
EnumSet<BlobType> blobTypes = BlobType.getAvailable();
|
||||
for (BlobType type : blobTypes) {
|
||||
new GetCodeHeapEntriesTest(type).test();
|
||||
}
|
||||
}
|
||||
|
||||
private final BlobType type;
|
||||
private GetCodeHeapEntriesTest(BlobType type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
private void test() {
|
||||
System.out.printf("type %s%n", type);
|
||||
long addr = WHITE_BOX.allocateCodeBlob(SIZE, type.id);
|
||||
Asserts.assertNE(0, addr, "allocation failed");
|
||||
CodeBlob[] blobs = CodeBlob.getCodeBlobs(type);
|
||||
Asserts.assertNotNull(blobs);
|
||||
CodeBlob blob = Arrays.stream(blobs)
|
||||
.filter(GetCodeHeapEntriesTest::filter)
|
||||
.findAny()
|
||||
.get();
|
||||
Asserts.assertNotNull(blob);
|
||||
Asserts.assertEQ(blob.code_blob_type, type);
|
||||
Asserts.assertGTE(blob.size, SIZE);
|
||||
|
||||
WHITE_BOX.freeCodeBlob(addr);
|
||||
blobs = CodeBlob.getCodeBlobs(type);
|
||||
long count = Arrays.stream(blobs)
|
||||
.filter(GetCodeHeapEntriesTest::filter)
|
||||
.count();
|
||||
Asserts.assertEQ(0L, count);
|
||||
}
|
||||
|
||||
private static boolean filter(CodeBlob blob) {
|
||||
if (blob == null) {
|
||||
return false;
|
||||
}
|
||||
return DUMMY_NAME.equals(blob.name);
|
||||
}
|
||||
}
|
|
@ -22,7 +22,9 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import sun.hotspot.code.BlobType;
|
||||
import sun.hotspot.code.NMethod;
|
||||
import com.oracle.java.testlibrary.Asserts;
|
||||
|
||||
/*
|
||||
* @test GetNMethodTest
|
||||
|
@ -52,21 +54,46 @@ public class GetNMethodTest extends CompilerWhiteBoxTest {
|
|||
|
||||
compile();
|
||||
checkCompiled();
|
||||
|
||||
NMethod nmethod = NMethod.get(method, testCase.isOsr());
|
||||
if (IS_VERBOSE) {
|
||||
System.out.println("nmethod = " + nmethod);
|
||||
}
|
||||
if (nmethod == null) {
|
||||
throw new RuntimeException("nmethod of compiled method is null");
|
||||
}
|
||||
if (nmethod.insts.length == 0) {
|
||||
throw new RuntimeException("compiled method's instructions is empty");
|
||||
Asserts.assertNotNull(nmethod,
|
||||
"nmethod of compiled method is null");
|
||||
Asserts.assertNotNull(nmethod.insts,
|
||||
"nmethod.insts of compiled method is null");
|
||||
Asserts.assertGT(nmethod.insts.length, 0,
|
||||
"compiled method's instructions is empty");
|
||||
Asserts.assertNotNull(nmethod.code_blob_type, "blob type is null");
|
||||
if (WHITE_BOX.getBooleanVMFlag("SegmentedCodeCache")) {
|
||||
Asserts.assertNE(nmethod.code_blob_type, BlobType.All);
|
||||
switch (nmethod.comp_level) {
|
||||
case 1:
|
||||
case 4:
|
||||
checkBlockType(nmethod, BlobType.MethodNonProfiled);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
checkBlockType(nmethod, BlobType.MethodNonProfiled);
|
||||
break;
|
||||
default:
|
||||
throw new Error("unexpected comp level " + nmethod);
|
||||
}
|
||||
} else {
|
||||
Asserts.assertEQ(nmethod.code_blob_type, BlobType.All);
|
||||
}
|
||||
|
||||
deoptimize();
|
||||
checkNotCompiled();
|
||||
nmethod = NMethod.get(method, testCase.isOsr());
|
||||
if (nmethod != null) {
|
||||
throw new RuntimeException("nmethod of non-compiled method isn't null");
|
||||
}
|
||||
Asserts.assertNull(nmethod,
|
||||
"nmethod of non-compiled method isn't null");
|
||||
}
|
||||
|
||||
private void checkBlockType(NMethod nmethod, BlobType expectedType) {
|
||||
Asserts.assertEQ(nmethod.code_blob_type, expectedType,
|
||||
String.format("blob_type[%s] for %d level isn't %s",
|
||||
nmethod.code_blob_type, nmethod.comp_level, expectedType));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||
* @run main ClassFileInstaller com.oracle.java.testlibrary.Platform
|
||||
* @run main/othervm/timeout=2400 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:PerMethodRecompilationCutoff=3 -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest
|
||||
* @run main/othervm/timeout=2400 -Xbootclasspath/a:. -Xmixed -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:PerMethodRecompilationCutoff=3 -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* IsMethodCompilableTest
|
||||
* @summary testing of WB::isMethodCompilable()
|
||||
* @author igor.ignatyev@oracle.com
|
||||
*/
|
||||
|
|
91
hotspot/test/compiler/whitebox/LockCompilationTest.java
Normal file
91
hotspot/test/compiler/whitebox/LockCompilationTest.java
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test LockCompilationTest
|
||||
* @bug 8059624
|
||||
* @library /testlibrary /testlibrary/whitebox
|
||||
* @build LockCompilationTest
|
||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* sun.hotspot.WhiteBox$WhiteBoxPermission
|
||||
* @run main/othervm/timeout=600 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* LockCompilationTest
|
||||
* @summary testing of WB::lock/unlockCompilation()
|
||||
*/
|
||||
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.concurrent.BrokenBarrierException;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
|
||||
import com.oracle.java.testlibrary.Asserts;
|
||||
|
||||
public class LockCompilationTest extends CompilerWhiteBoxTest {
|
||||
public static void main(String[] args) throws Exception {
|
||||
CompilerWhiteBoxTest.main(LockCompilationTest::new, args);
|
||||
}
|
||||
|
||||
private LockCompilationTest(TestCase testCase) {
|
||||
super(testCase);
|
||||
// to prevent inlining of #method
|
||||
WHITE_BOX.testSetDontInlineMethod(method, true);
|
||||
}
|
||||
|
||||
protected void test() throws Exception {
|
||||
checkNotCompiled();
|
||||
|
||||
System.out.println("locking compilation");
|
||||
WHITE_BOX.lockCompilation();
|
||||
|
||||
try {
|
||||
System.out.println("trying to compile");
|
||||
compile();
|
||||
// to check if it works correctly w/ safepoints
|
||||
System.out.println("going to safepoint");
|
||||
WHITE_BOX.fullGC();
|
||||
waitBackgroundCompilation();
|
||||
Asserts.assertTrue(
|
||||
WHITE_BOX.isMethodQueuedForCompilation(method),
|
||||
method + " must be in queue");
|
||||
Asserts.assertFalse(
|
||||
WHITE_BOX.isMethodCompiled(method, false),
|
||||
method + " must be not compiled");
|
||||
Asserts.assertEQ(
|
||||
WHITE_BOX.getMethodCompilationLevel(method, false), 0,
|
||||
method + " comp_level must be == 0");
|
||||
Asserts.assertFalse(
|
||||
WHITE_BOX.isMethodCompiled(method, true),
|
||||
method + " must be not osr_compiled");
|
||||
Asserts.assertEQ(
|
||||
WHITE_BOX.getMethodCompilationLevel(method, true), 0,
|
||||
method + " osr_comp_level must be == 0");
|
||||
} finally {
|
||||
System.out.println("unlocking compilation");
|
||||
WHITE_BOX.unlockCompilation();
|
||||
}
|
||||
waitBackgroundCompilation();
|
||||
Asserts.assertFalse(
|
||||
WHITE_BOX.isMethodQueuedForCompilation(method),
|
||||
method + " must not be in queue");
|
||||
}
|
||||
}
|
||||
|
|
@ -143,8 +143,14 @@ public class WhiteBox {
|
|||
}
|
||||
public native boolean enqueueMethodForCompilation(Executable method, int compLevel, int entry_bci);
|
||||
public native void clearMethodState(Executable method);
|
||||
public native void lockCompilation();
|
||||
public native void unlockCompilation();
|
||||
public native int getMethodEntryBci(Executable method);
|
||||
public native Object[] getNMethod(Executable method, boolean isOsr);
|
||||
public native long allocateCodeBlob(int size, int type);
|
||||
public native void freeCodeBlob(long addr);
|
||||
public native void forceNMethodSweep();
|
||||
public native Object[] getCodeHeapEntries(int type);
|
||||
|
||||
// Intered strings
|
||||
public native boolean isInStringTable(String str);
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.hotspot.code;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryPoolMXBean;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import sun.hotspot.WhiteBox;
|
||||
|
||||
public enum BlobType {
|
||||
// Execution level 1 and 4 (non-profiled) nmethods (including native nmethods)
|
||||
MethodNonProfiled(0, "CodeHeap 'non-profiled nmethods'"),
|
||||
// Execution level 2 and 3 (profiled) nmethods
|
||||
MethodProfiled(1, "CodeHeap 'profiled nmethods'"),
|
||||
// Non-nmethods like Buffers, Adapters and Runtime Stubs
|
||||
NonNMethod(2, "CodeHeap 'non-nmethods'"),
|
||||
// All types (No code cache segmentation)
|
||||
All(3, "CodeCache");
|
||||
|
||||
public final int id;
|
||||
private final String beanName;
|
||||
|
||||
private BlobType(int id, String beanName) {
|
||||
this.id = id;
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
public MemoryPoolMXBean getMemoryPool() {
|
||||
for (MemoryPoolMXBean bean : ManagementFactory.getMemoryPoolMXBeans()) {
|
||||
String name = bean.getName();
|
||||
if (beanName.equals(name)) {
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
public static EnumSet<BlobType> getAvailable() {
|
||||
WhiteBox whiteBox = WhiteBox.getWhiteBox();
|
||||
if (!whiteBox.getBooleanVMFlag("SegmentedCodeCache")) {
|
||||
// only All for non segmented world
|
||||
return EnumSet.of(All);
|
||||
}
|
||||
if (System.getProperty("java.vm.info").startsWith("interpreted ")) {
|
||||
// only NonNMethod for -Xint
|
||||
return EnumSet.of(NonNMethod);
|
||||
}
|
||||
|
||||
EnumSet<BlobType> result = EnumSet.complementOf(EnumSet.of(All));
|
||||
if (!whiteBox.getBooleanVMFlag("TieredCompilation")
|
||||
|| whiteBox.getIntxVMFlag("TieredStopAtLevel") <= 1) {
|
||||
// there is no MethodProfiled in non tiered world or pure C1
|
||||
result.remove(MethodProfiled);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.hotspot.code;
|
||||
|
||||
import sun.hotspot.WhiteBox;
|
||||
|
||||
public class CodeBlob {
|
||||
private static final WhiteBox WB = WhiteBox.getWhiteBox();
|
||||
public static CodeBlob[] getCodeBlobs(BlobType type) {
|
||||
Object[] obj = WB.getCodeHeapEntries(type.id);
|
||||
if (obj == null) {
|
||||
return null;
|
||||
}
|
||||
CodeBlob[] result = new CodeBlob[obj.length];
|
||||
for (int i = 0, n = result.length; i < n; ++i) {
|
||||
result[i] = new CodeBlob((Object[]) obj[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
protected CodeBlob(Object[] obj) {
|
||||
assert obj.length == 3;
|
||||
name = (String) obj[0];
|
||||
size = (Integer) obj[1];
|
||||
code_blob_type = BlobType.values()[(Integer) obj[2]];
|
||||
assert code_blob_type.id == (Integer) obj[2];
|
||||
}
|
||||
public final String name;
|
||||
public final int size;
|
||||
public final BlobType code_blob_type;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CodeBlob{"
|
||||
+ "name=" + name
|
||||
+ ", size=" + size
|
||||
+ ", code_blob_type=" + code_blob_type
|
||||
+ '}';
|
||||
}
|
||||
}
|
|
@ -27,28 +27,30 @@ package sun.hotspot.code;
|
|||
import java.lang.reflect.Executable;
|
||||
import sun.hotspot.WhiteBox;
|
||||
|
||||
public class NMethod {
|
||||
public class NMethod extends CodeBlob {
|
||||
private static final WhiteBox wb = WhiteBox.getWhiteBox();
|
||||
public static NMethod get(Executable method, boolean isOsr) {
|
||||
Object[] obj = wb.getNMethod(method, isOsr);
|
||||
return obj == null ? null : new NMethod(obj);
|
||||
}
|
||||
private NMethod(Object[] obj) {
|
||||
assert obj.length == 3;
|
||||
comp_level = (Integer) obj[0];
|
||||
insts = (byte[]) obj[1];
|
||||
compile_id = (Integer) obj[2];
|
||||
super((Object[])obj[0]);
|
||||
assert obj.length == 4;
|
||||
comp_level = (Integer) obj[1];
|
||||
insts = (byte[]) obj[2];
|
||||
compile_id = (Integer) obj[3];
|
||||
}
|
||||
public byte[] insts;
|
||||
public int comp_level;
|
||||
public int compile_id;
|
||||
public final byte[] insts;
|
||||
public final int comp_level;
|
||||
public final int compile_id;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NMethod{" +
|
||||
"insts=" + insts +
|
||||
", comp_level=" + comp_level +
|
||||
", compile_id=" + compile_id +
|
||||
'}';
|
||||
return "NMethod{"
|
||||
+ super.toString()
|
||||
+ ", insts=" + insts
|
||||
+ ", comp_level=" + comp_level
|
||||
+ ", compile_id=" + compile_id
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue