Mercurial > hg > graal-jvmci-8
changeset 24031:f2f59d888427 jdk8u112-b03
Merge
author | asaha |
---|---|
date | Thu, 14 Jul 2016 12:13:21 -0700 |
parents | 371fd9bb8202 (current diff) 15928d255046 (diff) |
children | c171546c49b5 |
files | |
diffstat | 12 files changed, 516 insertions(+), 74 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/vm/classfile/classFileParser.cpp Tue Jul 05 15:18:38 2016 -0700 +++ b/src/share/vm/classfile/classFileParser.cpp Thu Jul 14 12:13:21 2016 -0700 @@ -537,6 +537,9 @@ int name_index = cp->name_ref_index_at(index); Symbol* name = cp->symbol_at(name_index); Symbol* sig = cp->symbol_at(sig_index); + guarantee_property(sig->utf8_length() != 0, + "Illegal zero length constant pool entry at %d in class %s", + sig_index, CHECK_(nullHandle)); if (sig->byte_at(0) == JVM_SIGNATURE_FUNC) { verify_legal_method_signature(name, sig, CHECK_(nullHandle)); } else { @@ -560,8 +563,9 @@ verify_legal_field_name(name, CHECK_(nullHandle)); if (_need_verify && _major_version >= JAVA_7_VERSION) { // Signature is verified above, when iterating NameAndType_info. - // Need only to be sure it's the right type. - if (signature->byte_at(0) == JVM_SIGNATURE_FUNC) { + // Need only to be sure it's non-zero length and the right type. + if (signature->utf8_length() == 0 || + signature->byte_at(0) == JVM_SIGNATURE_FUNC) { throwIllegalSignature( "Field", name, signature, CHECK_(nullHandle)); } @@ -572,8 +576,9 @@ verify_legal_method_name(name, CHECK_(nullHandle)); if (_need_verify && _major_version >= JAVA_7_VERSION) { // Signature is verified above, when iterating NameAndType_info. - // Need only to be sure it's the right type. - if (signature->byte_at(0) != JVM_SIGNATURE_FUNC) { + // Need only to be sure it's non-zero length and the right type. + if (signature->utf8_length() == 0 || + signature->byte_at(0) != JVM_SIGNATURE_FUNC) { throwIllegalSignature( "Method", name, signature, CHECK_(nullHandle)); } @@ -584,8 +589,7 @@ // 4509014: If a class method name begins with '<', it must be "<init>". assert(name != NULL, "method name in constant pool is null"); unsigned int name_len = name->utf8_length(); - assert(name_len > 0, "bad method name"); // already verified as legal name - if (name->byte_at(0) == '<') { + if (name_len != 0 && name->byte_at(0) == '<') { if (name != vmSymbols::object_initializer_name()) { classfile_parse_error( "Bad method name at constant pool index %u in class file %s",
--- a/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp Tue Jul 05 15:18:38 2016 -0700 +++ b/src/share/vm/gc_implementation/g1/g1StringDedupTable.cpp Thu Jul 14 12:13:21 2016 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, 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 @@ -28,22 +28,23 @@ #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1SATBCardTableModRefBS.hpp" #include "gc_implementation/g1/g1StringDedupTable.hpp" +#include "gc_implementation/shared/concurrentGCThread.hpp" #include "memory/gcLocker.hpp" #include "memory/padded.inline.hpp" #include "oops/typeArrayOop.hpp" #include "runtime/mutexLocker.hpp" // -// Freelist in the deduplication table entry cache. Links table +// List of deduplication table entries. Links table // entries together using their _next fields. // -class G1StringDedupEntryFreeList : public CHeapObj<mtGC> { +class G1StringDedupEntryList : public CHeapObj<mtGC> { private: G1StringDedupEntry* _list; size_t _length; public: - G1StringDedupEntryFreeList() : + G1StringDedupEntryList() : _list(NULL), _length(0) { } @@ -63,6 +64,12 @@ return entry; } + G1StringDedupEntry* remove_all() { + G1StringDedupEntry* list = _list; + _list = NULL; + return list; + } + size_t length() { return _length; } @@ -84,43 +91,53 @@ // class G1StringDedupEntryCache : public CHeapObj<mtGC> { private: - // One freelist per GC worker to allow lock less freeing of - // entries while doing a parallel scan of the table. Using - // PaddedEnd to avoid false sharing. - PaddedEnd<G1StringDedupEntryFreeList>* _lists; - size_t _nlists; + // One cache/overflow list per GC worker to allow lock less freeing of + // entries while doing a parallel scan of the table. Using PaddedEnd to + // avoid false sharing. + size_t _nlists; + size_t _max_list_length; + PaddedEnd<G1StringDedupEntryList>* _cached; + PaddedEnd<G1StringDedupEntryList>* _overflowed; public: - G1StringDedupEntryCache(); + G1StringDedupEntryCache(size_t max_size); ~G1StringDedupEntryCache(); - // Get a table entry from the cache freelist, or allocate a new - // entry if the cache is empty. + // Set max number of table entries to cache. + void set_max_size(size_t max_size); + + // Get a table entry from the cache, or allocate a new entry if the cache is empty. G1StringDedupEntry* alloc(); - // Insert a table entry into the cache freelist. + // Insert a table entry into the cache. void free(G1StringDedupEntry* entry, uint worker_id); // Returns current number of entries in the cache. size_t size(); - // If the cache has grown above the given max size, trim it down - // and deallocate the memory occupied by trimmed of entries. - void trim(size_t max_size); + // Deletes overflowed entries. + void delete_overflowed(); }; -G1StringDedupEntryCache::G1StringDedupEntryCache() { - _nlists = MAX2(ParallelGCThreads, (size_t)1); - _lists = PaddedArray<G1StringDedupEntryFreeList, mtGC>::create_unfreeable((uint)_nlists); +G1StringDedupEntryCache::G1StringDedupEntryCache(size_t max_size) : + _nlists(MAX2(ParallelGCThreads, (size_t)1)), + _max_list_length(0), + _cached(PaddedArray<G1StringDedupEntryList, mtGC>::create_unfreeable((uint)_nlists)), + _overflowed(PaddedArray<G1StringDedupEntryList, mtGC>::create_unfreeable((uint)_nlists)) { + set_max_size(max_size); } G1StringDedupEntryCache::~G1StringDedupEntryCache() { ShouldNotReachHere(); } +void G1StringDedupEntryCache::set_max_size(size_t size) { + _max_list_length = size / _nlists; +} + G1StringDedupEntry* G1StringDedupEntryCache::alloc() { for (size_t i = 0; i < _nlists; i++) { - G1StringDedupEntry* entry = _lists[i].remove(); + G1StringDedupEntry* entry = _cached[i].remove(); if (entry != NULL) { return entry; } @@ -131,31 +148,55 @@ void G1StringDedupEntryCache::free(G1StringDedupEntry* entry, uint worker_id) { assert(entry->obj() != NULL, "Double free"); assert(worker_id < _nlists, "Invalid worker id"); + entry->set_obj(NULL); entry->set_hash(0); - _lists[worker_id].add(entry); + + if (_cached[worker_id].length() < _max_list_length) { + // Cache is not full + _cached[worker_id].add(entry); + } else { + // Cache is full, add to overflow list for later deletion + _overflowed[worker_id].add(entry); + } } size_t G1StringDedupEntryCache::size() { size_t size = 0; for (size_t i = 0; i < _nlists; i++) { - size += _lists[i].length(); + size += _cached[i].length(); } return size; } -void G1StringDedupEntryCache::trim(size_t max_size) { - size_t cache_size = 0; +void G1StringDedupEntryCache::delete_overflowed() { + double start = os::elapsedTime(); + uintx count = 0; + for (size_t i = 0; i < _nlists; i++) { - G1StringDedupEntryFreeList* list = &_lists[i]; - cache_size += list->length(); - while (cache_size > max_size) { - G1StringDedupEntry* entry = list->remove(); - assert(entry != NULL, "Should not be null"); - cache_size--; + G1StringDedupEntry* entry; + + { + // The overflow list can be modified during safepoints, therefore + // we temporarily join the suspendible thread set while removing + // all entries from the list. + SuspendibleThreadSetJoiner sts_join; + entry = _overflowed[i].remove_all(); + } + + // Delete all entries + while (entry != NULL) { + G1StringDedupEntry* next = entry->next(); delete entry; + entry = next; + count++; } } + + double end = os::elapsedTime(); + if (PrintStringDeduplicationStatistics) { + gclog_or_tty->print_cr("[GC concurrent-string-deduplication, deleted " UINTX_FORMAT " entries, " G1_STRDEDUP_TIME_FORMAT "]", count, end - start); + } } G1StringDedupTable* G1StringDedupTable::_table = NULL; @@ -192,7 +233,7 @@ void G1StringDedupTable::create() { assert(_table == NULL, "One string deduplication table allowed"); - _entry_cache = new G1StringDedupEntryCache(); + _entry_cache = new G1StringDedupEntryCache((size_t)(_min_size * _max_cache_factor)); _table = new G1StringDedupTable(_min_size); } @@ -375,6 +416,9 @@ // Update statistics _resize_count++; + // Update max cache size + _entry_cache->set_max_size((size_t)(size * _max_cache_factor)); + // Allocate the new table. The new table will be populated by workers // calling unlink_or_oops_do() and finally installed by finish_resize(). return new G1StringDedupTable(size, _table->_hash_seed); @@ -427,7 +471,7 @@ removed += unlink_or_oops_do(cl, table_half + partition_begin, table_half + partition_end, worker_id); } - // Delayed update avoid contention on the table lock + // Delayed update to avoid contention on the table lock if (removed > 0) { MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag); _table->_entries -= removed; @@ -545,10 +589,8 @@ } } -void G1StringDedupTable::trim_entry_cache() { - MutexLockerEx ml(StringDedupTable_lock, Mutex::_no_safepoint_check_flag); - size_t max_cache_size = (size_t)(_table->_size * _max_cache_factor); - _entry_cache->trim(max_cache_size); +void G1StringDedupTable::clean_entry_cache() { + _entry_cache->delete_overflowed(); } void G1StringDedupTable::print_statistics(outputStream* st) {
--- a/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp Tue Jul 05 15:18:38 2016 -0700 +++ b/src/share/vm/gc_implementation/g1/g1StringDedupTable.hpp Thu Jul 14 12:13:21 2016 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, 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 @@ -218,8 +218,8 @@ // and deletes the previously active table. static void finish_rehash(G1StringDedupTable* rehashed_table); - // If the table entry cache has grown too large, trim it down according to policy - static void trim_entry_cache(); + // If the table entry cache has grown too large, delete overflowed entries. + static void clean_entry_cache(); static void unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* cl, uint worker_id);
--- a/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp Tue Jul 05 15:18:38 2016 -0700 +++ b/src/share/vm/gc_implementation/g1/g1StringDedupThread.cpp Thu Jul 14 12:13:21 2016 -0700 @@ -100,14 +100,14 @@ } } - G1StringDedupTable::trim_entry_cache(); - stat.mark_done(); // Print statistics total_stat.add(stat); print(gclog_or_tty, stat, total_stat); } + + G1StringDedupTable::clean_entry_cache(); } terminate();
--- a/src/share/vm/opto/stringopts.cpp Tue Jul 05 15:18:38 2016 -0700 +++ b/src/share/vm/opto/stringopts.cpp Thu Jul 14 12:13:21 2016 -0700 @@ -1641,16 +1641,11 @@ } kit.store_String_value(kit.control(), result, char_array); - // Do not let stores that initialize this object be reordered with - // a subsequent store that would make this object accessible by - // other threads. - // Record what AllocateNode this StoreStore protects so that - // escape analysis can go from the MemBarStoreStoreNode to the - // AllocateNode and eliminate the MemBarStoreStoreNode if possible - // based on the escape status of the AllocateNode. - AllocateNode* alloc = AllocateNode::Ideal_allocation(result, _gvn); - assert(alloc != NULL, "should be newly allocated"); - kit.insert_mem_bar(Op_MemBarStoreStore, alloc->proj_out(AllocateNode::RawAddress)); + // The value field is final. Emit a barrier here to ensure that the effect + // of the initialization is committed to memory before any code publishes + // a reference to the newly constructed object (see Parse::do_exits()). + assert(AllocateNode::Ideal_allocation(result, _gvn) != NULL, "should be newly allocated"); + kit.insert_mem_bar(Op_MemBarRelease, result); } else { result = C->top(); }
--- a/test/compiler/jsr292/VMAnonymousClasses.java Tue Jul 05 15:18:38 2016 -0700 +++ b/test/compiler/jsr292/VMAnonymousClasses.java Thu Jul 14 12:13:21 2016 -0700 @@ -24,7 +24,7 @@ /** * @test * @bug 8058828 - * @run main/bootclasspath -Xbatch VMAnonymousClasses + * @run main/bootclasspath/othervm -Xbatch VMAnonymousClasses */ import jdk.internal.org.objectweb.asm.ClassWriter;
--- a/test/compiler/stringopts/TestStringObjectInitialization.java Tue Jul 05 15:18:38 2016 -0700 +++ b/test/compiler/stringopts/TestStringObjectInitialization.java Thu Jul 14 12:13:21 2016 -0700 @@ -27,6 +27,7 @@ /* * @test * @bug 8159244 + * @requires vm.gc == "Parallel" | vm.gc == "null" * @summary Verifies that no partially initialized String object escapes from * C2's String concat optimization in a highly concurrent setting. * This test triggers the bug in about 1 out of 10 runs.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/classFileParserBug/BadNameAndType.java Thu Jul 14 12:13:21 2016 -0700 @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2016, 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 8042660 + * @summary Constant pool NameAndType entries must point to non-zero length Utf8 strings + * @compile emptySigUtf8.jcod + * @compile emptyNameUtf8.jcod + * @run main/othervm -Xverify:all BadNameAndType + */ + +// Test that a constant pool NameAndType descriptor_index and/or name_index +// that points to a zero length Utf8 string causes a ClassFormatError. +public class BadNameAndType { + public static void main(String args[]) throws Throwable { + + System.out.println("Regression test for bug 8042660"); + + // Test descriptor_index pointing to zero-length string. + try { + Class newClass = Class.forName("emptySigUtf8"); + throw new RuntimeException("Expected ClassFormatError exception not thrown"); + } catch (java.lang.ClassFormatError e) { + System.out.println("Test BadNameAndType passed test case emptySigUtf8"); + } + + // Test name_index pointing to zero-length string. + try { + Class newClass = Class.forName("emptyNameUtf8"); + throw new RuntimeException("Expected ClassFormatError exception not thrown"); + } catch (java.lang.ClassFormatError e) { + System.out.println("Test BadNameAndType passed test case emptyNameUtf8"); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/classFileParserBug/emptyNameUtf8.jcod Thu Jul 14 12:13:21 2016 -0700 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2016, 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. + * + */ + +// This class has an illegal NameAndType at constant pool #4. It's illegal because +// the Utf8 that it points to at #27 is a zero length string which is not a valid +// name. Loading this class should cause a ClassFormatError exception. +class emptyNameUtf8 { + 0xCAFEBABE; + 0; // minor version + 52; // version + [29] { // Constant Pool + ; // first element is empty + Method #6 #15; // #1 at 0x0A + Field #16 #17; // #2 at 0x0F + String #18; // #3 at 0x14 + NameAndType #27 #28; // #4 at 0x9F + class #21; // #5 at 0x1C + class #22; // #6 at 0x1F + Utf8 "<init>"; // #7 at 0x22 + Utf8 "()V"; // #8 at 0x2B + Utf8 "Code"; // #9 at 0x2E + Utf8 "LineNumberTable"; // #10 at 0x35 + Utf8 "main"; // #11 at 0x47 + Utf8 "([Ljava/lang/String;)V"; // #12 at 0x4E + Utf8 "SourceFile"; // #13 at 0x67 + Utf8 "emptyNameUtf8.java"; // #14 at 0x74 + NameAndType #7 #8; // #15 at 0x81 + class #23; // #16 at 0x86 + NameAndType #24 #25; // #17 at 0x89 + Utf8 "Hello World"; // #18 at 0x8E + class #26; // #19 at 0x9C + Method #19 #4; // #20 at 0x17 + Utf8 "emptyNameUtf8"; // #21 at 0xA4 + Utf8 "java/lang/Object"; // #22 at 0xAC + Utf8 "java/lang/System"; // #23 at 0xBF + Utf8 "out"; // #24 at 0xD2 + Utf8 "Ljava/io/PrintStream;"; // #25 at 0xD8 + Utf8 "java/io/PrintStream"; // #26 at 0xF0 + Utf8 ""; // #27 at 0x0106 + Utf8 "()V"; // #28 at 0x0110 + } // Constant Pool + + 0x0021; // access + #5;// this_cpx + #6;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [0] { // fields + } // fields + + [2] { // methods + { // Member at 0x0134 + 0x0001; // access + #7; // name_cpx + #8; // sig_cpx + [1] { // Attributes + Attr(#9, 29) { // Code at 0x013C + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + }; + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 6) { // LineNumberTable at 0x0153 + [1] { // LineNumberTable + 0 2; // at 0x015F + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + ; + { // Member at 0x015F + 0x0009; // access + #11; // name_cpx + #12; // sig_cpx + [1] { // Attributes + Attr(#9, 37) { // Code at 0x0167 + 2; // max_stack + 1; // max_locals + Bytes[9]{ + 0xB200021203B60004; + 0xB1; + }; + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 10) { // LineNumberTable at 0x0182 + [2] { // LineNumberTable + 0 4; // at 0x018E + 8 5; // at 0x0192 + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + } // methods + + [1] { // Attributes + Attr(#13, 2) { // SourceFile at 0x0194 + #14; + } // end SourceFile + } // Attributes +} // end class emptyNameUtf8
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/classFileParserBug/emptySigUtf8.jcod Thu Jul 14 12:13:21 2016 -0700 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2016, 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. + * + */ + +// This class has an illegal NameAndType at constant pool #4. It's illegal because +// the type that it points to at #28 is a zero length Utf8 string which is not a +// valid signature. Loading this class should cause a ClassFormatError exception. +class emptySigUtf8 { + 0xCAFEBABE; + 0; // minor version + 52; // version + [29] { // Constant Pool + ; // first element is empty + Method #6 #15; // #1 at 0x0A + Field #16 #17; // #2 at 0x0F + String #18; // #3 at 0x14 + NameAndType #27 #28; // #4 at 0x9F + class #21; // #5 at 0x1C + class #22; // #6 at 0x1F + Utf8 "<init>"; // #7 at 0x22 + Utf8 "()V"; // #8 at 0x2B + Utf8 "Code"; // #9 at 0x2E + Utf8 "LineNumberTable"; // #10 at 0x35 + Utf8 "main"; // #11 at 0x47 + Utf8 "([Ljava/lang/String;)V"; // #12 at 0x4E + Utf8 "SourceFile"; // #13 at 0x67 + Utf8 "emptySigUtf8.java"; // #14 at 0x74 + NameAndType #7 #8; // #15 at 0x81 + class #23; // #16 at 0x86 + NameAndType #24 #25; // #17 at 0x89 + Utf8 "Hello World"; // #18 at 0x8E + class #26; // #19 at 0x9C + Method #19 #4; // #20 at 0x17 + Utf8 "emptySigUtf8"; // #21 at 0xA4 + Utf8 "java/lang/Object"; // #22 at 0xAC + Utf8 "java/lang/System"; // #23 at 0xBF + Utf8 "out"; // #24 at 0xD2 + Utf8 "Ljava/io/PrintStream;"; // #25 at 0xD8 + Utf8 "java/io/PrintStream"; // #26 at 0xF0 + Utf8 "hi"; // #27 at 0x0106 + Utf8 ""; // #28 at 0x0110 + } // Constant Pool + + 0x0021; // access + #5;// this_cpx + #6;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [0] { // fields + } // fields + + [2] { // methods + { // Member at 0x0134 + 0x0001; // access + #7; // name_cpx + #8; // sig_cpx + [1] { // Attributes + Attr(#9, 29) { // Code at 0x013C + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + }; + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 6) { // LineNumberTable at 0x0153 + [1] { // LineNumberTable + 0 2; // at 0x015F + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + ; + { // Member at 0x015F + 0x0009; // access + #11; // name_cpx + #12; // sig_cpx + [1] { // Attributes + Attr(#9, 37) { // Code at 0x0167 + 2; // max_stack + 1; // max_locals + Bytes[9]{ + 0xB200021203B60004; + 0xB1; + }; + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 10) { // LineNumberTable at 0x0182 + [2] { // LineNumberTable + 0 4; // at 0x018E + 8 5; // at 0x0192 + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + } // methods + + [1] { // Attributes + Attr(#13, 2) { // SourceFile at 0x0194 + #14; + } // end SourceFile + } // Attributes +} // end class emptySigUtf8
--- a/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java Tue Jul 05 15:18:38 2016 -0700 +++ b/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java Thu Jul 14 12:13:21 2016 -0700 @@ -24,6 +24,8 @@ package com.oracle.java.testlibrary; import java.io.IOException; +import java.util.Arrays; +import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -69,6 +71,58 @@ } /** + * Verify that the stdout contents of output buffer is empty + * + * @throws RuntimeException + * If stdout was not empty + */ + public void stdoutShouldBeEmpty() { + if (!getStdout().isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stdout was not empty"); + } + } + + /** + * Verify that the stderr contents of output buffer is empty + * + * @throws RuntimeException + * If stderr was not empty + */ + public void stderrShouldBeEmpty() { + if (!getStderr().isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stderr was not empty"); + } + } + + /** + * Verify that the stdout contents of output buffer is not empty + * + * @throws RuntimeException + * If stdout was empty + */ + public void stdoutShouldNotBeEmpty() { + if (getStdout().isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stdout was empty"); + } + } + + /** + * Verify that the stderr contents of output buffer is not empty + * + * @throws RuntimeException + * If stderr was empty + */ + public void stderrShouldNotBeEmpty() { + if (getStderr().isEmpty()) { + reportDiagnosticSummary(); + throw new RuntimeException("stderr was empty"); + } + } + + /** * Verify that the stdout and stderr contents of output buffer contains the string * * @param expectedString String that buffer should contain @@ -365,4 +419,18 @@ public int getExitValue() { return exitValue; } + + /** + * Get the contents of the output buffer (stdout and stderr) as list of strings. + * Output will be split by newlines. + * + * @return Contents of the output buffer as list of strings + */ + public List<String> asLines() { + return asLines(getOutput()); + } + + private List<String> asLines(String buffer) { + return Arrays.asList(buffer.split("(\\r\\n|\\n|\\r)")); + } }
--- a/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java Tue Jul 05 15:18:38 2016 -0700 +++ b/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java Thu Jul 14 12:13:21 2016 -0700 @@ -187,23 +187,36 @@ return executeProcess(pb); } - /** - * Executes a process, waits for it to finish and returns the process output. - * @param pb The ProcessBuilder to execute. - * @return The output from the process. - */ - public static OutputAnalyzer executeProcess(ProcessBuilder pb) throws Throwable { - OutputAnalyzer output = null; - try { - output = new OutputAnalyzer(pb.start()); - return output; - } catch (Throwable t) { - System.out.println("executeProcess() failed: " + t); - throw t; - } finally { - System.out.println(getProcessLog(pb, output)); + /** + * Executes a process, waits for it to finish and returns the process output. + * The process will have exited before this method returns. + * @param pb The ProcessBuilder to execute. + * @return The {@linkplain OutputAnalyzer} instance wrapping the process. + */ + public static OutputAnalyzer executeProcess(ProcessBuilder pb) throws Exception { + OutputAnalyzer output = null; + Process p = null; + boolean failed = false; + try { + p = pb.start(); + output = new OutputAnalyzer(p); + p.waitFor(); + + return output; + } catch (Throwable t) { + if (p != null) { + p.destroyForcibly().waitFor(); + } + + failed = true; + System.out.println("executeProcess() failed: " + t); + throw t; + } finally { + if (failed) { + System.err.println(getProcessLog(pb, output)); + } + } } - } /** * Executes a process, waits for it to finish and returns the process output.