提交 cd2ffae5 编写于 作者: K Kuai Wei 提交者: 云矅

[JWarmUp] port jwarmup to dragonwell 8u

Summary:
  Port jwarmup to dragonwell 8u hotspot

ref T19299187

Test Plan:
test/hotspot/jtreg/jwarmup/Issue11272598.java
test/hotspot/jtreg/jwarmup/TestDisableNCE.java
test/hotspot/jtreg/jwarmup/TestNotDeoptJITMethod.sh
test/hotspot/jtreg/jwarmup/issue9780156.sh
test/hotspot/jtreg/jwarmup/TestEagerCompilation.java
test/hotspot/jtreg/jwarmup/TestNotifyDeopt.sh
test/hotspot/jtreg/jwarmup/TestCheckIfCompilationIsComplete.sh
test/hotspot/jtreg/jwarmup/TestFlagAssertion.java
test/hotspot/jtreg/jwarmup/TestReadLogfile.java
test/hotspot/jtreg/jwarmup/TestClassInitChain.java
test/hotspot/jtreg/jwarmup/TestLogFlush.java
test/hotspot/jtreg/jwarmup/TestRecordNullMethodCounter.java
test/hotspot/jtreg/jwarmup/TestThrowInitializaitonException.java
test/hotspot/jtreg/jwarmup/TestDisableMethodData.sh
test/hotspot/jtreg/jwarmup/TestMethodRecorder.java
test/hotspot/jtreg/jwarmup/TestTieredCompilationInRecording.sh

Reviewers: 传胜, 三红, yumin.qi

Reviewed By: 传胜, 三红

Subscribers: 麦庶

Differential Revision: https://aone.alibaba-inc.com/code/D852146
上级 45188b6d
...@@ -40,6 +40,7 @@ SUNWprivate_1.1 { ...@@ -40,6 +40,7 @@ SUNWprivate_1.1 {
JVM_AssertionStatusDirectives; JVM_AssertionStatusDirectives;
JVM_Available; JVM_Available;
JVM_Bind; JVM_Bind;
JVM_CheckJWarmUpCompilationIsComplete;
JVM_ClassDepth; JVM_ClassDepth;
JVM_ClassLoaderDepth; JVM_ClassLoaderDepth;
JVM_Clone; JVM_Clone;
...@@ -205,6 +206,8 @@ SUNWprivate_1.1 { ...@@ -205,6 +206,8 @@ SUNWprivate_1.1 {
JVM_NewArray; JVM_NewArray;
JVM_NewInstanceFromConstructor; JVM_NewInstanceFromConstructor;
JVM_NewMultiArray; JVM_NewMultiArray;
JVM_NotifyApplicationStartUpIsDone;
JVM_NotifyJVMDeoptWarmUpMethods;
JVM_OnExit; JVM_OnExit;
JVM_Open; JVM_Open;
JVM_RaiseSignal; JVM_RaiseSignal;
......
...@@ -40,6 +40,7 @@ SUNWprivate_1.1 { ...@@ -40,6 +40,7 @@ SUNWprivate_1.1 {
JVM_AssertionStatusDirectives; JVM_AssertionStatusDirectives;
JVM_Available; JVM_Available;
JVM_Bind; JVM_Bind;
JVM_CheckJWarmUpCompilationIsComplete;
JVM_ClassDepth; JVM_ClassDepth;
JVM_ClassLoaderDepth; JVM_ClassLoaderDepth;
JVM_Clone; JVM_Clone;
...@@ -205,6 +206,8 @@ SUNWprivate_1.1 { ...@@ -205,6 +206,8 @@ SUNWprivate_1.1 {
JVM_NewArray; JVM_NewArray;
JVM_NewInstanceFromConstructor; JVM_NewInstanceFromConstructor;
JVM_NewMultiArray; JVM_NewMultiArray;
JVM_NotifyApplicationStartUpIsDone;
JVM_NotifyJVMDeoptWarmUpMethods;
JVM_OnExit; JVM_OnExit;
JVM_Open; JVM_Open;
JVM_RaiseSignal; JVM_RaiseSignal;
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "interpreter/interpreterGenerator.hpp" #include "interpreter/interpreterGenerator.hpp"
#include "interpreter/interpreterRuntime.hpp" #include "interpreter/interpreterRuntime.hpp"
#include "interpreter/templateTable.hpp" #include "interpreter/templateTable.hpp"
#include "jwarmup/jitWarmUp.hpp"
#include "oops/arrayOop.hpp" #include "oops/arrayOop.hpp"
#include "oops/methodData.hpp" #include "oops/methodData.hpp"
#include "oops/method.hpp" #include "oops/method.hpp"
...@@ -334,6 +335,24 @@ void InterpreterGenerator::generate_counter_incr( ...@@ -334,6 +335,24 @@ void InterpreterGenerator::generate_counter_incr(
__ incrementl(Address(rax, __ incrementl(Address(rax,
MethodCounters::interpreter_invocation_counter_offset())); MethodCounters::interpreter_invocation_counter_offset()));
} }
#ifdef _LP64
// JitWarmUp support, record method first invocation's initialization order
if (CompilationWarmUpRecording) {
Label skip_record;
JitWarmUp* jitwarmup = JitWarmUp::instance();
assert(jitwarmup != NULL, "jitwarmup should not be NULL");
const ExternalAddress current_init_order(jitwarmup->recorder()->current_init_order_addr());
__ movl(rcx, Address(rax,
MethodCounters::interpreter_invocation_counter_offset()));
__ cmp32(rcx, 1);
__ jcc(Assembler::above, skip_record);
__ mov32(rcx, current_init_order);
__ movl(Address(rbx, Method::first_invoke_init_order_offset()), rcx);
__ bind(skip_record);
}
#endif
// Update standard invocation counters // Update standard invocation counters
__ movl(rcx, invocation_counter); __ movl(rcx, invocation_counter);
__ incrementl(rcx, InvocationCounter::count_increment); __ incrementl(rcx, InvocationCounter::count_increment);
......
...@@ -672,6 +672,63 @@ ciField* ciEnv::get_field_by_index(ciInstanceKlass* accessor, ...@@ -672,6 +672,63 @@ ciField* ciEnv::get_field_by_index(ciInstanceKlass* accessor,
GUARDED_VM_ENTRY(return get_field_by_index_impl(accessor, index);) GUARDED_VM_ENTRY(return get_field_by_index_impl(accessor, index);)
} }
// ------------------------------------------------------------------
// ciEnv::check_field_resolved
//
// Check whether this field has been resolved.
bool ciEnv::check_field_resolved(ciInstanceKlass* accessor,
int index) {
GUARDED_VM_ENTRY(
ciConstantPoolCache* cache = accessor->field_cache();
if (cache != NULL) {
ciField* field = (ciField*)cache->get(index);
if (field != NULL) {
return true;
}
}
CompilerThread *thread = CompilerThread::current();
assert(accessor->get_instanceKlass()->is_linked(), "must be linked before using its constant-pool");
constantPoolHandle cpool(thread, accessor->get_instanceKlass()->constants());
// Get the field's name, signature, and type.
Symbol* name = cpool->name_ref_at(index);
if (name == NULL) {
return false;
}
int name_index = cpool->name_and_type_ref_index_at(index);
int sig_index = cpool->signature_ref_index_at(name_index);
Symbol* signature = cpool->symbol_at(sig_index);
if (signature == NULL) {
return false;
}
return true;
)
}
// ------------------------------------------------------------------
//
// Check if all fields needed by this method in ConstantPool are resolved
bool ciEnv::check_method_fields_all_resolved(ciMethod* method) {
ciInstanceKlass* klass = method->holder();
ciBytecodeStream str(method);
int start = 0;
int limit = method->code_size();
str.reset_to_bci(start);
Bytecodes::Code code;
while ((code = str.next()) != ciBytecodeStream::EOBC() &&
str.cur_bci() < limit) {
if (code == Bytecodes::_getfield ||
code == Bytecodes::_getstatic ||
code == Bytecodes::_putfield ||
code == Bytecodes::_putstatic) {
if (!check_field_resolved(klass, str.get_index_u2_cpcache())) {
return false;
}
}
}
return true;
}
// ------------------------------------------------------------------ // ------------------------------------------------------------------
// ciEnv::lookup_method // ciEnv::lookup_method
// //
......
...@@ -126,6 +126,8 @@ private: ...@@ -126,6 +126,8 @@ private:
ciInstanceKlass* accessor); ciInstanceKlass* accessor);
ciField* get_field_by_index(ciInstanceKlass* loading_klass, ciField* get_field_by_index(ciInstanceKlass* loading_klass,
int field_index); int field_index);
bool check_field_resolved(ciInstanceKlass* accessor,
int index);
ciMethod* get_method_by_index(constantPoolHandle cpool, ciMethod* get_method_by_index(constantPoolHandle cpool,
int method_index, Bytecodes::Code bc, int method_index, Bytecodes::Code bc,
ciInstanceKlass* loading_klass); ciInstanceKlass* loading_klass);
...@@ -317,6 +319,9 @@ public: ...@@ -317,6 +319,9 @@ public:
// Return state of appropriate compilability // Return state of appropriate compilability
int compilable() { return _compilable; } int compilable() { return _compilable; }
// Check if all fields needed by this method in ConstantPool are resolved
bool check_method_fields_all_resolved(ciMethod* method);
const char* retry_message() const { const char* retry_message() const {
switch (_compilable) { switch (_compilable) {
case ciEnv::MethodCompilable_not_at_tier: case ciEnv::MethodCompilable_not_at_tier:
......
...@@ -975,6 +975,10 @@ bool ciMethod::ensure_method_data(methodHandle h_m) { ...@@ -975,6 +975,10 @@ bool ciMethod::ensure_method_data(methodHandle h_m) {
if (is_native() || is_abstract() || h_m()->is_accessor()) { if (is_native() || is_abstract() || h_m()->is_accessor()) {
return true; return true;
} }
if (CompilationWarmUp && CURRENT_ENV->task()->is_jwarmup_compilation()) {
_method_data = CURRENT_ENV->get_empty_methodData();
return false;
}
if (h_m()->method_data() == NULL) { if (h_m()->method_data() == NULL) {
Method::build_interpreter_method_data(h_m, THREAD); Method::build_interpreter_method_data(h_m, THREAD);
if (HAS_PENDING_EXCEPTION) { if (HAS_PENDING_EXCEPTION) {
...@@ -1015,7 +1019,9 @@ ciMethodData* ciMethod::method_data() { ...@@ -1015,7 +1019,9 @@ ciMethodData* ciMethod::method_data() {
Thread* my_thread = JavaThread::current(); Thread* my_thread = JavaThread::current();
methodHandle h_m(my_thread, get_Method()); methodHandle h_m(my_thread, get_Method());
if (h_m()->method_data() != NULL) { if (CompilationWarmUp && CURRENT_ENV->task()->is_jwarmup_compilation()) {
_method_data = CURRENT_ENV->get_empty_methodData();
} else if (h_m()->method_data() != NULL) {
_method_data = CURRENT_ENV->get_method_data(h_m()->method_data()); _method_data = CURRENT_ENV->get_method_data(h_m()->method_data());
_method_data->load_data(); _method_data->load_data();
} else { } else {
......
...@@ -4133,6 +4133,14 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, ...@@ -4133,6 +4133,14 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
this_klass->set_has_default_methods(has_default_methods); this_klass->set_has_default_methods(has_default_methods);
this_klass->set_declares_default_methods(declares_default_methods); this_klass->set_declares_default_methods(declares_default_methods);
if (CompilationWarmUp || CompilationWarmUpRecording) {
if (_stream->source() == NULL) {
this_klass->set_source_file_path(NULL);
} else {
this_klass->set_source_file_path(SymbolTable::new_symbol(_stream->source(), THREAD));
}
}
if (!host_klass.is_null()) { if (!host_klass.is_null()) {
assert (this_klass->is_anonymous(), "should be the same"); assert (this_klass->is_anonymous(), "should be the same");
this_klass->set_host_klass(host_klass()); this_klass->set_host_klass(host_klass());
...@@ -4270,6 +4278,13 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, ...@@ -4270,6 +4278,13 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
instanceKlassHandle this_klass (THREAD, preserve_this_klass); instanceKlassHandle this_klass (THREAD, preserve_this_klass);
debug_only(this_klass->verify();) debug_only(this_klass->verify();)
if (CompilationWarmUp || CompilationWarmUpRecording) {
unsigned int crc32 = ClassLoader::crc32(0, (char*)(_stream->buffer()), _stream->length());
unsigned int class_bytes_size = _stream->length();
this_klass->set_crc32(crc32);
this_klass->set_bytes_size(class_bytes_size);
}
// Clear class if no error has occurred so destructor doesn't deallocate it // Clear class if no error has occurred so destructor doesn't deallocate it
_klass = NULL; _klass = NULL;
return this_klass; return this_klass;
......
...@@ -763,6 +763,14 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure, boo ...@@ -763,6 +763,14 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure, boo
ClassLoaderData* prev = NULL; ClassLoaderData* prev = NULL;
bool seen_dead_loader = false; bool seen_dead_loader = false;
// Unload PreloadClassChain
if (CompilationWarmUp) {
JitWarmUp* jwp = JitWarmUp::instance();
assert(jwp != NULL, "santiy check");
PreloadClassChain* chain = jwp->preloader()->chain();
chain->do_unloading(is_alive_closure);
}
// Save previous _unloading pointer for CMS which may add to unloading list before // Save previous _unloading pointer for CMS which may add to unloading list before
// purging and we don't want to rewalk the previously unloaded class loader data. // purging and we don't want to rewalk the previously unloaded class loader data.
_saved_unloading = _unloading; _saved_unloading = _unloading;
......
...@@ -273,6 +273,29 @@ Klass* SystemDictionary::resolve_array_class_or_null(Symbol* class_name, ...@@ -273,6 +273,29 @@ Klass* SystemDictionary::resolve_array_class_or_null(Symbol* class_name,
return k; return k;
} }
class SuperClassResolvingMark : public StackObj {
public:
SuperClassResolvingMark() {
initialize(Thread::current());
}
SuperClassResolvingMark(Thread* thread) {
initialize(thread);
}
~SuperClassResolvingMark() {
assert(CompilationWarmUp, "wrong usage");
_thread->super_class_resolving_recursive_dec();
}
protected:
void initialize(Thread* thread) {
assert(CompilationWarmUp, "wrong usage");
_thread = thread;
_thread->super_class_resolving_recursive_inc();
}
private:
Thread* _thread;
};
// Must be called for any super-class or super-interface resolution // Must be called for any super-class or super-interface resolution
// during class definition to allow class circularity checking // during class definition to allow class circularity checking
...@@ -373,11 +396,21 @@ Klass* SystemDictionary::resolve_super_or_fail(Symbol* child_name, ...@@ -373,11 +396,21 @@ Klass* SystemDictionary::resolve_super_or_fail(Symbol* child_name,
// java.lang.Object should have been found above // java.lang.Object should have been found above
assert(class_name != NULL, "null super class for resolving"); assert(class_name != NULL, "null super class for resolving");
// Resolve the super class or interface, check results on return // Resolve the super class or interface, check results on return
Klass* superk = SystemDictionary::resolve_or_null(class_name, Klass* superk = NULL;
class_loader, if (CompilationWarmUp) {
protection_domain, SuperClassResolvingMark scrm;
THREAD); superk =
SystemDictionary::resolve_or_null(class_name,
class_loader,
protection_domain,
THREAD);
} else {
superk =
SystemDictionary::resolve_or_null(class_name,
class_loader,
protection_domain,
THREAD);
}
KlassHandle superk_h(THREAD, superk); KlassHandle superk_h(THREAD, superk);
// Clean up of placeholders moved so that each classloadAction registrar self-cleans up // Clean up of placeholders moved so that each classloadAction registrar self-cleans up
...@@ -868,6 +901,14 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, ...@@ -868,6 +901,14 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name,
} }
#endif #endif
if (CompilationWarmUp) {
if (!class_has_been_loaded) {
JitWarmUp* jwp = JitWarmUp::instance();
assert(jwp != NULL, "sanity check");
jwp->preloader()->resolve_loaded_klass(k());
}
}
// return if the protection domain in NULL // return if the protection domain in NULL
if (protection_domain() == NULL) return k(); if (protection_domain() == NULL) return k();
...@@ -1155,6 +1196,12 @@ Klass* SystemDictionary::resolve_from_stream(Symbol* class_name, ...@@ -1155,6 +1196,12 @@ Klass* SystemDictionary::resolve_from_stream(Symbol* class_name,
} }
} ); } );
if (CompilationWarmUp) {
JitWarmUp* jwp = JitWarmUp::instance();
assert(jwp != NULL, "sanity check");
jwp->preloader()->resolve_loaded_klass(k());
}
return k(); return k();
} }
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "classfile/classFileStream.hpp" #include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp" #include "classfile/classLoader.hpp"
#include "jwarmup/jitWarmUp.hpp"
#include "oops/objArrayOop.hpp" #include "oops/objArrayOop.hpp"
#include "oops/symbol.hpp" #include "oops/symbol.hpp"
#include "runtime/java.hpp" #include "runtime/java.hpp"
...@@ -201,6 +202,8 @@ class SymbolPropertyTable; ...@@ -201,6 +202,8 @@ class SymbolPropertyTable;
class SystemDictionary : AllStatic { class SystemDictionary : AllStatic {
friend class VMStructs; friend class VMStructs;
friend class SystemDictionaryHandles; friend class SystemDictionaryHandles;
friend class JitWarmUp;
friend class PreloadJitInfo;
public: public:
enum WKID { enum WKID {
......
...@@ -410,6 +410,7 @@ ...@@ -410,6 +410,7 @@
template(signers_name, "signers_name") \ template(signers_name, "signers_name") \
template(loader_data_name, "loader_data") \ template(loader_data_name, "loader_data") \
template(dependencies_name, "dependencies") \ template(dependencies_name, "dependencies") \
template(jwarmup_dummy_name, "dummy") \
template(input_stream_void_signature, "(Ljava/io/InputStream;)V") \ template(input_stream_void_signature, "(Ljava/io/InputStream;)V") \
template(getFileURL_name, "getFileURL") \ template(getFileURL_name, "getFileURL") \
template(getFileURL_signature, "(Ljava/io/File;)Ljava/net/URL;") \ template(getFileURL_signature, "(Ljava/io/File;)Ljava/net/URL;") \
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "compiler/compilerOracle.hpp" #include "compiler/compilerOracle.hpp"
#include "compiler/disassembler.hpp" #include "compiler/disassembler.hpp"
#include "interpreter/bytecode.hpp" #include "interpreter/bytecode.hpp"
#include "jwarmup/jitWarmUp.hpp"
#include "oops/methodData.hpp" #include "oops/methodData.hpp"
#include "prims/jvmtiRedefineClassesTrace.hpp" #include "prims/jvmtiRedefineClassesTrace.hpp"
#include "prims/jvmtiImpl.hpp" #include "prims/jvmtiImpl.hpp"
...@@ -649,6 +650,10 @@ nmethod* nmethod::new_nmethod(methodHandle method, ...@@ -649,6 +650,10 @@ nmethod* nmethod::new_nmethod(methodHandle method,
DEBUG_ONLY(nm->verify();) DEBUG_ONLY(nm->verify();)
nm->log_new_nmethod(); nm->log_new_nmethod();
} }
if (CompilationWarmUpRecording && nm != NULL && comp_level >= CompilationWarmUpRecordMinLevel) {
int bci = nm->is_osr_method() ? nm->osr_entry_bci() : InvocationEntryBci;
JitWarmUp::instance()->recorder()->add_method(nm->method(), bci);
}
return nm; return nm;
} }
......
...@@ -331,6 +331,8 @@ void CompileTask::initialize(int compile_id, ...@@ -331,6 +331,8 @@ void CompileTask::initialize(int compile_id,
_comment = comment; _comment = comment;
_failure_reason = NULL; _failure_reason = NULL;
_is_jwarmup_compilation = false;
if (LogCompilation) { if (LogCompilation) {
_time_queued = os::elapsed_counter(); _time_queued = os::elapsed_counter();
if (hot_method.not_null()) { if (hot_method.not_null()) {
...@@ -1594,6 +1596,9 @@ CompileTask* CompileBroker::create_compile_task(CompileQueue* queue, ...@@ -1594,6 +1596,9 @@ CompileTask* CompileBroker::create_compile_task(CompileQueue* queue,
new_task->initialize(compile_id, method, osr_bci, comp_level, new_task->initialize(compile_id, method, osr_bci, comp_level,
hot_method, hot_count, comment, hot_method, hot_count, comment,
blocking); blocking);
if (strcmp(comment, "JitWarmUp") == 0) {
new_task->mark_jwarmup_compilation();
}
queue->add(new_task); queue->add(new_task);
return new_task; return new_task;
} }
......
...@@ -65,6 +65,7 @@ class CompileTask : public CHeapObj<mtCompiler> { ...@@ -65,6 +65,7 @@ class CompileTask : public CHeapObj<mtCompiler> {
int _hot_count; // information about its invocation counter int _hot_count; // information about its invocation counter
const char* _comment; // more info about the task const char* _comment; // more info about the task
const char* _failure_reason; const char* _failure_reason;
bool _is_jwarmup_compilation;
public: public:
CompileTask() { CompileTask() {
...@@ -84,6 +85,8 @@ class CompileTask : public CHeapObj<mtCompiler> { ...@@ -84,6 +85,8 @@ class CompileTask : public CHeapObj<mtCompiler> {
bool is_complete() const { return _is_complete; } bool is_complete() const { return _is_complete; }
bool is_blocking() const { return _is_blocking; } bool is_blocking() const { return _is_blocking; }
bool is_success() const { return _is_success; } bool is_success() const { return _is_success; }
bool is_jwarmup_compilation() const { return _is_jwarmup_compilation; }
void mark_jwarmup_compilation() { _is_jwarmup_compilation = true; }
nmethodLocker* code_handle() const { return _code_handle; } nmethodLocker* code_handle() const { return _code_handle; }
void set_code_handle(nmethodLocker* l) { _code_handle = l; } void set_code_handle(nmethodLocker* l) { _code_handle = l; }
......
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#include "precompiled.hpp"
#include "classfile/classLoaderData.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "compiler/compileBroker.hpp"
#include "jwarmup/jitWarmUp.hpp"
#include "jwarmup/jitWarmUpThread.hpp"
#include "oops/method.hpp"
#include "oops/typeArrayKlass.hpp"
#include "runtime/arguments.hpp"
#include "runtime/compilationPolicy.hpp"
#include "runtime/fieldType.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/os.hpp"
#include "runtime/thread.hpp"
#include "utilities/hashtable.inline.hpp"
#include "utilities/stack.hpp"
#include "utilities/stack.inline.hpp"
#include "runtime/atomic.hpp"
#include "jwarmup/jitWarmUpLog.hpp" // must be last one to use customized jwarmup log
#define JITWARMUP_VERSION 0x2
JitWarmUp* JitWarmUp::_instance = NULL;
JitWarmUp::JitWarmUp()
: _state(NOT_INIT),
_version(JITWARMUP_VERSION),
_dummy_method(NULL),
_recorder(NULL),
_preloader(NULL),
_excluding_matcher(NULL) {
}
JitWarmUp::~JitWarmUp() {
delete _recorder;
delete _preloader;
}
JitWarmUp* JitWarmUp::create_instance() {
_instance = new JitWarmUp();
return _instance;
}
// JitWarmUp Init functions
JitWarmUp::JitWarmUpState JitWarmUp::init_for_recording() {
assert(CompilationWarmUpRecording && !CompilationWarmUp, "JVM option verify failure");
_recorder = new ProfileRecorder();
_recorder->set_holder(this);
_recorder->init();
if (CompilationWarmUpRecordTime > 0) {
// use a thread to flush info
JitWarmUpFlushThread::spawn_wait_for_flush(CompilationWarmUpRecordTime);
}
if (_recorder->is_valid()) {
_state = JitWarmUp::IS_OK;
} else {
_state = JitWarmUp::IS_ERR;
}
return _state;
}
JitWarmUp::JitWarmUpState JitWarmUp::init_for_warmup() {
assert(!CompilationWarmUpRecording && CompilationWarmUp, "JVM option verify");
if (CompilationWarmUpExclude != NULL) {
_excluding_matcher = new (ResourceObj::C_HEAP, mtClass) SymbolMatcher<mtClass>(CompilationWarmUpExclude);
}
if (CompilationWarmUpExplicitDeopt && CompilationWarmUpDeoptTime > 0) {
log_warning(warmup)("[JitWarmUp] WARNING : CompilationWarmUpDeoptTime is unused when CompilationWarmUpExplicitDeopt is enable");
}
_preloader = new PreloadJitInfo();
_preloader->set_holder(this);
_preloader->init();
if (_preloader->is_valid()) {
_state = JitWarmUp::IS_OK;
} else {
_state = JitWarmUp::IS_ERR;
}
return _state;
}
// init JitWarmUp module
void JitWarmUp::init() {
if (CompilationWarmUp) {
init_for_warmup();
} else if(CompilationWarmUpRecording) {
init_for_recording();
}
// check valid
if ((CompilationWarmUpRecording || CompilationWarmUp) && !JitWarmUp::is_valid()) {
log_error(warmup)("[JitWarmUp] ERROR: init error.");
vm_exit(-1);
}
}
JitWarmUp::JitWarmUpState JitWarmUp::flush_logfile() {
// state in error
if(_state == IS_ERR) {
return _state;
}
_recorder->flush();
if (_recorder->is_valid()) {
_state = IS_OK;
} else {
_state = IS_ERR;
}
return _state;
}
bool JitWarmUp::commit_compilation(methodHandle m, int bci, TRAPS) {
// use C2 compiler
int comp_level = CompLevel_full_optimization;
if (CompilationPolicy::can_be_compiled(m, comp_level)) {
// Force compilation
CompileBroker::compile_method(m, bci, comp_level,
methodHandle(), 0,
"JitWarmUp", THREAD);
return true;
}
return false;
}
Symbol* JitWarmUp::get_class_loader_name(ClassLoaderData* cld) {
Handle class_loader(Thread::current(), cld->class_loader());
Symbol* loader_name = NULL;
if (class_loader() != NULL) {
loader_name = PreloadJitInfo::remove_meaningless_suffix(class_loader()->klass()->name());
} else {
loader_name = SymbolTable::new_symbol("NULL", Thread::current());
}
return loader_name;
}
ProfileRecorder::ProfileRecorder()
: _holder(NULL),
_logfile(NULL),
_pos(0),
_state(NOT_INIT),
_class_init_list(NULL),
_init_list_tail_node(NULL),
_dict(NULL),
_class_init_order_count(-1),
_flushed(false),
_logfile_name(NULL),
_max_symbol_length(0) {
}
ProfileRecorder::~ProfileRecorder() {
if (!CompilationWarmUpLogfile) {
os::free((void*)logfile_name());
}
delete _class_init_list;
}
#define PROFILE_RECORDER_HT_SIZE 10240
void ProfileRecorder::init() {
assert(_state == NOT_INIT, "state error");
if (CompilationWarmUp) {
log_error(warmup)("[JitWarmUp] ERROR: you can not set both CompilationWarmUp and CompilationWarmUpRecording");
_state = IS_ERR;
return;
}
if (!ProfileInterpreter) {
log_error(warmup)("[JitWarmUp] ERROR: flag ProfileInterpreter must be on");
_state = IS_ERR;
return;
}
// disable class unloading
if (ClassUnloading) {
log_error(warmup)("[JitWarmUp] ERROR: flag ClassUnloading must be off");
_state = IS_ERR;
return;
}
if (UseConcMarkSweepGC && CMSClassUnloadingEnabled) {
log_error(warmup)("[JitWarmUp] ERROR: if use CMS gc, flag CMSClassUnloadingEnabled must be off");
_state = IS_ERR;
return;
}
if (UseG1GC && ClassUnloadingWithConcurrentMark) {
log_error(warmup)("[JitWarmUp] ERROR: if use G1 gc, flag ClassUnloadingWithConcurrentMark must be off");
_state = IS_ERR;
return;
}
// check class data sharing
if (UseSharedSpaces) {
log_error(warmup)("[JitWarmUp] ERROR: flag UseSharedSpaces must be off");
_state = IS_ERR;
return;
}
// log file name
if (CompilationWarmUpLogfile == NULL) {
char* buf = (char*)os::malloc(100, mtInternal);
char fmt[] = "jwarmup_%p.profile";
Arguments::copy_expand_pid(fmt, sizeof(fmt), buf, 100);
_logfile_name = buf;
} else {
_logfile_name = CompilationWarmUpLogfile;
}
_class_init_list = new (ResourceObj::C_HEAP, mtInternal) LinkedListImpl<ClassSymbolEntry>();
_dict = new ProfileRecordDictionary(PROFILE_RECORDER_HT_SIZE);
_state = IS_OK;
log_debug(warmup)("[JitWarmUp] begin to collect, log file is %s", logfile_name());
}
int ProfileRecorder::assign_class_init_order(InstanceKlass* klass) {
// ignore anonymous class
if (klass->is_anonymous()) {
return -1;
}
Symbol* name = klass->name();
Symbol* path = klass->source_file_path();
Symbol* loader_name = JitWarmUp::get_class_loader_name(klass->class_loader_data());
MutexLockerEx mu(ProfileRecorder_lock);
if (_init_list_tail_node == NULL) {
// add head node
_class_init_list->add(ClassSymbolEntry(name, loader_name, path));
_init_list_tail_node = _class_init_list->head();
} else {
_class_init_list->insert_after(ClassSymbolEntry(name, loader_name, path),
_init_list_tail_node);
_init_list_tail_node = _init_list_tail_node->next();
}
_class_init_order_count++;
#ifndef PRODUCT
klass->set_initialize_order(_class_init_order_count);
#endif
return _class_init_order_count;
}
void ProfileRecorder::add_method(Method* m, int bci) {
MutexLockerEx mu(ProfileRecorder_lock, Mutex::_no_safepoint_check_flag);
// if is flushed, stop adding method
if (flushed()) {
return;
}
// not deal with OSR Compilation
if (bci != InvocationEntryBci) {
return;
}
assert(is_valid(), "JitWarmUp state must be OK");
unsigned int hash = compute_hash(m);
dict()->add_method(hash, m, bci);
}
// NYI
void ProfileRecorder::remove_method(Method* m) {
ShouldNotCallThis();
}
void ProfileRecorder::update_max_symbol_length(int len) {
if (len > _max_symbol_length) {
_max_symbol_length = len;
}
}
ProfileRecordDictionary::ProfileRecordDictionary(unsigned int size)
: Hashtable<Method*, mtInternal>(size, sizeof(ProfileRecorderEntry)),
_count(0) {
// do nothing
}
ProfileRecordDictionary::~ProfileRecordDictionary() {
free_buckets();
}
ProfileRecorderEntry* ProfileRecordDictionary::new_entry(unsigned int hash, Method* method) {
ProfileRecorderEntry* entry = (ProfileRecorderEntry*)Hashtable<Method*, mtInternal>::new_entry(hash, method);
entry->init();
return entry;
}
ProfileRecorderEntry* ProfileRecordDictionary::add_method(unsigned int hash, Method* method, int bci) {
// this method should be called after a compilation task done
assert_lock_strong(ProfileRecorder_lock);
int index = hash_to_index(hash);
ProfileRecorderEntry* entry = find_entry(hash, method);
if (entry != NULL) {
return entry;
}
// not existed
entry = new_entry(hash, method);
entry->set_bci(bci);
entry->set_order(count());
add_entry(index, entry);
_count++;
return entry;
}
ProfileRecorderEntry* ProfileRecordDictionary::find_entry(unsigned int hash, Method* method) {
int index = hash_to_index(hash);
for (ProfileRecorderEntry* p = bucket(index); p != NULL; p = p->next()) {
if (p->literal() == method) {
return p;
}
}
return NULL;
}
void ProfileRecordDictionary::free_entry(ProfileRecorderEntry* entry) {
Hashtable<Method*, mtInternal>::free_entry(entry);
}
// head section macro defines
// offset section
#define VERSION_OFFSET 0
#define MAGIC_NUMBER_OFFSET 4
#define FILE_SIZE_OFFSET 8
#define CRC32_OFFSET 12
#define APPID_OFFSET 16
#define MAX_SYMBOL_LENGTH_OFFSET 20
#define RECORD_COUNT_OFFSET 24
#define TIME_OFFSET 28
#define HEADER_SIZE 36
// width section
#define VERSION_WIDTH (MAGIC_NUMBER_OFFSET - VERSION_OFFSET)
#define MAGIC_WIDTH (FILE_SIZE_OFFSET - MAGIC_NUMBER_OFFSET)
#define FILE_SIZE_WIDTH (CRC32_OFFSET - FILE_SIZE_OFFSET)
#define CRC32_WIDTH (APPID_OFFSET - CRC32_OFFSET)
#define APPID_WIDTH (MAX_SYMBOL_LENGTH_OFFSET - APPID_OFFSET)
#define MAX_SYMBOL_LENGTH_WIDTH (RECORD_COUNT_OFFSET - MAX_SYMBOL_LENGTH_OFFSET)
#define RECORD_COUNTS_WIDTH (TIME_OFFSET - RECORD_COUNT_OFFSET)
#define TIME_WIDTH (HEADER_SIZE - TIME_OFFSET)
// default value
#define MAGIC_NUMBER 0xBABA
#define FILE_DEFAULT_NUMBER 0
#define CRC32_DEFAULT_NUMBER 0
static char record_buf[12];
void ProfileRecorder::write_u1(u1 value) {
*(u1*)record_buf = value;
_logfile->write(record_buf, 1);
_pos += 1;
}
void ProfileRecorder::write_u4(u4 value) {
*(u4*)record_buf = value;
_logfile->write(record_buf, 4);
_pos += 4;
}
void ProfileRecorder::overwrite_u4(u4 value, unsigned int offset) {
*(u4*)record_buf = value;
_logfile->write(record_buf, 4, offset);
}
void ProfileRecorder::write_u8(u8 value) {
*(u8*)record_buf = value;
_logfile->write(record_buf, 8);
_pos += 8;
}
void ProfileRecorder::write_string(const char* src, size_t len) {
_logfile->write(src, len);
_logfile->write("\0", 1);
_pos += len + 1;
update_max_symbol_length((int)len);
}
void ProfileRecorder::write_string(const char* src) {
write_string(src, ::strlen(src));
}
#define JVM_DEFINE_CLASS_PATH "_JVM_DefineClass_"
#define CRC32_BUF_SIZE 1024
static char crc32_buf[CRC32_BUF_SIZE];
int ProfileRecorder::compute_crc32(randomAccessFileStream* fs) {
long old_position = (long)fs->ftell();
fs->fseek(HEADER_SIZE, SEEK_SET);
int content_size = fs->fileSize() - HEADER_SIZE;
assert(content_size > 0, "sanity check");
int loops = content_size / CRC32_BUF_SIZE;
int rest_size = content_size % CRC32_BUF_SIZE;
int crc = 0;
for (int i = 0; i < loops; ++i) {
fs->read(crc32_buf, CRC32_BUF_SIZE, 1);
crc = ClassLoader::crc32(crc, crc32_buf, CRC32_BUF_SIZE);
}
if (rest_size > 0) {
fs->read(crc32_buf, rest_size, 1);
crc = ClassLoader::crc32(crc, crc32_buf, rest_size);
}
// reset
fs->fseek(old_position, SEEK_SET);
return crc;
}
#undef CRC32_BUF_SIZE
// buffer used in write_header()
static char header_buf[HEADER_SIZE];
void ProfileRecorder::write_header() {
assert(_logfile->is_open(), "");
// header info
size_t offset = 0;
// version number
*(unsigned int*)header_buf = holder()->version();
_pos += VERSION_WIDTH;
offset += VERSION_WIDTH;
// magic number
*(unsigned int*)((char*)header_buf + offset) = MAGIC_NUMBER;
_pos += MAGIC_WIDTH;
offset += MAGIC_WIDTH;
// file size
*(unsigned int*)((char*)header_buf + offset) = FILE_DEFAULT_NUMBER;
_pos += CRC32_WIDTH;
offset += CRC32_WIDTH;
// crc32
*(unsigned int*)((char*)header_buf + offset) = CRC32_DEFAULT_NUMBER;
_pos += CRC32_WIDTH;
offset += CRC32_WIDTH;
// App id
*(unsigned int*)((char*)header_buf + offset) = CompilationWarmUpAppID;
_pos += APPID_WIDTH;
offset += APPID_WIDTH;
// max symbol length
*(unsigned int*)((char*)header_buf + offset) = 0;
_pos += MAX_SYMBOL_LENGTH_WIDTH;
offset += MAX_SYMBOL_LENGTH_WIDTH;
// record counts
*(unsigned int*)((char*)header_buf + offset) = recorded_count();
_pos += RECORD_COUNTS_WIDTH;
offset += RECORD_COUNTS_WIDTH;
// record time
*(unsigned jlong*)((char*)header_buf + offset) = os::javaTimeMillis();
_pos += TIME_WIDTH;
offset += TIME_WIDTH;
// write to file
_logfile->write(header_buf, offset);
}
// write class initialize order section
void ProfileRecorder::write_inited_class() {
assert(_logfile->is_open(), "log file must be opened");
ResourceMark rm;
unsigned int begin_pos = _pos;
unsigned int size_anchor = begin_pos;
// size place holder
write_u4((u4)MAGIC_NUMBER);
// class init order, beginning from -1
write_u4((u4)class_init_count());
int cnt = 0;
const LinkedListNode<ClassSymbolEntry>* node = class_init_list()->head();
while (node != NULL) {
const ClassSymbolEntry* entry = node->peek();
char* class_name = entry->class_name()->as_C_string();
const char* class_loader_name = NULL;
if (entry->class_loader_name() == NULL) {
class_loader_name = "NULL";
} else {
class_loader_name = entry->class_loader_name()->as_C_string();
}
const char* path = NULL;
if (entry->path() == NULL) {
path = JVM_DEFINE_CLASS_PATH;
} else {
path = entry->path()->as_C_string();
}
write_string(class_name, strlen(class_name));
write_string(class_loader_name, strlen(class_loader_name));
write_string(path, strlen(path));
node = node->next();
cnt++;
}
assert(cnt == class_init_count(), "error happened in profile info record");
unsigned int end_pos = _pos;
unsigned int section_size = end_pos - begin_pos;
overwrite_u4(section_size, size_anchor);
}
// write profile information
void ProfileRecorder::write_record(Method* method, int bci, int order) {
ResourceMark rm;
unsigned int begin_pos = _pos;
unsigned int total_size = 0;
ConstMethod* cm = method->constMethod();
MethodCounters* mc = method->method_counters();
InstanceKlass* klass = cm->constants()->pool_holder();
unsigned int size_anchor = begin_pos;
// size place holder
write_u4((u4)MAGIC_NUMBER);
write_u4((u4)order);
// write compilation type
u1 compilation_type = bci == -1 ? 0 : 1;
write_u1(compilation_type);
// write method info
char* method_name = method->name()->as_C_string();
write_string(method_name, strlen(method_name));
char* method_sig = method->signature()->as_C_string();
write_string(method_sig, strlen(method_sig));
// first invoke init order
write_u4((u4)method->first_invoke_init_order());
// bytecode size
write_u4((u4)cm->code_size());
int method_hash = hashstr2((char *)(cm->code_base()), cm->code_size());
write_u4((u4)method_hash);
write_u4((u4)bci);
// write class info
char* class_name = klass->name()->as_C_string();
Symbol* path_sym = klass->source_file_path();
const char* path = NULL;
if (path_sym != NULL) {
path = path_sym->as_C_string();
} else {
path = JVM_DEFINE_CLASS_PATH;
}
oop class_loader = klass->class_loader();
const char* loader_name = NULL;
if (class_loader != NULL) {
loader_name = class_loader->klass()->name()->as_C_string();
} else {
loader_name = "NULL";
}
write_string(class_name, strlen(class_name));
write_string(loader_name, strlen(loader_name));
write_string(path, strlen(path));
write_u4((u4)klass->bytes_size());
write_u4((u4)klass->crc32());
write_u4((u4)0x00); // class hash field is reserved, not used yet
// method counters
if (mc!=NULL) {
write_u4((u4)mc->interpreter_invocation_count());
write_u4((u4)mc->interpreter_throwout_count());
write_u4((u4)mc->invocation_counter()->raw_counter());
write_u4((u4)mc->backedge_counter()->raw_counter());
} else {
log_warning(warmup)("[JitWarmUp] WARNING : method counter is NULL for method %s::%s %s",
class_name, method_name, method_sig);
write_u4((u4)0);
write_u4((u4)0);
write_u4((u4)0);
write_u4((u4)0);
}
unsigned int end_pos = _pos;
unsigned int section_size = end_pos - begin_pos;
overwrite_u4(section_size, size_anchor);
}
void ProfileRecorder::write_footer() {
}
void ProfileRecorder::flush() {
MutexLockerEx mu(ProfileRecorder_lock);
if (!is_valid() || flushed()) {
return;
}
set_flushed(true);
// open randomAccessFileStream
_logfile = new (ResourceObj::C_HEAP, mtInternal) randomAccessFileStream(logfile_name(), "wb+");
if (_logfile == NULL || !_logfile->is_open()) {
log_error(warmup)("[JitWarmUp] ERROR : open log file error! path is %s", logfile_name());
_state = IS_ERR;
return;
}
// head section
write_header();
// write class init section
write_inited_class();
// write method profile info
for (int index = 0; index < dict()->table_size(); index++) {
for (ProfileRecorderEntry* entry = dict()->bucket(index);
entry != NULL;
entry = entry->next()) {
write_record(entry->literal(), entry->bci(), entry->order());
}
}
// foot section
write_footer();
// set file size
overwrite_u4((u4)_pos, FILE_SIZE_OFFSET);
// set max symbol length
overwrite_u4((u4)_max_symbol_length, MAX_SYMBOL_LENGTH_OFFSET);
// compute and set file's crc32
int crc32 = ProfileRecorder::compute_crc32(_logfile);
overwrite_u4((u4)crc32, CRC32_OFFSET);
_logfile->flush();
// close fd
delete _logfile;
_logfile = NULL;
log_info(warmup)("[JitWarmUp] output profile info has done, file is %s", logfile_name());
}
// =========================== Preload Class Module ========================== //
PreloadClassDictionary::PreloadClassDictionary(int size)
: Hashtable<Symbol*, mtInternal>(size, sizeof(PreloadClassEntry)) {
// do nothing
}
PreloadClassDictionary::~PreloadClassDictionary() { }
PreloadClassEntry* PreloadClassDictionary::new_entry(Symbol* symbol) {
unsigned int hash = symbol->identity_hash();
PreloadClassEntry* entry = (PreloadClassEntry*)Hashtable<Symbol*, mtInternal>::
new_entry(hash, symbol);
entry->init();
return entry;
}
// NYI
void PreloadClassDictionary::remove_entry(unsigned int hash_value,
unsigned int class_size,
unsigned int crc32,
Symbol* symbol) {
ShouldNotCallThis();
}
PreloadClassEntry* PreloadClassDictionary::find_entry(InstanceKlass* k) {
Symbol* name = k->name();
Symbol* path = k->source_file_path();
if (path == NULL) {
path = SymbolTable::new_symbol(JVM_DEFINE_CLASS_PATH, Thread::current());
}
Symbol* loader_name = JitWarmUp::get_class_loader_name(k->class_loader_data());
int hash = name->identity_hash();
return find_entry(hash, name, loader_name, path);
}
PreloadClassEntry* PreloadClassDictionary::find_entry(unsigned int hash_value,
Symbol* name,
Symbol* loader_name,
Symbol* path) {
int index = hash_to_index(hash_value);
for (PreloadClassEntry* p = bucket(index); p != NULL; p = p->next()) {
if (p->literal()->fast_compare(name) == 0 &&
p->loader_name()->fast_compare(loader_name) == 0 &&
p->path()->fast_compare(path) == 0) {
return p;
}
}
// not found
return NULL;
}
PreloadClassEntry* PreloadClassDictionary::find_head_entry(unsigned int hash_value,
Symbol* name) {
int index = hash_to_index(hash_value);
for (PreloadClassEntry* p = bucket(index); p != NULL; p = p->next()) {
if (p->literal()->fast_compare(name) == 0) {
return p;
}
}
// not found
return NULL;
}
PreloadClassHolder* PreloadClassDictionary::find_holder(unsigned int hash_value,
unsigned int class_size,
unsigned int crc32,
Symbol* symbol,
Symbol* loader_name,
Symbol* path) {
PreloadClassEntry* entry = find_entry(hash_value, symbol, loader_name, path);
assert(entry != NULL, "JitWarmUp log file error");
return entry->find_holder_in_entry(class_size, crc32);
}
PreloadClassHolder* PreloadClassEntry::find_holder_in_entry(unsigned int size,
unsigned int crc32) {
for (PreloadClassHolder* p = this->head_holder(); p != NULL; p = p->next()) {
if (p->crc32() == crc32 && p->size() == size) {
return p;
}
}
// not found
return NULL;
}
PreloadMethodHolder* PreloadMethodHolder::clone_and_add() {
PreloadMethodHolder* clone = new PreloadMethodHolder(*this);
clone->set_next(_next);
_next = clone;
return clone;
}
PreloadClassEntry* PreloadClassDictionary::find_and_add_class_entry(unsigned int hash_value,
Symbol* name,
Symbol* loader_name,
Symbol* path,
int index) {
PreloadClassEntry* p = find_entry(hash_value, name, loader_name, path);
if (p == NULL) {
p = new_entry(name);
p->set_chain_offset(index);
p->set_loader_name(loader_name);
p->set_path(path);
add_entry(hash_to_index(hash_value), p);
}
return p;
}
PreloadMethodHolder::PreloadMethodHolder(Symbol* name, Symbol* signature)
: _name(name),
_signature(signature),
_size(0),
_hash(0),
_intp_invocation_count(0),
_intp_throwout_count(0),
_invocation_count(0),
_backage_count(0),
_mounted_offset(-1),
_owns_md_list(true),
_is_deopted(false),
_next(NULL),
_resolved_method(NULL),
_md_list(new (ResourceObj::C_HEAP, mtClass)
GrowableArray<MDRecordInfo*>(16, true, mtClass)) {
// do nothing
}
PreloadMethodHolder::PreloadMethodHolder(PreloadMethodHolder& rhs)
: _name(rhs._name),
_signature(rhs._signature),
_size(rhs._size),
_hash(rhs._hash),
_intp_invocation_count(rhs._intp_invocation_count),
_intp_throwout_count(rhs._intp_throwout_count),
_invocation_count(rhs._invocation_count),
_backage_count(rhs._backage_count),
_mounted_offset(rhs._mounted_offset),
_owns_md_list(false),
_is_deopted(false),
_next(NULL),
_resolved_method(NULL),
_md_list(rhs._md_list) {
}
PreloadMethodHolder::~PreloadMethodHolder() {
if (_owns_md_list) {
delete _md_list;
}
}
bool PreloadMethodHolder::check_matching(Method* method) {
// NYI size and hash not used yet
if (name()->fast_compare(method->name()) == 0
&& signature()->fast_compare(method->signature()) == 0) {
return true;
} else {
return false;
}
}
bool PreloadMethodHolder::is_alive(BoolObjectClosure* is_alive_closure) const {
if (_resolved_method == NULL) {
return false;
}
ClassLoaderData* data = _resolved_method->method_holder()->class_loader_data();
return data->is_alive(is_alive_closure);
}
PreloadClassHolder::PreloadClassHolder(Symbol* name, Symbol* loader_name,
Symbol* path, unsigned int size,
unsigned int hash, unsigned int crc32)
: _size(size),
_hash(hash),
_crc32(crc32),
_class_name(name),
_class_loader_name(loader_name),
_path(path),
_method_list(new (ResourceObj::C_HEAP, mtInternal)
GrowableArray<PreloadMethodHolder*>(16, true, mtClass)),
_resolved(false),
_next(NULL) {
// do nothing
}
PreloadClassHolder::~PreloadClassHolder() {
delete _method_list;
}
bool PreloadClassChain::PreloadClassChainEntry::is_all_initialized() {
int len = resolved_klasses()->length();
if (len == 0) {
// no resolved klasses in this entry
return false;
}
for (int i = 0; i < len; i++) {
InstanceKlass* k = resolved_klasses()->at(i);
// Thread which invokes notify_application_startup_is_done might be potentially
// blocked for a long time if class initialization (<clinit>) gets executed
// for quite a while, e.g : reading from network.
// we use is_not_initialized() as condition here instead of !is_initialized()
// to alleviate this case.
if (k != NULL && k->is_not_initialized() && !k->is_in_error_state() ) {
return false;
}
}
return true;
}
// warmup record methods when class is loaded,
// if class is redefined between class load and warmup compilation
// the recorded method oop is invalid, so we need check redefined
// class before warmup compilation
bool PreloadClassChain::PreloadClassChainEntry::has_redefined_class() {
int len = resolved_klasses()->length();
for (int i = 0; i < len; i++) {
InstanceKlass* k = resolved_klasses()->at(i);
if (k != NULL && k->has_been_redefined()) {
ResourceMark rm;
log_warning(warmup)("[JitWarmUp] WARNING: ignore redefined class after API"
" notifyApplicationStartUpIsDone : %s:%s@%s.", class_name()->as_C_string(),
loader_name()->as_C_string(), path()->as_C_string());
return true;
}
}
return false;
}
InstanceKlass* PreloadClassChain::PreloadClassChainEntry::get_first_uninitialized_klass() {
int len = resolved_klasses()->length();
for (int i = 0; i < len; i++) {
InstanceKlass* k = resolved_klasses()->at(i);
if (k != NULL && k->is_not_initialized()) {
return k;
}
}
return NULL;
}
PreloadMethodHolder* MethodHolderIterator::next() {
PreloadMethodHolder* next_holder = _cur->next();
if (next_holder != NULL) {
_cur = next_holder;
return _cur;
}
while (_index > 0) {
_index--;
PreloadClassChain::PreloadClassChainEntry* entry = _chain->at(_index);
if (entry->method_holder() != NULL) {
_cur = entry->method_holder();
return _cur;
}
}
_cur = NULL;
return _cur;
}
PreloadClassChain::PreloadClassChain(unsigned int size)
: _inited_index(-1),
_loaded_index(-1),
_length(size),
_state(NOT_INITED),
_entries(new PreloadClassChainEntry[size]),
_holder(NULL),
_init_timestamp(),
_last_timestamp(),
_deopt_index(-1),
_deopt_cur_holder(NULL),
_has_unmarked_compiling_flag(false) {
_init_timestamp.update();
_last_timestamp.update();
state_trans_to(INITED);
}
PreloadClassChain::~PreloadClassChain() {
delete[] _entries;
}
bool PreloadClassChain::state_trans_to(ClassChainState new_state) {
ClassChainState old_state = current_state();
if (old_state == new_state) {
log_warning(warmup)("JitWarmUp [WARNING]: warmup state already transfer to %d", new_state);
return true;
}
bool can_transfer = false;
switch (new_state) {
case ERROR_STATE:
if (old_state != WARMUP_DEOPTIMIZED) {
// almost all states could transfer to error state
// except jwarmup has done all work
can_transfer = true;
}
break;
default:
if (new_state == old_state + 1) {
can_transfer = true;
}
break;
}
if (can_transfer) {
if (Atomic::cmpxchg((jint)new_state, (jint*)&_state, (jint)old_state) == old_state) {
return true;
} else {
log_warning(warmup)("JitWarmUp [WARNING]: failed to transfer warmup state from %d to %d, conflict with other operation", old_state, new_state);
return false;
}
} else {
log_warning(warmup)("JitWarmUp [WARNING]: can not transfer warmup state from %d to %d", old_state, new_state);
return false;
}
}
void PreloadClassChain::record_loaded_class(InstanceKlass* k) {
Symbol* class_name = k->name();
unsigned int crc32 = k->crc32();
unsigned int size = k->bytes_size();
// state check, if warmup compilation was done, no need to record class
if (!can_record_class()) {
return;
}
PreloadClassEntry* class_entry = holder()->dict()->find_entry(k);
if (class_entry == NULL) {
// this class is NOT in jwarmup profile
return;
}
int chain_index = class_entry->chain_offset();
PreloadClassHolder* holder = class_entry->find_holder_in_entry(size, crc32);
if (holder != NULL) {
if (holder->resolved()) {
// same class may be loaded by different class loaders, now we can not
// know which one is recorded in profile and should be warmup, the simple
// solution here is skip duplicated class
Thread* t = Thread::current();
if (!t->in_super_class_resolving()) {
// just print a warning
assert(k->is_not_initialized(), "klass state error");
assert(t->is_Java_thread(), "sanity check");
ResourceMark rm;
log_warning(warmup)("[JitWarmUp] WARNING : duplicate load class %s at index %d",
k->name()->as_C_string(), chain_index);
}
return;
} else {
// resolve methods in holder
MutexLockerEx mu(PreloadClassChain_lock);
int methods = k->methods()->length();
for (int index = 0; index < methods; index++) {
Method* m = k->methods()->at(index);
resolve_method_info(m, holder);
}
{
ResourceMark rm;
log_debug(warmup)("[JitWarmUp] DEBUG : class %s at index %d is recorded",
k->name()->as_C_string(), chain_index);
}
holder->set_resolved();
}
} else {
ResourceMark rm;
log_debug(warmup)("[JitWarmUp] DEBUG : class %s is not in profile",
k->name()->as_C_string());
}
//set entry to loaded
{
// add loaded class to chain
MutexLockerEx mu(PreloadClassChain_lock);
assert(chain_index >= 0 && chain_index <= length(), "index out of bound");
assert(loaded_index() >= inited_index(), "loaded index must larger than inited index");
PreloadClassChainEntry* chain_entry = &_entries[chain_index];
// check state
if (chain_entry->is_skipped()) {
// the loaded class is skipped to record
ResourceMark rm;
log_warning(warmup)("[JitWarmUp] WARNING : loaded class %s at index %d is ignored",
k->name()->as_C_string(), chain_index);
return;
} else if (chain_entry->is_inited()) {
// warmup has compiled methods for this entry
return;
}
chain_entry->resolved_klasses()->append(k);
chain_entry->set_loaded();
// increase loaded index by chance
if (chain_index == loaded_index() + 1) {
update_loaded_index(chain_index);
}
} // end of MutexLocker guard
}
void PreloadClassChain::mount_method_at(PreloadMethodHolder* mh, int index) {
assert(index >= 0 && index < length(), "out of bound");
PreloadClassChainEntry* entry = &_entries[index];
entry->add_method_holder(mh);
}
void PreloadClassChain::update_loaded_index(int index) {
assert(index >= 0 && index < length(), "out of bound");
// out of bound or entry is not loaded
while (index < length() && !_entries[index].is_not_loaded()) {
index++;
}
set_loaded_index(index - 1);
}
void PreloadClassChain::compile_methodholders_queue(Stack<PreloadMethodHolder*, mtInternal>& compile_queue) {
while (!compile_queue.is_empty()) {
PreloadMethodHolder* pmh = compile_queue.pop();
compile_methodholder(pmh);
Thread* THREAD = Thread::current();
if (HAS_PENDING_EXCEPTION) {
ResourceMark rm;
log_warning(warmup)("[JitWarmUp] WARNING: Exceptions happened in compiling %s",
pmh->name()->as_C_string());
// ignore exception occurs during compilation
CLEAR_PENDING_EXCEPTION;
continue;
}
}
}
void PreloadClassChain::warmup_impl() {
Thread* THREAD = Thread::current();
if (!state_trans_to(WARMUP_COMPILING)) {
log_warning(warmup)("JitWarmUp [WARNING]: invalid state to begin compiling");
return;
}
/* iterate all PreloadClassChainEntry to submit warmup compilation*/
bool cancel_warmup = false;
for ( int index = 0; index < length(); index++ ) {
if (cancel_warmup) {
break;
}
InstanceKlass* klass = NULL;
// the stack used for storing methods that need be compiled
Stack<PreloadMethodHolder*, mtInternal> compile_queue;
{
MutexLockerEx mu(PreloadClassChain_lock);
PreloadClassChainEntry *entry = &_entries[index];
switch(entry->state()) {
case PreloadClassChainEntry::_not_loaded:
// skip non-loaded class
entry->set_skipped();
{
ResourceMark rm;
log_warning(warmup)("[JitWarmUp] WARNING: ignore class because it is not loaded before warmup"
" : %s:%s@%s.", entry->class_name()->as_C_string(),
entry->loader_name()->as_C_string(), entry->path()->as_C_string());
}
case PreloadClassChainEntry::_is_skipped:
break;
case PreloadClassChainEntry::_is_loaded:
// TODO: now only one klass is recorded in resolved_klasses, we can extend to initialize
// all recorded classes
// PreloadClassChain_lock is _safepoint_check_always, we can not initialize class here
// so defer initialization when mutex is out of scope
klass = entry->get_first_uninitialized_klass();
entry->set_inited();
case PreloadClassChainEntry::_is_inited:
if (!entry->has_redefined_class()){
PreloadMethodHolder* mh = entry->method_holder();
while (mh != NULL) {
compile_queue.push(mh);
mh = mh->next();
}
}
break;
default:
{
ResourceMark rm;
log_error(warmup)("[JitWarmUp] ERROR: class %s has invalid entry state %d.",
entry->class_name()->as_C_string(),
entry->state());
return;
}
}
} // end of mutex guard
// initialize loaded and uninitilaized klass
if (klass != NULL) {
// if exception occurs during initialization, just throws back to java code
assert(THREAD->is_Java_thread(), "sanity check");
klass->initialize(THREAD);
if (HAS_PENDING_EXCEPTION) {
Symbol *loader = JitWarmUp::get_class_loader_name(klass->class_loader_data());
ResourceMark rm;
log_error(warmup)("[JitWarmUp] ERROR: Exceptions happened in initializing %s being loaded by %s",
klass->name()->as_C_string(), loader->as_C_string());
return;
}
}
{
MutexLockerEx mu(PreloadClassChain_lock);
// update loaded_index and inited_index
refresh_indexes();
if (index > inited_index()) {
// we go beyond inited_index, can not continue
cancel_warmup = true;
}
}
// compile methods in compile_queue
compile_methodholders_queue(compile_queue);
}
}
bool PreloadClassChain::compile_methodholder(PreloadMethodHolder* mh) {
Thread* t = Thread::current();
methodHandle m(t, mh->resolved_method());
if (m() == NULL || m->compiled_by_jwarmup() || m->has_compiled_code()) {
return false;
}
InstanceKlass* klass = m->constants()->pool_holder();
// skip uninitialized klass
if (!klass->is_initialized()) {
return false;
}
m->set_compiled_by_jwarmup(true);
// not deal with osr compilation
int bci = InvocationEntryBci;
bool ret = JitWarmUp::commit_compilation(m, bci, t);
if (ret) {
ResourceMark rm;
log_info(warmup)("[JitWarmUp] preload method %s success compiled",
m->name_and_sig_as_C_string());
}
return ret;
}
void PreloadClassChain::refresh_indexes() {
assert_lock_strong(PreloadClassChain_lock);
int loaded = loaded_index();
int inited = inited_index();
for (int i = inited + 1; i < length(); i++) {
PreloadClassChainEntry* e = &_entries[i];
int len = e->resolved_klasses()->length();
if (e->is_not_loaded()) {
assert(len == 0, "wrong state");
}
if (e->is_loaded()) {
assert(len > 0, "class init chain entry state error");
if (e->is_all_initialized()) {
e->set_inited();
}
}
// refresh indexes
if (e->is_loaded() && i == loaded + 1) {
loaded = i;
} else if (e->is_inited() && i == inited + 1) {
loaded = i; // ???, loaded index may be reduced
inited = i;
} else if (e->is_skipped()) {
if (i == loaded + 1) {
loaded = i;
}
if (i == inited + 1) {
inited = i;
}
} else {
// break loop
break;
}
} // end of loop
assert(loaded >= inited, "loaded index must not less than inited index");
set_loaded_index(loaded);
set_inited_index(inited);
}
bool PreloadClassChain::should_deoptimize_methods() {
assert(CompilationWarmUp, "Sanity check");
assert(SafepointSynchronize::is_at_safepoint(), "must be in safepoint");
ClassChainState state = current_state();
if (state == WARMUP_DEOPTIMIZED || state == ERROR_STATE) {
return false;
}
if (!CompilationWarmUpExplicitDeopt && CompilationWarmUpDeoptTime > 0) {
if (_init_timestamp.seconds() < CompilationWarmUpDeoptTime) {
return false;
} else if (state == WARMUP_DONE) {
state_trans_to(WARMUP_PRE_DEOPTIMIZE);
} else {
// do nothing
}
}
if (current_state() != WARMUP_DEOPTIMIZING
&& current_state() != WARMUP_PRE_DEOPTIMIZE) {
return false;
}
Method* dummy_method = JitWarmUp::instance()->dummy_method();
if (dummy_method == NULL || dummy_method->code() == NULL) {
// dummy method is not compiled
return false;
}
// deoptimize interval
if (_last_timestamp.seconds() < CompilationWarmUpDeoptMinInterval) {
return false;
}
// if this safepoint doesn't allow the nested VMOperation, skip it
VM_Operation* op = VMThread::vm_operation();
if (op != NULL && !op->allow_nested_vm_operations()) {
return false;
}
// length is too short, maybe log file corrupted
if (_length <= 1) {
return false;
}
return true;
}
void PreloadClassChain::deopt_prologue() {
/*
* state transition:
* inside deopt_prologue, state should be WARMUP_PRE_DEOPTIMIZE or WARMUP_DEOPTIMIZING.
* If state is WARMUP_PRE_DEOPTIMIZE, we are first time to enter prologue,
* trans state to WARMUP_DEOPTIMIZING
* If state is WARMUP_DEOPTIMIZING, do nothing and return
*/
if (current_state() == WARMUP_PRE_DEOPTIMIZE) {
// first time we can start deoptimize warmup methods
if (state_trans_to(WARMUP_DEOPTIMIZING)) {
log_info(warmup)("JitWarmUp [INFO]: start deoptimize warmup methods");
_deopt_index = length() - 1;
while (_deopt_index > 0 && _deopt_cur_holder == NULL) {
PreloadClassChain::PreloadClassChainEntry* entry = this->at(_deopt_index);
_deopt_cur_holder = entry->method_holder();
_deopt_index--;
}
} else {
// we are in vm thread, no conflict with other threads
ShouldNotReachHere();
}
} else {
guarantee(current_state() == WARMUP_DEOPTIMIZING, "invalid warmup state");
}
}
void PreloadClassChain::deopt_epilogue() {
state_trans_to(WARMUP_DEOPTIMIZED);
log_info(warmup)("JitWarmUp [INFO]: all warmup methods are deoptimized");
}
void PreloadClassChain::invoke_deoptimize_vmop() {
VM_Deoptimize op;
VMThread::execute(&op);
}
void PreloadClassChain::deoptimize_methods() {
assert(SafepointSynchronize::is_at_safepoint(), "must be in safepoint");
deopt_prologue();
Method* dummy_method = JitWarmUp::instance()->dummy_method();
assert( dummy_method != NULL && dummy_method->code() != NULL, "dummy method must be compiled");
int dummy_compile_id = dummy_method->code()->compile_id();
MethodHolderIterator iter(this, _deopt_cur_holder, _deopt_index);
int num = 0;
while (*iter != NULL) {
PreloadMethodHolder* pmh = *iter;
if (pmh->resolved_method() == NULL) {
iter.next();
continue;
}
methodHandle m(pmh->resolved_method());
#ifndef PRODUCT
m->set_deopted_by_jwarmup(true);
#endif
pmh->set_deopted(true);
if (m->code() != NULL && m->code()->compile_id() > dummy_compile_id) {
// the method is compiled after warmup, ignore it
ResourceMark rm;
log_warning(warmup)("[JitWarmUp] WARNING : skip deoptimize %s because it is compiled after warmup",
m->name_and_sig_as_C_string());
iter.next();
continue;
}
int result = 0;
if (m->code() != NULL) {
m->code()->mark_for_deoptimization();
result++;
}
result += CodeCache::mark_for_deoptimization(m());
if (result > 0) {
ResourceMark rm;
log_warning(warmup)("[JitWarmUp] WARNING : deoptimize warmup method %s",
m->name_and_sig_as_C_string());
num++;
}
iter.next();
if (num == (int)CompilationWarmUpDeoptNumOfMethodsPerIter) {
break;
}
}
if (num > 0) {
invoke_deoptimize_vmop();
}
_last_timestamp.update();
// update index and cur_holder in PreloadClassChain
_deopt_index = iter.index();
_deopt_cur_holder = *iter;
if (*iter == NULL) {
deopt_epilogue();
}
}
void PreloadClassChain::do_unloading(BoolObjectClosure* is_alive) {
assert(SafepointSynchronize::is_at_safepoint(), "must be in safepoint");
if (deopt_has_done()) {
return;
}
for (int i = 0; i < length(); i++) {
PreloadClassChainEntry* entry = this->at(i);
GrowableArray<InstanceKlass*>* array = entry->resolved_klasses();
for (int i = 0; i < array->length(); i++) {
InstanceKlass* k = array->at(i);
if (k == NULL) {
continue;
}
// reset InstanceKlass pointer
ClassLoaderData* data = k->class_loader_data();
if (!data->is_alive(is_alive)) {
array->remove_at(i);
}
}
for (PreloadMethodHolder* holder = entry->method_holder(); holder != NULL;
holder = holder->next()) {
if (holder->deopted()) {
continue;
}
if (!holder->is_alive(is_alive)) {
// reset Method pointer to NULL
holder->set_resolved_method(NULL);
}
} // end of method holder loop
} // end of entry loop
}
PreloadMethodHolder* PreloadClassChain::resolve_method_info(Method* method, PreloadClassHolder* holder) {
// in runtime triggered by class load event
// FIX ME! O(n) search, should be binary search
// search for matched method holder that has minimal mounted_offset
PreloadMethodHolder* mh = NULL;
for (int i = 0; i < holder->method_list()->length(); i++) {
PreloadMethodHolder* current_mh = holder->method_list()->at(i);
if (current_mh->check_matching(method)) {
mh = current_mh;
break;
}
} // end of method_list loop
if (mh == NULL) {
// not found
return mh;
} else if (mh->resolved_method() == NULL) {
mh->set_resolved_method(method);
return mh;
} else {
// if the method has been resolved, it is likely same class are loaded again
// by different classloader. we clone a new holder for this method and
// append it to holder list
PreloadMethodHolder* new_holder = mh->clone_and_add();
new_holder->set_resolved_method(method);
return new_holder;
}
}
// JitWarmUp log parser
class JitWarmUpLogParser : CHeapObj<mtInternal> {
public:
JitWarmUpLogParser(randomAccessFileStream* fs, PreloadJitInfo* holder);
virtual ~JitWarmUpLogParser();
bool valid();
bool parse_header();
bool parse_class_init_section();
bool should_ignore_this_class(Symbol* s);
// whether method record section parsing is finished
bool has_next();
// parse a record from method record section
// return NULL means the record should be skipped
// or error occurred in parsing process
PreloadMethodHolder* next();
void inc_parsed_number() { _parsed_methods++; }
int parsed_methods() { return _parsed_methods; }
int total_methods() { return _total_methods; }
long file_size() { return _file_size; }
void set_file_size(long size) { _file_size = size; }
int max_symbol_length() { return _max_symbol_length; }
PreloadJitInfo* info_holder() { return _holder; }
void set_info_holder(PreloadJitInfo* holder) { _holder = holder; }
private:
// disable default constructor
JitWarmUpLogParser();
bool _is_valid;
bool _has_parsed_header;
// current position of log file in parsing process
int _position;
// method count that successful parsed from log file
int _parsed_methods;
// method count recorded in log file
int _total_methods;
long _file_size;
randomAccessFileStream* _fs;
int _max_symbol_length;
char* _parse_str_buf;
PreloadJitInfo* _holder;
Arena* _arena;
u1 read_u1();
u4 read_u4();
u8 read_u8();
char* read_string();
};
JitWarmUpLogParser::JitWarmUpLogParser(randomAccessFileStream* fs, PreloadJitInfo* holder)
: _is_valid(false),
_has_parsed_header(false),
_position(0),
_parsed_methods(0),
_total_methods(0),
_file_size(0),
_fs(fs),
_max_symbol_length(0),
_parse_str_buf(NULL),
_holder(holder),
_arena(new (mtInternal) Arena(mtInternal, 128)) {
}
JitWarmUpLogParser::~JitWarmUpLogParser() {
// fileStream lifecycle is not managed by this class
delete _arena;
}
char parse_int_buf[8];
u1 JitWarmUpLogParser::read_u1() {
_fs->read(parse_int_buf, 1, 1);
_position += 1;
return *(u1*)parse_int_buf;
}
u4 JitWarmUpLogParser::read_u4() {
_fs->read(parse_int_buf, 4, 1);
_position += 4;
return *(u4*)parse_int_buf;
}
u8 JitWarmUpLogParser::read_u8() {
_fs->read(parse_int_buf, 8, 1);
_position += 8;
return *(u8*)parse_int_buf;
}
char* JitWarmUpLogParser::read_string() {
int index = 0;
do {
_fs->read(_parse_str_buf + index, 1, 1);
index++;
} while (*(_parse_str_buf + index - 1) != '\0'
&& index <= _max_symbol_length + 1);
_position += index;
int len = index - 1;
if (len == 0) {
return NULL;
} else if (len > max_symbol_length()) {
log_error(warmup)("[JitWarmUp] ERROR : Parsed symbol length is longer than %d\n", max_symbol_length());
return NULL;
} else {
char* str = NEW_RESOURCE_ARRAY(char, len + 1);
::memcpy(str, _parse_str_buf, len + 1);
return str;
}
}
#define MAX_COUNT_VALUE (1024 * 1024 * 128)
#define LOGPARSER_ILLEGAL_STRING_CHECK(s, ret_value) \
if (_position > end_pos) { \
log_error(warmup)("[JitWarmUp] ERROR : read out of bound, " \
"file format error"); \
return ret_value; \
} \
if (s == NULL) { \
_position = end_pos; \
log_error(warmup)("[JitWarmUp] ERROR : illegal string in log file"); \
return ret_value; \
}
#define LOGPARSER_ILLEGAL_COUNT_CHECK(cnt, ret_value) \
if (_position > end_pos) { \
log_error(warmup)("[JitWarmUp] ERROR : read out of bound, " \
"file format error"); \
return ret_value; \
} \
if ((u4)cnt > MAX_COUNT_VALUE) { \
_position = end_pos; \
log_error(warmup)("[JitWarmUp] ERROR : illegal count (" \
UINT32_FORMAT ") too big", cnt); \
return ret_value; \
}
bool JitWarmUpLogParser::should_ignore_this_class(Symbol* s) {
// FIXME deal with spring auto-generated
ResourceMark rm;
char* name = s->as_C_string();
const char* CGLIB_SIG = "CGLIB$$";
const char* ACCESSER_SUFFIX = "ConstructorAccess";
if (::strstr(name, CGLIB_SIG) != NULL ||
::strstr(name, ACCESSER_SUFFIX) != NULL) {
return true;
}
JitWarmUp* jwp = info_holder()->holder();
SymbolMatcher<mtClass>* matcher = jwp->excluding_matcher();
if (matcher == NULL) {
return false;
}
return matcher->match(s);
}
bool JitWarmUpLogParser::parse_header() {
int begin_pos = _position;
int end_pos = begin_pos + HEADER_SIZE;
u4 version_number = read_u4();
u4 magic_number = read_u4();
u4 file_size = read_u4();
int crc32_recorded = (int)read_u4();
u4 appid = read_u4();
// valid version & magic number & file size
unsigned int version = JitWarmUp::instance()->version();
if (version_number != version) {
_is_valid = false;
log_error(warmup)("[JitWarmUp] ERROR : Version not match, expect %d but %d", version, version_number);
return false;
}
if (magic_number != MAGIC_NUMBER
|| (long)file_size != this->file_size()) {
_is_valid = false;
log_error(warmup)("[JitWarmUp] ERROR : illegal header");
return false;
}
// valid appid
if (CompilationWarmUpAppID != 0 && CompilationWarmUpAppID != appid) {
_is_valid = false;
log_error(warmup)("[JitWarmUp] ERROR : illegal CompilationWarmUpAppID");
return false;
}
// valid crc32
int crc32_actual = ProfileRecorder::compute_crc32(_fs);
if (crc32_recorded != crc32_actual) {
_is_valid = false;
log_error(warmup)("[JitWarmUp] ERROR : log file crc32 check failure");
return false;
}
u4 max_symbol_length = read_u4();
LOGPARSER_ILLEGAL_COUNT_CHECK(max_symbol_length, false);
_parse_str_buf = (char*)_arena->Amalloc(max_symbol_length + 2);
_max_symbol_length = (int)max_symbol_length;
u4 record_count = read_u4();
LOGPARSER_ILLEGAL_COUNT_CHECK(record_count, false);
_total_methods = record_count;
u4 utc_time = read_u8();
_is_valid = true;
return true;
}
#define CREATE_SYMBOL(char_name) \
SymbolTable::new_symbol(char_name, strlen(char_name), Thread::current())
bool JitWarmUpLogParser::parse_class_init_section() {
ResourceMark rm;
int begin_pos = _position;
u4 section_size = read_u4();
int end_pos = begin_pos + (int)section_size;
u4 cnt = read_u4();
LOGPARSER_ILLEGAL_COUNT_CHECK(cnt, false);
PreloadClassChain* chain = new PreloadClassChain(cnt);
info_holder()->set_chain(chain);
chain->set_holder(this->info_holder());
for (int i = 0; i < (int)cnt; i++) {
char* name_char = read_string();
LOGPARSER_ILLEGAL_STRING_CHECK(name_char, false);
char* loader_char = read_string();
LOGPARSER_ILLEGAL_STRING_CHECK(loader_char, false);
char* path_char = read_string();
LOGPARSER_ILLEGAL_STRING_CHECK(path_char, false);
Symbol* name = CREATE_SYMBOL(name_char);
Symbol* loader_name = CREATE_SYMBOL(loader_char);
Symbol* path = CREATE_SYMBOL(path_char);
loader_name = PreloadJitInfo::remove_meaningless_suffix(loader_name);
chain->at(i)->set_class_name(name);
chain->at(i)->set_loader_name(loader_name);
chain->at(i)->set_path(path);
// add to preload class dictionary
unsigned int hash_value = name->identity_hash();
PreloadClassEntry* e = info_holder()->dict()->
find_and_add_class_entry(hash_value, name, loader_name, path, i);
// e->chain_offset() < i : means same class symbol already existed in the chain
// should_ignore_this_class(name): means this class is in skipped list(build-in or user-defined)
// so set entry state is skipped, will be ignored in JitWarmUp
if (e->chain_offset() < i || should_ignore_this_class(name)) {
chain->at(i)->set_skipped();
} else {
Symbol* name_no_suffix = PreloadJitInfo::remove_meaningless_suffix(name);
if (name_no_suffix->fast_compare(name) != 0) {
unsigned int hash_no_suffix = name_no_suffix->identity_hash();
PreloadClassEntry* e_no_suffix = info_holder()->dict()->
find_and_add_class_entry(hash_no_suffix, name_no_suffix, loader_name, path, i);
if (e_no_suffix->chain_offset() < i) {
chain->at(i)->set_skipped();
}
}
}
} // end of for loop
// check section size
if (_position - begin_pos != (int)section_size) {
log_error(warmup)("[JitWarmUp] ERROR : log file init section parse error.");
return false;
}
return true;
}
bool JitWarmUpLogParser::valid() {
if(!_has_parsed_header) {
parse_header();
}
return _is_valid;
}
bool JitWarmUpLogParser::has_next() {
return _parsed_methods < _total_methods && _position < _file_size;
}
PreloadMethodHolder* JitWarmUpLogParser::next() {
ResourceMark rm;
_fs->fseek(_position, SEEK_SET);
int begin_pos = _position;
u4 section_size = read_u4();
int end_pos = begin_pos + section_size;
u4 comp_order = read_u4();
u1 compilation_type = read_u1();
// 0 means standard compile
// 1 means OSR compile
if (compilation_type != 0 && compilation_type != 1) {
log_error(warmup)("[JitWarmUp] ERROR : illegal compilation type in log file");
_position = end_pos;
return NULL;
}
// method info
char* method_name_char = read_string();
LOGPARSER_ILLEGAL_STRING_CHECK(method_name_char, NULL);
Symbol* method_name = CREATE_SYMBOL(method_name_char);
char* method_sig_char = read_string();
LOGPARSER_ILLEGAL_STRING_CHECK(method_sig_char, NULL);
Symbol* method_sig = CREATE_SYMBOL(method_sig_char);
u4 first_invoke_init_order = read_u4();
// INVALID_FIRST_INVOKE_INIT_ORDER means no first_invoke_init_order record in log file,
// so put this method at last entry of class init chain
if ((int)first_invoke_init_order == INVALID_FIRST_INVOKE_INIT_ORDER) {
first_invoke_init_order = this->info_holder()->chain()->length() - 1;
}
u4 method_size = read_u4();
u4 method_hash = read_u4();
int32_t bci = (int32_t)read_u4();
if (bci != InvocationEntryBci) {
LOGPARSER_ILLEGAL_COUNT_CHECK(bci, NULL);
}
// class info
char* class_name_char = read_string();
LOGPARSER_ILLEGAL_STRING_CHECK(class_name_char, NULL);
Symbol* class_name = CREATE_SYMBOL(class_name_char);
// ignore
if (should_ignore_this_class(class_name)) {
_position = end_pos;
return NULL;
}
char* class_loader_char = read_string();
LOGPARSER_ILLEGAL_STRING_CHECK(class_loader_char, NULL);
Symbol* class_loader = CREATE_SYMBOL(class_loader_char);
class_loader = PreloadJitInfo::remove_meaningless_suffix(class_loader);
char* path_char = read_string();
LOGPARSER_ILLEGAL_STRING_CHECK(path_char, NULL);
Symbol* path = CREATE_SYMBOL(path_char);
PreloadClassDictionary* dict = this->info_holder()->dict();
unsigned int dict_hash = class_name->identity_hash();
PreloadClassEntry* entry = dict->find_head_entry(dict_hash, class_name);
if (entry == NULL) {
log_warning(warmup)("[JitWarmUp] WARNING : class %s is missed in init section", class_name_char);
_position = end_pos;
return NULL;
}
u4 class_size = read_u4();
u4 class_crc32 = read_u4();
u4 class_hash = read_u4();
// method counters info
u4 intp_invocation_count = read_u4();
u4 intp_throwout_count = read_u4();
u4 invocation_count = read_u4();
u4 backedge_count = read_u4();
int class_chain_offset = entry->chain_offset();
PreloadClassHolder* holder = entry->find_holder_in_entry(class_size, class_crc32);
if (holder == NULL) {
holder = new PreloadClassHolder(class_name, class_loader, path, class_size, class_hash, class_crc32);
entry->add_class_holder(holder);
}
PreloadMethodHolder* mh = new PreloadMethodHolder(method_name, method_sig);
mh->set_intp_invocation_count(intp_invocation_count);
mh->set_intp_throwout_count(intp_throwout_count);
mh->set_invocation_count(invocation_count);
mh->set_backage_count(backedge_count);
mh->set_bci((int)bci);
mh->set_hash(method_hash);
mh->set_size(method_size);
// add class init chain relation
/*
int method_chain_offset = static_cast<int>(first_invoke_init_order) >= class_chain_offset ? first_invoke_init_order
: _holder->chain()->length() -1;
*/
int method_chain_offset = class_chain_offset;
mh->set_mounted_offset(method_chain_offset);
this->info_holder()->chain()->mount_method_at(mh, method_chain_offset);
holder->add_method(mh);
return mh;
}
#undef MAX_SIZE_VALUE
#undef MAX_COUNT_VALUE
#undef LOGPARSER_ILLEGAL_STRING_CHECK
#undef LOGPARSER_ILLEGAL_COUNT_CHECK
#undef CREATE_SYMBOL
#define INIT_PRECLASS_INIT_SIZE 4*1024*1024
#define PRELOAD_CLASS_HS_SIZE 10240
PreloadJitInfo::PreloadJitInfo()
: _dict(NULL),
_chain(NULL),
_loaded_count(0),
_state(NOT_INIT),
_holder(NULL),
_jvm_booted_is_done(false) {
}
PreloadJitInfo::~PreloadJitInfo() {
delete _dict;
delete _chain;
}
Symbol* PreloadJitInfo::remove_meaningless_suffix(Symbol* s) {
ResourceMark rm;
Thread* t = Thread::current();
Symbol* result = s;
char* s_char = s->as_C_string();
int len = (int)::strlen(s_char);
// first, remove $$+suffix
int i = 0;
for (i = 0; i < len - 1; i++) {
if (s_char[i] == '$' && s_char[i+1] == '$') {
break;
}
}
// has $$+suffix, remove it
if (i < len - 1) {
// example: s is $$123, convert to $
i = i == 0 ? i = 1: i;
result = SymbolTable::new_symbol(s_char, i, t);
s_char = result->as_C_string();
}
// second, remove number or $+number
len = (int)::strlen(s_char);
i = len - 1;
for (; i >= 0; i--) {
if (s_char[i] >= '0' && s_char[i] <= '9') {
continue;
} else if (s_char[i] == '$') {
continue;
} else {
break;
}
}
if (i != len - 1){
i = i == -1 ? 0 : i;
result = SymbolTable::new_symbol(s_char, i + 1, t);
}
return result;
}
void PreloadJitInfo::jvm_booted_is_done() {
_jvm_booted_is_done = true;
PreloadClassChain* chain = this->chain();
assert(chain != NULL, "PreloadClassChain is NULL");
}
void PreloadClassChain::eager_load_class_in_constantpool() {
int index = 0;
int klass_index = 0;
while (true) {
InstanceKlass* current_k = NULL;
{
MutexLockerEx mu(PreloadClassChain_lock);
if (index == length()) {
break;
}
PreloadClassChain::PreloadClassChainEntry* e = this->at(index);
GrowableArray<InstanceKlass*>* array = e->resolved_klasses();
assert(array != NULL, "should not be NULL");
// skip not loaded entry
if (e->is_skipped() || e->is_not_loaded() || klass_index >= array->length()) {
index++;
// reset index
klass_index = 0;
continue;
}
current_k = array->at(klass_index);
} // end of Mutex guard
if (current_k != NULL) {
current_k->constants()->preload_jwarmup_classes(Thread::current());
}
klass_index++;
} // end of while
}
void PreloadJitInfo::notify_application_startup_is_done() {
PreloadClassChain *chain = this->chain();
assert(chain != NULL, "PreloadClassChain is NULL");
chain->state_trans_to(PreloadClassChain::PRE_WARMUP);
// 1st, eager load classes, do eager initialize just once
log_info(warmup)("JitWarmUp [INFO]: start eager loading classes from constant pool");
chain->eager_load_class_in_constantpool();
// 2nd, warmup compilation
log_info(warmup)("JitWarmUp [INFO]: start warmup compilation");
chain->warmup_impl();
Thread *THREAD = Thread::current();
// if exception occurs in warmup compilation, return and throw
if (HAS_PENDING_EXCEPTION) {
return;
}
// 3rd, commit dummy method for compilation, check dummy method to know warmup compilation is completed
JitWarmUp *jwp = this->holder();
Method *dm = jwp->dummy_method();
guarantee(dm->code() == NULL, "dummy method has been compiled unexceptedly!");
methodHandle mh(THREAD, dm);
JitWarmUp::commit_compilation(mh, InvocationEntryBci, THREAD);
if (!chain->state_trans_to(PreloadClassChain::WARMUP_DONE)) {
// warmup has been marked as WARMUP_DONE, but compilation requests are still on
// going. warmup is really done when dummy method is compiled, check the dummy
// method to determine warmup is done
log_error(warmup)("JitWarmUp [ERROR]: can not change state to WARMUP_DONE");
} else {
log_info(warmup)("JitWarmUp [INFO]: warmup compilation is done");
}
}
bool PreloadJitInfo::should_load_class_eagerly(Symbol* s) {
// check black list
SymbolMatcher<mtClass>* matcher = holder()->excluding_matcher();
if (matcher != NULL && matcher->match(s)) {
return false;
}
int hash = s->identity_hash();
PreloadClassEntry* e = dict()->find_head_entry(hash, s);
// not in JitWarmUp log file
if (e == NULL) {
return false;
}
if (!CompilationWarmUpResolveClassEagerly) {
// check whether has been loaded
int offset = e->chain_offset();
PreloadClassChain::PreloadClassChainEntry* entry = chain()->at(offset);
return entry->is_not_loaded();
} else {
return true;
}
}
bool PreloadJitInfo::resolve_loaded_klass(InstanceKlass* k) {
if (k == NULL) { return false; }
// has loaded before
if (k->is_jwarmup_recorded()) {
return false;
}
{
MutexLockerEx mu(PreloadClassChain_lock);
// JitWarmUp compilation is done
if (!chain()->can_record_class()) {
return false;
}
}
// record in PreloadClassChain
// set flag before actually invoking record function due to
// the record_loaded_class may trigger recursive
// class recording
k->set_jwarmup_recorded(true);
chain()->record_loaded_class(k);
return true;
}
class RandomFileStreamGuard : StackObj {
public:
RandomFileStreamGuard(randomAccessFileStream* fs)
: _fs(fs) {
}
~RandomFileStreamGuard() { delete _fs; }
randomAccessFileStream* operator ->() const { return _fs; }
randomAccessFileStream* operator ()() const { return _fs; }
private:
randomAccessFileStream* _fs;
};
void PreloadJitInfo::init() {
if (CompilationWarmUpRecording) {
log_error(warmup)("[JitWarmUp] ERROR: you can not set both CompilationWarmUp and CompilationWarmUpRecording");
_state = IS_ERR;
return;
}
// check class data sharing
if (UseSharedSpaces) {
log_error(warmup)("[JitWarmUp] ERROR: flag UseSharedSpaces must be off");
_state = IS_ERR;
return;
}
_dict = new PreloadClassDictionary(PRELOAD_CLASS_HS_SIZE);
_loaded_count = 0; // init count
_state = IS_OK; // init state
// parse log
if (CompilationWarmUpLogfile == NULL) {
_state = IS_ERR;
return;
}
RandomFileStreamGuard fsg(new (ResourceObj::C_HEAP, mtInternal) randomAccessFileStream(
CompilationWarmUpLogfile, "rb+"));
JitWarmUpLogParser parser(fsg(), this);
if (!fsg->is_open()) {
log_error(warmup)("[JitWarmUp] ERROR : log file %s doesn't exist", CompilationWarmUpLogfile);
_state = IS_ERR;
return;
}
parser.set_file_size(fsg->fileSize());
// parse header section
if (!parser.parse_header()) {
// not valid log file format
_state = IS_ERR;
return;
}
// parse class init section
if (!parser.parse_class_init_section()) {
// invalid log file format
_state = IS_ERR;
return;
}
while (parser.has_next()) {
PreloadMethodHolder* holder = parser.next();
if (holder != NULL) {
//successfully parsed from log file
++_loaded_count;
}
parser.inc_parsed_number();
}
}
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#ifndef SHARED_VM_JWARMUP_JITWARMUP_HPP
#define SHARED_VM_JWARMUP_JITWARMUP_HPP
#include "code/codeBlob.hpp"
#include "libadt/dict.hpp"
#include "memory/allocation.hpp"
#include "oops/klass.hpp"
#include "oops/method.hpp"
#include "oops/methodCounters.hpp"
#include "oops/methodData.hpp"
#include "runtime/atomic.hpp"
#include "runtime/timer.hpp"
#include "runtime/mutexLocker.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/hashtable.hpp"
#include "utilities/linkedlist.hpp"
#include "utilities/ostream.hpp"
#include "utilities/symbolMatcher.hpp"
// forward
class ProfileRecorder;
class PreloadJitInfo;
#define INVALID_FIRST_INVOKE_INIT_ORDER -1
class JitWarmUp : public CHeapObj<mtInternal> {
protected:
JitWarmUp();
virtual ~JitWarmUp();
public:
enum JitWarmUpState {
NOT_INIT = 0,
IS_OK = 1,
IS_ERR = 2
};
bool is_valid() { return _state == JitWarmUp::IS_OK; }
unsigned int version() { return _version; }
// init in VM startup
void init();
// init for CompilationWarmUpRecording model
JitWarmUpState init_for_recording();
// init for CompilationWarmUp model
JitWarmUpState init_for_warmup();
static JitWarmUp* create_instance();
static JitWarmUp* instance() { return _instance; }
ProfileRecorder* recorder() { return _recorder; }
PreloadJitInfo* preloader() { return _preloader; }
SymbolMatcher<mtClass>* excluding_matcher() { return _excluding_matcher; }
void set_dummy_method(Method* m) { _dummy_method = m; }
Method* dummy_method() { return _dummy_method; }
// write log file for JitWarmUpRecording model
JitWarmUpState flush_logfile();
// commit a compilation task
static bool commit_compilation(methodHandle m, int bci, TRAPS);
// get loader name through ClassLoaderData, if ClassLoader is
// bootstrap classloader, return "NULL"
static Symbol* get_class_loader_name(ClassLoaderData* cld);
private:
// singleton holder
static JitWarmUp* _instance;
JitWarmUpState _state;
unsigned int _version; // JitWarmUp version, for verify logfile
Method* _dummy_method;
ProfileRecorder* _recorder;
PreloadJitInfo* _preloader;
SymbolMatcher<mtClass>* _excluding_matcher;
};
// =========================== Profile Recorder Module ========================== //
// this hashtable stores method profile info that will be
// record into log file
class ProfileRecorderEntry : public HashtableEntry<Method*, mtInternal> {
public:
ProfileRecorderEntry() { }
virtual ~ProfileRecorderEntry() { }
// not use ctor function because Hashtable::new_entry is C-style design
// It don't call ctor function when Hashtable constructing a entry
void init() {
_is_deopted = false;
_bci = InvocationEntryBci;
}
void set_bci(int bci) { _bci = bci; }
int bci() { return _bci; }
void set_order(int order) { _order = order; }
int order() { return _order; }
ProfileRecorderEntry* next() {
return (ProfileRecorderEntry*)HashtableEntry<Method*, mtInternal>::next();
}
private:
bool _is_deopted; // not used
int _bci; // bci of compilation task,
// InvocationEntryBci means standard compilation
// other means OSR compilation
int _order; // compilation order
};
// a hash table stores compiled method
class ProfileRecordDictionary : public Hashtable<Method*, mtInternal> {
friend class VMStructs;
friend class JitWarmUp;
public:
ProfileRecordDictionary(unsigned int size);
virtual ~ProfileRecordDictionary();
// add method into dictionary
// return entry that holds this method
ProfileRecorderEntry* add_method(unsigned int hash, Method* method, int bci);
// find a method in the dictionary
// if not found, return NULL
ProfileRecorderEntry* find_entry(unsigned int hash, Method* method);
void free_entry(ProfileRecorderEntry* entry);
unsigned int count() { return _count; }
// NYI
void print();
// virtual void print_on(outputStream* st) const;
ProfileRecorderEntry* bucket(int i) {
return (ProfileRecorderEntry*)Hashtable<Method*, mtInternal>::bucket(i);
}
private:
unsigned int _count; // entry count
// create an entry for a given method
ProfileRecorderEntry* new_entry(unsigned int hash, Method* method);
};
// This entry used in the list that records class symbol
class ClassSymbolEntry {
private:
Symbol* _class_name;
Symbol* _class_loader_name;
Symbol* _path;
public:
ClassSymbolEntry(Symbol* class_name, Symbol* class_loader_name, Symbol* path)
: _class_name(class_name),
_class_loader_name(class_loader_name),
_path(path) {
if (_class_name != NULL) _class_name->increment_refcount();
if (_class_loader_name != NULL) _class_loader_name->increment_refcount();
if (_path != NULL) _path->increment_refcount();
}
ClassSymbolEntry()
: _class_name(NULL),
_class_loader_name(NULL),
_path(NULL) {
}
~ClassSymbolEntry() {
if (_class_name != NULL) _class_name->decrement_refcount();
if (_class_loader_name != NULL) _class_loader_name->decrement_refcount();
if (_path != NULL) _path->decrement_refcount();
}
Symbol* class_name() const { return _class_name; }
Symbol* class_loader_name() const { return _class_loader_name; }
Symbol* path() const { return _path; }
// Necessary for LinkedList
bool equals(const ClassSymbolEntry& rhs) const {
return _class_name == rhs._class_name;
}
};
// Profiling data collection
// record compiled method in a hash table(class ProfileRecorder)
// record java class initialization order in a linkedlist(class LinkedListImpl<Entry>)
class ProfileRecorder : public CHeapObj<mtInternal> {
public:
ProfileRecorder();
virtual ~ProfileRecorder();
void init();
unsigned int recorded_count() { return _dict->count(); }
ProfileRecordDictionary* dict() { return _dict; }
JitWarmUp* holder() { return _holder; }
void set_holder(JitWarmUp* h) { _holder = h; }
unsigned int flushed() { return _flushed; }
void set_flushed(bool value) { _flushed = value; }
const char* logfile_name() { return _logfile_name; }
void set_logfile_name(const char* name) { _logfile_name = name; }
LinkedListImpl<ClassSymbolEntry>*
class_init_list() { return _class_init_list; }
int class_init_count() { return _class_init_order_count + 1; }
// add a method into recorder
void add_method(Method* method, int bci);
// remove a method from recorder
void remove_method(Method* method);
// flush collected information into log file
void flush();
// increment class initialize count
// class recorded and increase order number, returns the increased number.
// this function is thread safe
int assign_class_init_order(InstanceKlass* klass);
// current class init order count and its address.
address current_init_order_addr() { return (address)&_class_init_order_count; }
unsigned int compute_hash(Method* method) {
uint64_t m_addr = (uint64_t)method;
return (m_addr >> 3) * 2654435761UL; // Knuth multiply hash
}
bool is_valid() { return _state == IS_OK; }
static int compute_crc32(randomAccessFileStream* fs);
private:
enum RecorderState {
IS_OK = 0,
IS_ERR = 1,
NOT_INIT = 2
};
JitWarmUp* _holder;
// output stream
randomAccessFileStream* _logfile;
// position of log file in flush()
unsigned int _pos;
RecorderState _state;
// linked list that stores orderly initialization info of java classes
LinkedListImpl<ClassSymbolEntry>* _class_init_list;
LinkedListNode<ClassSymbolEntry>* _init_list_tail_node;
// hash table that stores compiled methods
ProfileRecordDictionary* _dict;
// counter of class initialization order
volatile int _class_init_order_count;
volatile bool _flushed;
// log file name
const char* _logfile_name;
// record max symbol length in log file
int _max_symbol_length;
private:
// flush section
void write_header();
void write_inited_class();
void write_record(Method* method, int bci, int order);
void write_footer();
void write_u1(u1 value);
void write_u4(u4 value);
void write_u8(u8 value);
void write_string(const char* src);
void write_string(const char* src, size_t len);
void overwrite_u4(u4 value, unsigned int offset);
void update_max_symbol_length(int len);
};
// =========================== Preload Class Module ========================== //
#define CLASSCACHE_HASHTABLE_SIZE 10240
// forward declare
class ProfileRecorder;
class PreloadClassHolder;
// a MDRecordInfo corresponds a ProfileData per bci (see oops/methodData.hpp)
// NYI about details
class MDRecordInfo : public CHeapObj<mtInternal> {
public:
// empty class
MDRecordInfo() { }
~MDRecordInfo() { }
};
// a method holder corresponds a method and its profile information
class PreloadMethodHolder : public CHeapObj<mtInternal> {
friend class PreloadClassHolder;
public:
PreloadMethodHolder(Symbol* name, Symbol* signature);
PreloadMethodHolder(PreloadMethodHolder& rhs);
virtual ~PreloadMethodHolder();
Symbol* name() const { return _name; }
Symbol* signature() const { return _signature; }
unsigned int intp_invocation_count() const { return _intp_invocation_count; }
unsigned int intp_throwout_count() const { return _intp_throwout_count; }
unsigned int invocation_count() const { return _invocation_count; }
unsigned int backage_count() const { return _backage_count; }
void set_intp_invocation_count(unsigned int value) { _intp_invocation_count = value; }
void set_intp_throwout_count(unsigned int value) { _intp_throwout_count = value; }
void set_invocation_count(unsigned int value) { _invocation_count = value; }
void set_backage_count(unsigned int value) { _backage_count = value; }
unsigned int hash() const { return _hash; }
unsigned int size() const { return _size; }
int bci() const { return _bci; }
int mounted_offset() const { return _mounted_offset; }
void set_hash(unsigned int value) { _hash = value; }
void set_size(unsigned int value) { _size = value; }
void set_bci(int value) { _bci = value; }
void set_mounted_offset(int value) { _mounted_offset = value; }
bool deopted() const { return _is_deopted; }
void set_deopted(bool value) { _is_deopted = value; }
// check for size/hash
bool check_matching(Method* method);
PreloadMethodHolder* next() const { return _next; }
void set_next(PreloadMethodHolder* h) { _next = h; }
Method* resolved_method() const { return _resolved_method; }
void set_resolved_method(Method* m) { _resolved_method = m; }
GrowableArray<MDRecordInfo*>* md_list() const { return _md_list; }
void set_md_list(GrowableArray<MDRecordInfo*>* value) { _md_list = value; }
PreloadMethodHolder* clone_and_add();
// whether the resolved method is alive
bool is_alive(BoolObjectClosure* is_alive_closure) const;
private:
// below members are parsed from log file
Symbol* _name;
Symbol* _signature;
unsigned int _size;
unsigned int _hash;
int _bci;
unsigned int _intp_invocation_count;
unsigned int _intp_throwout_count;
unsigned int _invocation_count;
unsigned int _backage_count;
int _mounted_offset;
// whether md_list array is owned by this
bool _owns_md_list;
// whether resolved method has been deoptimized by JitWarmUp
bool _is_deopted;
// A single LinkedList store entries for same init order
PreloadMethodHolder* _next;
// resolved method in holder's list
Method* _resolved_method;
// profile info array, shared between same PreloadMethodHolder
GrowableArray<MDRecordInfo*>* _md_list;
};
// a class holder corresponds a java class
class PreloadClassHolder : public CHeapObj<mtInternal> {
public:
PreloadClassHolder(Symbol* name, Symbol* loader_name,
Symbol* path, unsigned int size,
unsigned int hash, unsigned int crc32);
virtual ~PreloadClassHolder();
void add_method(PreloadMethodHolder* mh) {
assert(_method_list != NULL, "not initialize");
_method_list->append(mh);
}
unsigned int size() const { return _size; }
unsigned int hash() const { return _hash; }
unsigned int crc32() const { return _crc32; }
unsigned int methods_count() const { return _method_list->length(); }
Symbol* class_name() const { return _class_name; }
Symbol* class_loader_name() const { return _class_loader_name; }
Symbol* path() const { return _path; }
PreloadClassHolder* next() const { return _next; }
bool resolved() const { return _resolved; }
void set_resolved() { _resolved = true; }
void set_next(PreloadClassHolder* h) { _next = h; }
GrowableArray<PreloadMethodHolder*>* method_list() const { return _method_list; }
private:
// parsed from log file
unsigned int _size;
unsigned int _hash;
unsigned int _crc32;
Symbol* _class_name;
Symbol* _class_loader_name;
Symbol* _path;
// method holder list
GrowableArray<PreloadMethodHolder*>* _method_list;
// if the holder is resolved
bool _resolved;
unsigned int _class_init_chain_index;
// next class holder that has same class name
PreloadClassHolder* _next;
};
// a class entry corresponds a java class name symbol
// it mounts a list of PreloadClassHolder which has same name
class PreloadClassEntry : public HashtableEntry<Symbol*, mtInternal> {
friend class PreloadJitInfo;
public:
PreloadClassEntry(PreloadClassHolder* holder)
: _head_holder(holder),
_chain_offset(-1),
_loader_name(NULL),
_path(NULL) {
// do nothing
}
PreloadClassEntry()
: _head_holder(NULL),
_chain_offset(-1),
_loader_name(NULL),
_path(NULL) {
}
virtual ~PreloadClassEntry() { }
void init() {
_head_holder = NULL;
_chain_offset = -1;
_loader_name = NULL;
_path = NULL;
}
PreloadClassHolder* head_holder() { return _head_holder; }
void set_head_holder(PreloadClassHolder* h) { _head_holder = h; }
int chain_offset() { return _chain_offset; }
void set_chain_offset(int offset) { _chain_offset = offset; }
Symbol* loader_name() { return _loader_name; }
void set_loader_name(Symbol* s) { _loader_name = s; }
Symbol* path() { return _path; }
void set_path(Symbol* s) { _path = s; }
PreloadClassEntry* next() {
return (PreloadClassEntry*)HashtableEntry<Symbol*, mtInternal>::next();
}
// an entry has a chain of class holder
void add_class_holder(PreloadClassHolder* h) {
h->set_next(_head_holder);
_head_holder = h;
}
// find class holder with specified size&crc32
// if not found, return NULL
PreloadClassHolder* find_holder_in_entry(unsigned int size, unsigned int crc32);
private:
PreloadClassHolder* _head_holder; // head node of holder list
int _chain_offset; // chain index is initialization order of this class, used in class PreloadClassChain
Symbol* _loader_name; // classloader name
Symbol* _path; // class file path
};
// a hash table stores PreloadClassEntrys that parsed from log file
//
// PreloadClassDictionary extend Hashtable
// |
// + -- ClassEntry: +- ClassHolder +- class name
// . +- size
// . +- crc32
// . +- MethodHolder list
// . |
// . +- MDRecordInfo list
// .
// +- ClassHolder ..
//
class PreloadClassDictionary : public Hashtable<Symbol*, mtInternal> {
public:
PreloadClassDictionary(int size);
virtual ~PreloadClassDictionary();
// remove a class entry
void remove_entry(unsigned int hash_value, unsigned int class_size,
unsigned int crc32, Symbol* symbol);
// find a class entry with name, classloader and path
PreloadClassEntry* find_entry(unsigned int hash_value, Symbol* name,
Symbol* loader_name, Symbol* path);
// find the first class entry with the given class name
PreloadClassEntry* find_head_entry(unsigned int hash_value, Symbol* name);
PreloadClassEntry* find_entry(InstanceKlass* k);
// find a specified class holder
PreloadClassHolder* find_holder(unsigned int hash_value, unsigned int class_size,
unsigned int crc32, Symbol* name,
Symbol* loader_name, Symbol* path);
PreloadClassEntry* bucket(int i) {
return (PreloadClassEntry*)Hashtable<Symbol*, mtInternal>::bucket(i);
}
// find or create a class entry, if not found, new a entry and return it
PreloadClassEntry* find_and_add_class_entry(unsigned int hash_value, Symbol* symbol,
Symbol* loader_name, Symbol* path,
int order);
private:
// new entry
PreloadClassEntry* new_entry(Symbol* symbol);
};
class PreloadClassChain;
// traverse MethodHolder from end to begin in PreloadClassChain
class MethodHolderIterator {
public:
MethodHolderIterator()
: _chain(NULL),
_cur(NULL),
_index(-1) {
}
MethodHolderIterator(PreloadClassChain* chain, PreloadMethodHolder* holder, int index)
: _chain(chain),
_cur(holder),
_index(index) {
}
~MethodHolderIterator() { /* do nothing */ }
PreloadMethodHolder* operator*() { return _cur; }
int index() { return _index; }
bool initialized() { return _chain != NULL; }
PreloadMethodHolder* next();
private:
PreloadClassChain* _chain;
PreloadMethodHolder* _cur;
int _index; // current holder's position in PreloadClassChain
};
// record java class load event
// forcely initialize class in order(from jwarmup log file)
// PreloadClassChain member layout & force initialization diagram
//
//
// state -------- | PreloadClassChainEntry : +-----------------+
// v | | class name |
// ----- | | state |
// head entry -> | 3 | <-------------+ | method list |
// | 3 | | InstanceKlass* |
// | 3 | +-----------------+
// | 3 | <- | method(compiled) | <- | method(compiled) |
// | 1 |
// init_index -> | 3 | <- | method(compilable) |
// | 2 |
// load_index -> | 2 |
// | 0 |
// | 2 | <- | method(not compiled) | <- | method(not compiled) |
// | 3 |
// .
// .
// | 0 |
// | 2 |
// | 0 |
// | 0 |
// | 0 |
// -----
// Entry state: 0 : class is NOT loaded
// 1 : entry skipped
// 2 : class has been loaded
// 3 : class has been initialized
// Compiling methods list which begins the entry at index i
// need ensure that all entries before index i have been either initialized or skipped
//
class PreloadClassChain : public CHeapObj<mtClass> {
public:
class PreloadClassChainEntry : public CHeapObj<mtClass> {
public:
enum InitState {
_not_loaded = 0,
_is_skipped,
_is_loaded,
_is_inited
};
PreloadClassChainEntry()
: _class_name(NULL),
_loader_name(NULL),
_path(NULL),
_state(_not_loaded),
_method_holder(NULL),
_resolved_klasses(new (ResourceObj::C_HEAP, mtClass)
GrowableArray<InstanceKlass*>(1, true, mtClass)) { }
PreloadClassChainEntry(Symbol* class_name, Symbol* loader_name, Symbol* path)
: _class_name(class_name),
_loader_name(loader_name),
_path(path),
_state(_not_loaded),
_method_holder(NULL),
_resolved_klasses(new (ResourceObj::C_HEAP, mtClass)
GrowableArray<InstanceKlass*>(1, true, mtClass)) { }
virtual ~PreloadClassChainEntry() { }
Symbol* class_name() const { return _class_name; }
Symbol* loader_name() const { return _loader_name; }
Symbol* path() const { return _path; }
void set_class_name(Symbol* name) { _class_name = name; }
void set_loader_name(Symbol* name) { _loader_name = name; }
void set_path(Symbol* path) { _path = path; }
GrowableArray<InstanceKlass*>* resolved_klasses()
{ return _resolved_klasses; }
// entry state
bool is_not_loaded() const { return _state == _not_loaded; }
bool is_skipped() const { return _state == _is_skipped; }
bool is_loaded() const { return _state == _is_loaded; }
bool is_inited() const { return _state == _is_inited; }
void set_not_loaded() { _state = _not_loaded; }
void set_skipped() { _state = _is_skipped; }
void set_loaded() { _state = _is_loaded; }
void set_inited() { _state = _is_inited; }
int state() { return _state; }
void add_method_holder(PreloadMethodHolder* h) {
h->set_next(_method_holder);
_method_holder = h;
}
bool is_all_initialized();
// check if any resolved classes has been redefined before warmup compilation
bool has_redefined_class();
InstanceKlass* get_first_uninitialized_klass();
PreloadMethodHolder* method_holder() { return _method_holder; }
private:
Symbol* _class_name;
Symbol* _loader_name;
Symbol* _path;
int _state;
PreloadMethodHolder* _method_holder;
GrowableArray<InstanceKlass*>* _resolved_klasses;
};
PreloadClassChain(unsigned int size);
virtual ~PreloadClassChain();
enum ClassChainState {
NOT_INITED = 0,
INITED = 1,
PRE_WARMUP = 2,
WARMUP_COMPILING = 3,
WARMUP_DONE = 4,
WARMUP_PRE_DEOPTIMIZE = 5,
WARMUP_DEOPTIMIZING = 6,
WARMUP_DEOPTIMIZED = 7,
ERROR_STATE = 8
};
bool state_trans_to(ClassChainState new_state);
ClassChainState current_state() { return _state; }
int inited_index() const { return _inited_index; }
int loaded_index() const { return _loaded_index; }
int length() const { return _length; }
void set_inited_index(int index) { _inited_index = index; }
void set_loaded_index(int index) { _loaded_index = index; }
void set_length(int length) { _length = length; }
bool has_unmarked_compiling_flag() { return _has_unmarked_compiling_flag; }
void set_has_unmarked_compiling_flag(bool value) { _has_unmarked_compiling_flag = value; }
PreloadJitInfo* holder() { return _holder; }
void set_holder(PreloadJitInfo* preloader) { _holder = preloader; }
bool can_do_initialize() {
return _state == PRE_WARMUP;
}
bool notify_deopt_signal() {
return state_trans_to(WARMUP_PRE_DEOPTIMIZE);
}
// recording loaded class is only doable before warmup compilation
bool can_record_class() {
return _state == INITED || _state == PRE_WARMUP || _state == WARMUP_COMPILING;
}
bool deopt_has_started() {
return _state == WARMUP_DEOPTIMIZING || _state == WARMUP_DEOPTIMIZED;
}
bool deopt_has_done() {
return _state == WARMUP_DEOPTIMIZED;
}
// record java class load event,
// update indexes and do class loading eagerly
void record_loaded_class(InstanceKlass* klass);
PreloadClassChainEntry* at(int index) { return &_entries[index]; }
// refresh indexes and entry's state
void refresh_indexes();
// iterate preload class chain and submit warmup compilation requests
void warmup_impl();
// mount method
void mount_method_at(PreloadMethodHolder* mh, int index);
// a PreloadMethodHolder represents a java method
bool compile_methodholder(PreloadMethodHolder* mh);
// fix InstanceKlass* and Method* pointer during metaspace gc
void do_unloading(BoolObjectClosure* is_alive);
// proactive deoptimize methods in safepoint after CompilationWarmUpDeoptTime second
void deopt_prologue();
void deopt_epilogue();
bool should_deoptimize_methods();
// deoptimize CompilationWarmUpDeoptNumOfMethodsPerIter number methods per invocation
void deoptimize_methods();
// invoke a VM_Deoptimize operation
void invoke_deoptimize_vmop();
// load class eagerly that occurs in JitWarmUp log file through constant-pool traversal
void eager_load_class_in_constantpool();
// for debug
void print_not_loaded_before(int index);
void print_method_mount_before(int index);
private:
// left of _inited_index(contain it) has been initialization
int _inited_index;
// left of _loaded_index(contain it) has been loaded
int _loaded_index;
// length of entries
int _length;
// state of PreloadClassChain
volatile ClassChainState _state;
PreloadClassChainEntry* _entries;
PreloadJitInfo* _holder;
// method deoptimization support
TimeStamp _init_timestamp; // timestamp of deoptimization beginning
TimeStamp _last_timestamp; // timestamp of last deoptimization task
int _deopt_index;
PreloadMethodHolder* _deopt_cur_holder;
bool _has_unmarked_compiling_flag;
void compile_methodholders_queue(Stack<PreloadMethodHolder*, mtInternal>& compile_queue);
// update _loaded_index
void update_loaded_index(int index);
// assign profile info to this method
PreloadMethodHolder* resolve_method_info(Method* method,
PreloadClassHolder* holder);
};
// This class about preload & compile method from
// log file in JitWarmUp model
class PreloadJitInfo : public CHeapObj<mtInternal> {
public:
enum PreloadInfoState {
NOT_INIT = 0,
IS_OK = 1,
IS_ERR = 2
};
PreloadJitInfo();
virtual ~PreloadJitInfo();
bool is_valid() { return _state == IS_OK; }
void init();
bool should_load_class_eagerly(Symbol* s);
PreloadClassDictionary* dict() { return _dict; }
uint64_t loaded_count() { return _loaded_count; }
PreloadClassChain* chain() { return _chain; }
void set_chain(PreloadClassChain* chain) { _chain = chain; }
JitWarmUp* holder() { return _holder; }
void set_holder(JitWarmUp* h) { _holder = h; }
// record java class loading and assign profile info to this klass
bool resolve_loaded_klass(InstanceKlass* klass);
// will be called after jvm booted (in runtime/init.cpp)
void jvm_booted_is_done();
// will be called by JWarmUP java API nofityApplicationStartUpIsDone
void notify_application_startup_is_done();
// remove known meaningless suffix
static Symbol* remove_meaningless_suffix(Symbol* s);
private:
PreloadClassDictionary* _dict;
PreloadClassChain* _chain;
uint64_t _loaded_count; // methods parsed from JitWarmUp log file
PreloadInfoState _state;
JitWarmUp* _holder;
bool _jvm_booted_is_done;
};
#endif //SHARED_VM_JWARMUP_JITWARMUP_HPP
/*
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_JWARMUP_JITWARMUPLOG_HPP
#define SHARE_VM_JWARMUP_JITWARMUPLOG_HPP
/*
* We use this file to be compatible with log framework in JDK11
* To avoid conflict with jfr log, it's only used by jitWarmUp.cpp
*/
#include "runtime/os.hpp"
#include "utilities/debug.hpp"
#ifdef log_error
#undef log_error
#endif
#ifdef log_warning
#undef log_warning
#endif
#ifdef log_info
#undef log_info
#endif
#ifdef log_debug
#undef log_debug
#endif
#ifdef log_trace
#undef log_trace
#endif
#ifdef log_is_enabled
#undef log_is_enabled
#endif
#define log_error(...) (!log_is_enabled(Error, __VA_ARGS__)) ? (void)0 : tty->print_cr
#define log_warning(...) (!log_is_enabled(Warning, __VA_ARGS__)) ? (void)0 : tty->print_cr
#define log_info(...) (!log_is_enabled(Info, __VA_ARGS__)) ? (void)0 : tty->print_cr
#define log_debug(...) (!log_is_enabled(Debug, __VA_ARGS__)) ? (void)0 : tty->print_cr
#define log_trace(...) (!log_is_enabled(Trace, __VA_ARGS__)) ? (void)0 : tty->print_cr
#define log_is_enabled(level, ...) (LogImplWarmUp::is_level(LogLevel::level))
class LogImplWarmUp {
public:
static bool is_level(LogLevelType level) {
if (PrintCompilationWarmUpDetail || level >= (jint)LogLevel::Info) {
return true;
}
return false;
}
};
#endif
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#include "precompiled.hpp"
#include "code/codeCache.hpp"
#include "jwarmup/jitWarmUp.hpp"
#include "jwarmup/jitWarmUpThread.hpp"
#include "runtime/java.hpp"
#include "runtime/mutex.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/orderAccess.hpp"
JitWarmUpFlushThread* JitWarmUpFlushThread::_jwp_thread = NULL;
JitWarmUpFlushThread::JitWarmUpFlushThread(unsigned int sec) : NamedThread() {
set_name("JitWarmUp Flush Thread");
set_sleep_sec(sec);
if (os::create_thread(this, os::vm_thread)) {
os::set_priority(this, MaxPriority);
} else {
tty->print_cr("[JitWarmUp] ERROR : failed to create JitWarmUpFlushThread");
vm_exit(-1);
}
}
JitWarmUpFlushThread::~JitWarmUpFlushThread() {
// do nothing
}
void JitWarmUpFlushThread::run() {
assert(_jwp_thread == this, "sanity check");
this->record_stack_base_and_size();
this->_has_started = true;
os::sleep(this, 1000 * sleep_sec(), false);
JitWarmUp::instance()->flush_logfile();
{
MutexLockerEx mu(JitWarmUpPrint_lock);
_jwp_thread = NULL;
}
}
void JitWarmUpFlushThread::spawn_wait_for_flush(unsigned int sec) {
JitWarmUpFlushThread* t = new JitWarmUpFlushThread(sec);
_jwp_thread = t;
Thread::start(t);
}
void JitWarmUpFlushThread::print_jwarmup_threads_on(outputStream* st) {
MutexLockerEx mu(JitWarmUpPrint_lock);
if (_jwp_thread == NULL || !_jwp_thread->has_started()) {
return;
}
st->print("\"%s\" ", _jwp_thread->name());
_jwp_thread->print_on(st);
st->cr();
}
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#ifndef SHARE_VM_JWARMUP_JITWARMUPTHREAD_HPP
#define SHARE_VM_JWARMUP_JITWARMUPTHREAD_HPP
#include "runtime/thread.hpp"
class JitWarmUpFlushThread : public NamedThread {
protected:
JitWarmUpFlushThread(unsigned int sec);
virtual ~JitWarmUpFlushThread();
public:
virtual void run();
bool has_started() { return _has_started; }
unsigned int sleep_sec() { return _sleep_sec; }
void set_sleep_sec(unsigned int sec) { _sleep_sec = sec; }
static void spawn_wait_for_flush(unsigned int sec);
static void print_jwarmup_threads_on(outputStream* st);
private:
volatile bool _has_started;
unsigned int _sleep_sec;
static JitWarmUpFlushThread* _jwp_thread;
};
#endif //SHARE_VM_JWARMUP_JITWARMUPTHREAD_HPP
...@@ -330,6 +330,31 @@ int hashstr(const void *t) { ...@@ -330,6 +330,31 @@ int hashstr(const void *t) {
return (int)((sum+xsum[k]) >> 1); // Hash key, un-modulo'd table size return (int)((sum+xsum[k]) >> 1); // Hash key, un-modulo'd table size
} }
// compute hash from char array with given length
int hashstr2(const char *s, int len) {
char c, k = 0;
int32_t sum = 0;
int cnt = 0;
// make sure xsum array is initialized
if( !initflag ) { // Not initializated yet?
xsum[0] = (1<<shft[0])+1; // Initialize
for(int i = 1; i < MAXID; i++) {
xsum[i] = (1<<shft[i])+1+xsum[i-1];
}
initflag = 1; // Never again
}
while(cnt < len) { // Get characters till null or MAXID-1
c = *s++;
c = (c<<1) + 1; // Characters are always odd!
sum += c + (c<<shft[k++]); // Universal hash function
k %= MAXID;
cnt++;
}
return (int)((sum+xsum[k]) >> 1); // Hash key, un-modulo'd table size
}
//------------------------------hashptr-------------------------------------- //------------------------------hashptr--------------------------------------
// Slimey cheap hash function; no guaranteed performance. Better than the // Slimey cheap hash function; no guaranteed performance. Better than the
// default for pointers, especially on MS-DOS machines. // default for pointers, especially on MS-DOS machines.
......
...@@ -89,6 +89,7 @@ class Dict : public ResourceObj { // Dictionary structure ...@@ -89,6 +89,7 @@ class Dict : public ResourceObj { // Dictionary structure
// Hashing functions // Hashing functions
int hashstr(const void *s); // Nice string hash int hashstr(const void *s); // Nice string hash
int hashstr2(const char *s, int len); // hash string with given length
// Slimey cheap hash function; no guaranteed performance. Better than the // Slimey cheap hash function; no guaranteed performance. Better than the
// default for pointers, especially on MS-DOS machines. // default for pointers, especially on MS-DOS machines.
int hashptr(const void *key); int hashptr(const void *key);
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "classfile/systemDictionary.hpp" #include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp" #include "classfile/vmSymbols.hpp"
#include "interpreter/linkResolver.hpp" #include "interpreter/linkResolver.hpp"
#include "jwarmup/jitWarmUp.hpp"
#include "memory/heapInspection.hpp" #include "memory/heapInspection.hpp"
#include "memory/metadataFactory.hpp" #include "memory/metadataFactory.hpp"
#include "memory/oopFactory.hpp" #include "memory/oopFactory.hpp"
...@@ -41,6 +42,8 @@ ...@@ -41,6 +42,8 @@
#include "runtime/javaCalls.hpp" #include "runtime/javaCalls.hpp"
#include "runtime/signature.hpp" #include "runtime/signature.hpp"
#include "runtime/vframe.hpp" #include "runtime/vframe.hpp"
#include "utilities/stack.hpp"
#include "utilities/stack.inline.hpp"
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
...@@ -56,12 +59,19 @@ ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, T ...@@ -56,12 +59,19 @@ ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, T
// the resolved_references array, which is recreated at startup time. // the resolved_references array, which is recreated at startup time.
// But that could be moved to InstanceKlass (although a pain to access from // But that could be moved to InstanceKlass (although a pain to access from
// assembly code). Maybe it could be moved to the cpCache which is RW. // assembly code). Maybe it could be moved to the cpCache which is RW.
return new (loader_data, size, false, MetaspaceObj::ConstantPoolType, THREAD) ConstantPool(tags); if (CompilationWarmUp) {
Array<u1>* jwp_tags = NULL;
jwp_tags = MetadataFactory::new_array<u1>(loader_data, length, 0, CHECK_NULL);
return new (loader_data, size, false, MetaspaceObj::ConstantPoolType, THREAD) ConstantPool(tags, jwp_tags);
} else {
return new (loader_data, size, false, MetaspaceObj::ConstantPoolType, THREAD) ConstantPool(tags);
}
} }
ConstantPool::ConstantPool(Array<u1>* tags) { ConstantPool::ConstantPool(Array<u1>* tags) {
set_length(tags->length()); set_length(tags->length());
set_tags(NULL); set_tags(NULL);
set_jwp_tags(NULL);
set_cache(NULL); set_cache(NULL);
set_reference_map(NULL); set_reference_map(NULL);
set_resolved_references(NULL); set_resolved_references(NULL);
...@@ -81,6 +91,37 @@ ConstantPool::ConstantPool(Array<u1>* tags) { ...@@ -81,6 +91,37 @@ ConstantPool::ConstantPool(Array<u1>* tags) {
set_tags(tags); set_tags(tags);
} }
ConstantPool::ConstantPool(Array<u1>* tags, Array<u1>* jwp_tags) {
assert(CompilationWarmUp, "must in CompilationWarmUp");
assert(jwp_tags != NULL, "invariant");
assert(jwp_tags->length() == tags->length(), "invariant");
set_length(tags->length());
set_tags(NULL);
set_jwp_tags(NULL);
set_cache(NULL);
set_reference_map(NULL);
set_resolved_references(NULL);
set_operands(NULL);
set_pool_holder(NULL);
set_flags(0);
// only set to non-zero if constant pool is merged by RedefineClasses
set_version(0);
set_lock(new Monitor(Monitor::nonleaf + 2, "A constant pool lock"));
// initialize tag array
int length = tags->length();
for (int index = 0; index < length; index++) {
tags->at_put(index, JVM_CONSTANT_Invalid);
}
set_tags(tags);
for (int i = 0; i < jwp_tags->length(); i++) {
jwp_tags->at_put(i, _jwp_has_not_been_traversed);
}
set_jwp_tags(jwp_tags);
}
void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) { void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) {
MetadataFactory::free_metadata(loader_data, cache()); MetadataFactory::free_metadata(loader_data, cache());
set_cache(NULL); set_cache(NULL);
...@@ -95,6 +136,12 @@ void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) { ...@@ -95,6 +136,12 @@ void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) {
// free tag array // free tag array
MetadataFactory::free_array<u1>(loader_data, tags()); MetadataFactory::free_array<u1>(loader_data, tags());
set_tags(NULL); set_tags(NULL);
if (CompilationWarmUp) {
assert(jwp_tags() != NULL, "should not be NULL");
MetadataFactory::free_array<u1>(loader_data, jwp_tags());
set_jwp_tags(NULL);
}
} }
void ConstantPool::release_C_heap_structures() { void ConstantPool::release_C_heap_structures() {
...@@ -1899,6 +1946,88 @@ void ConstantPool::preload_and_initialize_all_classes(ConstantPool* obj, TRAPS) ...@@ -1899,6 +1946,88 @@ void ConstantPool::preload_and_initialize_all_classes(ConstantPool* obj, TRAPS)
#endif #endif
void ConstantPool::preload_jwarmup_classes(TRAPS) {
constantPoolHandle cp(THREAD, this);
guarantee(cp->pool_holder() != NULL, "must be fully loaded");
if (THREAD->in_eagerly_loading_class()) {
return;
}
THREAD->set_in_eagerly_loading_class(true);
Stack<InstanceKlass*, mtClass> s;
s.push(cp->pool_holder());
preload_jwarmup_classes_impl(s, THREAD);
THREAD->set_in_eagerly_loading_class(false);
}
// should not be guarded in PreloadClassChain_lock
Klass* ConstantPool::resolve_class_from_slot(int which, TRAPS) {
assert(THREAD->is_Java_thread(), "must be a Java thread");
if (CompilationWarmUpResolveClassEagerly) {
Klass* k = klass_at(which, CHECK_NULL);
return k;
} else {
// Create a handle for the mirror. This will preserve the resolved class
// until the loader_data is registered.
Handle mirror_handle;
constantPoolHandle this_oop(THREAD, this);
Symbol* name = NULL;
Handle loader;
{
if (this_oop->tag_at(which).is_unresolved_klass()) {
if (this_oop->tag_at(which).is_unresolved_klass_in_error()) {
return NULL;
} else {
name = this_oop->klass_name_at(which);
loader = Handle(THREAD, this_oop->pool_holder()->class_loader());
}
}
}
oop protection_domain = this_oop->pool_holder()->protection_domain();
Handle h_prot (THREAD, protection_domain);
Klass* k_oop = SystemDictionary::resolve_or_fail(name, loader, h_prot, true, THREAD);
return k_oop;
}
}
// use bfs instead recusive
void ConstantPool::preload_jwarmup_classes_impl(Stack<InstanceKlass*, mtClass>& s,
TRAPS) {
JitWarmUp* jwp = JitWarmUp::instance();
while (!s.is_empty()) {
constantPoolHandle cp(s.pop()->constants());
for (int i = 0; i< cp->length(); i++) {
bool is_unresolved = false;
Symbol* name = NULL;
{
if (cp->tag_at(i).is_unresolved_klass() && !cp->jwarmup_traversed_at(i)) {
name = cp->klass_name_at(i);
is_unresolved = true;
cp->jwarmup_has_traversed_at(i);
}
}
if (is_unresolved) {
if (name != NULL && !jwp->preloader()->should_load_class_eagerly(name)) {
continue;
}
// Load class from ConstantPool slot, if flag CompilationWarmUpResolveClassEagerly
// is on, update ConstantPool status accordingly and assign to that slot.
Klass* klass = cp->resolve_class_from_slot(i, THREAD);
if (HAS_PENDING_EXCEPTION) {
ResourceMark rm;
tty->print_cr("[JitWarmUp] WARNING : resolve %s from constant pool failed",
name->as_C_string());
// ignore LinkageError in loading class
if (PENDING_EXCEPTION->is_a(SystemDictionary::LinkageError_klass())) {
CLEAR_PENDING_EXCEPTION;
}
}
if (klass != NULL && klass->oop_is_instance()) {
s.push((InstanceKlass*)klass);
}
} // end of if is_unresolved
} // end of loop
} // end of while
}
// Printing // Printing
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "oops/typeArrayOop.hpp" #include "oops/typeArrayOop.hpp"
#include "runtime/handles.hpp" #include "runtime/handles.hpp"
#include "utilities/constantTag.hpp" #include "utilities/constantTag.hpp"
#include "utilities/stack.hpp"
#ifdef TARGET_ARCH_x86 #ifdef TARGET_ARCH_x86
# include "bytes_x86.hpp" # include "bytes_x86.hpp"
#endif #endif
...@@ -96,6 +97,13 @@ class ConstantPool : public Metadata { ...@@ -96,6 +97,13 @@ class ConstantPool : public Metadata {
jobject _resolved_references; jobject _resolved_references;
Array<u2>* _reference_map; Array<u2>* _reference_map;
enum {
_jwp_has_not_been_traversed = 0,
_jwp_has_been_traversed = 1
};
Array<u1>* _jwp_tags; // the jwp tag array records the corresponding tag whether is traversed
enum { enum {
_has_preresolution = 1, // Flags _has_preresolution = 1, // Flags
_on_stack = 2 _on_stack = 2
...@@ -114,6 +122,7 @@ class ConstantPool : public Metadata { ...@@ -114,6 +122,7 @@ class ConstantPool : public Metadata {
Monitor* _lock; Monitor* _lock;
void set_tags(Array<u1>* tags) { _tags = tags; } void set_tags(Array<u1>* tags) { _tags = tags; }
void set_jwp_tags(Array<u1>* tags) { _jwp_tags = tags; }
void tag_at_put(int which, jbyte t) { tags()->at_put(which, t); } void tag_at_put(int which, jbyte t) { tags()->at_put(which, t); }
void release_tag_at_put(int which, jbyte t) { tags()->release_at_put(which, t); } void release_tag_at_put(int which, jbyte t) { tags()->release_at_put(which, t); }
...@@ -164,6 +173,8 @@ class ConstantPool : public Metadata { ...@@ -164,6 +173,8 @@ class ConstantPool : public Metadata {
} }
ConstantPool(Array<u1>* tags); ConstantPool(Array<u1>* tags);
// for JWarmUP
ConstantPool(Array<u1>* tags, Array<u1>* jwp_tags);
ConstantPool() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); } ConstantPool() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); }
public: public:
static ConstantPool* allocate(ClassLoaderData* loader_data, int length, TRAPS); static ConstantPool* allocate(ClassLoaderData* loader_data, int length, TRAPS);
...@@ -173,6 +184,18 @@ class ConstantPool : public Metadata { ...@@ -173,6 +184,18 @@ class ConstantPool : public Metadata {
Array<u1>* tags() const { return _tags; } Array<u1>* tags() const { return _tags; }
Array<u2>* operands() const { return _operands; } Array<u2>* operands() const { return _operands; }
Array<u1>* jwp_tags() const { return _jwp_tags; }
bool jwarmup_traversed_at(int which) {
assert(0 < which && which < jwp_tags()->length(), "out of bound");
return jwp_tags()->at(which) == _jwp_has_been_traversed;
}
void jwarmup_has_traversed_at(int which) {
assert(which < jwp_tags()->length(), "out of bound");
jwp_tags()->at_put(which, _jwp_has_been_traversed);
}
bool has_preresolution() const { return (_flags & _has_preresolution) != 0; } bool has_preresolution() const { return (_flags & _has_preresolution) != 0; }
void set_has_preresolution() { _flags |= _has_preresolution; } void set_has_preresolution() { _flags |= _has_preresolution; }
...@@ -887,6 +910,13 @@ class ConstantPool : public Metadata { ...@@ -887,6 +910,13 @@ class ConstantPool : public Metadata {
// Compile the world support // Compile the world support
static void preload_and_initialize_all_classes(ConstantPool* constant_pool, TRAPS); static void preload_and_initialize_all_classes(ConstantPool* constant_pool, TRAPS);
#endif #endif
void preload_jwarmup_classes(TRAPS);
Klass* resolve_class_from_slot(int which, TRAPS);
private:
void preload_jwarmup_classes_impl(Stack<InstanceKlass*, mtClass>& s, TRAPS);
}; };
class SymbolHashMapEntry : public CHeapObj<mtSymbol> { class SymbolHashMapEntry : public CHeapObj<mtSymbol> {
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include "interpreter/oopMapCache.hpp" #include "interpreter/oopMapCache.hpp"
#include "interpreter/rewriter.hpp" #include "interpreter/rewriter.hpp"
#include "jvmtifiles/jvmti.h" #include "jvmtifiles/jvmti.h"
#include "jwarmup/jitWarmUp.hpp"
#include "memory/genOopClosures.inline.hpp" #include "memory/genOopClosures.inline.hpp"
#include "memory/heapInspection.hpp" #include "memory/heapInspection.hpp"
#include "memory/iterator.inline.hpp" #include "memory/iterator.inline.hpp"
...@@ -322,6 +323,14 @@ InstanceKlass::InstanceKlass(int vtable_len, ...@@ -322,6 +323,14 @@ InstanceKlass::InstanceKlass(int vtable_len,
// Set temporary value until parseClassFile updates it with the real instance // Set temporary value until parseClassFile updates it with the real instance
// size. // size.
set_layout_helper(Klass::instance_layout_helper(0, true)); set_layout_helper(Klass::instance_layout_helper(0, true));
set_jwarmup_recorded(false);
#ifndef PRODUCT
set_initialize_order(-1);
#endif
set_crc32(0);
set_bytes_size(0);
set_source_file_path(NULL);
} }
...@@ -376,6 +385,13 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) { ...@@ -376,6 +385,13 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
// Need to take this class off the class loader data list. // Need to take this class off the class loader data list.
loader_data->remove_class(this); loader_data->remove_class(this);
if (CompilationWarmUp || CompilationWarmUpRecording) {
if (source_file_path() != NULL) {
source_file_path()->decrement_refcount();
set_source_file_path(NULL);
}
}
// The array_klass for this class is created later, after error handling. // The array_klass for this class is created later, after error handling.
// For class redefinition, we keep the original class so this scratch class // For class redefinition, we keep the original class so this scratch class
// doesn't have an array class. Either way, assert that there is nothing // doesn't have an array class. Either way, assert that there is nothing
...@@ -884,6 +900,9 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) { ...@@ -884,6 +900,9 @@ void InstanceKlass::initialize_impl(instanceKlassHandle this_oop, TRAPS) {
this_oop->set_init_state(being_initialized); this_oop->set_init_state(being_initialized);
this_oop->set_init_thread(self); this_oop->set_init_thread(self);
} }
if (CompilationWarmUpRecording) {
JitWarmUp::instance()->recorder()->assign_class_init_order(this_oop());
}
// Step 7 // Step 7
// Next, if C is a class rather than an interface, initialize its super class and super // Next, if C is a class rather than an interface, initialize its super class and super
......
...@@ -208,6 +208,21 @@ class InstanceKlass: public Klass { ...@@ -208,6 +208,21 @@ class InstanceKlass: public Klass {
// if this class is unloaded. // if this class is unloaded.
Symbol* _array_name; Symbol* _array_name;
// if not using JWarmUP, default value is 0
unsigned int _crc32;
// if not using JWarmUP, default value is 0
unsigned int _class_bytes_size;
// CompilationWarmUp eager init support
bool _is_jwarmup_recorded;
// source file path, e.g. /home/xxx/liba.jar
Symbol* _source_file_path;
#ifndef PRODUCT
int _initialize_order;
#endif
// Number of heapOopSize words used by non-static fields in this klass // Number of heapOopSize words used by non-static fields in this klass
// (including inherited fields but after header_size()). // (including inherited fields but after header_size()).
int _nonstatic_field_size; int _nonstatic_field_size;
...@@ -656,6 +671,23 @@ class InstanceKlass: public Klass { ...@@ -656,6 +671,23 @@ class InstanceKlass: public Klass {
Symbol* array_name() { return _array_name; } Symbol* array_name() { return _array_name; }
void set_array_name(Symbol* name) { assert(_array_name == NULL || name == NULL, "name already created"); _array_name = name; } void set_array_name(Symbol* name) { assert(_array_name == NULL || name == NULL, "name already created"); _array_name = name; }
// JWarmUP support
unsigned int crc32() { return _crc32; }
void set_crc32(unsigned int crc32) { _crc32 = crc32; }
unsigned int bytes_size() { return _class_bytes_size; }
void set_bytes_size(unsigned int size) { _class_bytes_size = size; }
bool is_jwarmup_recorded() { return _is_jwarmup_recorded; }
void set_jwarmup_recorded(bool value) { _is_jwarmup_recorded = value; }
Symbol* source_file_path() { return _source_file_path; }
void set_source_file_path(Symbol* value) { _source_file_path = value; }
#ifndef PRODUCT
unsigned int initialize_order() { return _initialize_order; }
void set_initialize_order(int order) { _initialize_order = order; }
#endif
// nonstatic oop-map blocks // nonstatic oop-map blocks
static int nonstatic_oop_map_size(unsigned int oop_map_count) { static int nonstatic_oop_map_size(unsigned int oop_map_count) {
return oop_map_count * OopMapBlock::size_in_words(); return oop_map_count * OopMapBlock::size_in_words();
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "interpreter/bytecodes.hpp" #include "interpreter/bytecodes.hpp"
#include "interpreter/interpreter.hpp" #include "interpreter/interpreter.hpp"
#include "interpreter/oopMapCache.hpp" #include "interpreter/oopMapCache.hpp"
#include "jwarmup/jitWarmUp.hpp"
#include "memory/gcLocker.hpp" #include "memory/gcLocker.hpp"
#include "memory/generation.hpp" #include "memory/generation.hpp"
#include "memory/heapInspection.hpp" #include "memory/heapInspection.hpp"
...@@ -96,6 +97,13 @@ Method::Method(ConstMethod* xconst, AccessFlags access_flags, int size) { ...@@ -96,6 +97,13 @@ Method::Method(ConstMethod* xconst, AccessFlags access_flags, int size) {
clear_method_counters(); clear_method_counters();
set_vtable_index(Method::garbage_vtable_index); set_vtable_index(Method::garbage_vtable_index);
set_first_invoke_init_order(INVALID_FIRST_INVOKE_INIT_ORDER);
set_compiled_by_jwarmup(false);
#ifndef PRODUCT
set_deopted_by_jwarmup(false);
#endif
// Fix and bury in Method* // Fix and bury in Method*
set_interpreter_entry(NULL); // sets i2i entry and from_int set_interpreter_entry(NULL); // sets i2i entry and from_int
set_adapter_entry(NULL); set_adapter_entry(NULL);
......
...@@ -136,6 +136,12 @@ class Method : public Metadata { ...@@ -136,6 +136,12 @@ class Method : public Metadata {
nmethod* volatile _code; // Points to the corresponding piece of native code nmethod* volatile _code; // Points to the corresponding piece of native code
volatile address _from_interpreted_entry; // Cache of _code ? _adapter->i2c_entry() : _i2i_entry volatile address _from_interpreted_entry; // Cache of _code ? _adapter->i2c_entry() : _i2i_entry
int _first_invoke_init_order; // record class initialize order when this method first been invoked
bool _compiled_by_jwarmup;
#ifndef PRODUCT
bool _deopted_by_jwarmup;
#endif
// Constructor // Constructor
Method(ConstMethod* xconst, AccessFlags access_flags, int size); Method(ConstMethod* xconst, AccessFlags access_flags, int size);
public: public:
...@@ -202,6 +208,21 @@ class Method : public Metadata { ...@@ -202,6 +208,21 @@ class Method : public Metadata {
return constMethod()->type_annotations(); return constMethod()->type_annotations();
} }
int first_invoke_init_order() { return _first_invoke_init_order; }
void set_first_invoke_init_order(int value) { _first_invoke_init_order = value; }
bool compiled_by_jwarmup() { return _compiled_by_jwarmup; }
void set_compiled_by_jwarmup(bool value) { _compiled_by_jwarmup = value; }
#ifndef PRODUCT
bool deopted_by_jwarmup() { return _deopted_by_jwarmup; }
void set_deopted_by_jwarmup(bool value) { _deopted_by_jwarmup = value; }
#endif
static ByteSize first_invoke_init_order_offset() {
return byte_offset_of(Method, _first_invoke_init_order);
}
// Helper routine: get klass name + "." + method name + signature as // Helper routine: get klass name + "." + method name + signature as
// C string, for the purpose of providing more useful NoSuchMethodErrors // C string, for the purpose of providing more useful NoSuchMethodErrors
// and fatal error handling. The string is allocated in resource // and fatal error handling. The string is allocated in resource
......
...@@ -282,6 +282,8 @@ class ProfileData : public ResourceObj { ...@@ -282,6 +282,8 @@ class ProfileData : public ResourceObj {
friend class TypeEntries; friend class TypeEntries;
friend class ReturnTypeEntry; friend class ReturnTypeEntry;
friend class TypeStackSlotEntries; friend class TypeStackSlotEntries;
friend class ProfileRecorder;
friend class PreloadJitInfo;
private: private:
#ifndef PRODUCT #ifndef PRODUCT
enum { enum {
......
...@@ -207,7 +207,8 @@ JVMState* VirtualCallGenerator::generate(JVMState* jvms) { ...@@ -207,7 +207,8 @@ JVMState* VirtualCallGenerator::generate(JVMState* jvms) {
if (!UseInlineCaches || !ImplicitNullChecks || !os::zero_page_read_protected() || if (!UseInlineCaches || !ImplicitNullChecks || !os::zero_page_read_protected() ||
((ImplicitNullCheckThreshold > 0) && caller_md && ((ImplicitNullCheckThreshold > 0) && caller_md &&
(caller_md->trap_count(Deoptimization::Reason_null_check) (caller_md->trap_count(Deoptimization::Reason_null_check)
>= (uint)ImplicitNullCheckThreshold))) { >= (uint)ImplicitNullCheckThreshold)) ||
(CompilationWarmUp && kit.C->env()->task()->is_jwarmup_compilation())) {
// Make an explicit receiver null_check as part of this call. // Make an explicit receiver null_check as part of this call.
// Since we share a map with the caller, his JVMS gets adjusted. // Since we share a map with the caller, his JVMS gets adjusted.
receiver = kit.null_check_receiver_before_call(method()); receiver = kit.null_check_receiver_before_call(method());
......
...@@ -728,6 +728,14 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr ...@@ -728,6 +728,14 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
print_compile_messages(); print_compile_messages();
if (CompilationWarmUp) {
bool fields_resolved = ci_env->check_method_fields_all_resolved(method());
if (!fields_resolved) {
_failure_reason = "fields needed by method are not all resolved";
return;
}
}
_ilt = InlineTree::build_inline_tree_root(); _ilt = InlineTree::build_inline_tree_root();
// Even if NO memory addresses are used, MergeMem nodes must have at least 1 slice // Even if NO memory addresses are used, MergeMem nodes must have at least 1 slice
......
...@@ -2749,9 +2749,14 @@ bool GraphKit::seems_never_null(Node* obj, ciProfileData* data) { ...@@ -2749,9 +2749,14 @@ bool GraphKit::seems_never_null(Node* obj, ciProfileData* data) {
&& obj != null() // And not the -Xcomp stupid case? && obj != null() // And not the -Xcomp stupid case?
&& !too_many_traps(Deoptimization::Reason_null_check) && !too_many_traps(Deoptimization::Reason_null_check)
) { ) {
if (data == NULL) bool compiledByWarmUp = CompilationWarmUp && this->C->env()->task()->is_jwarmup_compilation();
if (data == NULL) {
if (compiledByWarmUp) {
return false;
}
// Edge case: no mature data. Be optimistic here. // Edge case: no mature data. Be optimistic here.
return true; return true;
}
// If the profile has not seen a null, assume it won't happen. // If the profile has not seen a null, assume it won't happen.
assert(java_bc() == Bytecodes::_checkcast || assert(java_bc() == Bytecodes::_checkcast ||
java_bc() == Bytecodes::_instanceof || java_bc() == Bytecodes::_instanceof ||
...@@ -2821,6 +2826,12 @@ Node* GraphKit::maybe_cast_profiled_obj(Node* obj, ...@@ -2821,6 +2826,12 @@ Node* GraphKit::maybe_cast_profiled_obj(Node* obj,
bool not_null) { bool not_null) {
// type == NULL if profiling tells us this object is always null // type == NULL if profiling tells us this object is always null
if (type != NULL) { if (type != NULL) {
if (CompilationWarmUp) {
if (this->C->env()->task()->is_jwarmup_compilation()) {
return obj;
}
}
Deoptimization::DeoptReason class_reason = Deoptimization::Reason_speculate_class_check; Deoptimization::DeoptReason class_reason = Deoptimization::Reason_speculate_class_check;
Deoptimization::DeoptReason null_reason = Deoptimization::Reason_null_check; Deoptimization::DeoptReason null_reason = Deoptimization::Reason_null_check;
if (!too_many_traps(null_reason) && !too_many_recompiles(null_reason) && if (!too_many_traps(null_reason) && !too_many_recompiles(null_reason) &&
......
...@@ -96,6 +96,9 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo ...@@ -96,6 +96,9 @@ void PhaseCFG::implicit_null_check(Block* block, Node *proj, Node *val, int allo
// mechanism exists (yet) to set the switches at an os_cpu level // mechanism exists (yet) to set the switches at an os_cpu level
if( !ImplicitNullChecks || MacroAssembler::needs_explicit_null_check(0)) return; if( !ImplicitNullChecks || MacroAssembler::needs_explicit_null_check(0)) return;
// to reduce deoptimization, disable implicit_null_check for jwarmup compilation
if (CompilationWarmUp && this->C->env()->task()->is_jwarmup_compilation()) return;
// Make sure the ptr-is-null path appears to be uncommon! // Make sure the ptr-is-null path appears to be uncommon!
float f = block->end()->as_MachIf()->_prob; float f = block->end()->as_MachIf()->_prob;
if( proj->Opcode() == Op_IfTrue ) f = 1.0f - f; if( proj->Opcode() == Op_IfTrue ) f = 1.0f - f;
......
...@@ -35,8 +35,10 @@ ...@@ -35,8 +35,10 @@
#include "classfile/systemDictionaryShared.hpp" #include "classfile/systemDictionaryShared.hpp"
#endif #endif
#include "classfile/vmSymbols.hpp" #include "classfile/vmSymbols.hpp"
#include "code/codeCache.hpp"
#include "gc_interface/collectedHeap.inline.hpp" #include "gc_interface/collectedHeap.inline.hpp"
#include "interpreter/bytecode.hpp" #include "interpreter/bytecode.hpp"
#include "jwarmup/jitWarmUp.hpp"
#include "memory/oopFactory.hpp" #include "memory/oopFactory.hpp"
#include "memory/referenceType.hpp" #include "memory/referenceType.hpp"
#include "memory/universe.inline.hpp" #include "memory/universe.inline.hpp"
...@@ -51,6 +53,7 @@ ...@@ -51,6 +53,7 @@
#include "prims/nativeLookup.hpp" #include "prims/nativeLookup.hpp"
#include "prims/privilegedStack.hpp" #include "prims/privilegedStack.hpp"
#include "runtime/arguments.hpp" #include "runtime/arguments.hpp"
#include "runtime/compilationPolicy.hpp"
#include "runtime/dtraceJSDT.hpp" #include "runtime/dtraceJSDT.hpp"
#include "runtime/handles.inline.hpp" #include "runtime/handles.inline.hpp"
#include "runtime/init.hpp" #include "runtime/init.hpp"
...@@ -4682,3 +4685,66 @@ JVM_ENTRY(void, JVM_GetVersionInfo(JNIEnv* env, jvm_version_info* info, size_t i ...@@ -4682,3 +4685,66 @@ JVM_ENTRY(void, JVM_GetVersionInfo(JNIEnv* env, jvm_version_info* info, size_t i
info->is_attachable = AttachListener::is_attach_supported(); info->is_attachable = AttachListener::is_attach_supported();
} }
JVM_END JVM_END
JVM_ENTRY(void, JVM_NotifyApplicationStartUpIsDone(JNIEnv* env, jclass clz))
{
JVMWrapper("JVM_NotifyApplicationStartUpIsDone");
if (!CompilationWarmUp) {
tty->print_cr("CompilationWarmUp is off, "
"notifyApplicationStartUpIsDone is invalid");
return;
}
Handle mirror(THREAD, JNIHandles::resolve_non_null(clz));
assert(mirror() != NULL, "sanity check");
Klass* k = java_lang_Class::as_Klass(mirror());
Method* dummy_method = k->lookup_method(vmSymbols::jwarmup_dummy_name(), vmSymbols::void_method_signature());
assert(dummy_method != NULL, "Cannot find dummy method in com.alibaba.jwarmup.JWarmUp");
JitWarmUp* jwp = JitWarmUp::instance();
assert(jwp != NULL, "sanity check");
jwp->set_dummy_method(dummy_method);
jwp->preloader()->notify_application_startup_is_done();
}
JVM_END
JVM_ENTRY(jboolean, JVM_CheckJWarmUpCompilationIsComplete(JNIEnv *env, jclass ignored))
{
JVMWrapper("JVM_CheckJWarmUpCompilationIsComplete");
if (!CompilationWarmUp) {
tty->print_cr("CompilationWarmUp is off, "
"checkIfCompilationIsComplete is invalid");
return JNI_TRUE;
}
JitWarmUp* jwp = JitWarmUp::instance();
Method* dm = jwp->dummy_method();
assert(dm != NULL, "sanity check");
if (dm->code() != NULL) {
return JNI_TRUE;
} else {
return JNI_FALSE;
}
}
JVM_END
JVM_ENTRY(void, JVM_NotifyJVMDeoptWarmUpMethods(JNIEnv *env, jclass clazz))
{
JVMWrapper("JVM_NotifyJVMDeoptWarmUpMethods");
if (!(CompilationWarmUp && CompilationWarmUpExplicitDeopt)) {
tty->print_cr("CompilationWarmUp or CompilationWarmUpExplicitDeopt is off, "
"notifyJVMDeoptWarmUpMethods is invalid");
return;
}
JitWarmUp* jwp = JitWarmUp::instance();
Method* dm = jwp->dummy_method();
if (dm != NULL && dm->code() != NULL) {
PreloadClassChain* chain = jwp->preloader()->chain();
assert(chain != NULL, "sanity check");
if (chain->notify_deopt_signal()) {
tty->print_cr("JitWarmUp: receive signal to deoptimize warmup methods");
} else {
tty->print_cr("JitWarmUp: deoptimize signal is ignore");
}
} else {
tty->print_cr("JitWarmUp: deoptimize signal is ignore because warmup is not finished");
}
}
JVM_END
...@@ -1705,6 +1705,15 @@ typedef struct JDK1_1InitArgs { ...@@ -1705,6 +1705,15 @@ typedef struct JDK1_1InitArgs {
jint debugPort; jint debugPort;
} JDK1_1InitArgs; } JDK1_1InitArgs;
JNIEXPORT void JNICALL
JVM_NotifyApplicationStartUpIsDone(JNIEnv* env, jclass clz);
JNIEXPORT jboolean JNICALL
JVM_CheckJWarmUpCompilationIsComplete(JNIEnv* env, jclass ignored);
JNIEXPORT void JNICALL
JVM_NotifyJVMDeoptWarmUpMethods(JNIEnv* env, jclass clz);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif /* __cplusplus */ #endif /* __cplusplus */
......
...@@ -1121,6 +1121,288 @@ WB_ENTRY(void, WB_PrintOsInfo(JNIEnv* env, jobject o)) ...@@ -1121,6 +1121,288 @@ WB_ENTRY(void, WB_PrintOsInfo(JNIEnv* env, jobject o))
os::print_os_info(tty); os::print_os_info(tty);
WB_END WB_END
WB_ENTRY(jobjectArray, WB_GetClassInitOrderList(JNIEnv* env, jobject o))
ResourceMark rm(THREAD);
ThreadToNativeFromVM ttn(thread);
jclass clazz = env->FindClass(vmSymbols::java_lang_String()->as_C_string());
CHECK_JNI_EXCEPTION_(env, NULL);
if (!CompilationWarmUpRecording) {
return NULL;
}
LinkedListImpl<ClassSymbolEntry>* lst =
JitWarmUp::instance()->recorder()->class_init_list();
if (lst == NULL) {
return NULL;
}
jsize size = (jsize)lst->size();
jobjectArray result = NULL;
result = env->NewObjectArray(size, clazz, NULL);
if (result == NULL) {
return result;
}
int idx = 0;
LinkedListNode<ClassSymbolEntry>* node = lst->head();
while(node != NULL) {
ResourceMark rm_inner(THREAD);
Symbol* class_name = node->peek()->class_name();
jobject obj = env->NewStringUTF(class_name->as_C_string());
CHECK_JNI_EXCEPTION_(env, NULL);
assert(idx < size, "index out of bound");
env->SetObjectArrayElement(result, idx, obj);
idx++;
node = node->next();
}
return result;
WB_END
WB_ENTRY(jobjectArray, WB_GetClassChainSymbolList(JNIEnv* env, jobject o))
ResourceMark rm(THREAD);
ThreadToNativeFromVM ttn(thread);
jclass clazz = env->FindClass(vmSymbols::java_lang_String()->as_C_string());
CHECK_JNI_EXCEPTION_(env, NULL);
if (!CompilationWarmUp) {
return NULL;
}
PreloadClassChain* chain = JitWarmUp::instance()->preloader()->chain();
if (chain == NULL) {
return NULL;
}
jsize size = (jsize)chain->length();
jobjectArray result = NULL;
result = env->NewObjectArray(size, clazz, NULL);
if (result == NULL) {
return result;
}
for (int i = 0; i < size; i++) {
ResourceMark rm_inner(THREAD);
Symbol* name = chain->at(i)->class_name();
if (name == NULL) {
continue;
}
jobject obj = env->NewStringUTF(name->as_C_string());
CHECK_JNI_EXCEPTION_(env, NULL);
env->SetObjectArrayElement(result, i, obj);
}
return result;
WB_END
WB_ENTRY(jintArray, WB_GetClassChainStateList(JNIEnv* env, jobject o))
ResourceMark rm(THREAD);
ThreadToNativeFromVM ttn(thread);
CHECK_JNI_EXCEPTION_(env, NULL);
if (!CompilationWarmUp) {
return NULL;
}
PreloadClassChain* chain = JitWarmUp::instance()->preloader()->chain();
if (chain == NULL) {
return NULL;
}
jsize size = (jsize)chain->length();
jintArray result = NULL;
result = env->NewIntArray(size);
if (result == NULL) {
return result;
}
jint* arr = env->GetIntArrayElements(result, NULL);
for (int i = 0; i < size; i++) {
arr[i] = chain->at(i)->state();
}
env->ReleaseIntArrayElements(result, arr, 0);
return result;
WB_END
WB_ENTRY(jobjectArray, WB_GetCompiledMethodList(JNIEnv* env, jobject o))
ResourceMark rm(THREAD);
ThreadToNativeFromVM ttn(thread);
jclass clazz = env->FindClass(vmSymbols::java_lang_String()->as_C_string());
CHECK_JNI_EXCEPTION_(env, NULL);
if (!CompilationWarmUpRecording) {
return NULL;
}
ProfileRecordDictionary* dict = JitWarmUp::instance()->recorder()->dict();
if (dict == NULL) {
return NULL;
}
jsize size = (jsize)dict->count();
jobjectArray result = NULL;
result = env->NewObjectArray(size, clazz, NULL);
if (result == NULL) {
return result;
}
int count = 0;
for (int index = 0; index < dict->table_size(); index++) {
for (ProfileRecorderEntry* entry = dict->bucket(index);
entry != NULL;
entry = entry->next()) {
ResourceMark rm_inner(THREAD);
Symbol* method_name = entry->literal()->name();
jobject obj = env->NewStringUTF(method_name->as_C_string());
CHECK_JNI_EXCEPTION_(env, NULL);
if (count >= size) {
break;
}
env->SetObjectArrayElement(result, count, obj);
count++;
}
}
return result;
WB_END
WB_ENTRY(jobjectArray, WB_GetClassListFromLogfile(JNIEnv* env, jobject o))
ResourceMark rm(THREAD);
ThreadToNativeFromVM ttn(thread);
jclass clazz = env->FindClass(vmSymbols::java_lang_String()->as_C_string());
CHECK_JNI_EXCEPTION_(env, NULL);
JitWarmUp* jwp = JitWarmUp::instance();
if (jwp == NULL) {
return NULL;
}
PreloadJitInfo* preloader = jwp->preloader();
if (preloader == NULL) {
return NULL;
}
PreloadClassDictionary* dict = preloader->dict();
if (dict == NULL) {
return NULL;
}
int entry_count = 0;
for (int index = 0; index < dict->table_size(); index++) {
for (PreloadClassEntry* entry = dict->bucket(index);
entry != NULL;
entry = entry->next()) {
entry_count++;
}
}
jsize size = (jsize)entry_count;
jobjectArray result = NULL;
result = env->NewObjectArray(size, clazz, NULL);
if (result == NULL) {
return result;
}
int count = 0;
for (int index = 0; index < dict->table_size(); index++) {
for (PreloadClassEntry* entry = dict->bucket(index);
entry != NULL;
entry = entry->next()) {
ResourceMark rm_inner(THREAD);
Symbol* class_name = entry->literal();
jobject obj = env->NewStringUTF(class_name->as_C_string());
CHECK_JNI_EXCEPTION_(env, NULL);
//assert(index < size, "index out of bound");
if (count >= size) {
break;
}
env->SetObjectArrayElement(result, count, obj);
count++;
}
}
return result;
WB_END
WB_ENTRY(jobjectArray, WB_GetMethodListFromLogfile(JNIEnv* env, jobject o))
ResourceMark rm(THREAD);
ThreadToNativeFromVM ttn(thread);
jclass clazz = env->FindClass(vmSymbols::java_lang_String()->as_C_string());
CHECK_JNI_EXCEPTION_(env, NULL);
JitWarmUp* jwp = JitWarmUp::instance();
if (jwp == NULL) {
return NULL;
}
PreloadJitInfo* preloader = jwp->preloader();
if (preloader == NULL) {
return NULL;
}
PreloadClassDictionary* dict = preloader->dict();
if (dict == NULL) {
return NULL;
}
jsize size = (jsize)preloader->loaded_count();
jobjectArray result = NULL;
result = env->NewObjectArray(size, clazz, NULL);
if (result == NULL) {
return result;
}
int count = 0;
for (int index = 0; index < dict->table_size(); index++) {
for (PreloadClassEntry* entry = dict->bucket(index);
entry != NULL;
entry = entry->next()) {
for (PreloadClassHolder* holder = entry->head_holder();
holder != NULL;
holder = holder->next()) {
GrowableArray<PreloadMethodHolder*>* arr = holder->method_list();
if (arr == NULL) {
continue;
}
int arr_len = arr->length();
for (int i = 0; i < arr_len; i++ ) {
PreloadMethodHolder* mh = arr->at(i);
ResourceMark rm_inner(THREAD);
Symbol* method_name = mh->name();
jobject obj = env->NewStringUTF(method_name->as_C_string());
CHECK_JNI_EXCEPTION_(env, NULL);
//assert(index < size, "index out of bound");
if (count >= size) {
break;
}
env->SetObjectArrayElement(result, count, obj);
count++;
} // end of method list loop
} // end of class holder loop
} // end of entry bucket loop
} // end of table size loop
return result;
WB_END
WB_ENTRY(jboolean, WB_TestFixDanglingPointerInDeopt(JNIEnv* env, jobject o, jstring name))
Handle h_name(THREAD, JNIHandles::resolve(name));
if (h_name.is_null()) return false;
Symbol* sym = java_lang_String::as_symbol(h_name(), CHECK_false);
JitWarmUp* jwp = JitWarmUp::instance();
PreloadClassChain* chain = jwp->preloader()->chain();
assert(chain != NULL, "sanity check");
int index = chain->length() - 1;
PreloadMethodHolder* begin_holder = NULL;
while (index > 0 && begin_holder == NULL) {
PreloadClassChain::PreloadClassChainEntry* entry = chain->at(index);
begin_holder = entry->method_holder();
index--;
}
if (begin_holder == NULL) {
return false;
}
MethodHolderIterator iter(chain, begin_holder, index);
while (*iter != NULL) {
PreloadMethodHolder* pmh = *iter;
if (pmh->name()->fast_compare(sym) == 0) {
if (pmh->resolved_method() != NULL) {
return false;
}
}
iter.next();
}
return true;
WB_END
#define CC (char*) #define CC (char*)
static JNINativeMethod methods[] = { static JNINativeMethod methods[] = {
...@@ -1243,6 +1525,20 @@ static JNINativeMethod methods[] = { ...@@ -1243,6 +1525,20 @@ static JNINativeMethod methods[] = {
{CC"printOsInfo", CC"()V", (void*)&WB_PrintOsInfo }, {CC"printOsInfo", CC"()V", (void*)&WB_PrintOsInfo },
{CC"getHeapAlignment", CC"()J", (void*)&WB_GetHeapAlignment}, {CC"getHeapAlignment", CC"()J", (void*)&WB_GetHeapAlignment},
{CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob }, {CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob },
{CC"getClassListFromLogfile", CC"()[Ljava/lang/String;",
(void*)&WB_GetClassListFromLogfile },
{CC"getMethodListFromLogfile", CC"()[Ljava/lang/String;",
(void*)&WB_GetMethodListFromLogfile },
{CC"getCompiledMethodList", CC"()[Ljava/lang/String;",
(void*)&WB_GetCompiledMethodList },
{CC"getClassChainSymbolList", CC"()[Ljava/lang/String;",
(void*)&WB_GetClassChainSymbolList },
{CC"getClassChainStateList", CC"()[I",
(void*)&WB_GetClassChainStateList },
{CC"testFixDanglingPointerInDeopt",
CC"(Ljava/lang/String;)Z", (void*)&WB_TestFixDanglingPointerInDeopt},
{CC"getClassInitOrderList", CC"()[Ljava/lang/String;",
(void*)&WB_GetClassInitOrderList }
}; };
#undef CC #undef CC
......
...@@ -4026,6 +4026,51 @@ class CommandLineFlags { ...@@ -4026,6 +4026,51 @@ class CommandLineFlags {
"Print JFR log ") \ "Print JFR log ") \
\ \
product(bool, EnableJFR, false, "Enable JFR feature") \ product(bool, EnableJFR, false, "Enable JFR feature") \
\
lp64_product(bool, CompilationWarmUpRecording, false, \
"Collect profiling information for JWarmUP") \
\
lp64_product(bool, CompilationWarmUp, false, \
"Enable CompilationWarmUp from a log file") \
\
manageable(bool, PrintCompilationWarmUpDetail, false, \
"Print detail information for jitWarmUp") \
\
lp64_product(ccstr, CompilationWarmUpLogfile, NULL, \
"Log file name for JWarmUP") \
\
lp64_product(uintx, CompilationWarmUpRecordTime, 0, \
"Sleep time (in seconds) before flushing profling " \
"information to log file ") \
\
lp64_product(uintx, CompilationWarmUpAppID, 0, \
"Application ID written in log file for verification ") \
\
lp64_product(ccstr, CompilationWarmUpExclude, NULL, \
"CompilationWarmUp excluding list ") \
\
lp64_product(bool, CompilationWarmUpExplicitDeopt, false, \
"Deoptimize JWarmUP methods by explicit api") \
\
lp64_product(uintx, CompilationWarmUpDeoptTime, 1200, \
"Sleep time (in seconds) before deoptimizing methods " \
"compiled by JWarmUP ") \
\
diagnostic(uintx, CompilationWarmUpDeoptMinInterval, 5, \
"JWarmUp method deoptimization minimum interval (in seconds)") \
\
diagnostic(uintx, CompilationWarmUpDeoptNumOfMethodsPerIter, 10, \
"The max number of methods marked for " \
"deoptimization per iteration") \
\
diagnostic(bool, CompilationWarmUpResolveClassEagerly, true, \
"resolve class from constant pool eagerly") \
\
lp64_product(bool, DeoptimizeBeforeWarmUp, false, \
"Deoptimize recorded methods before JWarmUP compilation") \
\
lp64_product(intx, CompilationWarmUpRecordMinLevel, 3, \
"Minimal compilation level recorded in JWarmUP recording phase") \
/* /*
* Macros for factoring of globals * Macros for factoring of globals
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "code/icBuffer.hpp" #include "code/icBuffer.hpp"
#include "gc_interface/collectedHeap.hpp" #include "gc_interface/collectedHeap.hpp"
#include "interpreter/bytecodes.hpp" #include "interpreter/bytecodes.hpp"
#include "jwarmup/jitWarmUp.hpp"
#include "memory/universe.hpp" #include "memory/universe.hpp"
#include "prims/methodHandles.hpp" #include "prims/methodHandles.hpp"
#include "runtime/handles.inline.hpp" #include "runtime/handles.inline.hpp"
...@@ -106,6 +107,14 @@ jint init_globals() { ...@@ -106,6 +107,14 @@ jint init_globals() {
if (status != JNI_OK) if (status != JNI_OK)
return status; return status;
if (CompilationWarmUpRecording) {
JitWarmUp* jwp = JitWarmUp::create_instance();
jwp->init_for_recording();
if (!jwp->is_valid()) {
tty->print_cr("[JitWarmUp] ERROR: init error.");
vm_exit(-1);
}
}
interpreter_init(); // before any methods loaded interpreter_init(); // before any methods loaded
invocationCounter_init(); // before any methods loaded invocationCounter_init(); // before any methods loaded
marksweep_init(); marksweep_init();
...@@ -113,6 +122,14 @@ jint init_globals() { ...@@ -113,6 +122,14 @@ jint init_globals() {
templateTable_init(); templateTable_init();
InterfaceSupport_init(); InterfaceSupport_init();
SharedRuntime::generate_stubs(); SharedRuntime::generate_stubs();
if (CompilationWarmUp) {
JitWarmUp* jwp = JitWarmUp::create_instance();
jwp->init_for_warmup();
if (!jwp->is_valid()) {
tty->print_cr("[JitWarmUp] ERROR: init error.");
vm_exit(-1);
}
}
universe2_init(); // dependent on codeCache_init and stubRoutines_init1 universe2_init(); // dependent on codeCache_init and stubRoutines_init1
referenceProcessor_init(); referenceProcessor_init();
jni_handles_init(); jni_handles_init();
......
...@@ -39,6 +39,9 @@ ...@@ -39,6 +39,9 @@
Mutex* Patching_lock = NULL; Mutex* Patching_lock = NULL;
Monitor* SystemDictionary_lock = NULL; Monitor* SystemDictionary_lock = NULL;
Mutex* ProfileRecorder_lock = NULL;
Mutex* PreloadClassChain_lock = NULL;
Mutex* JitWarmUpPrint_lock = NULL;
Mutex* PackageTable_lock = NULL; Mutex* PackageTable_lock = NULL;
Mutex* CompiledIC_lock = NULL; Mutex* CompiledIC_lock = NULL;
Mutex* InlineCacheBuffer_lock = NULL; Mutex* InlineCacheBuffer_lock = NULL;
...@@ -218,6 +221,9 @@ void mutex_init() { ...@@ -218,6 +221,9 @@ void mutex_init() {
def(JmethodIdCreation_lock , Mutex , leaf, true ); // used for creating jmethodIDs. def(JmethodIdCreation_lock , Mutex , leaf, true ); // used for creating jmethodIDs.
def(SystemDictionary_lock , Monitor, leaf, true ); // lookups done by VM thread def(SystemDictionary_lock , Monitor, leaf, true ); // lookups done by VM thread
def(ProfileRecorder_lock , Mutex , nonleaf+2, true ); // used for JitWarmUp
def(PreloadClassChain_lock , Mutex , max_nonleaf, true ); // used for JitWarmUp
def(JitWarmUpPrint_lock , Mutex , max_nonleaf, true ); // used for JitWarmUp
def(PackageTable_lock , Mutex , leaf, false); def(PackageTable_lock , Mutex , leaf, false);
def(InlineCacheBuffer_lock , Mutex , leaf, true ); def(InlineCacheBuffer_lock , Mutex , leaf, true );
def(VMStatistic_lock , Mutex , leaf, false); def(VMStatistic_lock , Mutex , leaf, false);
......
...@@ -47,6 +47,9 @@ ...@@ -47,6 +47,9 @@
extern Mutex* Patching_lock; // a lock used to guard code patching of compiled code extern Mutex* Patching_lock; // a lock used to guard code patching of compiled code
extern Monitor* SystemDictionary_lock; // a lock on the system dictonary extern Monitor* SystemDictionary_lock; // a lock on the system dictonary
extern Mutex* ProfileRecorder_lock; // a lock on the JWarmUP class ProfileRecorder
extern Mutex* PreloadClassChain_lock; // a lock on the JWarmUP preload class chain
extern Mutex* JitWarmUpPrint_lock; // a lock on the JWarmUP jstack print
extern Mutex* PackageTable_lock; // a lock on the class loader package table extern Mutex* PackageTable_lock; // a lock on the class loader package table
extern Mutex* CompiledIC_lock; // a lock used to guard compiled IC patching and access extern Mutex* CompiledIC_lock; // a lock used to guard compiled IC patching and access
extern Mutex* InlineCacheBuffer_lock; // a lock used to guard the InlineCacheBuffer extern Mutex* InlineCacheBuffer_lock; // a lock used to guard the InlineCacheBuffer
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include "code/scopeDesc.hpp" #include "code/scopeDesc.hpp"
#include "gc_interface/collectedHeap.hpp" #include "gc_interface/collectedHeap.hpp"
#include "interpreter/interpreter.hpp" #include "interpreter/interpreter.hpp"
#include "jwarmup/jitWarmUp.hpp"
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "memory/universe.inline.hpp" #include "memory/universe.inline.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
...@@ -602,6 +603,15 @@ void SafepointSynchronize::do_cleanup_tasks() { ...@@ -602,6 +603,15 @@ void SafepointSynchronize::do_cleanup_tasks() {
event_safepoint_cleanup_task_commit(event, name); event_safepoint_cleanup_task_commit(event, name);
} }
if (CompilationWarmUp) {
JitWarmUp* jwp = JitWarmUp::instance();
assert(jwp != NULL, "sanity check");
PreloadClassChain* chain = jwp->preloader()->chain();
if (chain->should_deoptimize_methods()) {
chain->deoptimize_methods();
}
}
// rotate log files? // rotate log files?
if (UseGCLogFileRotation) { if (UseGCLogFileRotation) {
const char* name = "rotate gc log"; const char* name = "rotate gc log";
......
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#include "interpreter/linkResolver.hpp" #include "interpreter/linkResolver.hpp"
#include "interpreter/oopMapCache.hpp" #include "interpreter/oopMapCache.hpp"
#include "jvmtifiles/jvmtiEnv.hpp" #include "jvmtifiles/jvmtiEnv.hpp"
#include "jwarmup/jitWarmUp.hpp"
#include "jwarmup/jitWarmUpThread.hpp"
#include "memory/gcLocker.inline.hpp" #include "memory/gcLocker.inline.hpp"
#include "memory/metaspaceShared.hpp" #include "memory/metaspaceShared.hpp"
#include "memory/oopFactory.hpp" #include "memory/oopFactory.hpp"
...@@ -230,6 +232,7 @@ Thread::Thread() { ...@@ -230,6 +232,7 @@ Thread::Thread() {
set_active_handles(NULL); set_active_handles(NULL);
set_free_handle_block(NULL); set_free_handle_block(NULL);
set_last_handle_mark(NULL); set_last_handle_mark(NULL);
set_in_eagerly_loading_class(false);
// This initial value ==> never claimed. // This initial value ==> never claimed.
_oops_do_parity = 0; _oops_do_parity = 0;
...@@ -251,6 +254,7 @@ Thread::Thread() { ...@@ -251,6 +254,7 @@ Thread::Thread() {
_current_pending_monitor = NULL; _current_pending_monitor = NULL;
_current_pending_monitor_is_from_java = true; _current_pending_monitor_is_from_java = true;
_current_waiting_monitor = NULL; _current_waiting_monitor = NULL;
_super_class_resolving_recursive_count = 0;
_num_nested_signal = 0; _num_nested_signal = 0;
omFreeList = NULL ; omFreeList = NULL ;
omFreeCount = 0 ; omFreeCount = 0 ;
...@@ -3689,6 +3693,12 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { ...@@ -3689,6 +3693,12 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
BiasedLocking::init(); BiasedLocking::init();
if (CompilationWarmUp) {
JitWarmUp* jwp = JitWarmUp::instance();
assert(jwp != NULL, "sanity check");
jwp->preloader()->jvm_booted_is_done();
}
#if INCLUDE_RTM_OPT #if INCLUDE_RTM_OPT
RTMLockingCounters::init(); RTMLockingCounters::init();
#endif #endif
...@@ -4376,6 +4386,11 @@ void Threads::print_on(outputStream* st, bool print_stacks, bool internal_format ...@@ -4376,6 +4386,11 @@ void Threads::print_on(outputStream* st, bool print_stacks, bool internal_format
st->cr(); st->cr();
} }
CompileBroker::print_compiler_threads_on(st); CompileBroker::print_compiler_threads_on(st);
if (CompilationWarmUpRecording) {
JitWarmUpFlushThread::print_jwarmup_threads_on(st);
st->cr();
}
st->flush(); st->flush();
} }
......
...@@ -211,6 +211,18 @@ class Thread: public ThreadShadow { ...@@ -211,6 +211,18 @@ class Thread: public ThreadShadow {
void leave_signal_handler() { _num_nested_signal--; } void leave_signal_handler() { _num_nested_signal--; }
bool is_inside_signal_handler() const { return _num_nested_signal > 0; } bool is_inside_signal_handler() const { return _num_nested_signal > 0; }
// JWarmUP support
private:
int _super_class_resolving_recursive_count;
bool _in_eagerly_loading_class;
public:
bool in_eagerly_loading_class() { return _in_eagerly_loading_class; }
void set_in_eagerly_loading_class(bool value) { _in_eagerly_loading_class = value; }
void super_class_resolving_recursive_inc() { _super_class_resolving_recursive_count++; }
void super_class_resolving_recursive_dec() { _super_class_resolving_recursive_count--; }
bool in_super_class_resolving() const { return _super_class_resolving_recursive_count > 0; }
private: private:
// Debug tracing // Debug tracing
static void trace(const char* msg, const Thread* const thread) PRODUCT_RETURN; static void trace(const char* msg, const Thread* const thread) PRODUCT_RETURN;
......
...@@ -390,6 +390,7 @@ template class BasicHashtable<mtGC>; ...@@ -390,6 +390,7 @@ template class BasicHashtable<mtGC>;
template class Hashtable<ConstantPool*, mtClass>; template class Hashtable<ConstantPool*, mtClass>;
template class RehashableHashtable<Symbol*, mtSymbol>; template class RehashableHashtable<Symbol*, mtSymbol>;
template class RehashableHashtable<oopDesc*, mtSymbol>; template class RehashableHashtable<oopDesc*, mtSymbol>;
template class Hashtable<Symbol*, mtInternal>;
template class Hashtable<Symbol*, mtSymbol>; template class Hashtable<Symbol*, mtSymbol>;
template class Hashtable<Klass*, mtClass>; template class Hashtable<Klass*, mtClass>;
template class Hashtable<oop, mtClass>; template class Hashtable<oop, mtClass>;
...@@ -408,3 +409,7 @@ template class BasicHashtable<mtClass>; ...@@ -408,3 +409,7 @@ template class BasicHashtable<mtClass>;
template class BasicHashtable<mtSymbol>; template class BasicHashtable<mtSymbol>;
template class BasicHashtable<mtCode>; template class BasicHashtable<mtCode>;
template class BasicHashtable<mtInternal>; template class BasicHashtable<mtInternal>;
template class Hashtable<Method*, mtInternal>;
template class Hashtable<Method*, mtNone>;
template class BasicHashtable<mtNone>;
template class Hashtable<Symbol*, mtNone>;
...@@ -754,6 +754,39 @@ void fileStream::flush() { ...@@ -754,6 +754,39 @@ void fileStream::flush() {
fflush(_file); fflush(_file);
} }
randomAccessFileStream::randomAccessFileStream() : fileStream() { }
randomAccessFileStream::randomAccessFileStream(const char* file_name)
: fileStream(file_name) { }
randomAccessFileStream::randomAccessFileStream(const char* file_name, const char* opentype)
: fileStream(file_name, opentype) { }
randomAccessFileStream::randomAccessFileStream(FILE* file, bool need_close)
: fileStream(file, need_close) { }
void randomAccessFileStream::write(const char* s, size_t len, long pos) {
assert(pos <= fileSize(), "pos check");
if (_file != NULL) {
long old_pos = ::ftell(_file);
if (old_pos != pos) {
int ret = fseek(pos, SEEK_SET);
assert(ret != -1, "fseek return value check");
}
size_t count = fwrite(s, 1, len, _file);
if (old_pos != pos) {
fseek(old_pos, SEEK_SET);
}
}
}
void randomAccessFileStream::write(const char* s, size_t len) {
if (_file != NULL) {
// Make an unused local variable to avoid warning from gcc 4.x compiler.
size_t count = fwrite(s, 1, len, _file);
}
}
fdStream::fdStream(const char* file_name) { fdStream::fdStream(const char* file_name) {
_fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666); _fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
_need_close = true; _need_close = true;
......
...@@ -202,7 +202,7 @@ class fileStream : public outputStream { ...@@ -202,7 +202,7 @@ class fileStream : public outputStream {
fileStream(const char* file_name); fileStream(const char* file_name);
fileStream(const char* file_name, const char* opentype); fileStream(const char* file_name, const char* opentype);
fileStream(FILE* file, bool need_close = false) { _file = file; _need_close = need_close; } fileStream(FILE* file, bool need_close = false) { _file = file; _need_close = need_close; }
~fileStream(); virtual ~fileStream();
bool is_open() const { return _file != NULL; } bool is_open() const { return _file != NULL; }
void set_need_close(bool b) { _need_close = b;} void set_need_close(bool b) { _need_close = b;}
virtual void write(const char* c, size_t len); virtual void write(const char* c, size_t len);
...@@ -214,6 +214,20 @@ class fileStream : public outputStream { ...@@ -214,6 +214,20 @@ class fileStream : public outputStream {
void flush(); void flush();
}; };
class randomAccessFileStream : public fileStream {
public:
randomAccessFileStream();
randomAccessFileStream(const char* file_name);
randomAccessFileStream(const char* file_name, const char* opentype);
randomAccessFileStream(FILE* file, bool need_close = false);
virtual ~randomAccessFileStream() { }
virtual void write(const char* c, size_t len);
// random write support, write data to specified position
virtual void write(const char* c, size_t len, long pos);
int fseek(long offset, int pos) { return ::fseek(_file, offset, pos); }
long ftell() { return ::ftell(_file); }
};
CDS_ONLY(extern fileStream* classlist_file;) CDS_ONLY(extern fileStream* classlist_file;)
// unlike fileStream, fdStream does unbuffered I/O by calling // unlike fileStream, fdStream does unbuffered I/O by calling
......
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#include "precompiled.hpp"
#include "memory/resourceArea.hpp"
#include "oops/symbol.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/symbolMatcher.hpp"
template <MEMFLAGS F> SymbolMatcher<F>::SymbolMatcher(const char* regexes)
: _patterns(new (ResourceObj::C_HEAP, F)
GrowableArray<SymbolRegexPattern>(4, true, F)) {
assert(regexes != NULL, "illegal regexes");
int size = (int)strlen(regexes);
int pattern_size = 0;
char* pattern_begin = (char*)&regexes[0];
for (int i = 0; i < size + 1; i++) {
if (regexes[i] == ',' || regexes[i] == ';' || i == size) {
add_pattern(pattern_begin, pattern_size);
// reset
pattern_size = -1;
pattern_begin = (char*)&regexes[i+1];
}
pattern_size++;
}
}
template <MEMFLAGS F> SymbolMatcher<F>::~SymbolMatcher() {
delete _patterns;
}
template <MEMFLAGS F> void SymbolMatcher<F>::add_pattern(const char* s, int len) {
if (len == 0) {
return;
}
_patterns->push(SymbolRegexPattern(s, len));
}
template <MEMFLAGS F> bool SymbolMatcher<F>::match(Symbol* symbol) {
ResourceMark rm;
char* s = symbol->as_C_string();
return match(s);
}
template <MEMFLAGS F> bool SymbolMatcher<F>::match(const char* s) {
int regex_num = _patterns->length();
for (int i = 0; i < regex_num; i++) {
const char* regex = _patterns->at(i).origin_regex();
int regex_len = _patterns->at(i).length();
if (pattern_match(regex, regex_len, s)) {
return true;
}
}
return false;
}
template <MEMFLAGS F> bool SymbolMatcher<F>::pattern_match(const char* regex, int regex_len, const char* s) {
int s_len = (int)strlen(s);
if (s_len < regex_len - 1) {
return false;
}
for (int i =0; i < regex_len; i++) {
if (regex[i] == '*') {
return true;
}
if (regex[i] == s[i]) {
continue;
}
if ((regex[i] == '.' && s[i] == '/')
|| (regex[i] == '/' && s[i] == '.')) {
continue;
}
if (regex[i] != '*' && regex[i] != s[i]) {
return false;
}
}
return (s_len == regex_len);
}
void test_symbol_matcher() {
const char* str = NULL;
const char* regexes1 = "com.alibaba.Test,org.*,org.apache.logging*";
SymbolMatcher<mtClass>* matcher1 = new (ResourceObj::C_HEAP, mtClass) SymbolMatcher<mtClass>(regexes1);
str = "com/alibaba/Test";
assert(matcher1->match(str) == true, "");
str = "com/alibaba/Test2";
assert(matcher1->match(str) == false, "");
str = "org/alibaba/Test2";
assert(matcher1->match(str) == true, "");
str = "org/A";
assert(matcher1->match(str) == true, "");
str = "org.";
assert(matcher1->match(str) == true, "");
str = ".";
assert(matcher1->match(str) == false, "");
str = "";
assert(matcher1->match(str) == false, "");
str = "org/apache/logging/Flag";
assert(matcher1->match(str) == true, "");
const char* regexes2 = "com/alibaba.Test,,a.,";
SymbolMatcher<mtClass>* matcher2 = new (ResourceObj::C_HEAP, mtClass) SymbolMatcher<mtClass>(regexes2);
str = "";
assert(matcher2->match(str) == false, "");
str = "com.alibaba.Test";
assert(matcher2->match(str) == true, "");
str = "a.a";
assert(matcher2->match(str) == false, "");
const char* regexes3 = "org.apache.logging*";
SymbolMatcher<mtClass>* matcher3 = new (ResourceObj::C_HEAP, mtClass) SymbolMatcher<mtClass>(regexes3);
str = "org/apache/logging/x";
assert(matcher3->match(str) == true, "");
str = "org/apache/loggingxx";
assert(matcher3->match(str) == true, "");
delete matcher1;
delete matcher2;
}
template class SymbolMatcher<mtClass>;
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
#ifndef SHARED_VM_UTILITIES_SYMBOLMATCHER_HPP
#define SHARED_VM_UTILITIES_SYMBOLMATCHER_HPP
#include "memory/allocation.hpp"
#include "utilities/growableArray.hpp"
class SymbolRegexPattern {
public:
SymbolRegexPattern() { }
SymbolRegexPattern(const char* pattern, int length)
: _pattern(pattern),
_length(length) {
}
~SymbolRegexPattern() { }
const char* origin_regex() { return _pattern; }
void set_origin_regex(char* s) { _pattern = s; }
int length() { return _length; }
void set_length(int value) { _length = value; }
private:
const char* _pattern;
int _length;
};
template <MEMFLAGS F>
class SymbolMatcher : public ResourceObj {
public:
SymbolMatcher(const char* regexes);
virtual ~SymbolMatcher();
GrowableArray<SymbolRegexPattern>* patterns() { return _patterns; }
bool match(Symbol* symbol);
bool match(const char* s);
private:
void add_pattern(const char* src, int len);
bool pattern_match(const char* regex, int regex_len, const char* s);
GrowableArray<SymbolRegexPattern>* _patterns;
};
#endif //SHARED_VM_UTILITIES_SYMBOLMATCHER_HPP
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
import java.lang.reflect.Method;
import java.util.*;
import java.io.File;
import com.alibaba.jwarmup.*;
import com.oracle.java.testlibrary.*;
import static com.oracle.java.testlibrary.Asserts.*;
/*
* @test Issue11272598
* @library /testlibrary
* @build Issue11272598
* @run main/othervm Issue11272598
* @summary test to verify jwarmup method doesn't get de-optimized many times if virtual call receiver is null
*/
public class Issue11272598 {
public static void main(String[] args) throws Exception {
ProcessBuilder pb = null;
OutputAnalyzer output = null;
File logfile = null;
String classPath = System.getProperty("test.class.path");
try {
output = ProcessTools.executeProcess("pwd");
System.out.println(output.getOutput());
} catch (Throwable e) {
e.printStackTrace();
}
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-Xbootclasspath/a:.",
"-XX:+CompilationWarmUpRecording",
"-XX:-ClassUnloading",
"-XX:-Inline",
"-XX:+UseConcMarkSweepGC",
"-XX:-CMSClassUnloadingEnabled",
"-XX:-UseSharedSpaces",
"-XX:CompilationWarmUpLogfile=./jitwarmup.log",
"-XX:+PrintCompilationWarmUpDetail",
"-XX:CompilationWarmUpRecordTime=10",
"-XX:+PrintCompilation",
"-XX:+UnlockDiagnosticVMOptions",
"-cp", classPath,
InnerA.class.getName(), "recording");
output = new OutputAnalyzer(pb.start());
output.shouldContain("foo");
output.shouldHaveExitValue(0);
System.out.println(output.getOutput());
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-Xbootclasspath/a:.",
"-XX:+CompilationWarmUp",
"-XX:-Inline",
"-XX:-UseSharedSpaces",
"-XX:CompilationWarmUpLogfile=./jitwarmup.log",
"-XX:+PrintCompilationWarmUpDetail",
"-XX:+PrintCompilation",
"-XX:+UnlockDiagnosticVMOptions", //"-XX:+WhiteBoxAPI",
"-XX:+CompilationWarmUpResolveClassEagerly",
"-cp", classPath,
InnerA.class.getName(), "startup");
output = new OutputAnalyzer(pb.start());
System.out.println(output.getOutput());
output.shouldHaveExitValue(0);
assertTrue(getDeoptimizationCount(output.getOutput()) == 1);
}
public static int getDeoptimizationCount(String output) {
String[] lines = output.split("\n");
int count = 0;
for (String line : lines) {
if (line.contains("::foo") && line.contains("made not entrant")) {
count++;
}
}
return count;
}
public static class InnerA {
static {
System.out.println("InnerA initialize");
}
@Override
public int hashCode() {
if (ls.size() > 1) {
System.out.println("avoid optimization");
}
return 1;
}
public static List<String> ls = new ArrayList<String>();
public static void foo(InnerA a) {
a.hashCode();
if (ls.size() > 1) {
System.out.println("avoid optimization");
}
}
public static void main(String[] args) throws Exception {
if ("recording".equals(args[0])) {
System.out.println("begin recording!");
// initialize InnerA
InnerA a = new InnerA();
for (int i = 0; i < 20000; i++) {
foo(a);
}
Thread.sleep(1000);
foo(a);
Thread.sleep(10000);
System.out.println("done!");
} else {
System.out.println("begin startup!");
JWarmUp.notifyApplicationStartUpIsDone();
// doNotCheck not in args
if (args.length < 2) {
while (!JWarmUp.checkIfCompilationIsComplete()) {
Thread.sleep(1000);
}
}
for (int i = 0; i < 100000; i++) {
try {
InnerA a = new InnerA();
foo(a);
foo(null);
if ( i % 10000 == 1) {
System.gc();
}
} catch (Exception e) {
// do nothing
}
}
System.out.println("done!");
}
}
}
}
#!/bin/sh
#
# Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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.
#
# @test
# @summary test checkIfCompilationIsComplete API
# @run shell TestCheckIfCompilationIsComplete.sh
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
JAVA=${TESTJAVA}${FS}bin${FS}java
JAVAC=${TESTJAVA}${FS}bin${FS}javac
TEST_CLASS=TmpTestCheckIfCompilationComplete
TEST_SOURCE=${TEST_CLASS}.java
###################################################################################
cat > ${TESTCLASSES}${FS}$TEST_SOURCE << EOF
import java.lang.reflect.Method;
import java.util.*;
import com.alibaba.jwarmup.*;
public class TmpTestCheckIfCompilationComplete {
public static String[] aa = new String[0];
public static List<String> ls = new ArrayList<String>();
public String foo() {
for (int i = 0; i < 12000; i++) {
foo2(aa);
}
ls.add("x");
return ls.get(0);
}
public void foo2(String[] a) {
String s = "aa";
if (ls.size() > 100 && a.length < 100) {
ls.clear();
} else {
ls.add(s);
}
}
public static void doBiz() throws Exception {
TmpTestCheckIfCompilationComplete a = new TmpTestCheckIfCompilationComplete();
a.foo();
Thread.sleep(10000);
a.foo();
System.out.println("process is done!");
}
public static void main(String[] args) throws Exception {
if (args[0].equals("recording")) {
doBiz();
} else if (args[0].equals("compilation")) {
JWarmUp.notifyApplicationStartUpIsDone();
while (!JWarmUp.checkIfCompilationIsComplete()) {
Thread.sleep(1000);
}
System.out.println("the JWarmUp Compilation is Done");
System.out.println("Test Done");
}
}
}
EOF
# Do compilation
${JAVAC} -cp ${TESTCLASSES} -d ${TESTCLASSES} ${TESTCLASSES}${FS}$TEST_SOURCE >> /dev/null 2>&1
if [ $? != '0' ]
then
printf "Failed to compile ${TESTCLASSES}${FS}${TEST_SOURCE}"
exit 1
fi
#run Recording Model
${JAVA} -XX:-TieredCompilation -XX:-UseSharedSpaces -XX:+CompilationWarmUpRecording -XX:-ClassUnloading -XX:+PrintCompilation -XX:+PrintCompilationWarmUpDetail -XX:CompilationWarmUpRecordTime=10 -XX:CompilationWarmUpLogfile=./jitwarmup.log -cp ${TESTCLASSES} ${TEST_CLASS} recording > output.txt 2>&1
sleep 1
${JAVA} -XX:-TieredCompilation -XX:-UseSharedSpaces -XX:+CompilationWarmUp -XX:+PrintCompilation -XX:+PrintCompilationWarmUpDetail -XX:CompilationWarmUpLogfile=./jitwarmup.log -cp ${TESTCLASSES} ${TEST_CLASS} compilation > output.txt 2>&1
function assert()
{
i=0
notify_line_no=0
while read line
do
i=$(($i+1))
echo $i
echo $line
if [[ $line =~ "Compilation" ]]; then
notify_line_no=$i
echo "notify_line_no is $notify_line_no"
fi
done < output.txt
if [[ $notify_line_no == $(($i-1)) ]]; then
exit 0
else
exit -1
fi
}
assert
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
import sun.hotspot.WhiteBox;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.*;
import com.oracle.java.testlibrary.*;
import static com.oracle.java.testlibrary.Asserts.*;
/*
* @test TestClassInitChain
* @library /testlibrary /testlibrary/whitebox
* @build TestClassInitChain
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm TestClassInitChain
* @summary test ClassInitChain structure
*/
public class TestClassInitChain {
private static String classPath;
private static final int HEADER_SIZE = 32;
private static final int APPID_OFFSET = 16;
public static String generateOriginLogfile() throws Exception {
ProcessBuilder pb = null;
OutputAnalyzer output = null;
File logfile = new File("./jitwarmup.log");
classPath = System.getProperty("test.class.path");
try {
output = ProcessTools.executeProcess("pwd");
System.out.println(output.getOutput());
} catch (Throwable e) {
e.printStackTrace();
}
String className = InnerA.class.getName();
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-Xbootclasspath/a:.",
"-XX:+CompilationWarmUpRecording",
"-XX:-ClassUnloading",
"-XX:+UseConcMarkSweepGC",
"-XX:-CMSClassUnloadingEnabled",
"-XX:-UseSharedSpaces",
"-XX:CompilationWarmUpLogfile=./" + logfile.getName(),
"-XX:CompilationWarmUpRecordTime=15",
"-XX:CompilationWarmUpAppID=123",
"-XX:+PrintCompilationWarmUpDetail",
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"-cp", classPath,
className, "collection");
output = new OutputAnalyzer(pb.start());
output.shouldContain("[JitWarmUp] output profile info has done");
output.shouldContain("process is done!");
output.shouldHaveExitValue(0);
System.out.println(output.getOutput());
if (!logfile.exists()) {
throw new Error("jit log not exist");
}
return logfile.getName();
}
public static OutputAnalyzer testReadLogfileAndGetResult(String filename) throws Exception {
ProcessBuilder pb = null;
OutputAnalyzer output = null;
// test read logfile
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-Xbootclasspath/a:.",
"-XX:-UseSharedSpaces",
"-XX:+CompilationWarmUp",
"-XX:CompilationWarmUpLogfile=./" + filename,
"-XX:+PrintCompilationWarmUpDetail",
"-XX:CompilationWarmUpAppID=123",
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"-cp", classPath,
InnerA.class.getName(), "compilation");
output = new OutputAnalyzer(pb.start());
System.out.println(output.getOutput());
return output;
}
public static void main(String[] args) throws Exception {
OutputAnalyzer output = null;
String fileName = generateOriginLogfile();
// test origin log file
output = testReadLogfileAndGetResult(fileName);
output.shouldContain("Test Class Init Chain OK");
output.shouldHaveExitValue(0);
}
public static class InnerB {
static {
System.out.println("InnerB initialize");
}
public Object content;
}
public static class InnerA {
private static WhiteBox whiteBox;
static {
System.out.println("InnerA initialize");
}
public static String[] aa = new String[0];
public static List<String> ls = new ArrayList<String>();
public String foo() {
for (int i = 0; i < 12000; i++) {
foo2(aa);
}
ls.add("x");
return ls.get(0);
}
public void foo2(String[] a) {
String s = "aa";
if (ls.size() > 100 && a.length < 100) {
ls.clear();
} else {
ls.add(s);
}
}
public static void doBiz() throws Exception {
InnerA a = new InnerA();
a.foo();
InnerB b = new InnerB();
// avoid optimization
System.out.println("b is" + b);
Thread.sleep(20000);
a.foo();
System.out.println("process is done!");
}
public static void main(String[] args) throws Exception {
if (args[0].equals("collection")) {
doBiz();
} else if (args[0].equals("compilation")) {
whiteBox = WhiteBox.getWhiteBox();
String classAName = InnerA.class.getName();
String classBName = InnerB.class.getName();
String[] classList = whiteBox.getClassChainSymbolList();
System.out.println("class list length is " + classList.length);
int[] stateList = whiteBox.getClassChainStateList();
int orderA = -1;
int orderB = -1;
int stateA = -1;
int stateB = -1;
for (int i = 0; i < classList.length; i++) {
if (classList[i] == null) {
continue;
}
if (classList[i].equals(classAName)) {
orderA = i;
stateA = stateList[1];
}
if (classList[i].equals(classBName)) {
orderB = i;
stateB = stateList[i];
}
}
assertTrue(orderA != -1);
assertTrue(orderB != -1);
assertTrue(orderB > orderA);
assertTrue(stateA >= 2);
assertTrue(stateB >= 2);
System.out.println("Test Class Init Chain OK");
}
}
}
}
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
import sun.hotspot.WhiteBox;
import com.oracle.java.testlibrary.*;
/*
* @test TestClassInitOrder
* @library /testlibrary /testlibrary/whitebox
* @build TestClassInitOrder
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -Xbootclasspath/a:. -XX:-TieredCompilation
* -XX:-UseSharedSpaces
* -XX:+CompilationWarmUpRecording
* -XX:-ClassUnloading
* -XX:+UseConcMarkSweepGC
* -XX:-CMSClassUnloadingEnabled
* -XX:+PrintCompilationWarmUpDetail
* -XX:CompilationWarmUpLogfile=./test.log
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* TestClassInitOrder
* @summary Verify class initialization order in JitWarmUp recording
*/
public class TestClassInitOrder {
private static WhiteBox whiteBox;
public static void main(String[] args) throws Exception {
whiteBox = WhiteBox.getWhiteBox();
InnerA a = new InnerA();
System.out.println("after new A");
InnerB b = new InnerB();
System.out.println("after new B");
String[] list = whiteBox.getClassInitOrderList();
System.out.println(list.length);
String InnerAName = InnerA.class.getName();
String InnerBName = InnerB.class.getName();
int orderA = 0;
int orderB = 0;
for (int i = 0; i < list.length; i++) {
String s = list[i];
if (s.equals(InnerAName)) {
orderA = i;
} else if (s.equals(InnerBName)) {
orderB = i;
}
}
System.out.println("Class A order is " + orderA);
System.out.println("Class B order is " + orderB);
Asserts.assertTrue(orderA < orderB);
}
public static class InnerA {
static {
System.out.println("InnerA initialize");
}
}
public static class InnerB {
static {
System.out.println("InnerB initialize");
}
}
}
#!/bin/sh
#
# Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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.
#
# @test
# @summary disable MethodData in compilation made by JWarmUp
# @run shell TestDisableMethodData.sh
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
JAVA=${TESTJAVA}${FS}bin${FS}java
JAVAC=${TESTJAVA}${FS}bin${FS}javac
TEST_CLASS=TmpTestDisableMethodData
TEST_SOURCE=${TEST_CLASS}.java
###################################################################################
cat > ${TESTCLASSES}${FS}$TEST_SOURCE << EOF
import java.lang.reflect.Method;
import java.util.*;
import com.alibaba.jwarmup.*;
public class TmpTestDisableMethodData {
public static class TmpBase {
public void bar() { }
}
public static class TmpA extends TmpBase {
public static long a = 0;
@Override
public void bar() { a++; }
}
public static class TmpB extends TmpBase {
public static long b = 0;
@Override
public void bar() { b++; }
}
public static String[] aa = new String[0];
public static List<String> ls = new ArrayList<String>();
public String foo() {
for (int i = 0; i < 22000; i++) {
foo2(new TmpA());
}
foo2(new TmpB());
ls.add("x");
return ls.get(0);
}
public void foo2(TmpBase t) {
if (t instanceof TmpB) {
return;
}
String s = "aa";
if (ls.size() > 2000) {
ls.clear();
} else {
ls.add(s);
}
}
public static void doBiz() throws Exception {
TmpTestDisableMethodData a = new TmpTestDisableMethodData();
a.foo();
Thread.sleep(10000);
a.foo();
System.out.println("process is done!");
}
public static void main(String[] args) throws Exception {
if (args[0].equals("recording")) {
doBiz();
} else if (args[0].equals("compilation")) {
// invoke foo2 once
TmpTestDisableMethodData a = new TmpTestDisableMethodData();
for (int i = 0; i < 9687; i++) {
a.foo2(new TmpB());
}
System.gc();
JWarmUp.notifyApplicationStartUpIsDone();
while (!JWarmUp.checkIfCompilationIsComplete()) {
Thread.sleep(1000);
}
// Here, a.foo2 will be compiled by JWarmup but without MethodData info.
// and, wait for the deoptimization made by JWarmup.
for (int i = 0; i < 5; i++) {
Thread.sleep(4000);
System.gc();
}
for (int i = 0; i < 19687; i++) {
// Here, methods already be deoptimized by JWarmup.
a.foo2(new TmpB());
}
Thread.sleep(1000);
// a.foo2 will be compiled by C2 in optimal performance.
System.gc();
System.out.println("re-compilation done by normal C2");
// deoptimization should occur as it is made by normal C2 compilation
doBiz();
System.out.println("Test Done");
}
}
}
EOF
# Do compilation
${JAVAC} -cp ${TESTCLASSES} -d ${TESTCLASSES} ${TESTCLASSES}${FS}$TEST_SOURCE >> /dev/null 2>&1
if [ $? != '0' ]
then
printf "Failed to compile ${TESTCLASSES}${FS}${TEST_SOURCE}"
exit 1
fi
#run Recording Model
${JAVA} -XX:-Inline -XX:CompileCommand=exclude,*.foo -XX:-TieredCompilation -XX:-UseSharedSpaces -XX:+CompilationWarmUpRecording -XX:-ClassUnloading -XX:+PrintCompilation -XX:+PrintCompilationWarmUpDetail -XX:CompilationWarmUpRecordTime=10 -XX:CompilationWarmUpLogfile=./jitwarmup.log -cp ${TESTCLASSES} ${TEST_CLASS} recording > output.txt 2>&1
cat output.txt
echo "----------------------------------"
sleep 1
${JAVA} -XX:-Inline -XX:CompilationWarmUpDeoptTime=3 -XX:CompileCommand=exclude,*.foo -XX:-TieredCompilation -XX:-UseSharedSpaces -XX:+CompilationWarmUp -XX:+PrintCompilation -XX:+PrintCompilationWarmUpDetail -XX:CompilationWarmUpLogfile=./jitwarmup.log -cp ${TESTCLASSES} ${TEST_CLASS} compilation > output.txt 2>&1
cat output.txt
function assert()
{
i=0
notify_line_no=0
while read line
do
i=$(($i+1))
echo $i
echo $line
if [[ $line =~ "made not entrant" ]]; then
deopt_line_no=$i
fi
if [[ $line =~ "re-compilation" ]]; then
recom_line_no=$i
fi
done < output.txt
if [[ $deopt_line_no > $recom_line_no ]]; then
echo "deoptimization happens after normal c2 compilation, it is OK."
exit 0
else
echo "deopt_line_no is $deopt_line_no"
echo "recom_line_no is $recom_line_no"
exit -1
fi
}
assert
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
import sun.hotspot.WhiteBox;
import java.lang.reflect.Method;
import java.util.*;
import java.io.File;
import com.alibaba.jwarmup.*;
import com.oracle.java.testlibrary.*;
import static com.oracle.java.testlibrary.Asserts.*;
/*
* @test TestDisableNCE
* @library /testlibrary /testlibrary/whitebox
* @build TestDisableNCE
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm TestDisableNCE
* @summary verify the methods submitted via JWarmup are not de-optimized because of NCE
*/
public class TestDisableNCE {
public static void main(String[] args) throws Exception {
ProcessBuilder pb = null;
OutputAnalyzer output = null;
File logfile = null;
String classPath = System.getProperty("test.class.path");
try {
output = ProcessTools.executeProcess("pwd");
System.out.println(output.getOutput());
} catch (Throwable e) {
e.printStackTrace();
}
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-Xbootclasspath/a:.",
"-XX:+CompilationWarmUpRecording",
"-XX:-ClassUnloading",
"-XX:-Inline",
"-XX:-UseSharedSpaces",
"-XX:+UseConcMarkSweepGC",
"-XX:-CMSClassUnloadingEnabled",
"-XX:CompilationWarmUpLogfile=./jitwarmup.log",
"-XX:+PrintCompilationWarmUpDetail",
"-XX:CompilationWarmUpRecordTime=10",
"-XX:+PrintCompilation",
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+WhiteBoxAPI",
"-cp", classPath,
InnerA.class.getName(), "recording");
output = new OutputAnalyzer(pb.start());
output.shouldContain("foo");
output.shouldHaveExitValue(0);
System.out.println(output.getOutput());
// test read logfile
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-Xbootclasspath/a:.",
"-XX:+CompilationWarmUp",
"-XX:-Inline",
"-XX:-UseSharedSpaces",
"-XX:CompilationWarmUpLogfile=./jitwarmup.log",
"-XX:+PrintCompilationWarmUpDetail",
"-XX:+PrintCompilation",
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"-XX:+CompilationWarmUpResolveClassEagerly",
"-cp", classPath,
InnerA.class.getName(), "startup");
output = new OutputAnalyzer(pb.start());
System.out.println(output.getOutput());
// output.shouldNotContain("made not entrant");
output.shouldMatch("InnerA.foo.*success compiled");
output.shouldNotMatch("foo.*made not entrant");
output.shouldHaveExitValue(0);
logfile = new File("./jitwarmup.log");
if (logfile.exists()) {
try {
logfile.delete();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
public static class InnerB {
public String cc;
}
public static class InnerA {
static {
System.out.println("InnerA initialize");
}
public Object[] aa;
public Object bb;
public static List<String> ls = new ArrayList<String>();
public static void foo(InnerA a) {
// null check test
Object[] oo = a.aa;
// class check test
String[] ss = (String[])a.aa;
// instanceof test
if (a.bb instanceof InnerB) {
System.out.println("avoid opitimize");
}
if (ss.length > 1) {
System.out.println("avoid opitimize");
}
}
public static void main(String[] args) throws Exception {
if ("recording".equals(args[0])) {
System.out.println("begin recording!");
// initialize InnerA
InnerA a = new InnerA();
a.aa = new String[0];
a.bb = new String("xx");
for (int i = 0; i < 20000; i++) {
foo(a);
}
Thread.sleep(1000);
foo(a);
Thread.sleep(10000);
System.out.println("done!");
} else {
System.out.println("begin startup!");
JWarmUp.notifyApplicationStartUpIsDone();
while (!JWarmUp.checkIfCompilationIsComplete()) {
Thread.sleep(1000);
}
try {
InnerA a = new InnerA();
a.aa = null;
a.bb = null;
foo(a);
foo(null);
// The above NULL values should not cause the de-optimization for JWarmup compiled methods.
} catch (Exception e) {
System.out.println("NPE!");
}
System.out.println("done!");
}
}
}
}
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
import sun.hotspot.WhiteBox;
import java.io.*;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.*;
import com.oracle.java.testlibrary.*;
import static com.oracle.java.testlibrary.Asserts.*;
/*
* @test TestEagerCompilation
* @library /testlibrary /testlibrary/whitebox
* @build TestEagerCompilation
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm TestEagerCompilation
* @summary test eager compilation for method through ClassInitChain
*/
public class TestEagerCompilation {
private static String classPath;
private static final int HEADER_SIZE = 32;
private static final int APPID_OFFSET = 16;
public static String generateOriginLogfile() throws Exception {
ProcessBuilder pb = null;
OutputAnalyzer output = null;
File logfile = new File("./jitwarmup.log");
classPath = System.getProperty("test.class.path");
try {
output = ProcessTools.executeProcess("pwd");
System.out.println(output.getOutput());
} catch (Throwable e) {
e.printStackTrace();
}
String className = InnerA.class.getName();
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-Xbootclasspath/a:.",
"-XX:+CompilationWarmUpRecording",
"-XX:-ClassUnloading",
"-XX:+UseConcMarkSweepGC",
"-XX:-CMSClassUnloadingEnabled",
"-XX:-UseSharedSpaces",
"-XX:CompilationWarmUpLogfile=./" + logfile.getName(),
"-XX:CompilationWarmUpRecordTime=10",
"-XX:CompilationWarmUpAppID=123",
"-XX:+PrintCompilationWarmUpDetail",
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"-cp", classPath,
className, "recording");
output = new OutputAnalyzer(pb.start());
output.shouldContain("[JitWarmUp] output profile info has done");
output.shouldContain("process is done!");
output.shouldHaveExitValue(0);
System.out.println(output.getOutput());
if (!logfile.exists()) {
throw new Error("jit log not exist");
}
return logfile.getName();
}
public static String generateOriginLogfileWithG1() throws Exception {
ProcessBuilder pb = null;
OutputAnalyzer output = null;
File logfile = new File("./jitwarmup.log");
classPath = System.getProperty("test.class.path");
try {
output = ProcessTools.executeProcess("pwd");
System.out.println(output.getOutput());
} catch (Throwable e) {
e.printStackTrace();
}
String className = InnerA.class.getName();
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-Xbootclasspath/a:.",
"-XX:-ClassUnloading",
"-XX:+UseG1GC",
"-XX:-ClassUnloadingWithConcurrentMark",
"-XX:-UseSharedSpaces",
"-XX:+CompilationWarmUpRecording",
"-XX:CompilationWarmUpLogfile=./" + logfile.getName(),
"-XX:CompilationWarmUpRecordTime=10",
"-XX:CompilationWarmUpAppID=123",
"-XX:+PrintCompilationWarmUpDetail",
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"-cp", classPath,
className, "recording");
output = new OutputAnalyzer(pb.start());
output.shouldContain("[JitWarmUp] output profile info has done");
output.shouldContain("process is done!");
output.shouldHaveExitValue(0);
System.out.println(output.getOutput());
if (!logfile.exists()) {
throw new Error("jit log not exist");
}
return logfile.getName();
}
public static OutputAnalyzer testJitWarmUpJavaAPI(String filename) throws Exception {
ProcessBuilder pb = null;
OutputAnalyzer output = null;
// test read logfile
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-Xbootclasspath/a:.",
"-XX:-UseSharedSpaces",
"-XX:+CompilationWarmUp",
"-XX:CompilationWarmUpLogfile=./" + filename,
"-XX:+PrintCompilationWarmUpDetail",
"-XX:CompilationWarmUpAppID=123",
"-XX:+PrintCompilation",
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"-cp", classPath,
InnerA.class.getName(), "compilation");
output = new OutputAnalyzer(pb.start());
System.out.println(output.getOutput());
return output;
}
public static OutputAnalyzer testJitWarmUpJavaAPIwithEagerResolve(String filename) throws Exception {
ProcessBuilder pb = null;
OutputAnalyzer output = null;
// test read logfile
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-Xbootclasspath/a:.",
"-XX:-UseSharedSpaces",
"-XX:+CompilationWarmUp",
"-XX:CompilationWarmUpLogfile=./" + filename,
"-XX:+PrintCompilationWarmUpDetail",
"-XX:CompilationWarmUpAppID=123",
"-XX:+PrintCompilation",
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"-XX:+CompilationWarmUpResolveClassEagerly",
"-cp", classPath,
InnerA.class.getName(), "compilation");
output = new OutputAnalyzer(pb.start());
System.out.println(output.getOutput());
return output;
}
public static OutputAnalyzer testJitWarmUpJavaAPIWithG1(String filename) throws Exception {
ProcessBuilder pb = null;
OutputAnalyzer output = null;
// test read logfile
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-Xbootclasspath/a:.",
"-XX:-UseSharedSpaces",
"-XX:+CompilationWarmUp",
"-XX:+UseG1GC",
"-XX:-ClassUnloadingWithConcurrentMark",
"-XX:CompilationWarmUpLogfile=./" + filename,
"-XX:+PrintCompilationWarmUpDetail",
"-XX:CompilationWarmUpAppID=123",
"-XX:+PrintCompilation",
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"-cp", classPath,
InnerA.class.getName(), "compilation");
output = new OutputAnalyzer(pb.start());
System.out.println(output.getOutput());
return output;
}
public static OutputAnalyzer testJitWarmDeopt(String filename) throws Exception {
ProcessBuilder pb = null;
OutputAnalyzer output = null;
// test read logfile
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-Xbootclasspath/a:.",
"-XX:-UseSharedSpaces",
"-XX:+CompilationWarmUp",
"-XX:CompilationWarmUpLogfile=./" + filename,
"-XX:+PrintCompilationWarmUpDetail",
"-XX:CompilationWarmUpAppID=123",
"-XX:CompilationWarmUpDeoptTime=5",
"-XX:+PrintCompilation",
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"-cp", classPath,
InnerA.class.getName(), "deopt");
output = new OutputAnalyzer(pb.start());
System.out.println(output.getOutput());
return output;
}
private static String methodName = "TestEagerCompilation$InnerA.foo2([Ljava/lang/String;)V";
public static void main(String[] args) throws Exception {
OutputAnalyzer output = null;
String fileName = generateOriginLogfile();
// test origin log file
output = testJitWarmUpJavaAPI(fileName);
output.shouldContain("Test Eager Compilation OK");
output.shouldContain(methodName);
output.shouldHaveExitValue(0);
output = testJitWarmUpJavaAPIwithEagerResolve(fileName);
output.shouldContain("Test Eager Compilation OK");
output.shouldContain(methodName);
output.shouldHaveExitValue(0);
fileName = generateOriginLogfileWithG1();
output = testJitWarmUpJavaAPIWithG1(fileName);
output.shouldContain("Test Eager Compilation OK");
output.shouldContain(methodName);
output.shouldHaveExitValue(0);
}
public static class InnerB {
static {
System.out.println("InnerB initialize");
}
public Object content;
}
public static class InnerA {
private static WhiteBox whiteBox;
static {
System.out.println("InnerA initialize");
}
public static String[] aa = new String[0];
public static List<String> ls = new ArrayList<String>();
public String foo() {
for (int i = 0; i < 12000; i++) {
foo2(aa);
}
ls.add("x");
return ls.get(0);
}
public void foo2(String[] a) {
String s = "aa";
if (ls.size() > 100 && a.length < 100) {
ls.clear();
} else {
ls.add(s);
}
}
public static void doBiz() throws Exception {
InnerA a = new InnerA();
a.foo();
InnerB b = new InnerB();
System.out.println(b);
Thread.sleep(15000);
a.foo();
System.out.println("process is done!");
}
public static void main(String[] args) throws Exception {
if (args[0].equals("recording")) {
doBiz();
} else if (args[0].equals("compilation")) {
Class c = Class.forName("com.alibaba.jwarmup.JWarmUp");
Method m2 = c.getMethod("notifyApplicationStartUpIsDone");
m2.invoke(null);
System.out.println("invoke to notifyApplicationStartUpIsDone is Done");
// wait for compilation
Thread.sleep(5000);
System.out.println("Test Eager Compilation OK");
} else if (args[0].equals("optimistic")) {
// wait for compilation
Thread.sleep(5000);
System.out.println("Test Eager Compilation OK");
} else if (args[0].equals("deopt")) {
Class c = Class.forName("com.alibaba.jwarmup.JWarmUp");
Method m2 = c.getMethod("notifyApplicationStartUpIsDone");
m2.invoke(null);
System.out.println("invoke to notifyApplicationStartUpIsDone is Done");
// wait for compilation
Thread.sleep(1000);
doBiz();
Thread.sleep(5000);
System.out.println("Test Eager Compilation OK");
}
}
}
}
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
import java.io.File;
import com.oracle.java.testlibrary.*;
/*
* @test
* @summary Test JitWarmUp model required flag
*
* @library /testlibrary
* @run main TestFlagAssertion
*/
public class TestFlagAssertion {
public static void main(String[] args) throws Exception {
ProcessBuilder pb;
OutputAnalyzer output;
pb = ProcessTools.createJavaProcessBuilder("-XX:+CompilationWarmUpRecording",
"-XX:+TieredCompilation",
"-XX:-ProfileInterpreter",
"-version");
output = new OutputAnalyzer(pb.start());
output.shouldContain("[JitWarmUp] ERROR: flag ProfileInterpreter must be on");
output.shouldContain("[JitWarmUp] ERROR: init error");
System.out.println(output.getOutput());
pb = ProcessTools.createJavaProcessBuilder("-XX:+CompilationWarmUpRecording",
"-XX:-TieredCompilation",
"-XX:+ClassUnloading",
"-version");
output = new OutputAnalyzer(pb.start());
output.shouldContain("[JitWarmUp] ERROR: flag ClassUnloading must be off");
output.shouldContain("[JitWarmUp] ERROR: init error");
System.out.println(output.getOutput());
}
}
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
import java.util.*;
import java.io.File;
import com.oracle.java.testlibrary.*;
import static com.oracle.java.testlibrary.Asserts.*;
/*
* @test TestLogFlush
* @library /testlibrary
* @run main TestLogFlush
* @summary test flushing profiling information into log in jitwarmup recording model
*/
public class TestLogFlush {
public static void testFlush(String className) throws Exception {
ProcessBuilder pb = null;
OutputAnalyzer output = null;
File logfile = null;
String classPath = System.getProperty("test.class.path");
try {
output = ProcessTools.executeProcess("pwd");
System.out.println(output.getOutput());
} catch (Throwable e) {
e.printStackTrace();
}
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-XX:+CompilationWarmUpRecording",
"-XX:-ClassUnloading",
"-XX:+UseConcMarkSweepGC",
"-XX:-CMSClassUnloadingEnabled",
"-XX:-UseSharedSpaces",
"-XX:CompilationWarmUpLogfile=./jitwarmup.log",
"-XX:+PrintCompilationWarmUpDetail",
"-XX:CompilationWarmUpRecordTime=10",
"-cp", classPath,
className);
output = new OutputAnalyzer(pb.start());
output.shouldContain("[JitWarmUp] output profile info has done");
output.shouldContain("process is done!");
output.shouldHaveExitValue(0);
System.out.println(output.getOutput());
logfile = new File("./jitwarmup.log");
if (!logfile.exists()) {
throw new Error("jit log not exist");
}
try {
logfile.delete();
} catch (Throwable e) {
e.printStackTrace();
}
// test file name is not manually specified
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-XX:+CompilationWarmUpRecording",
"-XX:-ClassUnloading",
"-XX:+UseConcMarkSweepGC",
"-XX:-CMSClassUnloadingEnabled",
"-XX:-UseSharedSpaces",
"-XX:+PrintCompilationWarmUpDetail",
"-XX:CompilationWarmUpRecordTime=10",
"-cp", classPath,
className);
output = new OutputAnalyzer(pb.start());
output.shouldContain("[JitWarmUp] output profile info has done");
output.shouldContain("process is done!");
output.shouldHaveExitValue(0);
System.out.println(output.getOutput());
logfile = null;
File path = new File(".");
if (path.isDirectory()) {
File[] fs = path.listFiles();
for (File f : fs) {
if (f.isFile() && f.getName().startsWith("jwarmup_")) {
logfile = f;
}
}
}
assertTrue(logfile != null);
try {
logfile.delete();
} catch (Throwable e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
testFlush(InnerA.class.getName());
}
public static class InnerA {
static {
System.out.println("InnerA initialize");
}
public static String[] aa = new String[0];
public static List<String> ls = new ArrayList<String>();
public String foo() {
for (int i = 0; i < 12000; i++) {
foo2(aa);
}
ls.add("x");
return ls.get(0);
}
public void foo2(String[] a) {
String s = "aa";
if (ls.size() > 100 && a.length < 100) {
ls.clear();
} else {
ls.add(s);
}
}
public static void main(String[] args) throws Exception {
InnerA a = new InnerA();
a.foo();
Thread.sleep(3000);
a.foo();
Thread.sleep(15000);
System.out.println("process is done!");
}
}
}
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
import com.oracle.java.testlibrary.*;
import static com.oracle.java.testlibrary.Asserts.*;
import sun.hotspot.WhiteBox;
import java.util.*;
/*
* @test TestMethodRecorder
* @library /testlibrary /testlibrary/whitebox
* @build TestMethodRecorder
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm -Xbootclasspath/a:. -XX:-TieredCompilation
* -XX:+CompilationWarmUpRecording
* -XX:-ClassUnloading
* -XX:+UseConcMarkSweepGC
* -XX:-CMSClassUnloadingEnabled
* -XX:-UseSharedSpaces
* -XX:+PrintCompilationWarmUpDetail
* -XX:CompilationWarmUpLogfile=./test.log
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* TestMethodRecorder
* @summary Test method recording in CompilationWarmUpRecording model
*/
public class TestMethodRecorder {
private static WhiteBox whiteBox;
public static void main(String[] args) throws Exception {
whiteBox = WhiteBox.getWhiteBox();
InnerA a = new InnerA();
a.foo();
Thread.sleep(3000);
a.foo();
String[] list = whiteBox.getCompiledMethodList();
System.out.println(list.length);
String methodName = "foo2";
boolean contain = false;
for (int i = 0; i < list.length; i++) {
String s = list[i];
if (s.equals(methodName)) {
contain = true;
}
System.out.println("method is " + s);
}
assertTrue(contain);
}
public static class InnerA {
static {
System.out.println("InnerA initialize");
}
public static String[] aa = new String[0];
public static List<String> ls = new ArrayList<String>();
public String foo() {
for (int i = 0; i < 12000; i++) {
foo2(aa);
}
ls.add("x");
return ls.get(0);
}
public void foo2(String[] a) {
String s = "aa";
if (ls.size() > 100 && a.length < 100) {
ls.clear();
} else {
ls.add(s);
}
}
}
}
#!/bin/sh
#
# Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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.
#
# @test
# @summary test JWarmUp deoptimize will skip methods compiled by JIT
# @run shell TestNotDeoptJITMethod.sh
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
JAVA=${TESTJAVA}${FS}bin${FS}java
JAVAC=${TESTJAVA}${FS}bin${FS}javac
TEST_CLASS=TmpTestNotDeoptJITMethod
TEST_SOURCE=${TEST_CLASS}.java
###################################################################################
cat > ${TESTCLASSES}${FS}$TEST_SOURCE << EOF
import java.lang.reflect.Method;
import java.util.*;
import com.alibaba.jwarmup.*;
public class TmpTestNotDeoptJITMethod {
public static String[] aa = new String[0];
public static List<String> ls = new ArrayList<String>();
public String foo(int mode) throws Exception {
for (int i = 0; i < 12000; i++) {
foo2(aa, mode, i);
}
ls.add("x");
return ls.get(0);
}
public void foo2(String[] a, int mode, int index) throws Exception {
String s = "aa";
if (mode == 1 && index == 10000) {
a[index]=s; // out of range
}
if (ls.size() > 100 && a.length < 100) {
ls.clear();
} else {
ls.add(s);
}
}
public static void doBiz(int mode){
TmpTestNotDeoptJITMethod a = new TmpTestNotDeoptJITMethod();
try{
a.foo(mode);
} catch (Exception ex){
ex.printStackTrace();
}
try{
// re-warmup foo to let jit compile it
a.foo(0);
} catch (Exception ex){
ex.printStackTrace();
}
try{
Thread.sleep(10000);
a.foo(0);
} catch (Exception ex){
ex.printStackTrace();
}
System.out.println("process is done!");
}
public static void main(String[] args) throws Exception {
if (args[0].equals("recording")) {
doBiz(0);
} else if (args[0].equals("compilation")) {
JWarmUp.notifyApplicationStartUpIsDone();
while (!JWarmUp.checkIfCompilationIsComplete()) {
Thread.sleep(1000);
}
System.out.println("the JWarmUp Compilation is Done, notify jvm to deoptimize warmup methods");
new Thread(()-> doBiz(1)).start();
Thread.sleep(2000);
JWarmUp.notifyJVMDeoptWarmUpMethods();
Thread.sleep(6000);
System.gc();
System.out.println("Test Done");
}
}
}
EOF
# Do compilation
${JAVAC} -cp ${TESTCLASSES} -d ${TESTCLASSES} ${TESTCLASSES}${FS}$TEST_SOURCE >> /dev/null 2>&1
if [ $? != '0' ]
then
printf "Failed to compile ${TESTCLASSES}${FS}${TEST_SOURCE}"
exit 1
fi
#run Recording Model
${JAVA} -XX:-TieredCompilation -XX:+CompilationWarmUpRecording -XX:-ClassUnloading -XX:-UseSharedSpaces -XX:+PrintCompilation -XX:+PrintCompilationWarmUpDetail -XX:CompilationWarmUpRecordTime=10 -XX:CompilationWarmUpLogfile=./jitwarmup.log -XX:CompileThreshold=3000 -cp ${TESTCLASSES} ${TEST_CLASS} recording > output_record.txt 2>&1
sleep 1
${JAVA} -XX:-TieredCompilation -XX:+CompilationWarmUp -XX:-UseSharedSpaces -XX:+PrintCompilation -XX:+PrintCompilationWarmUpDetail -Xbatch -XX:CompilationWarmUpLogfile=./jitwarmup.log -XX:+CompilationWarmUpExplicitDeopt -XX:CompilationWarmUpDeoptTime=1200 -XX:-UseOnStackReplacement -cp ${TESTCLASSES} ${TEST_CLASS} compilation > output.txt 2>&1
function check_output()
{
#TmpTestNotDeoptJITMethod.foo2 should be re-compiled by jit
skip_messages=`grep "skip deoptimize TmpTestNotDeoptJITMethod.foo2" output.txt|wc -l`
if (( $skip_message -ne 1 )); then
exit -1
fi
exit 0
}
check_output
#!/bin/sh
#
# Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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.
#
# @test
# @summary test notifyJVMDeoptWarmUpMethods API
# @run shell TestNotifyDeopt.sh
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
JAVA=${TESTJAVA}${FS}bin${FS}java
JAVAC=${TESTJAVA}${FS}bin${FS}javac
TEST_CLASS=TmpTestNotifyDeopt
TEST_SOURCE=${TEST_CLASS}.java
###################################################################################
cat > ${TESTCLASSES}${FS}$TEST_SOURCE << EOF
import java.lang.reflect.Method;
import java.util.*;
import com.alibaba.jwarmup.*;
public class TmpTestNotifyDeopt {
public static String[] aa = new String[0];
public static List<String> ls = new ArrayList<String>();
public String foo() {
for (int i = 0; i < 12000; i++) {
foo2(aa);
}
ls.add("x");
return ls.get(0);
}
public void foo2(String[] a) {
String s = "aa";
if (ls.size() > 100 && a.length < 100) {
ls.clear();
} else {
ls.add(s);
}
}
public static void doBiz() {
try {
TmpTestNotifyDeopt a = new TmpTestNotifyDeopt();
a.foo();
Thread.sleep(10000);
a.foo();
System.out.println("process is done!");
} catch( Exception ex ){
ex.printStackTrace();
System.exit(-1);
}
}
public static void main(String[] args) throws Exception {
if (args[0].equals("recording")) {
doBiz();
} else if (args[0].equals("compilation")) {
JWarmUp.notifyApplicationStartUpIsDone();
while (!JWarmUp.checkIfCompilationIsComplete()) {
Thread.sleep(1000);
}
System.out.println("the JWarmUp Compilation is Done, notify jvm to deoptimize warmup methods");
new Thread(()->doBiz());
JWarmUp.notifyJVMDeoptWarmUpMethods();
Thread.sleep(6000);
System.gc();
System.out.println("Test Done");
}
}
}
EOF
# Do compilation
${JAVAC} -cp ${TESTCLASSES} -d ${TESTCLASSES} ${TESTCLASSES}${FS}$TEST_SOURCE >> /dev/null 2>&1
if [ $? != '0' ]
then
printf "Failed to compile ${TESTCLASSES}${FS}${TEST_SOURCE}"
exit 1
fi
#run Recording Model
${JAVA} -XX:-TieredCompilation -XX:-UseSharedSpaces -XX:+CompilationWarmUpRecording -XX:-ClassUnloading -XX:+PrintCompilationWarmUpDetail -XX:CompilationWarmUpRecordTime=10 -XX:CompilationWarmUpLogfile=./jitwarmup.log -cp ${TESTCLASSES} ${TEST_CLASS} recording > output.txt 2>&1
sleep 1
${JAVA} -XX:-TieredCompilation -XX:-UseSharedSpaces -XX:+CompilationWarmUp -XX:+PrintCompilationWarmUpDetail -XX:CompileThreshold=500000 -XX:CompilationWarmUpLogfile=./jitwarmup.log -XX:+CompilationWarmUpExplicitDeopt -XX:CompilationWarmUpDeoptTime=1200 -cp ${TESTCLASSES} ${TEST_CLASS} compilation > output.txt 2>&1
function check_output()
{
# check warning for conflict CompilationWarmUpDeoptTime
deopt_time_warning=`grep "WARNING : CompilationWarmUpDeoptTime is unused" output.txt|wc -l`
if [[ $deopt_time_warning -ne 1 ]]; then
echo "err by deopt time $deopt_time_warning"
exit -1
fi
# check warmup method is deoptimized
deopt_method_messages=`grep "WARNING : deoptimize warmup method" output.txt|wc -l`
if [[ $deopt_method_messages -eq 0 ]]; then
echo "err by deopt messages $deopt_method_messages"
exit -1
fi
# check every deoptimized method is compiled by warmup
warmup_methods=`grep "preload method" output.txt|awk '{print $4}'`
deopt_methods=`grep "WARNING : deoptimize warmup method" output.txt|awk '{print $7}'`
echo "warmup:$warmup_methods"
echo "deopt:$deopt_methods"
for m in $deopt_methods
do
found=0
for wm in $warmup_methods
do
if [[ $m == $wm ]]; then
found=1
fi
done
if [[ $found -ne 1 ]]; then
echo "not found $m"
exit -1
fi
done
exit 0
}
check_output
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
import sun.hotspot.WhiteBox;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.*;
import com.oracle.java.testlibrary.*;
import static com.oracle.java.testlibrary.Asserts.*;
/*
* @test TestReadLogfile
* @library /testlibrary /testlibrary/whitebox
* @build TestReadLogfile
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm TestReadLogfile
* @summary test jitwarmup read class init section & method section from log file
*/
public class TestReadLogfile {
private static String classPath;
private static final int HEADER_SIZE = 36;
private static final int APPID_OFFSET = 16;
public static String generateOriginLogfile() throws Exception {
ProcessBuilder pb = null;
OutputAnalyzer output = null;
File logfile = new File("./jitwarmup.log");
classPath = System.getProperty("test.class.path");
try {
output = ProcessTools.executeProcess("pwd");
System.out.println(output.getOutput());
} catch (Throwable e) {
e.printStackTrace();
}
String className = InnerA.class.getName();
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-Xbootclasspath/a:.",
"-XX:+CompilationWarmUpRecording",
"-XX:-ClassUnloading",
"-XX:+UseConcMarkSweepGC",
"-XX:-CMSClassUnloadingEnabled",
"-XX:-UseSharedSpaces",
"-XX:CompilationWarmUpLogfile=./" + logfile.getName(),
"-XX:CompilationWarmUpRecordTime=10",
"-XX:CompilationWarmUpAppID=123",
"-XX:+PrintCompilationWarmUpDetail",
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"-cp", classPath,
className, "collection");
output = new OutputAnalyzer(pb.start());
output.shouldContain("[JitWarmUp] output profile info has done");
output.shouldContain("process is done!");
output.shouldHaveExitValue(0);
System.out.println(output.getOutput());
if (!logfile.exists()) {
throw new Error("jit log not exist");
}
return logfile.getName();
}
public static OutputAnalyzer testReadLogfileAndGetResult(String filename) throws Exception {
ProcessBuilder pb = null;
OutputAnalyzer output = null;
// test read logfile
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-Xbootclasspath/a:.",
"-XX:-UseSharedSpaces",
"-XX:+CompilationWarmUp",
"-XX:CompilationWarmUpLogfile=./" + filename,
"-XX:+PrintCompilationWarmUpDetail",
"-XX:CompilationWarmUpAppID=123",
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
"-cp", classPath,
TestReadLogfile.InnerA.class.getName(), "compilation");
output = new OutputAnalyzer(pb.start());
System.out.println(output.getOutput());
return output;
}
private static byte[] getFileContent(String name) throws IOException{
ByteBuffer byteBuffer = null;
FileChannel fc = null;
File originFile = null;
FileInputStream ifs = null;
try {
originFile = new File("./" + name);
ifs = new FileInputStream(originFile);
fc = ifs.getChannel();
byteBuffer = ByteBuffer.allocate((int)fc.size());
while (fc.read(byteBuffer) > 0) {
// read
}
} finally {
if (fc != null) {
fc.close();
ifs.close();
}
}
return byteBuffer.array();
}
private static File createNewFile(String fileName) throws IOException {
File f = new File("./" + fileName);
if (f.exists()) {
f.delete();
}
f.createNewFile();
return f;
}
private static int readIntAsJavaInteger(RandomAccessFile f) throws IOException {
byte b1 = f.readByte();
byte b2 = f.readByte();
byte b3 = f.readByte();
byte b4 = f.readByte();
int result = (b1 & 0xff) | ((b2 << 8) & 0xff00)
| ((b3 << 16) & 0xff0000) | (b4 << 24);
return result;
}
private static byte[] IntegerAsBytes(Integer res) {
byte[] targets = new byte[4];
targets[0] = (byte) (res & 0xff);
targets[1] = (byte) ((res >> 8) & 0xff);
targets[2] = (byte) ((res >> 16) & 0xff);
targets[3] = (byte) (res >>> 24);
return targets;
}
// illegal header
public static String generateIllegalLogfile1(String originLogfileName) throws IOException {
String fileName = "jitwarmup_1.log";
File f = createNewFile(fileName);
byte[] originContent = getFileContent(originLogfileName);
RandomAccessFile raf = new RandomAccessFile(f, "rw");
raf.write(originContent, 0, originContent.length);
byte[] illegalHeader = {0x1,0x2,0x0,0x0,(byte)0xba,(byte)0xbb};
raf.seek(0);
raf.write(illegalHeader, 0, illegalHeader.length);
raf.close();
return fileName;
}
// illegal class init section size, size too large
public static String generateIllegalLogfile2(String originLogfileName) throws IOException {
String fileName = "jitwarmup_2.log";
File f = createNewFile(fileName);
byte[] originContent = getFileContent(originLogfileName);
RandomAccessFile raf = new RandomAccessFile(f, "rw");
raf.write(originContent, 0, originContent.length);
raf.seek(HEADER_SIZE);
int origin_size = readIntAsJavaInteger(raf);
raf.seek(HEADER_SIZE);
System.out.println("origin size is" + origin_size);
raf.write(IntegerAsBytes(origin_size + 18)); // illegal size
raf.close();
return fileName;
}
// illegal record section size, size too large
public static String generateIllegalLogfile3(String originLogfileName) throws IOException {
String fileName = "jitwarmup_3.log";
File f = createNewFile(fileName);
byte[] originContent = getFileContent(originLogfileName);
RandomAccessFile raf = new RandomAccessFile(f, "rw");
raf.write(originContent, 0, originContent.length);
raf.seek(HEADER_SIZE);
int init_section_size = readIntAsJavaInteger(raf);
raf.seek(HEADER_SIZE + init_section_size);
int record_section_size = readIntAsJavaInteger(raf);
System.out.println("record_section size is" + record_section_size);
raf.write(IntegerAsBytes(Integer.MAX_VALUE - 1)); // illegal size, too big
raf.close();
return fileName;
}
// illegal app id
public static String generateIllegalLogfile4(String originLogfileName) throws IOException {
String fileName = "jitwarmup_4.log";
File f = createNewFile(fileName);
byte[] originContent = getFileContent(originLogfileName);
RandomAccessFile raf = new RandomAccessFile(f, "rw");
raf.write(originContent, 0, originContent.length);
raf.seek(APPID_OFFSET);
int origin_appid = readIntAsJavaInteger(raf);
raf.seek(APPID_OFFSET);
System.out.println("origin appid is" + origin_appid);
raf.write(IntegerAsBytes(origin_appid + 1)); // illegal appid
raf.close();
return fileName;
}
public static void main(String[] args) throws Exception {
OutputAnalyzer output = null;
String originLogfileName = generateOriginLogfile();
// test origin log file
output = testReadLogfileAndGetResult(originLogfileName);
output.shouldContain("read log file OK");
output.shouldHaveExitValue(0);
// generate and test illegal log file header
output = testReadLogfileAndGetResult(generateIllegalLogfile1(originLogfileName));
output.shouldNotContain("read log file OK");
// generate and test illegal class init section size
output = testReadLogfileAndGetResult(generateIllegalLogfile2(originLogfileName));
output.shouldNotContain("read log file OK");
// generate and test illegal record section size
output = testReadLogfileAndGetResult(generateIllegalLogfile3(originLogfileName));
output.shouldNotContain("read log file OK");
// generate and test illegal appid
output = testReadLogfileAndGetResult(generateIllegalLogfile4(originLogfileName));
output.shouldNotContain("read log file OK");
}
public static class InnerA {
private static WhiteBox whiteBox;
static {
System.out.println("InnerA initialize");
}
public static String[] aa = new String[0];
public static List<String> ls = new ArrayList<String>();
public String foo() {
for (int i = 0; i < 12000; i++) {
foo2(aa);
}
ls.add("x");
return ls.get(0);
}
public void foo2(String[] a) {
String s = "aa";
if (ls.size() > 100 && a.length < 100) {
ls.clear();
} else {
ls.add(s);
}
}
public static void main(String[] args) throws Exception {
if (args[0].equals("collection")) {
InnerA a = new InnerA();
a.foo();
Thread.sleep(15000);
a.foo();
System.out.println("process is done!");
} else if (args[0].equals("compilation")) {
whiteBox = WhiteBox.getWhiteBox();
String className = InnerA.class.getName();
String[] classList = whiteBox.getClassListFromLogfile();
System.out.println("class list length is " + classList.length);
boolean containClass = false;
for (int i = 0; i < classList.length; i++) {
if (classList[i].equals(className)) {
containClass = true;
System.out.println("contain class OK");
}
}
String methodName = "foo2";
String[] methodList = whiteBox.getMethodListFromLogfile();
System.out.println("method list length is " + methodList.length);
assertTrue(methodList.length > 0);
boolean containMethod = false;
for (int i = 0; i < methodList.length; i++) {
if (methodList[i].equals(methodName)) {
containMethod = true;
System.out.println("contain method OK");
}
}
if (containClass && containMethod) {
System.out.println("read log file OK");
}
}
}
}
}
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
import sun.hotspot.WhiteBox;
import java.lang.reflect.Method;
import java.util.*;
import java.io.File;
import com.alibaba.jwarmup.*;
import com.oracle.java.testlibrary.*;
import static com.oracle.java.testlibrary.Asserts.*;
/*
* @test TestRecordNullMethodCounter
* @library /testlibrary /testlibrary/whitebox
* @build TestRecordNullMethodCounter
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm TestRecordNullMethodCounter
* @summary test jwarmup record doesn't crash if method counter is null
*/
public class TestRecordNullMethodCounter {
public static void main(String[] args) throws Exception {
ProcessBuilder pb = null;
OutputAnalyzer output = null;
File logfile = null;
String classPath = System.getProperty("test.class.path");
try {
output = ProcessTools.executeProcess("pwd");
System.out.println(output.getOutput());
} catch (Throwable e) {
e.printStackTrace();
}
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-Xbootclasspath/a:.",
"-XX:+CompilationWarmUpRecording",
"-XX:-ClassUnloading",
"-Xcomp",
"-XX:-UseSharedSpaces",
"-XX:CompilationWarmUpLogfile=./jitwarmup.log",
"-XX:+PrintCompilationWarmUpDetail",
"-XX:CompilationWarmUpRecordTime=5",
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+WhiteBoxAPI",
"-cp", classPath,
InnerA.class.getName());
output = new OutputAnalyzer(pb.start());
output.shouldHaveExitValue(0);
output.shouldContain("[JitWarmUp] WARNING : method counter is NULL for method");
System.out.println(output.getOutput());
}
public static class InnerA {
public static void main(String[] args) throws Exception {
java.lang.Thread.sleep(10000); // sleep 10s
}
}
}
/*
* Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* 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.
*/
import sun.hotspot.WhiteBox;
import java.lang.reflect.Method;
import java.util.*;
import java.io.File;
import com.alibaba.jwarmup.*;
import com.oracle.java.testlibrary.*;
import static com.oracle.java.testlibrary.Asserts.*;
/*
* @test TestThrowInitializaitonException
* @library /testlibrary
* @build TestThrowInitializaitonException
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* @run main/othervm TestThrowInitializaitonException
* @summary test throwing ExceptionInInitializerError in notifyApplicationStartUpIsDone API
*/
public class TestThrowInitializaitonException {
public static void main(String[] args) throws Exception {
ProcessBuilder pb = null;
OutputAnalyzer output = null;
File logfile = null;
String classPath = System.getProperty("test.class.path");
try {
output = ProcessTools.executeProcess("pwd");
System.out.println(output.getOutput());
} catch (Throwable e) {
e.printStackTrace();
}
pb = ProcessTools.createJavaProcessBuilder("-Xbootclasspath/a:.",
"-XX:+CompilationWarmUpRecording",
"-XX:-ClassUnloading",
"-XX:-Inline",
"-XX:+UseConcMarkSweepGC",
"-XX:-CMSClassUnloadingEnabled",
"-XX:-UseSharedSpaces",
"-XX:CompilationWarmUpLogfile=./jitwarmup.log",
"-XX:+PrintCompilationWarmUpDetail",
"-XX:CompilationWarmUpRecordTime=10",
"-XX:+PrintCompilation",
"-XX:+UnlockDiagnosticVMOptions",
"-XX:+WhiteBoxAPI",
"-cp", classPath,
InnerA.class.getName(), "recording");
output = new OutputAnalyzer(pb.start());
System.out.println(output.getOutput());
// test read logfile
pb = ProcessTools.createJavaProcessBuilder("-XX:-TieredCompilation",
"-Xbootclasspath/a:.",
"-XX:-UseSharedSpaces",
"-XX:+CompilationWarmUp",
"-XX:-Inline",
"-XX:CompilationWarmUpLogfile=./jitwarmup.log",
"-XX:+PrintCompilationWarmUpDetail",
"-XX:+PrintCompilation",
"-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI",
// "-XX:+DeoptimizeBeforeWarmUp",
"-cp", classPath,
InnerA.class.getName(), "startup");
output = new OutputAnalyzer(pb.start());
System.out.println(output.getOutput());
output.shouldContain("catched java.lang.ExceptionInInitializerError");
output.shouldHaveExitValue(0);
logfile = new File("./jitwarmup.log");
if (logfile.exists()) {
try {
logfile.delete();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
public static class InnerB {
static {
System.out.println("InnerB initialize");
if (InnerA.flag) {
throw new NullPointerException();
}
}
}
public static class InnerA {
static {
System.out.println("InnerA initialize");
}
public static boolean flag = true;
public static void main(String[] args) throws Exception {
if ("recording".equals(args[0])) {
System.out.println("begin recording!");
try {
InnerA a = new InnerA();
InnerB b = new InnerB();
} catch (Throwable e) {
// ignore
}
Thread.sleep(10000);
System.out.println("done!");
} else {
try {
System.out.println("begin startup!");
JWarmUp.notifyApplicationStartUpIsDone();
Thread.sleep(3000);
} catch (Throwable e) {
System.out.println("catched " + e.getClass().getName());
}
}
}
}
}
#!/bin/sh
#
# Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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.
#
# @test
# @summary test TieredCompilation in JWarmUp recording phase
# @run shell TestTieredCompilationInRecording.sh
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
JAVA=${TESTJAVA}${FS}bin${FS}java
JAVAC=${TESTJAVA}${FS}bin${FS}javac
TEST_CLASS=TmpTestTieredCompilationInRecording
TEST_SOURCE=${TEST_CLASS}.java
###################################################################################
cat > ${TESTCLASSES}${FS}$TEST_SOURCE << EOF
import java.lang.reflect.Method;
import java.util.*;
import com.alibaba.jwarmup.*;
public class TmpTestTieredCompilationInRecording {
public static String[] aa = new String[0];
public static List<String> ls = new ArrayList<String>();
public String foo() {
for (int i = 0; i < 12000; i++) {
foo2(aa);
}
ls.add("x");
return ls.get(0);
}
public void foo2(String[] a) {
String s = "aa";
if (ls.size() > 100 && a.length < 100) {
ls.clear();
} else {
ls.add(s);
}
}
public static void doBiz() throws Exception {
TmpTestTieredCompilationInRecording a = new TmpTestTieredCompilationInRecording();
a.foo();
Thread.sleep(1000);
a.foo();
a.foo();
Thread.sleep(1000);
a.foo();
Thread.sleep(1000);
a.foo();
Thread.sleep(10000);
a.foo();
System.out.println("process is done!");
}
public static void main(String[] args) throws Exception {
if (args[0].equals("collection")) {
doBiz();
} else if (args[0].equals("startup")) {
JWarmUp.notifyApplicationStartUpIsDone();
if (!JWarmUp.checkIfCompilationIsComplete()) {
Thread.sleep(1000);
}
System.out.println("the JWarmUp Compilation is Done");
System.out.println("Test Done");
}
}
}
EOF
# Do compilation
${JAVAC} -cp ${TESTCLASSES} -d ${TESTCLASSES} ${TESTCLASSES}${FS}$TEST_SOURCE >> /dev/null 2>&1
if [ $? != '0' ]
then
printf "Failed to compile ${TESTCLASSES}${FS}${TEST_SOURCE}"
exit 1
fi
#run Recording Model
${JAVA} -XX:+CompilationWarmUpRecording -XX:-ClassUnloading -XX:-UseSharedSpaces -XX:+PrintCompilation -XX:+PrintCompilationWarmUpDetail -XX:CompilationWarmUpRecordTime=10 -XX:CompilationWarmUpLogfile=./jitwarmup.log -cp ${TESTCLASSES} ${TEST_CLASS} collection > output.txt.recording 2>&1
sleep 1
${JAVA} -XX:-TieredCompilation -XX:+CompilationWarmUp -XX:-UseSharedSpaces -XX:+PrintCompilation -XX:+PrintCompilationWarmUpDetail -XX:CompilationWarmUpLogfile=./jitwarmup.log -cp ${TESTCLASSES} ${TEST_CLASS} startup > output.txt 2>&1
function assert()
{
i=0
has_foo2=0
while read line
do
i=$(($i+1))
echo $i
echo $line
if [[ $line =~ "foo2" ]]; then
has_foo2=$i
fi
done < output.txt
if [[ $has_foo2 != 0 ]]; then
exit 0
else
exit -1
fi
}
assert
#!/bin/sh
#
# Copyright (c) 2019 Alibaba Group Holding Limited. 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. Alibaba designates this
# particular file as subject to the "Classpath" exception as provided
# by Oracle in the LICENSE file that accompanied this code.
#
# 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.
#
# @test
# @summary test issue 9780156
# @run shell issue9780156.sh
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
JAVA=${TESTJAVA}${FS}bin${FS}java
JAVAC=${TESTJAVA}${FS}bin${FS}javac
JAR=${TESTJAVA}${FS}bin${FS}jar
TEST_MAIN_CLASS=TmpTestMain
TEST_MAIN_SOURCE=${TEST_MAIN_CLASS}.java
TEST_CLASS_A=TmpClassA
TEST_SOURCE_A=${TEST_CLASS_A}.java
TEST_CLASS_B=TmpClassB
TEST_SOURCE_B=${TEST_CLASS_B}.java
JARNAME=testjar.jar
###################################################################################
cat > ${TESTCLASSES}${FS}$TEST_SOURCE_A << EOF
import java.util.*;
public class TmpClassA {
static {
System.out.println("init TmpClassA");
}
public static void fooA() {
System.out.println(TmpClassB.class);
}
TmpClassB bb;
}
EOF
cat > ${TESTCLASSES}${FS}$TEST_SOURCE_B << EOF
public class TmpClassB {
static {
System.out.println("init TmpClassB");
}
}
EOF
cat > ${TESTCLASSES}${FS}$TEST_MAIN_SOURCE << EOF
import java.lang.reflect.Method;
import java.util.*;
import java.io.*;
import java.net.*;
public class TmpTestMain {
public static class TmpClassloader extends URLClassLoader {
public TmpClassloader(URL[] urls) {
super(urls);
}
public TmpClassloader(String dir) throws MalformedURLException {
super(new URL[] { new URL("file:" + basePath + File.separatorChar + dir + File.separatorChar + jarName) });
}
public static String basePath = "${TESTCLASSES}";
public static String jarName = "${JARNAME}";
}
public static void foo(String dir) throws Exception {
TmpClassloader tcl = new TmpClassloader(dir);
Class c1 = tcl.loadClass("TmpClassA");
c1.newInstance();
Class c2 = tcl.loadClass("TmpClassB");
c2.newInstance();
}
public static void bar(String dir) throws Exception {
TmpClassloader tcl = new TmpClassloader(dir);
Class c1 = tcl.loadClass("TmpClassA");
c1.newInstance();
}
public static void main(String[] args) throws Exception {
try {
foo("dir1");
bar("dir2");
Class c = Class.forName("com.alibaba.jwarmup.JWarmUp");
Method m = c.getMethod("notifyApplicationStartUpIsDone");
Method m2 = c.getMethod("checkIfCompilationIsComplete");
m.invoke(null);
while ((Boolean) m2.invoke(null) == false) {
Thread.sleep(1000);
}
System.out.println("the JWarmUp Compilation is Done");
System.out.println("Test Done");
foo("dir2");
Thread.sleep(6000);
} catch (Exception e) {
e.printStackTrace();
}
}
}
EOF
# Do compilation
${JAVAC} -cp ${TESTCLASSES} -d ${TESTCLASSES} ${TESTCLASSES}${FS}$TEST_MAIN_SOURCE
if [ $? != '0' ]
then
printf "Failed to compile ${TESTCLASSES}${FS}${TEST_MAIN_SOURCE}"
exit 1
fi
${JAVAC} -cp ${TESTCLASSES} -d ${TESTCLASSES} ${TESTCLASSES}${FS}$TEST_SOURCE_A
if [ $? != '0' ]
then
printf "Failed to compile ${TESTCLASSES}${FS}${TEST_SOURCE_A}"
exit 1
fi
${JAVAC} -cp ${TESTCLASSES} -d ${TESTCLASSES} ${TESTCLASSES}${FS}$TEST_SOURCE_B
if [ $? != '0' ]
then
printf "Failed to compile ${TESTCLASSES}${FS}${TEST_SOURCE_B}"
exit 1
fi
rm -f ${JARNAME}
cp ${TESTCLASSES}${FS}${TEST_CLASS_A}.class .
cp ${TESTCLASSES}${FS}${TEST_CLASS_B}.class .
rm ${TESTCLASSES}${FS}${TEST_CLASS_A}.class
rm ${TESTCLASSES}${FS}${TEST_CLASS_B}.class
${JAR} cvf ${JARNAME} ${TEST_CLASS_A}.class ${TEST_CLASS_B}.class
mkdir -p ${TESTCLASSES}${FS}dir1${FS}
mkdir -p ${TESTCLASSES}${FS}dir2${FS}
cp ${JARNAME} ${TESTCLASSES}${FS}dir1${FS}
cp ${JARNAME} ${TESTCLASSES}${FS}dir2${FS}
#run Recording Model
${JAVA} -verbose:class -XX:-TieredCompilation -XX:-UseSharedSpaces -XX:+CompilationWarmUpRecording -XX:-ClassUnloading -XX:+PrintCompilation -XX:+PrintCompilationWarmUpDetail -XX:CompilationWarmUpRecordTime=5 -XX:CompilationWarmUpLogfile=./jitwarmup.log -cp ${TESTCLASSES} ${TEST_MAIN_CLASS} > output.txt 2>&1
sleep 1
${JAVA} -verbose:class -XX:-TieredCompilation -XX:-UseSharedSpaces -XX:+CompilationWarmUp -XX:+PrintCompilation -XX:+PrintCompilationWarmUpDetail -XX:CompilationWarmUpLogfile=./jitwarmup.log -cp ${TESTCLASSES} ${TEST_MAIN_CLASS} > output.txt 2>&1
function assert()
{
i=0
while read line
do
echo $line
if [[ $line =~ "Loaded TmpClassB" ]]; then
i=$(($i+1))
echo $i
fi
done < output.txt
if [[ $i == 3 ]]; then
exit 0
else
exit -1
fi
}
assert
...@@ -213,6 +213,17 @@ public class WhiteBox { ...@@ -213,6 +213,17 @@ public class WhiteBox {
public native int getContextForObject(Object obj); public native int getContextForObject(Object obj);
public native void printRegionInfo(int context); public native void printRegionInfo(int context);
// JitWarmUp
public native String[] getClassInitOrderList();
public native String[] getCompiledMethodList();
public native String[] getClassListFromLogfile();
public native String[] getClassLoadedRecordList();
public native String[] getMethodListFromLogfile();
public native boolean forceCompileInJitWarmUp(Executable method);
public native String[] getClassChainSymbolList();
public native int[] getClassChainStateList();
public native boolean testFixDanglingPointerInDeopt(String name);
// VM flags // VM flags
public native void setBooleanVMFlag(String name, boolean value); public native void setBooleanVMFlag(String name, boolean value);
public native void setIntxVMFlag(String name, long value); public native void setIntxVMFlag(String name, long value);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册