--- a/hotspot/src/share/vm/oops/constantPool.cpp Thu Jan 31 17:43:01 2013 -0800
+++ b/hotspot/src/share/vm/oops/constantPool.cpp Fri Feb 01 22:41:34 2013 -0800
@@ -1129,7 +1129,7 @@
(len = old_off) * sizeof(u2));
fillp += len;
// first part of src
- Copy::conjoint_memory_atomic(to_cp->operands()->adr_at(0),
+ Copy::conjoint_memory_atomic(from_cp->operands()->adr_at(0),
new_operands->adr_at(fillp),
(len = from_off) * sizeof(u2));
fillp += len;
@@ -1139,7 +1139,7 @@
(len = old_len - old_off) * sizeof(u2));
fillp += len;
// second part of src
- Copy::conjoint_memory_atomic(to_cp->operands()->adr_at(from_off),
+ Copy::conjoint_memory_atomic(from_cp->operands()->adr_at(from_off),
new_operands->adr_at(fillp),
(len = from_len - from_off) * sizeof(u2));
fillp += len;
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Thu Jan 31 17:43:01 2013 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Feb 01 22:41:34 2013 -0800
@@ -278,76 +278,23 @@
case JVM_CONSTANT_NameAndType:
{
int name_ref_i = scratch_cp->name_ref_index_at(scratch_i);
- int new_name_ref_i = 0;
- bool match = (name_ref_i < *merge_cp_length_p) &&
- scratch_cp->compare_entry_to(name_ref_i, *merge_cp_p, name_ref_i,
- THREAD);
- if (!match) {
- // forward reference in *merge_cp_p or not a direct match
-
- int found_i = scratch_cp->find_matching_entry(name_ref_i, *merge_cp_p,
- THREAD);
- if (found_i != 0) {
- guarantee(found_i != name_ref_i,
- "compare_entry_to() and find_matching_entry() do not agree");
-
- // Found a matching entry somewhere else in *merge_cp_p so
- // just need a mapping entry.
- new_name_ref_i = found_i;
- map_index(scratch_cp, name_ref_i, found_i);
- } else {
- // no match found so we have to append this entry to *merge_cp_p
- append_entry(scratch_cp, name_ref_i, merge_cp_p, merge_cp_length_p,
- THREAD);
- // The above call to append_entry() can only append one entry
- // so the post call query of *merge_cp_length_p is only for
- // the sake of consistency.
- new_name_ref_i = *merge_cp_length_p - 1;
- }
- }
+ int new_name_ref_i = find_or_append_indirect_entry(scratch_cp, name_ref_i, merge_cp_p,
+ merge_cp_length_p, THREAD);
int signature_ref_i = scratch_cp->signature_ref_index_at(scratch_i);
- int new_signature_ref_i = 0;
- match = (signature_ref_i < *merge_cp_length_p) &&
- scratch_cp->compare_entry_to(signature_ref_i, *merge_cp_p,
- signature_ref_i, THREAD);
- if (!match) {
- // forward reference in *merge_cp_p or not a direct match
-
- int found_i = scratch_cp->find_matching_entry(signature_ref_i,
- *merge_cp_p, THREAD);
- if (found_i != 0) {
- guarantee(found_i != signature_ref_i,
- "compare_entry_to() and find_matching_entry() do not agree");
-
- // Found a matching entry somewhere else in *merge_cp_p so
- // just need a mapping entry.
- new_signature_ref_i = found_i;
- map_index(scratch_cp, signature_ref_i, found_i);
- } else {
- // no match found so we have to append this entry to *merge_cp_p
- append_entry(scratch_cp, signature_ref_i, merge_cp_p,
- merge_cp_length_p, THREAD);
- // The above call to append_entry() can only append one entry
- // so the post call query of *merge_cp_length_p is only for
- // the sake of consistency.
- new_signature_ref_i = *merge_cp_length_p - 1;
- }
- }
+ int new_signature_ref_i = find_or_append_indirect_entry(scratch_cp, signature_ref_i,
+ merge_cp_p, merge_cp_length_p,
+ THREAD);
// If the referenced entries already exist in *merge_cp_p, then
// both new_name_ref_i and new_signature_ref_i will both be 0.
// In that case, all we are appending is the current entry.
- if (new_name_ref_i == 0) {
- new_name_ref_i = name_ref_i;
- } else {
+ if (new_name_ref_i != name_ref_i) {
RC_TRACE(0x00080000,
("NameAndType entry@%d name_ref_index change: %d to %d",
*merge_cp_length_p, name_ref_i, new_name_ref_i));
}
- if (new_signature_ref_i == 0) {
- new_signature_ref_i = signature_ref_i;
- } else {
+ if (new_signature_ref_i != signature_ref_i) {
RC_TRACE(0x00080000,
("NameAndType entry@%d signature_ref_index change: %d to %d",
*merge_cp_length_p, signature_ref_i, new_signature_ref_i));
@@ -369,76 +316,12 @@
case JVM_CONSTANT_Methodref:
{
int klass_ref_i = scratch_cp->uncached_klass_ref_index_at(scratch_i);
- int new_klass_ref_i = 0;
- bool match = (klass_ref_i < *merge_cp_length_p) &&
- scratch_cp->compare_entry_to(klass_ref_i, *merge_cp_p, klass_ref_i,
- THREAD);
- if (!match) {
- // forward reference in *merge_cp_p or not a direct match
-
- int found_i = scratch_cp->find_matching_entry(klass_ref_i, *merge_cp_p,
- THREAD);
- if (found_i != 0) {
- guarantee(found_i != klass_ref_i,
- "compare_entry_to() and find_matching_entry() do not agree");
-
- // Found a matching entry somewhere else in *merge_cp_p so
- // just need a mapping entry.
- new_klass_ref_i = found_i;
- map_index(scratch_cp, klass_ref_i, found_i);
- } else {
- // no match found so we have to append this entry to *merge_cp_p
- append_entry(scratch_cp, klass_ref_i, merge_cp_p, merge_cp_length_p,
- THREAD);
- // The above call to append_entry() can only append one entry
- // so the post call query of *merge_cp_length_p is only for
- // the sake of consistency. Without the optimization where we
- // use JVM_CONSTANT_UnresolvedClass, then up to two entries
- // could be appended.
- new_klass_ref_i = *merge_cp_length_p - 1;
- }
- }
-
- int name_and_type_ref_i =
- scratch_cp->uncached_name_and_type_ref_index_at(scratch_i);
- int new_name_and_type_ref_i = 0;
- match = (name_and_type_ref_i < *merge_cp_length_p) &&
- scratch_cp->compare_entry_to(name_and_type_ref_i, *merge_cp_p,
- name_and_type_ref_i, THREAD);
- if (!match) {
- // forward reference in *merge_cp_p or not a direct match
-
- int found_i = scratch_cp->find_matching_entry(name_and_type_ref_i,
- *merge_cp_p, THREAD);
- if (found_i != 0) {
- guarantee(found_i != name_and_type_ref_i,
- "compare_entry_to() and find_matching_entry() do not agree");
-
- // Found a matching entry somewhere else in *merge_cp_p so
- // just need a mapping entry.
- new_name_and_type_ref_i = found_i;
- map_index(scratch_cp, name_and_type_ref_i, found_i);
- } else {
- // no match found so we have to append this entry to *merge_cp_p
- append_entry(scratch_cp, name_and_type_ref_i, merge_cp_p,
- merge_cp_length_p, THREAD);
- // The above call to append_entry() can append more than
- // one entry so the post call query of *merge_cp_length_p
- // is required in order to get the right index for the
- // JVM_CONSTANT_NameAndType entry.
- new_name_and_type_ref_i = *merge_cp_length_p - 1;
- }
- }
-
- // If the referenced entries already exist in *merge_cp_p, then
- // both new_klass_ref_i and new_name_and_type_ref_i will both be
- // 0. In that case, all we are appending is the current entry.
- if (new_klass_ref_i == 0) {
- new_klass_ref_i = klass_ref_i;
- }
- if (new_name_and_type_ref_i == 0) {
- new_name_and_type_ref_i = name_and_type_ref_i;
- }
+ int new_klass_ref_i = find_or_append_indirect_entry(scratch_cp, klass_ref_i,
+ merge_cp_p, merge_cp_length_p, THREAD);
+
+ int name_and_type_ref_i = scratch_cp->uncached_name_and_type_ref_index_at(scratch_i);
+ int new_name_and_type_ref_i = find_or_append_indirect_entry(scratch_cp, name_and_type_ref_i,
+ merge_cp_p, merge_cp_length_p, THREAD);
const char *entry_name;
switch (scratch_cp->tag_at(scratch_i).value()) {
@@ -481,6 +364,72 @@
(*merge_cp_length_p)++;
} break;
+ // this is an indirect CP entry so it needs special handling
+ case JVM_CONSTANT_MethodType:
+ {
+ int ref_i = scratch_cp->method_type_index_at(scratch_i);
+ int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p,
+ merge_cp_length_p, THREAD);
+ if (new_ref_i != ref_i) {
+ RC_TRACE(0x00080000,
+ ("MethodType entry@%d ref_index change: %d to %d",
+ *merge_cp_length_p, ref_i, new_ref_i));
+ }
+ (*merge_cp_p)->method_type_index_at_put(*merge_cp_length_p, new_ref_i);
+ if (scratch_i != *merge_cp_length_p) {
+ // The new entry in *merge_cp_p is at a different index than
+ // the new entry in scratch_cp so we need to map the index values.
+ map_index(scratch_cp, scratch_i, *merge_cp_length_p);
+ }
+ (*merge_cp_length_p)++;
+ } break;
+
+ // this is an indirect CP entry so it needs special handling
+ case JVM_CONSTANT_MethodHandle:
+ {
+ int ref_kind = scratch_cp->method_handle_ref_kind_at(scratch_i);
+ int ref_i = scratch_cp->method_handle_index_at(scratch_i);
+ int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p,
+ merge_cp_length_p, THREAD);
+ if (new_ref_i != ref_i) {
+ RC_TRACE(0x00080000,
+ ("MethodHandle entry@%d ref_index change: %d to %d",
+ *merge_cp_length_p, ref_i, new_ref_i));
+ }
+ (*merge_cp_p)->method_handle_index_at_put(*merge_cp_length_p, ref_kind, new_ref_i);
+ if (scratch_i != *merge_cp_length_p) {
+ // The new entry in *merge_cp_p is at a different index than
+ // the new entry in scratch_cp so we need to map the index values.
+ map_index(scratch_cp, scratch_i, *merge_cp_length_p);
+ }
+ (*merge_cp_length_p)++;
+ } break;
+
+ // this is an indirect CP entry so it needs special handling
+ case JVM_CONSTANT_InvokeDynamic:
+ {
+ // TBD: cross-checks and possible extra appends into CP and bsm operands
+ // are needed as well. This issue is tracked by a separate bug 8007037.
+ int bss_idx = scratch_cp->invoke_dynamic_bootstrap_specifier_index(scratch_i);
+
+ int ref_i = scratch_cp->invoke_dynamic_name_and_type_ref_index_at(scratch_i);
+ int new_ref_i = find_or_append_indirect_entry(scratch_cp, ref_i, merge_cp_p,
+ merge_cp_length_p, THREAD);
+ if (new_ref_i != ref_i) {
+ RC_TRACE(0x00080000,
+ ("InvokeDynamic entry@%d name_and_type ref_index change: %d to %d",
+ *merge_cp_length_p, ref_i, new_ref_i));
+ }
+
+ (*merge_cp_p)->invoke_dynamic_at_put(*merge_cp_length_p, bss_idx, new_ref_i);
+ if (scratch_i != *merge_cp_length_p) {
+ // The new entry in *merge_cp_p is at a different index than
+ // the new entry in scratch_cp so we need to map the index values.
+ map_index(scratch_cp, scratch_i, *merge_cp_length_p);
+ }
+ (*merge_cp_length_p)++;
+ } break;
+
// At this stage, Class or UnresolvedClass could be here, but not
// ClassIndex
case JVM_CONSTANT_ClassIndex: // fall through
@@ -507,6 +456,35 @@
} // end append_entry()
+int VM_RedefineClasses::find_or_append_indirect_entry(constantPoolHandle scratch_cp,
+ int ref_i, constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS) {
+
+ int new_ref_i = ref_i;
+ bool match = (ref_i < *merge_cp_length_p) &&
+ scratch_cp->compare_entry_to(ref_i, *merge_cp_p, ref_i, THREAD);
+
+ if (!match) {
+ // forward reference in *merge_cp_p or not a direct match
+ int found_i = scratch_cp->find_matching_entry(ref_i, *merge_cp_p, THREAD);
+ if (found_i != 0) {
+ guarantee(found_i != ref_i, "compare_entry_to() and find_matching_entry() do not agree");
+ // Found a matching entry somewhere else in *merge_cp_p so just need a mapping entry.
+ new_ref_i = found_i;
+ map_index(scratch_cp, ref_i, found_i);
+ } else {
+ // no match found so we have to append this entry to *merge_cp_p
+ append_entry(scratch_cp, ref_i, merge_cp_p, merge_cp_length_p, THREAD);
+ // The above call to append_entry() can only append one entry
+ // so the post call query of *merge_cp_length_p is only for
+ // the sake of consistency.
+ new_ref_i = *merge_cp_length_p - 1;
+ }
+ }
+
+ return new_ref_i;
+} // end find_or_append_indirect_entry()
+
+
void VM_RedefineClasses::swap_all_method_annotations(int i, int j, instanceKlassHandle scratch_class, TRAPS) {
AnnotationArray* save;
@@ -1564,6 +1542,7 @@
case Bytecodes::_getfield : // fall through
case Bytecodes::_getstatic : // fall through
case Bytecodes::_instanceof : // fall through
+ case Bytecodes::_invokedynamic : // fall through
case Bytecodes::_invokeinterface: // fall through
case Bytecodes::_invokespecial : // fall through
case Bytecodes::_invokestatic : // fall through
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp Thu Jan 31 17:43:01 2013 -0800
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.hpp Fri Feb 01 22:41:34 2013 -0800
@@ -421,10 +421,11 @@
// and in all direct and indirect subclasses.
void increment_class_counter(InstanceKlass *ik, TRAPS);
- // Support for constant pool merging (these routines are in alpha
- // order):
+ // Support for constant pool merging (these routines are in alpha order):
void append_entry(constantPoolHandle scratch_cp, int scratch_i,
constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS);
+ int find_or_append_indirect_entry(constantPoolHandle scratch_cp, int scratch_i,
+ constantPoolHandle *merge_cp_p, int *merge_cp_length_p, TRAPS);
int find_new_index(int old_index);
bool is_unresolved_class_mismatch(constantPoolHandle cp1, int index1,
constantPoolHandle cp2, int index2);
--- a/hotspot/src/share/vm/runtime/arguments.cpp Thu Jan 31 17:43:01 2013 -0800
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Fri Feb 01 22:41:34 2013 -0800
@@ -827,7 +827,8 @@
return true;
}
- const char * const argname = *arg == '+' || *arg == '-' ? arg + 1 : arg;
+ bool has_plus_minus = (*arg == '+' || *arg == '-');
+ const char* const argname = has_plus_minus ? arg + 1 : arg;
if (is_newly_obsolete(arg, &since)) {
char version[256];
since.to_string(version, sizeof(version));
@@ -838,13 +839,29 @@
// For locked flags, report a custom error message if available.
// Otherwise, report the standard unrecognized VM option.
- Flag* locked_flag = Flag::find_flag((char*)argname, strlen(argname), true);
- if (locked_flag != NULL) {
+ size_t arg_len;
+ const char* equal_sign = strchr(argname, '=');
+ if (equal_sign == NULL) {
+ arg_len = strlen(argname);
+ } else {
+ arg_len = equal_sign - argname;
+ }
+
+ Flag* found_flag = Flag::find_flag((char*)argname, arg_len, true);
+ if (found_flag != NULL) {
char locked_message_buf[BUFLEN];
- locked_flag->get_locked_message(locked_message_buf, BUFLEN);
+ found_flag->get_locked_message(locked_message_buf, BUFLEN);
if (strlen(locked_message_buf) == 0) {
- jio_fprintf(defaultStream::error_stream(),
- "Unrecognized VM option '%s'\n", argname);
+ if (found_flag->is_bool() && !has_plus_minus) {
+ jio_fprintf(defaultStream::error_stream(),
+ "Missing +/- setting for VM option '%s'\n", argname);
+ } else if (!found_flag->is_bool() && has_plus_minus) {
+ jio_fprintf(defaultStream::error_stream(),
+ "Unexpected +/- setting in VM option '%s'\n", argname);
+ } else {
+ jio_fprintf(defaultStream::error_stream(),
+ "Improperly specified VM option '%s'\n", argname);
+ }
} else {
jio_fprintf(defaultStream::error_stream(), "%s", locked_message_buf);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/OutputAnalyzerTest.java Fri Feb 01 22:41:34 2013 -0800
@@ -0,0 +1,108 @@
+/*
+ * 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
+ * @summary Test the OutputAnalyzer utility class
+ * @library /testlibrary
+ */
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+
+public class OutputAnalyzerTest {
+
+ public static void main(String args[]) throws Exception {
+
+ String stdout = "aaaaaa";
+ String stderr = "bbbbbb";
+
+ OutputAnalyzer output = new OutputAnalyzer(stdout, stderr);
+
+ if (!stdout.equals(output.getStdout())) {
+ throw new Exception("getStdout() returned '" + output.getStdout() + "', expected '" + stdout + "'");
+ }
+
+ if (!stderr.equals(output.getStderr())) {
+ throw new Exception("getStderr() returned '" + output.getStderr() + "', expected '" + stderr + "'");
+ }
+
+ try {
+ output.shouldContain(stdout);
+ output.stdoutShouldContain(stdout);
+ output.shouldContain(stderr);
+ output.stderrShouldContain(stderr);
+ } catch (RuntimeException e) {
+ throw new Exception("shouldContain() failed", e);
+ }
+
+ try {
+ output.shouldContain("cccc");
+ throw new Exception("shouldContain() failed to throw exception");
+ } catch (RuntimeException e) {
+ // expected
+ }
+
+ try {
+ output.stdoutShouldContain(stderr);
+ throw new Exception("stdoutShouldContain() failed to throw exception");
+ } catch (RuntimeException e) {
+ // expected
+ }
+
+ try {
+ output.stderrShouldContain(stdout);
+ throw new Exception("stdoutShouldContain() failed to throw exception");
+ } catch (RuntimeException e) {
+ // expected
+ }
+
+ try {
+ output.shouldNotContain("cccc");
+ output.stdoutShouldNotContain("cccc");
+ output.stderrShouldNotContain("cccc");
+ } catch (RuntimeException e) {
+ throw new Exception("shouldNotContain() failed", e);
+ }
+
+ try {
+ output.shouldNotContain(stdout);
+ throw new Exception("shouldContain() failed to throw exception");
+ } catch (RuntimeException e) {
+ // expected
+ }
+
+ try {
+ output.stdoutShouldNotContain(stdout);
+ throw new Exception("shouldContain() failed to throw exception");
+ } catch (RuntimeException e) {
+ // expected
+ }
+
+ try {
+ output.stderrShouldNotContain(stderr);
+ throw new Exception("shouldContain() failed to throw exception");
+ } catch (RuntimeException e) {
+ // expected
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/JDKToolFinder.java Fri Feb 01 22:41:34 2013 -0800
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+package com.oracle.java.testlibrary;
+
+import java.io.File;
+
+public final class JDKToolFinder {
+
+ private JDKToolFinder() {
+ }
+
+ /**
+ * Returns the full path to an executable in jdk/bin based on System property
+ * test.jdk (set by jtreg test suite)
+ *
+ * @return Full path to an executable in jdk/bin
+ */
+ public static String getJDKTool(String tool) {
+ String binPath = System.getProperty("test.jdk");
+ if (binPath == null) {
+ throw new RuntimeException("System property 'test.jdk' not set. This property is normally set by jtreg. "
+ + "When running test separately, set this property using '-Dtest.jdk=/path/to/jdk'.");
+ }
+
+ binPath += File.separatorChar + "bin" + File.separatorChar + tool;
+
+ return binPath;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/OutputAnalyzer.java Fri Feb 01 22:41:34 2013 -0800
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ */
+
+package com.oracle.java.testlibrary;
+
+import java.io.IOException;
+
+public final class OutputAnalyzer {
+
+ private final String stdout;
+ private final String stderr;
+ private final int exitValue;
+
+ /**
+ * Create an OutputAnalyzer, a utility class for verifying output and exit
+ * value from a Process
+ *
+ * @param process Process to analyze
+ * @throws IOException If an I/O error occurs.
+ */
+ public OutputAnalyzer(Process process) throws IOException {
+ OutputBuffer output = ProcessTools.getOutput(process);
+ exitValue = process.exitValue();
+ this.stdout = output.getStdout();
+ this.stderr = output.getStderr();
+ }
+
+ /**
+ * Create an OutputAnalyzer, a utility class for verifying output
+ *
+ * @param buf String buffer to analyze
+ */
+ public OutputAnalyzer(String buf) {
+ this(buf, buf);
+ }
+
+ /**
+ * Create an OutputAnalyzer, a utility class for verifying output
+ *
+ * @param stdout stdout buffer to analyze
+ * @param stderr stderr buffer to analyze
+ */
+ public OutputAnalyzer(String stdout, String stderr) {
+ this.stdout = stdout;
+ this.stderr = stderr;
+ exitValue = -1;
+ }
+
+ /**
+ * Verify that the stdout and stderr contents of output buffer contains the string
+ *
+ * @param expectedString String that buffer should contain
+ * @throws RuntimeException If the string was not found
+ */
+ public void shouldContain(String expectedString) {
+ if (!stdout.contains(expectedString) && !stderr.contains(expectedString)) {
+ throw new RuntimeException("'" + expectedString + "' missing from stdout/stderr: [" + stdout + stderr + "]\n");
+ }
+ }
+
+ /**
+ * Verify that the stdout contents of output buffer contains the string
+ *
+ * @param expectedString String that buffer should contain
+ * @throws RuntimeException If the string was not found
+ */
+ public void stdoutShouldContain(String expectedString) {
+ if (!stdout.contains(expectedString)) {
+ throw new RuntimeException("'" + expectedString + "' missing from stdout: [" + stdout + "]\n");
+ }
+ }
+
+ /**
+ * Verify that the stderr contents of output buffer contains the string
+ *
+ * @param expectedString String that buffer should contain
+ * @throws RuntimeException If the string was not found
+ */
+ public void stderrShouldContain(String expectedString) {
+ if (!stderr.contains(expectedString)) {
+ throw new RuntimeException("'" + expectedString + "' missing from stderr: [" + stderr + "]\n");
+ }
+ }
+
+ /**
+ * Verify that the stdout and stderr contents of output buffer does not contain the string
+ *
+ * @param expectedString String that the buffer should not contain
+ * @throws RuntimeException If the string was found
+ */
+ public void shouldNotContain(String notExpectedString) {
+ if (stdout.contains(notExpectedString)) {
+ throw new RuntimeException("'" + notExpectedString + "' found in stdout: [" + stdout + "]\n");
+ }
+ if (stderr.contains(notExpectedString)) {
+ throw new RuntimeException("'" + notExpectedString + "' found in stderr: [" + stderr + "]\n");
+ }
+ }
+
+ /**
+ * Verify that the stdout contents of output buffer does not contain the string
+ *
+ * @param expectedString String that the buffer should not contain
+ * @throws RuntimeException If the string was found
+ */
+ public void stdoutShouldNotContain(String notExpectedString) {
+ if (stdout.contains(notExpectedString)) {
+ throw new RuntimeException("'" + notExpectedString + "' found in stdout: [" + stdout + "]\n");
+ }
+ }
+
+ /**
+ * Verify that the stderr contents of output buffer does not contain the string
+ *
+ * @param expectedString String that the buffer should not contain
+ * @throws RuntimeException If the string was found
+ */
+ public void stderrShouldNotContain(String notExpectedString) {
+ if (stderr.contains(notExpectedString)) {
+ throw new RuntimeException("'" + notExpectedString + "' found in stderr: [" + stderr + "]\n");
+ }
+ }
+
+ /**
+ * Verifiy the exit value of the process
+ *
+ * @param expectedExitValue Expected exit value from process
+ * @throws RuntimeException If the exit value from the process did not match the expected value
+ */
+ public void shouldHaveExitValue(int expectedExitValue) {
+ if (getExitValue() != expectedExitValue) {
+ throw new RuntimeException("Exit value " + getExitValue() + " , expected to get " + expectedExitValue);
+ }
+ }
+
+ /**
+ * Get the contents of the output buffer (stdout and stderr)
+ *
+ * @return Content of the output buffer
+ */
+ public String getOutput() {
+ return stdout + stderr;
+ }
+
+ /**
+ * Get the contents of the stdout buffer
+ *
+ * @return Content of the stdout buffer
+ */
+ public String getStdout() {
+ return stdout;
+ }
+
+ /**
+ * Get the contents of the stderr buffer
+ *
+ * @return Content of the stderr buffer
+ */
+ public String getStderr() {
+ return stderr;
+ }
+
+ /**
+ * Get the process exit value
+ *
+ * @return Process exit value
+ */
+ public int getExitValue() {
+ return exitValue;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/OutputBuffer.java Fri Feb 01 22:41:34 2013 -0800
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+package com.oracle.java.testlibrary;
+
+public class OutputBuffer {
+ private final String stdout;
+ private final String stderr;
+
+ /**
+ * Create an OutputBuffer, a class for storing and managing stdout and stderr
+ * results separately
+ *
+ * @param stdout stdout result
+ * @param stderr stderr result
+ */
+ public OutputBuffer(String stdout, String stderr) {
+ this.stdout = stdout;
+ this.stderr = stderr;
+ }
+
+ /**
+ * Returns the stdout result
+ *
+ * @return stdout result
+ */
+ public String getStdout() {
+ return stdout;
+ }
+
+ /**
+ * Returns the stderr result
+ *
+ * @return stderr result
+ */
+ public String getStderr() {
+ return stderr;
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java Fri Feb 01 22:41:34 2013 -0800
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ */
+
+package com.oracle.java.testlibrary;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.lang.management.RuntimeMXBean;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+
+import sun.management.VMManagement;
+
+public final class ProcessTools {
+
+ private ProcessTools() {
+ }
+
+ /**
+ * Pumps stdout and stderr from running the process into a String.
+ *
+ * @param processHandler ProcessHandler to run.
+ * @return Output from process.
+ * @throws IOException If an I/O error occurs.
+ */
+ public static OutputBuffer getOutput(ProcessBuilder processBuilder) throws IOException {
+ return getOutput(processBuilder.start());
+ }
+
+ /**
+ * Pumps stdout and stderr the running process into a String.
+ *
+ * @param process Process to pump.
+ * @return Output from process.
+ * @throws IOException If an I/O error occurs.
+ */
+ public static OutputBuffer getOutput(Process process) throws IOException {
+ ByteArrayOutputStream stderrBuffer = new ByteArrayOutputStream();
+ ByteArrayOutputStream stdoutBuffer = new ByteArrayOutputStream();
+ StreamPumper outPumper = new StreamPumper(process.getInputStream(), stdoutBuffer);
+ StreamPumper errPumper = new StreamPumper(process.getErrorStream(), stderrBuffer);
+ Thread outPumperThread = new Thread(outPumper);
+ Thread errPumperThread = new Thread(errPumper);
+
+ outPumperThread.setDaemon(true);
+ errPumperThread.setDaemon(true);
+
+ outPumperThread.start();
+ errPumperThread.start();
+
+ try {
+ process.waitFor();
+ outPumperThread.join();
+ errPumperThread.join();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return null;
+ }
+
+ return new OutputBuffer(stdoutBuffer.toString(), stderrBuffer.toString());
+ }
+
+ /**
+ * Get the process id of the current running Java process
+ *
+ * @return Process id
+ */
+ public static int getProcessId() throws Exception {
+
+ // Get the current process id using a reflection hack
+ RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
+ Field jvm = runtime.getClass().getDeclaredField("jvm");
+
+ jvm.setAccessible(true);
+ VMManagement mgmt = (sun.management.VMManagement) jvm.get(runtime);
+
+ Method pid_method = mgmt.getClass().getDeclaredMethod("getProcessId");
+
+ pid_method.setAccessible(true);
+
+ int pid = (Integer) pid_method.invoke(mgmt);
+
+ return pid;
+ }
+
+ /**
+ * Get platform specific VM arguments (e.g. -d64 on 64bit Solaris)
+ *
+ * @return String[] with platform specific arguments, empty if there are none
+ */
+ public static String[] getPlatformSpecificVMArgs() {
+ String osName = System.getProperty("os.name");
+ String dataModel = System.getProperty("sun.arch.data.model");
+
+ if (osName.equals("SunOS") && dataModel.equals("64")) {
+ return new String[] { "-d64" };
+ }
+
+ return new String[] {};
+ }
+
+ /**
+ * Create ProcessBuilder using the java launcher from the jdk to be tested and
+ * with any platform specific arguments prepended
+ */
+ public static ProcessBuilder createJavaProcessBuilder(String... command) throws Exception {
+ String javapath = JDKToolFinder.getJDKTool("java");
+
+ ArrayList<String> args = new ArrayList<>();
+ args.add(javapath);
+ Collections.addAll(args, getPlatformSpecificVMArgs());
+ Collections.addAll(args, command);
+
+ return new ProcessBuilder(args.toArray(new String[args.size()]));
+
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/StreamPumper.java Fri Feb 01 22:41:34 2013 -0800
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+package com.oracle.java.testlibrary;
+
+import java.io.OutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+
+public final class StreamPumper implements Runnable {
+
+ private static final int BUF_SIZE = 256;
+
+ private final OutputStream out;
+ private final InputStream in;
+
+ /**
+ * Create a StreamPumper that reads from in and writes to out.
+ *
+ * @param in The stream to read from.
+ * @param out The stream to write to.
+ */
+ public StreamPumper(InputStream in, OutputStream out) {
+ this.in = in;
+ this.out = out;
+ }
+
+ /**
+ * Implements Thread.run(). Continuously read from <code>in</code> and write
+ * to <code>out</code> until <code>in</code> has reached end of stream. Abort
+ * on interruption. Abort on IOExceptions.
+ */
+ @Override
+ public void run() {
+ int length;
+ InputStream localIn = in;
+ OutputStream localOut = out;
+ byte[] buffer = new byte[BUF_SIZE];
+
+ try {
+ while (!Thread.interrupted() && (length = localIn.read(buffer)) > 0) {
+ localOut.write(buffer, 0, length);
+ }
+ } catch (IOException e) {
+ // Just abort if something like this happens.
+ e.printStackTrace();
+ } finally {
+ try {
+ localOut.flush();
+ in.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+}