Mercurial > hg > openjdk > jdk7u > hotspot
changeset 5564:d9bbda3eef89
Merge
author | asaha |
---|---|
date | Wed, 07 Jan 2015 12:20:45 -0800 |
parents | fddbf8bf7698 (current diff) 2b2682c6972e (diff) |
children | effb7f4183cf |
files | .hgtags src/share/vm/prims/jvm.cpp src/share/vm/runtime/arguments.cpp src/share/vm/runtime/vmStructs.cpp |
diffstat | 43 files changed, 979 insertions(+), 217 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Tue Dec 23 13:53:21 2014 -0800 +++ b/.hgtags Wed Jan 07 12:20:45 2015 -0800 @@ -790,3 +790,5 @@ 05fe7a87d14908eb3f21a0d29fc72cee2f996b7f jdk7u80-b00 e2533d62ca887078e4b952a75a75680cfb7894b9 jdk7u80-b01 bad107a5d096b070355c5a2d80aa50bc5576144b jdk7u80-b02 +9d2b485d2a58ea57ab2b3c06b2128f456ab39a38 jdk7u80-b03 +a89267b51c40cba0b26fe84831478389723c8321 jdk7u80-b04
--- a/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -26,8 +26,8 @@ #include "runtime/os.hpp" #include "vm_version_sparc.hpp" -static bool detect_niagara() { - char cpu[128]; +static bool cpuinfo_field_contains(const char* field, const char* value) { + char line[1024]; bool rv = false; FILE* fp = fopen("/proc/cpuinfo", "r"); @@ -35,9 +35,10 @@ return rv; } - while (!feof(fp)) { - if (fscanf(fp, "cpu\t\t: %100[^\n]", &cpu) == 1) { - if (strstr(cpu, "Niagara") != NULL) { + while (fgets(line, sizeof(line), fp) != NULL) { + assert(strlen(line) < sizeof(line) - 1, "buffer line[1024] is too small."); + if (strncmp(line, field, strlen(field)) == 0) { + if (strstr(line, value) != NULL) { rv = true; } break; @@ -45,8 +46,15 @@ } fclose(fp); + return rv; +} - return rv; +static bool detect_niagara() { + return cpuinfo_field_contains("cpu", "Niagara"); +} + +static bool detect_blkinit() { + return cpuinfo_field_contains("cpucaps", "blkinit"); } int VM_Version::platform_features(int features) { @@ -58,5 +66,9 @@ features = niagara1_m | T_family_m; } + if (detect_blkinit()) { + features |= blk_init_instructions_m; + } + return features; }
--- a/src/share/vm/c1/c1_globals.hpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/c1/c1_globals.hpp Wed Jan 07 12:20:45 2015 -0800 @@ -269,9 +269,6 @@ develop(bool, InstallMethods, true, \ "Install methods at the end of successful compilations") \ \ - product(intx, CompilationRepeat, 0, \ - "Number of times to recompile method before returning result") \ - \ develop(intx, NMethodSizeLimit, (64*K)*wordSize, \ "Maximum size of a compiled method.") \ \
--- a/src/share/vm/classfile/classLoader.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/classfile/classLoader.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -197,7 +197,7 @@ } -ClassFileStream* ClassPathDirEntry::open_stream(const char* name) { +ClassFileStream* ClassPathDirEntry::open_stream(const char* name, TRAPS) { // construct full path name char path[JVM_MAXPATHLEN]; if (jio_snprintf(path, sizeof(path), "%s%s%s", _dir, os::file_separator(), name) == -1) { @@ -240,7 +240,7 @@ FREE_C_HEAP_ARRAY(char, _zip_name, mtClass); } -ClassFileStream* ClassPathZipEntry::open_stream(const char* name) { +ClassFileStream* ClassPathZipEntry::open_stream(const char* name, TRAPS) { // enable call to C land JavaThread* thread = JavaThread::current(); ThreadToNativeFromVM ttn(thread); @@ -284,24 +284,24 @@ } } -LazyClassPathEntry::LazyClassPathEntry(char* path, struct stat st) : ClassPathEntry() { +LazyClassPathEntry::LazyClassPathEntry(char* path, const struct stat* st) : ClassPathEntry() { _path = strdup(path); - _st = st; + _st = *st; _meta_index = NULL; _resolved_entry = NULL; + _has_error = false; } bool LazyClassPathEntry::is_jar_file() { return ((_st.st_mode & S_IFREG) == S_IFREG); } -ClassPathEntry* LazyClassPathEntry::resolve_entry() { +ClassPathEntry* LazyClassPathEntry::resolve_entry(TRAPS) { if (_resolved_entry != NULL) { return (ClassPathEntry*) _resolved_entry; } ClassPathEntry* new_entry = NULL; - ClassLoader::create_class_path_entry(_path, _st, &new_entry, false); - assert(new_entry != NULL, "earlier code should have caught this"); + new_entry = ClassLoader::create_class_path_entry(_path, &_st, false, CHECK_NULL); { ThreadCritical tc; if (_resolved_entry == NULL) { @@ -314,12 +314,21 @@ return (ClassPathEntry*) _resolved_entry; } -ClassFileStream* LazyClassPathEntry::open_stream(const char* name) { +ClassFileStream* LazyClassPathEntry::open_stream(const char* name, TRAPS) { if (_meta_index != NULL && !_meta_index->may_contain(name)) { return NULL; } - return resolve_entry()->open_stream(name); + if (_has_error) { + return NULL; + } + ClassPathEntry* cpe = resolve_entry(THREAD); + if (cpe == NULL) { + _has_error = true; + return NULL; + } else { + return cpe->open_stream(name, THREAD); + } } bool LazyClassPathEntry::is_lazy() { @@ -465,20 +474,19 @@ } } -void ClassLoader::create_class_path_entry(char *path, struct stat st, ClassPathEntry **new_entry, bool lazy) { +ClassPathEntry* ClassLoader::create_class_path_entry(char *path, const struct stat* st, bool lazy, TRAPS) { JavaThread* thread = JavaThread::current(); if (lazy) { - *new_entry = new LazyClassPathEntry(path, st); - return; + return new LazyClassPathEntry(path, st); } - if ((st.st_mode & S_IFREG) == S_IFREG) { + ClassPathEntry* new_entry = NULL; + if ((st->st_mode & S_IFREG) == S_IFREG) { // Regular file, should be a zip file // Canonicalized filename char canonical_path[JVM_MAXPATHLEN]; if (!get_canonical_path(path, canonical_path, JVM_MAXPATHLEN)) { // This matches the classic VM - EXCEPTION_MARK; - THROW_MSG(vmSymbols::java_io_IOException(), "Bad pathname"); + THROW_MSG_(vmSymbols::java_io_IOException(), "Bad pathname", NULL); } char* error_msg = NULL; jzfile* zip; @@ -489,7 +497,7 @@ zip = (*ZipOpen)(canonical_path, &error_msg); } if (zip != NULL && error_msg == NULL) { - *new_entry = new ClassPathZipEntry(zip, path); + new_entry = new ClassPathZipEntry(zip, path); if (TraceClassLoading) { tty->print_cr("[Opened %s]", path); } @@ -504,16 +512,16 @@ msg = NEW_RESOURCE_ARRAY(char, len); ; jio_snprintf(msg, len - 1, "error in opening JAR file <%s> %s", error_msg, path); } - EXCEPTION_MARK; - THROW_MSG(vmSymbols::java_lang_ClassNotFoundException(), msg); + THROW_MSG_(vmSymbols::java_lang_ClassNotFoundException(), msg, NULL); } } else { // Directory - *new_entry = new ClassPathDirEntry(path); + new_entry = new ClassPathDirEntry(path); if (TraceClassLoading) { tty->print_cr("[Path %s]", path); } } + return new_entry; } @@ -572,13 +580,14 @@ } } -void ClassLoader::update_class_path_entry_list(const char *path, +void ClassLoader::update_class_path_entry_list(char *path, bool check_for_duplicates) { struct stat st; - if (os::stat((char *)path, &st) == 0) { + if (os::stat(path, &st) == 0) { // File or directory found ClassPathEntry* new_entry = NULL; - create_class_path_entry((char *)path, st, &new_entry, LazyBootClassLoader); + Thread* THREAD = Thread::current(); + new_entry = create_class_path_entry(path, &st, LazyBootClassLoader, CHECK); // The kernel VM adds dynamically to the end of the classloader path and // doesn't reorder the bootclasspath which would break java.lang.Package // (see PackageInfo). @@ -895,7 +904,7 @@ PerfClassTraceTime::CLASS_LOAD); ClassPathEntry* e = _first_entry; while (e != NULL) { - stream = e->open_stream(name); + stream = e->open_stream(name, CHECK_(instanceKlassHandle())); if (stream != NULL) { break; } @@ -1258,11 +1267,16 @@ } void LazyClassPathEntry::compile_the_world(Handle loader, TRAPS) { - resolve_entry()->compile_the_world(loader, CHECK); + ClassPathEntry* cpe = resolve_entry(THREAD); + if (cpe != NULL) { + cpe->compile_the_world(loader, CHECK); + } } bool LazyClassPathEntry::is_rt_jar() { - return resolve_entry()->is_rt_jar(); + Thread* THREAD = Thread::current(); + ClassPathEntry* cpe = resolve_entry(THREAD); + return (cpe != NULL) ? cpe->is_jar_file() : false; } void ClassLoader::compile_the_world() {
--- a/src/share/vm/classfile/classLoader.hpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/classfile/classLoader.hpp Wed Jan 07 12:20:45 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2013, 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 @@ -63,7 +63,7 @@ ClassPathEntry(); // Attempt to locate file_name through this class path entry. // Returns a class file parsing stream if successfull. - virtual ClassFileStream* open_stream(const char* name) = 0; + virtual ClassFileStream* open_stream(const char* name, TRAPS) = 0; // Debugging NOT_PRODUCT(virtual void compile_the_world(Handle loader, TRAPS) = 0;) NOT_PRODUCT(virtual bool is_rt_jar() = 0;) @@ -77,7 +77,7 @@ bool is_jar_file() { return false; } const char* name() { return _dir; } ClassPathDirEntry(char* dir); - ClassFileStream* open_stream(const char* name); + ClassFileStream* open_stream(const char* name, TRAPS); // Debugging NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) NOT_PRODUCT(bool is_rt_jar();) @@ -107,7 +107,7 @@ const char* name() { return _zip_name; } ClassPathZipEntry(jzfile* zip, const char* zip_name); ~ClassPathZipEntry(); - ClassFileStream* open_stream(const char* name); + ClassFileStream* open_stream(const char* name, TRAPS); void contents_do(void f(const char* name, void* context), void* context); // Debugging NOT_PRODUCT(void compile_the_world(Handle loader, TRAPS);) @@ -125,13 +125,14 @@ char* _path; // dir or file struct stat _st; MetaIndex* _meta_index; + bool _has_error; volatile ClassPathEntry* _resolved_entry; - ClassPathEntry* resolve_entry(); + ClassPathEntry* resolve_entry(TRAPS); public: bool is_jar_file(); const char* name() { return _path; } - LazyClassPathEntry(char* path, struct stat st); - ClassFileStream* open_stream(const char* name); + LazyClassPathEntry(char* path, const struct stat* st); + ClassFileStream* open_stream(const char* name, TRAPS); void set_meta_index(MetaIndex* meta_index) { _meta_index = meta_index; } virtual bool is_lazy(); // Debugging @@ -207,14 +208,15 @@ static void setup_meta_index(); static void setup_bootstrap_search_path(); static void load_zip_library(); - static void create_class_path_entry(char *path, struct stat st, ClassPathEntry **new_entry, bool lazy); + static ClassPathEntry* create_class_path_entry(char *path, const struct stat* st, + bool lazy, TRAPS); // Canonicalizes path names, so strcmp will work properly. This is mainly // to avoid confusing the zip library static bool get_canonical_path(char* orig, char* out, int len); public: // Used by the kernel jvm. - static void update_class_path_entry_list(const char *path, + static void update_class_path_entry_list(char *path, bool check_for_duplicates); static void print_bootclasspath();
--- a/src/share/vm/classfile/javaClasses.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/classfile/javaClasses.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -575,6 +575,7 @@ instanceKlass::cast(k())->do_local_static_fields(&initialize_static_field, CHECK_NULL); } // set the classLoader field in the java_lang_Class instance + assert(class_loader() == k->class_loader(), "should be same"); set_class_loader(mirror(), class_loader()); return mirror(); } else {
--- a/src/share/vm/compiler/compileBroker.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/compiler/compileBroker.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -1594,22 +1594,6 @@ if (method()->number_of_breakpoints() == 0) { // Compile the method. if ((UseCompiler || AlwaysCompileLoopMethods) && CompileBroker::should_compile_new_jobs()) { -#ifdef COMPILER1 - // Allow repeating compilations for the purpose of benchmarking - // compile speed. This is not useful for customers. - if (CompilationRepeat != 0) { - int compile_count = CompilationRepeat; - while (compile_count > 0) { - invoke_compiler_on_method(task); - nmethod* nm = method->code(); - if (nm != NULL) { - nm->make_zombie(); - method->clear_code(); - } - compile_count--; - } - } -#endif /* COMPILER1 */ invoke_compiler_on_method(task); } else { // After compilation is disabled, remove remaining methods from queue
--- a/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -492,7 +492,7 @@ // heap remains parsable. const bool limit_exceeded = size_policy()->gc_overhead_limit_exceeded(); const bool softrefs_clear = collector_policy()->all_soft_refs_clear(); - assert(!limit_exceeded || softrefs_clear, "Should have been cleared"); + if (limit_exceeded && softrefs_clear) { *gc_overhead_limit_was_exceeded = true; size_policy()->set_gc_overhead_limit_exceeded(false);
--- a/src/share/vm/memory/collectorPolicy.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/memory/collectorPolicy.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -642,7 +642,7 @@ const bool limit_exceeded = size_policy()->gc_overhead_limit_exceeded(); const bool softrefs_clear = all_soft_refs_clear(); - assert(!limit_exceeded || softrefs_clear, "Should have been cleared"); + if (limit_exceeded && softrefs_clear) { *gc_overhead_limit_was_exceeded = true; size_policy()->set_gc_overhead_limit_exceeded(false);
--- a/src/share/vm/oops/arrayKlass.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/oops/arrayKlass.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -124,7 +124,7 @@ ResourceMark rm(THREAD); k->initialize_supers(super_klass(), CHECK); k->vtable()->initialize_vtable(false, CHECK); - java_lang_Class::create_mirror(k, CHECK); + java_lang_Class::create_mirror(k, Handle(THREAD, k->class_loader()), CHECK); } objArrayOop arrayKlass::compute_secondary_supers(int num_extra_slots, TRAPS) {
--- a/src/share/vm/oops/methodDataOop.hpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/oops/methodDataOop.hpp Wed Jan 07 12:20:45 2015 -0800 @@ -1203,7 +1203,7 @@ // Whole-method sticky bits and flags public: enum { - _trap_hist_limit = 17, // decoupled from Deoptimization::Reason_LIMIT + _trap_hist_limit = 18, // decoupled from Deoptimization::Reason_LIMIT _trap_hist_mask = max_jubyte, _extra_data_count = 4 // extra DataLayout headers, for trap history }; // Public flag values
--- a/src/share/vm/oops/objArrayKlass.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/oops/objArrayKlass.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -202,6 +202,15 @@ } } +// Protect against _bottom_klass being null, when called from Universe::fixup_mirrors +oop objArrayKlass::class_loader() const { + if (bottom_klass() != NULL) { + return Klass::cast(bottom_klass())->class_loader(); + } else { + return NULL; + } +} + klassOop objArrayKlass::array_klass_impl(bool or_null, int n, TRAPS) { objArrayKlassHandle h_this(THREAD, as_klassOop());
--- a/src/share/vm/oops/objArrayKlass.hpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/oops/objArrayKlass.hpp Wed Jan 07 12:20:45 2015 -0800 @@ -68,7 +68,7 @@ // Compute protection domain oop protection_domain() { return Klass::cast(bottom_klass())->protection_domain(); } // Compute class loader - oop class_loader() const { return Klass::cast(bottom_klass())->class_loader(); } + oop class_loader() const; private: // Either oop or narrowOop depending on UseCompressedOops.
--- a/src/share/vm/opto/c2_globals.hpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/opto/c2_globals.hpp Wed Jan 07 12:20:45 2015 -0800 @@ -448,6 +448,9 @@ product(bool, DoEscapeAnalysis, true, \ "Perform escape analysis") \ \ + product(double, EscapeAnalysisTimeout, 20. DEBUG_ONLY(+40.), \ + "Abort EA when it reaches time limit (in sec)") \ + \ develop(bool, ExitEscapeAnalysisOnTimeout, true, \ "Exit or throw assert in EA when it reaches time limit") \ \
--- a/src/share/vm/opto/connode.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/opto/connode.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -439,6 +439,102 @@ return this; } +uint CastIINode::size_of() const { + return sizeof(*this); +} + +uint CastIINode::cmp(const Node &n) const { + return TypeNode::cmp(n) && ((CastIINode&)n)._carry_dependency == _carry_dependency; +} + +Node *CastIINode::Identity(PhaseTransform *phase) { + if (_carry_dependency) { + return this; + } + return ConstraintCastNode::Identity(phase); +} + +const Type *CastIINode::Value(PhaseTransform *phase) const { + const Type *res = ConstraintCastNode::Value(phase); + + // Try to improve the type of the CastII if we recognize a CmpI/If + // pattern. + if (_carry_dependency) { + if (in(0) != NULL && in(0)->in(0) != NULL && in(0)->in(0)->is_If()) { + assert(in(0)->is_IfFalse() || in(0)->is_IfTrue(), "should be If proj"); + Node* proj = in(0); + if (proj->in(0)->in(1)->is_Bool()) { + Node* b = proj->in(0)->in(1); + if (b->in(1)->Opcode() == Op_CmpI) { + Node* cmp = b->in(1); + if (cmp->in(1) == in(1) && phase->type(cmp->in(2))->isa_int()) { + const TypeInt* in2_t = phase->type(cmp->in(2))->is_int(); + const Type* t = TypeInt::INT; + BoolTest test = b->as_Bool()->_test; + if (proj->is_IfFalse()) { + test = test.negate(); + } + BoolTest::mask m = test._test; + jlong lo_long = min_jint; + jlong hi_long = max_jint; + if (m == BoolTest::le || m == BoolTest::lt) { + hi_long = in2_t->_hi; + if (m == BoolTest::lt) { + hi_long -= 1; + } + } else if (m == BoolTest::ge || m == BoolTest::gt) { + lo_long = in2_t->_lo; + if (m == BoolTest::gt) { + lo_long += 1; + } + } else if (m == BoolTest::eq) { + lo_long = in2_t->_lo; + hi_long = in2_t->_hi; + } else if (m == BoolTest::ne) { + // can't do any better + } else { + stringStream ss; + test.dump_on(&ss); + fatal(err_msg_res("unexpected comparison %s", ss.as_string())); + } + int lo_int = (int)lo_long; + int hi_int = (int)hi_long; + + if (lo_long != (jlong)lo_int) { + lo_int = min_jint; + } + if (hi_long != (jlong)hi_int) { + hi_int = max_jint; + } + + t = TypeInt::make(lo_int, hi_int, Type::WidenMax); + + res = res->filter(t); + + return res; + } + } + } + } + } + return res; +} + +Node *CastIINode::Ideal_DU_postCCP(PhaseCCP *ccp) { + if (_carry_dependency) { + return NULL; + } + return ConstraintCastNode::Ideal_DU_postCCP(ccp); +} + +#ifndef PRODUCT +void CastIINode::dump_spec(outputStream *st) const { + TypeNode::dump_spec(st); + if (_carry_dependency) { + st->print(" carry dependency"); + } +} +#endif //=============================================================================
--- a/src/share/vm/opto/connode.hpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/opto/connode.hpp Wed Jan 07 12:20:45 2015 -0800 @@ -233,10 +233,25 @@ //------------------------------CastIINode------------------------------------- // cast integer to integer (different range) class CastIINode: public ConstraintCastNode { + private: + // Can this node be removed post CCP or does it carry a required dependency? + const bool _carry_dependency; + + protected: + virtual uint cmp( const Node &n ) const; + virtual uint size_of() const; + public: - CastIINode (Node *n, const Type *t ): ConstraintCastNode(n,t) {} + CastIINode(Node *n, const Type *t, bool carry_dependency = false) + : ConstraintCastNode(n,t), _carry_dependency(carry_dependency) {} virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegI; } + virtual Node *Identity( PhaseTransform *phase ); + virtual const Type *Value( PhaseTransform *phase ) const; + virtual Node *Ideal_DU_postCCP( PhaseCCP * ); +#ifndef PRODUCT + virtual void dump_spec(outputStream *st) const; +#endif }; //------------------------------CastPPNode-------------------------------------
--- a/src/share/vm/opto/doCall.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/opto/doCall.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -735,10 +735,16 @@ // each arm of the Phi. If I know something clever about the exceptions // I'm loading the class from, I can replace the LoadKlass with the // klass constant for the exception oop. - if( ex_node->is_Phi() ) { - ex_klass_node = new (C) PhiNode( ex_node->in(0), TypeKlassPtr::OBJECT ); - for( uint i = 1; i < ex_node->req(); i++ ) { - Node* p = basic_plus_adr( ex_node->in(i), ex_node->in(i), oopDesc::klass_offset_in_bytes() ); + if (ex_node->is_Phi()) { + ex_klass_node = new (C) PhiNode(ex_node->in(0), TypeKlassPtr::OBJECT); + for (uint i = 1; i < ex_node->req(); i++) { + Node* ex_in = ex_node->in(i); + if (ex_in == top() || ex_in == NULL) { + // This path was not taken. + ex_klass_node->init_req(i, top()); + continue; + } + Node* p = basic_plus_adr(ex_in, ex_in, oopDesc::klass_offset_in_bytes()); Node* k = _gvn.transform( LoadKlassNode::make(_gvn, immutable_memory(), p, TypeInstPtr::KLASS, TypeKlassPtr::OBJECT) ); ex_klass_node->init_req( i, k ); }
--- a/src/share/vm/opto/escape.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/opto/escape.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -37,6 +37,8 @@ ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) : _nodes(C->comp_arena(), C->unique(), C->unique(), NULL), + _in_worklist(C->comp_arena()), + _next_pidx(0), _collecting(true), _verify(false), _compile(C), @@ -120,13 +122,19 @@ if (C->root() != NULL) { ideal_nodes.push(C->root()); } + // Processed ideal nodes are unique on ideal_nodes list + // but several ideal nodes are mapped to the phantom_obj. + // To avoid duplicated entries on the following worklists + // add the phantom_obj only once to them. + ptnodes_worklist.append(phantom_obj); + java_objects_worklist.append(phantom_obj); for( uint next = 0; next < ideal_nodes.size(); ++next ) { Node* n = ideal_nodes.at(next); // Create PointsTo nodes and add them to Connection Graph. Called // only once per ideal node since ideal_nodes is Unique_Node list. add_node_to_connection_graph(n, &delayed_worklist); PointsToNode* ptn = ptnode_adr(n->_idx); - if (ptn != NULL) { + if (ptn != NULL && ptn != phantom_obj) { ptnodes_worklist.append(ptn); if (ptn->is_JavaObject()) { java_objects_worklist.append(ptn->as_JavaObject()); @@ -395,7 +403,7 @@ } case Op_CreateEx: { // assume that all exception objects globally escape - add_java_object(n, PointsToNode::GlobalEscape); + map_ideal_node(n, phantom_obj); break; } case Op_LoadKlass: @@ -1016,13 +1024,8 @@ // on graph complexity. Observed 8 passes in jvm2008 compiler.compiler. // Set limit to 20 to catch situation when something did go wrong and // bailout Escape Analysis. - // Also limit build time to 30 sec (60 in debug VM). + // Also limit build time to 20 sec (60 in debug VM), EscapeAnalysisTimeout flag. #define CG_BUILD_ITER_LIMIT 20 -#ifdef ASSERT -#define CG_BUILD_TIME_LIMIT 60.0 -#else -#define CG_BUILD_TIME_LIMIT 30.0 -#endif // Propagate GlobalEscape and ArgEscape escape states and check that // we still have non-escaping objects. The method pushs on _worklist @@ -1033,12 +1036,13 @@ // Now propagate references to all JavaObject nodes. int java_objects_length = java_objects_worklist.length(); elapsedTimer time; + bool timeout = false; int new_edges = 1; int iterations = 0; do { while ((new_edges > 0) && - (iterations++ < CG_BUILD_ITER_LIMIT) && - (time.seconds() < CG_BUILD_TIME_LIMIT)) { + (iterations++ < CG_BUILD_ITER_LIMIT)) { + double start_time = time.seconds(); time.start(); new_edges = 0; // Propagate references to phantom_object for nodes pushed on _worklist @@ -1047,7 +1051,26 @@ for (int next = 0; next < java_objects_length; ++next) { JavaObjectNode* ptn = java_objects_worklist.at(next); new_edges += add_java_object_edges(ptn, true); + +#define SAMPLE_SIZE 4 + if ((next % SAMPLE_SIZE) == 0) { + // Each 4 iterations calculate how much time it will take + // to complete graph construction. + time.stop(); + double stop_time = time.seconds(); + double time_per_iter = (stop_time - start_time) / (double)SAMPLE_SIZE; + double time_until_end = time_per_iter * (double)(java_objects_length - next); + if ((start_time + time_until_end) >= EscapeAnalysisTimeout) { + timeout = true; + break; // Timeout + } + start_time = stop_time; + time.start(); + } +#undef SAMPLE_SIZE + } + if (timeout) break; if (new_edges > 0) { // Update escape states on each iteration if graph was updated. if (!find_non_escaped_objects(ptnodes_worklist, non_escaped_worklist)) { @@ -1055,9 +1078,12 @@ } } time.stop(); + if (time.seconds() >= EscapeAnalysisTimeout) { + timeout = true; + break; + } } - if ((iterations < CG_BUILD_ITER_LIMIT) && - (time.seconds() < CG_BUILD_TIME_LIMIT)) { + if ((iterations < CG_BUILD_ITER_LIMIT) && !timeout) { time.start(); // Find fields which have unknown value. int fields_length = oop_fields_worklist.length(); @@ -1070,18 +1096,21 @@ } } time.stop(); + if (time.seconds() >= EscapeAnalysisTimeout) { + timeout = true; + break; + } } else { new_edges = 0; // Bailout } } while (new_edges > 0); // Bailout if passed limits. - if ((iterations >= CG_BUILD_ITER_LIMIT) || - (time.seconds() >= CG_BUILD_TIME_LIMIT)) { + if ((iterations >= CG_BUILD_ITER_LIMIT) || timeout) { Compile* C = _compile; if (C->log() != NULL) { C->log()->begin_elem("connectionGraph_bailout reason='reached "); - C->log()->text("%s", (iterations >= CG_BUILD_ITER_LIMIT) ? "iterations" : "time"); + C->log()->text("%s", timeout ? "time" : "iterations"); C->log()->end_elem(" limit'"); } assert(ExitEscapeAnalysisOnTimeout, err_msg_res("infinite EA connection graph build (%f sec, %d iterations) with %d nodes and worklist size %d", @@ -1098,7 +1127,6 @@ #endif #undef CG_BUILD_ITER_LIMIT -#undef CG_BUILD_TIME_LIMIT // Find fields initialized by NULL for non-escaping Allocations. int non_escaped_length = non_escaped_worklist.length(); @@ -1222,8 +1250,8 @@ } } } - while(_worklist.length() > 0) { - PointsToNode* use = _worklist.pop(); + for (int l = 0; l < _worklist.length(); l++) { + PointsToNode* use = _worklist.at(l); if (PointsToNode::is_base_use(use)) { // Add reference from jobj to field and from field to jobj (field's base). use = PointsToNode::get_use_node(use)->as_Field(); @@ -1270,6 +1298,8 @@ add_field_uses_to_worklist(use->as_Field()); } } + _worklist.clear(); + _in_worklist.Reset(); return new_edges; } @@ -1838,7 +1868,7 @@ return; } Compile* C = _compile; - ptadr = new (C->comp_arena()) LocalVarNode(C, n, es); + ptadr = new (C->comp_arena()) LocalVarNode(this, n, es); _nodes.at_put(n->_idx, ptadr); } @@ -1849,7 +1879,7 @@ return; } Compile* C = _compile; - ptadr = new (C->comp_arena()) JavaObjectNode(C, n, es); + ptadr = new (C->comp_arena()) JavaObjectNode(this, n, es); _nodes.at_put(n->_idx, ptadr); } @@ -1865,7 +1895,7 @@ es = PointsToNode::GlobalEscape; } Compile* C = _compile; - FieldNode* field = new (C->comp_arena()) FieldNode(C, n, es, offset, is_oop); + FieldNode* field = new (C->comp_arena()) FieldNode(this, n, es, offset, is_oop); _nodes.at_put(n->_idx, field); } @@ -1879,7 +1909,7 @@ return; } Compile* C = _compile; - ptadr = new (C->comp_arena()) ArraycopyNode(C, n, es); + ptadr = new (C->comp_arena()) ArraycopyNode(this, n, es); _nodes.at_put(n->_idx, ptadr); // Add edge from arraycopy node to source object. (void)add_edge(ptadr, src);
--- a/src/share/vm/opto/escape.hpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/opto/escape.hpp Wed Jan 07 12:20:45 2015 -0800 @@ -125,6 +125,8 @@ class FieldNode; class ArraycopyNode; +class ConnectionGraph; + // ConnectionGraph nodes class PointsToNode : public ResourceObj { GrowableArray<PointsToNode*> _edges; // List of nodes this node points to @@ -137,6 +139,7 @@ Node* const _node; // Ideal node corresponding to this PointsTo node. const int _idx; // Cached ideal node's _idx + const uint _pidx; // Index of this node public: typedef enum { @@ -165,17 +168,9 @@ } NodeFlags; - PointsToNode(Compile *C, Node* n, EscapeState es, NodeType type): - _edges(C->comp_arena(), 2, 0, NULL), - _uses (C->comp_arena(), 2, 0, NULL), - _node(n), - _idx(n->_idx), - _type((u1)type), - _escape((u1)es), - _fields_escape((u1)es), - _flags(ScalarReplaceable) { - assert(n != NULL && es != UnknownEscape, "sanity"); - } + inline PointsToNode(ConnectionGraph* CG, Node* n, EscapeState es, NodeType type); + + uint pidx() const { return _pidx; } Node* ideal_node() const { return _node; } int idx() const { return _idx; } @@ -243,14 +238,14 @@ class LocalVarNode: public PointsToNode { public: - LocalVarNode(Compile *C, Node* n, EscapeState es): - PointsToNode(C, n, es, LocalVar) {} + LocalVarNode(ConnectionGraph *CG, Node* n, EscapeState es): + PointsToNode(CG, n, es, LocalVar) {} }; class JavaObjectNode: public PointsToNode { public: - JavaObjectNode(Compile *C, Node* n, EscapeState es): - PointsToNode(C, n, es, JavaObject) { + JavaObjectNode(ConnectionGraph *CG, Node* n, EscapeState es): + PointsToNode(CG, n, es, JavaObject) { if (es > NoEscape) set_scalar_replaceable(false); } @@ -262,8 +257,8 @@ const bool _is_oop; // Field points to object bool _has_unknown_base; // Has phantom_object base public: - FieldNode(Compile *C, Node* n, EscapeState es, int offs, bool is_oop): - PointsToNode(C, n, es, Field), + FieldNode(ConnectionGraph *CG, Node* n, EscapeState es, int offs, bool is_oop): + PointsToNode(CG, n, es, Field), _offset(offs), _is_oop(is_oop), _has_unknown_base(false) {} @@ -284,8 +279,8 @@ class ArraycopyNode: public PointsToNode { public: - ArraycopyNode(Compile *C, Node* n, EscapeState es): - PointsToNode(C, n, es, Arraycopy) {} + ArraycopyNode(ConnectionGraph *CG, Node* n, EscapeState es): + PointsToNode(CG, n, es, Arraycopy) {} }; // Iterators for PointsTo node's edges: @@ -323,11 +318,14 @@ class ConnectionGraph: public ResourceObj { + friend class PointsToNode; private: GrowableArray<PointsToNode*> _nodes; // Map from ideal nodes to // ConnectionGraph nodes. GrowableArray<PointsToNode*> _worklist; // Nodes to be processed + VectorSet _in_worklist; + uint _next_pidx; bool _collecting; // Indicates whether escape information // is still being collected. If false, @@ -353,6 +351,8 @@ } uint nodes_size() const { return _nodes.length(); } + uint next_pidx() { return _next_pidx++; } + // Add nodes to ConnectionGraph. void add_local_var(Node* n, PointsToNode::EscapeState es); void add_java_object(Node* n, PointsToNode::EscapeState es); @@ -396,15 +396,26 @@ int add_java_object_edges(JavaObjectNode* jobj, bool populate_worklist); // Put node on worklist if it is (or was) not there. - void add_to_worklist(PointsToNode* pt) { - _worklist.push(pt); - return; + inline void add_to_worklist(PointsToNode* pt) { + PointsToNode* ptf = pt; + uint pidx_bias = 0; + if (PointsToNode::is_base_use(pt)) { + // Create a separate entry in _in_worklist for a marked base edge + // because _worklist may have an entry for a normal edge pointing + // to the same node. To separate them use _next_pidx as bias. + ptf = PointsToNode::get_use_node(pt)->as_Field(); + pidx_bias = _next_pidx; + } + if (!_in_worklist.test_set(ptf->pidx() + pidx_bias)) { + _worklist.append(pt); + } } // Put on worklist all uses of this node. - void add_uses_to_worklist(PointsToNode* pt) { - for (UseIterator i(pt); i.has_next(); i.next()) - _worklist.push(i.get()); + inline void add_uses_to_worklist(PointsToNode* pt) { + for (UseIterator i(pt); i.has_next(); i.next()) { + add_to_worklist(i.get()); + } } // Put on worklist all field's uses and related field nodes. @@ -517,8 +528,8 @@ } // Helper functions bool is_oop_field(Node* n, int offset, bool* unsafe); - static Node* get_addp_base(Node *addp); - static Node* find_second_addp(Node* addp, Node* n); + static Node* get_addp_base(Node *addp); + static Node* find_second_addp(Node* addp, Node* n); // offset of a field reference int address_offset(Node* adr, PhaseTransform *phase); @@ -587,4 +598,17 @@ #endif }; +inline PointsToNode::PointsToNode(ConnectionGraph *CG, Node* n, EscapeState es, NodeType type): + _edges(CG->_compile->comp_arena(), 2, 0, NULL), + _uses (CG->_compile->comp_arena(), 2, 0, NULL), + _node(n), + _idx(n->_idx), + _pidx(CG->next_pidx()), + _type((u1)type), + _escape((u1)es), + _fields_escape((u1)es), + _flags(ScalarReplaceable) { + assert(n != NULL && es != UnknownEscape, "sanity"); +} + #endif // SHARE_VM_OPTO_ESCAPE_HPP
--- a/src/share/vm/opto/ifg.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/opto/ifg.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -571,15 +571,35 @@ if( !n->is_Proj() || // Could also be a flags-projection of a dead ADD or such. (n2lidx(def) && !liveout.member(n2lidx(def)) ) ) { - b->_nodes.remove(j - 1); - if( lrgs(r)._def == n ) lrgs(r)._def = 0; - n->disconnect_inputs(NULL, C); - _cfg._bbs.map(n->_idx,NULL); - n->replace_by(C->top()); - // Since yanking a Node from block, high pressure moves up one - hrp_index[0]--; - hrp_index[1]--; - continue; + bool remove = true; + if (n->is_MachProj()) { + // Don't remove KILL projections if their "defining" nodes have + // memory effects (have SCMemProj projection node) - + // they are not dead even when their result is not used. + // For example, compareAndSwapL (and other CAS) and EncodeISOArray nodes. + // The method add_input_to_liveout() keeps such nodes alive (put them on liveout list) + // when it sees SCMemProj node in a block. Unfortunately SCMemProj node could be placed + // in block in such order that KILL MachProj nodes are processed first. + uint cnt = def->outcnt(); + for (uint i = 0; i < cnt; i++) { + Node* proj = def->raw_out(i); + if (proj->Opcode() == Op_SCMemProj) { + remove = false; + break; + } + } + } + if (remove) { + b->_nodes.remove(j - 1); + if( lrgs(r)._def == n ) lrgs(r)._def = 0; + n->disconnect_inputs(NULL, C); + _cfg._bbs.map(n->_idx,NULL); + n->replace_by(C->top()); + // Since yanking a Node from block, high pressure moves up one + hrp_index[0]--; + hrp_index[1]--; + continue; + } } // Fat-projections kill many registers which cannot be used to
--- a/src/share/vm/opto/loopTransform.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/opto/loopTransform.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -863,6 +863,20 @@ return n; } +bool PhaseIdealLoop::cast_incr_before_loop(Node* incr, Node* ctrl, Node* loop) { + Node* castii = new (C) CastIINode(incr, TypeInt::INT, true); + castii->set_req(0, ctrl); + register_new_node(castii, ctrl); + for (DUIterator_Fast imax, i = incr->fast_outs(imax); i < imax; i++) { + Node* n = incr->fast_out(i); + if (n->is_Phi() && n->in(0) == loop) { + int nrep = n->replace_edge(incr, castii); + return true; + } + } + return false; +} + //------------------------------insert_pre_post_loops-------------------------- // Insert pre and post loops. If peel_only is set, the pre-loop can not have // more iterations added. It acts as a 'peel' only, no lower-bound RCE, no @@ -1060,6 +1074,24 @@ } } + // Nodes inside the loop may be control dependent on a predicate + // that was moved before the preloop. If the back branch of the main + // or post loops becomes dead, those nodes won't be dependent on the + // test that guards that loop nest anymore which could lead to an + // incorrect array access because it executes independently of the + // test that was guarding the loop nest. We add a special CastII on + // the if branch that enters the loop, between the input induction + // variable value and the induction variable Phi to preserve correct + // dependencies. + + // CastII for the post loop: + bool inserted = cast_incr_before_loop(zer_opaq->in(1), zer_taken, post_head); + assert(inserted, "no castII inserted"); + + // CastII for the main loop: + inserted = cast_incr_before_loop(pre_incr, min_taken, main_head); + assert(inserted, "no castII inserted"); + // Step B4: Shorten the pre-loop to run only 1 iteration (for now). // RCE and alignment may change this later. Node *cmp_end = pre_end->cmp_node();
--- a/src/share/vm/opto/loopnode.hpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/opto/loopnode.hpp Wed Jan 07 12:20:45 2015 -0800 @@ -602,6 +602,8 @@ return ctrl; } + bool cast_incr_before_loop(Node* incr, Node* ctrl, Node* loop); + public: bool has_node( Node* n ) const { return _nodes[n->_idx] != NULL; } // check if transform created new nodes that need _ctrl recorded
--- a/src/share/vm/opto/loopopts.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/opto/loopopts.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -1393,7 +1393,8 @@ // loop. Happens if people set a loop-exit flag; then test the flag // in the loop to break the loop, then test is again outside of the // loop to determine which way the loop exited. - if( use->is_If() || use->is_CMove() ) { + // Loop predicate If node connects to Bool node through Opaque1 node. + if (use->is_If() || use->is_CMove() || C->is_predicate_opaq(use)) { // Since this code is highly unlikely, we lazily build the worklist // of such Nodes to go split. if( !split_if_set )
--- a/src/share/vm/opto/parse.hpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/opto/parse.hpp Wed Jan 07 12:20:45 2015 -0800 @@ -528,8 +528,9 @@ float dynamic_branch_prediction(float &cnt); float branch_prediction(float &cnt, BoolTest::mask btest, int target_bci); - bool seems_never_taken(float prob); - bool seems_stable_comparison(BoolTest::mask btest, Node* c); + bool seems_never_taken(float prob) const; + bool path_is_suitable_for_uncommon_trap(float prob) const; + bool seems_stable_comparison() const; void do_ifnull(BoolTest::mask btest, Node* c); void do_if(BoolTest::mask btest, Node* c);
--- a/src/share/vm/opto/parse2.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/opto/parse2.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -884,7 +884,7 @@ // some branches (e.g., _213_javac.Assembler.eliminate) validly produce // very small but nonzero probabilities, which if confused with zero // counts would keep the program recompiling indefinitely. -bool Parse::seems_never_taken(float prob) { +bool Parse::seems_never_taken(float prob) const { return prob < PROB_MIN; } @@ -895,53 +895,12 @@ // if a path is never taken, its controlling comparison is // already acting in a stable fashion. If the comparison // seems stable, we will put an expensive uncommon trap -// on the untaken path. To be conservative, and to allow -// partially executed counted loops to be compiled fully, -// we will plant uncommon traps only after pointer comparisons. -bool Parse::seems_stable_comparison(BoolTest::mask btest, Node* cmp) { - for (int depth = 4; depth > 0; depth--) { - // The following switch can find CmpP here over half the time for - // dynamic language code rich with type tests. - // Code using counted loops or array manipulations (typical - // of benchmarks) will have many (>80%) CmpI instructions. - switch (cmp->Opcode()) { - case Op_CmpP: - // A never-taken null check looks like CmpP/BoolTest::eq. - // These certainly should be closed off as uncommon traps. - if (btest == BoolTest::eq) - return true; - // A never-failed type check looks like CmpP/BoolTest::ne. - // Let's put traps on those, too, so that we don't have to compile - // unused paths with indeterminate dynamic type information. - if (ProfileDynamicTypes) - return true; - return false; - - case Op_CmpI: - // A small minority (< 10%) of CmpP are masked as CmpI, - // as if by boolean conversion ((p == q? 1: 0) != 0). - // Detect that here, even if it hasn't optimized away yet. - // Specifically, this covers the 'instanceof' operator. - if (btest == BoolTest::ne || btest == BoolTest::eq) { - if (_gvn.type(cmp->in(2))->singleton() && - cmp->in(1)->is_Phi()) { - PhiNode* phi = cmp->in(1)->as_Phi(); - int true_path = phi->is_diamond_phi(); - if (true_path > 0 && - _gvn.type(phi->in(1))->singleton() && - _gvn.type(phi->in(2))->singleton()) { - // phi->region->if_proj->ifnode->bool->cmp - BoolNode* bol = phi->in(0)->in(1)->in(0)->in(1)->as_Bool(); - btest = bol->_test._test; - cmp = bol->in(1); - continue; - } - } - } - return false; - } +// on the untaken path. +bool Parse::seems_stable_comparison() const { + if (C->too_many_traps(method(), bci(), Deoptimization::Reason_unstable_if)) { + return false; } - return false; + return true; } //-------------------------------repush_if_args-------------------------------- @@ -1166,6 +1125,14 @@ } } +bool Parse::path_is_suitable_for_uncommon_trap(float prob) const { + // Don't want to speculate on uncommon traps when running with -Xcomp + if (!UseInterpreter) { + return false; + } + return (seems_never_taken(prob) && seems_stable_comparison()); +} + //----------------------------adjust_map_after_if------------------------------ // Adjust the JVM state to reflect the result of taking this path. // Basically, it means inspecting the CmpNode controlling this @@ -1179,33 +1146,9 @@ bool is_fallthrough = (path == successor_for_bci(iter().next_bci())); - if (seems_never_taken(prob) && seems_stable_comparison(btest, c)) { - // If this might possibly turn into an implicit null check, - // and the null has never yet been seen, we need to generate - // an uncommon trap, so as to recompile instead of suffering - // with very slow branches. (We'll get the slow branches if - // the program ever changes phase and starts seeing nulls here.) - // - // We do not inspect for a null constant, since a node may - // optimize to 'null' later on. - // - // Null checks, and other tests which expect inequality, - // show btest == BoolTest::eq along the non-taken branch. - // On the other hand, type tests, must-be-null tests, - // and other tests which expect pointer equality, - // show btest == BoolTest::ne along the non-taken branch. - // We prune both types of branches if they look unused. + if (path_is_suitable_for_uncommon_trap(prob)) { repush_if_args(); - // We need to mark this branch as taken so that if we recompile we will - // see that it is possible. In the tiered system the interpreter doesn't - // do profiling and by the time we get to the lower tier from the interpreter - // the path may be cold again. Make sure it doesn't look untaken - if (is_fallthrough) { - profile_not_taken_branch(!ProfileInterpreter); - } else { - profile_taken_branch(iter().get_dest(), !ProfileInterpreter); - } - uncommon_trap(Deoptimization::Reason_unreached, + uncommon_trap(Deoptimization::Reason_unstable_if, Deoptimization::Action_reinterpret, NULL, (is_fallthrough ? "taken always" : "taken never"));
--- a/src/share/vm/opto/phaseX.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/opto/phaseX.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -1323,15 +1323,27 @@ } } - if( use->is_Cmp() ) { // Enable CMP/BOOL optimization + uint use_op = use->Opcode(); + if(use->is_Cmp()) { // Enable CMP/BOOL optimization add_users_to_worklist(use); // Put Bool on worklist - // Look for the 'is_x2logic' pattern: "x ? : 0 : 1" and put the - // phi merging either 0 or 1 onto the worklist if (use->outcnt() > 0) { Node* bol = use->raw_out(0); if (bol->outcnt() > 0) { Node* iff = bol->raw_out(0); - if (iff->outcnt() == 2) { + if (use_op == Op_CmpI && + iff->is_CountedLoopEnd()) { + CountedLoopEndNode* cle = iff->as_CountedLoopEnd(); + if (cle->limit() == n && cle->phi() != NULL) { + // If an opaque node feeds into the limit condition of a + // CountedLoop, we need to process the Phi node for the + // induction variable when the opaque node is removed: + // the range of values taken by the Phi is now known and + // so its type is also known. + _worklist.push(cle->phi()); + } + } else if (iff->outcnt() == 2) { + // Look for the 'is_x2logic' pattern: "x ? : 0 : 1" and put the + // phi merging either 0 or 1 onto the worklist Node* ifproj0 = iff->raw_out(0); Node* ifproj1 = iff->raw_out(1); if (ifproj0->outcnt() > 0 && ifproj1->outcnt() > 0) { @@ -1343,9 +1355,26 @@ } } } + if (use_op == Op_CmpI) { + Node* in1 = use->in(1); + for (uint i = 0; i < in1->outcnt(); i++) { + if (in1->raw_out(i)->Opcode() == Op_CastII) { + Node* castii = in1->raw_out(i); + if (castii->in(0) != NULL && castii->in(0)->in(0) != NULL && castii->in(0)->in(0)->is_If()) { + Node* ifnode = castii->in(0)->in(0); + if (ifnode->in(1) != NULL && ifnode->in(1)->is_Bool() && ifnode->in(1)->in(1) == use) { + // Reprocess a CastII node that may depend on an + // opaque node value when the opaque node is + // removed. In case it carries a dependency we can do + // a better job of computing its type. + _worklist.push(castii); + } + } + } + } + } } - uint use_op = use->Opcode(); // If changed Cast input, check Phi users for simple cycles if( use->is_ConstraintCast() || use->is_CheckCastPP() ) { for (DUIterator_Fast i2max, i2 = use->fast_outs(i2max); i2 < i2max; i2++) {
--- a/src/share/vm/opto/subnode.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/opto/subnode.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -1066,12 +1066,10 @@ //------------------------------dump_spec------------------------------------- // Print special per-node info -#ifndef PRODUCT void BoolTest::dump_on(outputStream *st) const { const char *msg[] = {"eq","gt","??","lt","ne","le","??","ge"}; st->print(msg[_test]); } -#endif //============================================================================= uint BoolNode::hash() const { return (Node::hash() << 3)|(_test._test+1); }
--- a/src/share/vm/opto/subnode.hpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/opto/subnode.hpp Wed Jan 07 12:20:45 2015 -0800 @@ -273,9 +273,7 @@ mask commute( ) const { return mask("038147858"[_test]-'0'); } mask negate( ) const { return mask(_test^4); } bool is_canonical( ) const { return (_test == BoolTest::ne || _test == BoolTest::lt || _test == BoolTest::le); } -#ifndef PRODUCT void dump_on(outputStream *st) const; -#endif }; //------------------------------BoolNode---------------------------------------
--- a/src/share/vm/prims/jvm.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/prims/jvm.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -4611,7 +4611,7 @@ JVM_ENTRY(void, JVM_GetVersionInfo(JNIEnv* env, jvm_version_info* info, size_t info_size)) { - memset(info, 0, sizeof(info_size)); + memset(info, 0, info_size); info->jvm_version = Abstract_VM_Version::jvm_version(); info->update_version = 0; /* 0 in HotSpot Express VM */
--- a/src/share/vm/runtime/arguments.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/runtime/arguments.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -266,6 +266,7 @@ { "Tier1MaxInlineSize", JDK_Version::jdk_update(7,40), JDK_Version::jdk(8) }, { "Tier1LoopOptsCount", JDK_Version::jdk_update(7,40), JDK_Version::jdk(8) }, { "UseSpinning", JDK_Version::jdk_update(7,40), JDK_Version::jdk(8) }, + { "CompilationRepeat", JDK_Version::jdk_update(7,80), JDK_Version::jdk(9) }, #ifdef PRODUCT { "DesiredMethodLimit", JDK_Version::jdk_update(7, 2), JDK_Version::jdk(8) }, @@ -2485,6 +2486,23 @@ #endif // -D } else if (match_option(option, "-D", &tail)) { + if (CheckEndorsedAndExtDirs) { + if (match_option(option, "-Djava.endorsed.dirs=", &tail)) { + // abort if -Djava.endorsed.dirs is set + jio_fprintf(defaultStream::output_stream(), + "-Djava.endorsed.dirs will not be supported in a future release.\n" + "Refer to JEP 220 for details (http://openjdk.java.net/jeps/220).\n"); + return JNI_EINVAL; + } + if (match_option(option, "-Djava.ext.dirs=", &tail)) { + // abort if -Djava.ext.dirs is set + jio_fprintf(defaultStream::output_stream(), + "-Djava.ext.dirs will not be supported in a future release.\n" + "Refer to JEP 220 for details (http://openjdk.java.net/jeps/220).\n"); + return JNI_EINVAL; + } + } + if (!add_property(tail)) { return JNI_ENOMEM; } @@ -2874,6 +2892,146 @@ return JNI_OK; } +static bool has_jar_files(const char* directory) { + DIR* dir = os::opendir(directory); + if (dir == NULL) return false; + + struct dirent *entry; + char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(directory), mtInternal); + bool hasJarFile = false; + while (!hasJarFile && (entry = os::readdir(dir, (dirent *) dbuf)) != NULL) { + const char* name = entry->d_name; + const char* ext = name + strlen(name) - 4; + hasJarFile = ext > name && (os::file_name_strcmp(ext, ".jar") == 0); + } + FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); + os::closedir(dir); + return hasJarFile ; +} + +// returns the number of directories in the given path containing JAR files +// If the skip argument is not NULL, it will skip that directory +static int check_non_empty_dirs(const char* path, const char* type, const char* skip) { + const char separator = *os::path_separator(); + const char* const end = path + strlen(path); + int nonEmptyDirs = 0; + while (path < end) { + const char* tmp_end = strchr(path, separator); + if (tmp_end == NULL) { + if ((skip == NULL || strcmp(path, skip) != 0) && has_jar_files(path)) { + nonEmptyDirs++; + jio_fprintf(defaultStream::output_stream(), + "Non-empty %s directory: %s\n", type, path); + } + path = end; + } else { + char* dirpath = NEW_C_HEAP_ARRAY(char, tmp_end - path + 1, mtInternal); + memcpy(dirpath, path, tmp_end - path); + dirpath[tmp_end - path] = '\0'; + if ((skip == NULL || strcmp(dirpath, skip) != 0) && has_jar_files(dirpath)) { + nonEmptyDirs++; + jio_fprintf(defaultStream::output_stream(), + "Non-empty %s directory: %s\n", type, dirpath); + } + FREE_C_HEAP_ARRAY(char, dirpath, mtInternal); + path = tmp_end + 1; + } + } + return nonEmptyDirs; +} + +// Returns true if endorsed standards override mechanism and extension mechanism +// are not used. +static bool check_endorsed_and_ext_dirs() { + if (!CheckEndorsedAndExtDirs) + return true; + + char endorsedDir[JVM_MAXPATHLEN]; + char extDir[JVM_MAXPATHLEN]; + const char* fileSep = os::file_separator(); + jio_snprintf(endorsedDir, sizeof(endorsedDir), "%s%slib%sendorsed", + Arguments::get_java_home(), fileSep, fileSep); + jio_snprintf(extDir, sizeof(extDir), "%s%slib%sext", + Arguments::get_java_home(), fileSep, fileSep); + + // check endorsed directory + int nonEmptyDirs = check_non_empty_dirs(Arguments::get_endorsed_dir(), "endorsed", NULL); + + // check the extension directories but skip the default lib/ext directory + nonEmptyDirs += check_non_empty_dirs(Arguments::get_ext_dirs(), "extension", extDir); + + // List of JAR files installed in the default lib/ext directory. + // -XX:+CheckEndorsedAndExtDirs checks if any non-JDK file installed + static const char* jdk_ext_jars[] = { + "access-bridge-32.jar", + "access-bridge-64.jar", + "access-bridge.jar", + "cldrdata.jar", + "dnsns.jar", + "jaccess.jar", + "jfxrt.jar", + "localedata.jar", + "nashorn.jar", + "sunec.jar", + "sunjce_provider.jar", + "sunmscapi.jar", + "sunpkcs11.jar", + "ucrypto.jar", + "zipfs.jar", + NULL + }; + + // check if the default lib/ext directory has any non-JDK jar files; if so, error + DIR* dir = os::opendir(extDir); + if (dir != NULL) { + int num_ext_jars = 0; + struct dirent *entry; + char *dbuf = NEW_C_HEAP_ARRAY(char, os::readdir_buf_size(extDir), mtInternal); + while ((entry = os::readdir(dir, (dirent *) dbuf)) != NULL) { + const char* name = entry->d_name; + const char* ext = name + strlen(name) - 4; + if (ext > name && (os::file_name_strcmp(ext, ".jar") == 0)) { + bool is_jdk_jar = false; + const char* jarfile = NULL; + for (int i=0; (jarfile = jdk_ext_jars[i]) != NULL; i++) { + if (os::file_name_strcmp(name, jarfile) == 0) { + is_jdk_jar = true; + break; + } + } + if (!is_jdk_jar) { + jio_fprintf(defaultStream::output_stream(), + "%s installed in <JAVA_HOME>/lib/ext\n", name); + num_ext_jars++; + } + } + } + FREE_C_HEAP_ARRAY(char, dbuf, mtInternal); + os::closedir(dir); + if (num_ext_jars > 0) { + nonEmptyDirs += 1; + } + } + + // check if the default lib/endorsed directory exists; if so, error + dir = os::opendir(endorsedDir); + if (dir != NULL) { + jio_fprintf(defaultStream::output_stream(), "<JAVA_HOME>/lib/endorsed exists\n"); + os::closedir(dir); + nonEmptyDirs += 1; + } + + if (nonEmptyDirs > 0) { + jio_fprintf(defaultStream::output_stream(), + "Endorsed standards override mechanism and extension mechanism " + "will not be supported in a future release.\n" + "Refer to JEP 220 for details (http://openjdk.java.net/jeps/220).\n"); + return false; + } + + return true; +} + jint Arguments::finalize_vm_init_args(SysClassPath* scp_p, bool scp_assembly_required) { // This must be done after all -D arguments have been processed. scp_p->expand_endorsed(); @@ -2883,6 +3041,10 @@ Arguments::set_sysclasspath(scp_p->combined_path()); } + if (!check_endorsed_and_ext_dirs()) { + return JNI_ERR; + } + // This must be done after all arguments have been processed. // java_compiler() true means set to "NONE" or empty. if (java_compiler() && !xdebug_mode()) {
--- a/src/share/vm/runtime/arguments.hpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/runtime/arguments.hpp Wed Jan 07 12:20:45 2015 -0800 @@ -543,6 +543,7 @@ static char *get_sysclasspath() { return _sun_boot_class_path->value(); } static char* get_meta_index_path() { return _meta_index_path; } static char* get_meta_index_dir() { return _meta_index_dir; } + static char* get_ext_dirs() { return _java_ext_dirs->value(); } // Operation modi static Mode mode() { return _mode; }
--- a/src/share/vm/runtime/deoptimization.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/runtime/deoptimization.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -1796,7 +1796,8 @@ "div0_check", "age", "predicate", - "loop_limit_check" + "loop_limit_check", + "unstable_if" }; const char* Deoptimization::_trap_action_name[Action_LIMIT] = { // Note: Keep this in sync. with enum DeoptAction.
--- a/src/share/vm/runtime/deoptimization.hpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/runtime/deoptimization.hpp Wed Jan 07 12:20:45 2015 -0800 @@ -59,6 +59,7 @@ Reason_age, // nmethod too old; tier threshold reached Reason_predicate, // compiler generated predicate failed Reason_loop_limit_check, // compiler generated loop limits check failed + Reason_unstable_if, // a branch predicted always false was taken Reason_LIMIT, // Note: Keep this enum in sync. with _trap_reason_name. Reason_RECORDED_LIMIT = Reason_bimorphic // some are not recorded per bc @@ -311,6 +312,8 @@ return reason; else if (reason == Reason_div0_check) // null check due to divide-by-zero? return Reason_null_check; // recorded per BCI as a null check + else if (reason == Reason_unstable_if) + return Reason_intrinsic; else return Reason_none; }
--- a/src/share/vm/runtime/globals.hpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/runtime/globals.hpp Wed Jan 07 12:20:45 2015 -0800 @@ -1154,6 +1154,9 @@ product(bool, CheckJNICalls, false, \ "Verify all arguments to JNI calls") \ \ + product(bool, CheckEndorsedAndExtDirs, false, \ + "Verify the endorsed and extension directories are not used") \ + \ product(bool, UseFastJNIAccessors, true, \ "Use optimized versions of Get<Primitive>Field") \ \
--- a/src/share/vm/runtime/vmStructs.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/runtime/vmStructs.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -2433,6 +2433,7 @@ declare_constant(Deoptimization::Reason_age) \ declare_constant(Deoptimization::Reason_predicate) \ declare_constant(Deoptimization::Reason_loop_limit_check) \ + declare_constant(Deoptimization::Reason_unstable_if) \ declare_constant(Deoptimization::Reason_LIMIT) \ declare_constant(Deoptimization::Reason_RECORDED_LIMIT) \ \
--- a/src/share/vm/services/runtimeService.cpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/services/runtimeService.cpp Wed Jan 07 12:20:45 2015 -0800 @@ -44,6 +44,7 @@ PerfCounter* RuntimeService::_thread_interrupt_signaled_count = NULL; PerfCounter* RuntimeService::_interrupted_before_count = NULL; PerfCounter* RuntimeService::_interrupted_during_count = NULL; +double RuntimeService::_last_safepoint_sync_time_sec = 0.0; void RuntimeService::init() { // Make sure the VM version is initialized @@ -123,6 +124,7 @@ // update the time stamp to begin recording safepoint time _safepoint_timer.update(); + _last_safepoint_sync_time_sec = 0.0; if (UsePerfData) { _total_safepoints->inc(); if (_app_timer.is_updated()) { @@ -135,6 +137,9 @@ if (UsePerfData) { _sync_time_ticks->inc(_safepoint_timer.ticks_since_update()); } + if (PrintGCApplicationStoppedTime) { + _last_safepoint_sync_time_sec = last_safepoint_time_sec(); + } } void RuntimeService::record_safepoint_end() { @@ -150,8 +155,10 @@ gclog_or_tty->date_stamp(PrintGCDateStamps); gclog_or_tty->stamp(PrintGCTimeStamps); gclog_or_tty->print_cr("Total time for which application threads " - "were stopped: %3.7f seconds", - last_safepoint_time_sec()); + "were stopped: %3.7f seconds, " + "Stopping threads took: %3.7f seconds", + last_safepoint_time_sec(), + _last_safepoint_sync_time_sec); } // update the time stamp to begin recording app time
--- a/src/share/vm/services/runtimeService.hpp Tue Dec 23 13:53:21 2014 -0800 +++ b/src/share/vm/services/runtimeService.hpp Wed Jan 07 12:20:45 2015 -0800 @@ -40,6 +40,7 @@ static TimeStamp _safepoint_timer; static TimeStamp _app_timer; + static double _last_safepoint_sync_time_sec; public: static void init();
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/exceptions/CatchInlineExceptions.java Wed Jan 07 12:20:45 2015 -0800 @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8059299 + * @summary assert(adr_type != NULL) failed: expecting TypeKlassPtr + * @run main/othervm -Xbatch CatchInlineExceptions + */ + +class Exception1 extends Exception {}; +class Exception2 extends Exception {}; + +public class CatchInlineExceptions { + private static int counter0; + private static int counter1; + private static int counter2; + private static int counter; + + static void foo(int i) throws Exception { + if ((i & 1023) == 2) { + counter0++; + throw new Exception2(); + } + } + + static void test(int i) throws Exception { + try { + foo(i); + } + catch (Exception e) { + if (e instanceof Exception1) { + counter1++; + } else if (e instanceof Exception2) { + counter2++; + } + counter++; + throw e; + } + } + + public static void main(String[] args) throws Throwable { + for (int i = 0; i < 15000; i++) { + try { + test(i); + } catch (Exception e) { + // expected + } + } + if (counter1 != 0) { + throw new RuntimeException("Failed: counter1(" + counter1 + ") != 0"); + } + if (counter2 != counter0) { + throw new RuntimeException("Failed: counter2(" + counter2 + ") != counter0(" + counter0 + ")"); + } + if (counter2 != counter) { + throw new RuntimeException("Failed: counter2(" + counter2 + ") != counter(" + counter + ")"); + } + System.out.println("TEST PASSED"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/loopopts/TestDeadBackbranchArrayAccess.java Wed Jan 07 12:20:45 2015 -0800 @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 8054478 + * @summary dead backbranch in main loop results in erroneous array access + * @run main/othervm -XX:CompileOnly=TestDeadBackbranchArrayAccess -XX:+TieredCompilation -Xcomp TestDeadBackbranchArrayAccess + * + */ + +public class TestDeadBackbranchArrayAccess { + static char[] pattern0 = {0}; + static char[] pattern1 = {1}; + + static void test(char[] array) { + if (pattern1 == null) return; + + int i = 0; + int pos = 0; + char c = array[pos]; + + while (i >= 0 && (c == pattern0[i] || c == pattern1[i])) { + i--; + pos--; + if (pos != -1) { + c = array[pos]; + } + } + } + + public static void main(String[] args) { + for (int i = 0; i < 1000000; i++) { + test(new char[1]); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/CheckEndorsedAndExtDirs/EndorsedExtDirs.java Wed Jan 07 12:20:45 2015 -0800 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8064667 + * @summary Sanity test for -XX:+CheckEndorsedAndExtDirs + * @library /testlibrary + * @run main/othervm EndorsedExtDirs + */ + +import com.oracle.java.testlibrary.*; +import java.io.File; +import java.io.IOException; +import java.nio.file.DirectoryStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +public class EndorsedExtDirs { + static final String cpath = System.getProperty("test.classes", "."); + public static void main(String arg[]) throws Exception { + fatalError("-XX:+CheckEndorsedAndExtDirs", "-Djava.endorsed.dirs=foo"); + fatalError("-XX:+CheckEndorsedAndExtDirs", "-Djava.ext.dirs=bar"); + testNonEmptySystemExtDirs(); + } + + static void testNonEmptySystemExtDirs() throws Exception { + String home = System.getProperty("java.home"); + Path ext = Paths.get(home, "lib", "ext"); + String extDirs = System.getProperty("java.ext.dirs"); + String[] dirs = extDirs.split(File.pathSeparator); + long count = 0; + for (String d : dirs) { + Path path = Paths.get(d); + if (Files.notExists(path) || path.equals(ext)) continue; + try (DirectoryStream<Path> jars = + Files.newDirectoryStream(path, "*.jar")) + { + for (Path j : jars) { + count++; + } + } + } + if (count > 0) { + fatalError("-XX:+CheckEndorsedAndExtDirs"); + } + } + + static ProcessBuilder newProcessBuilder(String... args) { + List<String> commands = new ArrayList<>(); + String java = System.getProperty("java.home") + "/bin/java"; + commands.add(java); + for (String s : args) { + commands.add(s); + } + commands.add("-cp"); + commands.add(cpath); + commands.add("EndorsedExtDirs"); + + System.out.println("Process " + commands); + return new ProcessBuilder(commands); + } + + static void fatalError(String... args) throws Exception { + fatalError(newProcessBuilder(args)); + } + + static void fatalError(ProcessBuilder pb) throws Exception { + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Could not create the Java Virtual Machine"); + output.shouldHaveExitValue(1); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/LoadClass/LoadClassNegative.java Wed Jan 07 12:20:45 2015 -0800 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @key regression + * @bug 8020675 + * @summary make sure there is no fatal error if a class is loaded from an invalid jar file which is in the bootclasspath + * @library /testlibrary + * @build TestForName + * @build LoadClassNegative + * @run main LoadClassNegative + */ + +import java.io.File; +import com.oracle.java.testlibrary.*; + +public class LoadClassNegative { + + public static void main(String args[]) throws Exception { + String bootCP = "-Xbootclasspath/a:" + System.getProperty("test.src") + + File.separator + "dummy.jar"; + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + bootCP, + "TestForName"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("ClassNotFoundException"); + output.shouldHaveExitValue(0); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/LoadClass/ShowClassLoader.java Wed Jan 07 12:20:45 2015 -0800 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @key regression + * @bug 8058927 + * @summary Make sure array class has the right class loader + * @run main ShowClassLoader + */ + +public class ShowClassLoader { + + public static void main(String[] args) { + Object[] oa = new Object[0]; + ShowClassLoader[] sa = new ShowClassLoader[0]; + + System.out.println("Classloader for Object[] is " + oa.getClass().getClassLoader()); + System.out.println("Classloader for SCL[] is " + sa.getClass().getClassLoader() ); + + if (sa.getClass().getClassLoader() == null) { + throw new RuntimeException("Wrong class loader"); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/LoadClass/TestForName.java Wed Jan 07 12:20:45 2015 -0800 @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2013, 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. + */ + +public class TestForName { + public static void main(String[] args) { + try { + Class cls = Class.forName("xxx"); + System.out.println("Class = " + cls.getName()); + } catch (ClassNotFoundException cnfe) { + cnfe.printStackTrace(); + } + } +}