8017611: Auto corrector for mistyped vm options

Fri, 28 Jun 2013 20:18:04 -0700

author
tamao
date
Fri, 28 Jun 2013 20:18:04 -0700
changeset 5343
6e3634222155
parent 5342
5ea20b3bd249
child 5344
536976a22f5f

8017611: Auto corrector for mistyped vm options
Summary: The auto corrector for mistyped vm options fuzzy-matches existing flags based on string similarity (Dice's coefficient).
Reviewed-by: kvn, dsamersoff, hseigel, johnc

src/share/vm/runtime/arguments.cpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/globals.cpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/globals.hpp file | annotate | diff | comparison | revisions
test/gc/arguments/TestUnrecognizedVMOptionsHandling.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/runtime/arguments.cpp	Mon Jul 01 09:30:23 2013 -0700
     1.2 +++ b/src/share/vm/runtime/arguments.cpp	Fri Jun 28 20:18:04 2013 -0700
     1.3 @@ -849,7 +849,7 @@
     1.4      arg_len = equal_sign - argname;
     1.5    }
     1.6  
     1.7 -  Flag* found_flag = Flag::find_flag((char*)argname, arg_len, true);
     1.8 +  Flag* found_flag = Flag::find_flag((const char*)argname, arg_len, true);
     1.9    if (found_flag != NULL) {
    1.10      char locked_message_buf[BUFLEN];
    1.11      found_flag->get_locked_message(locked_message_buf, BUFLEN);
    1.12 @@ -870,6 +870,14 @@
    1.13    } else {
    1.14      jio_fprintf(defaultStream::error_stream(),
    1.15                  "Unrecognized VM option '%s'\n", argname);
    1.16 +    Flag* fuzzy_matched = Flag::fuzzy_match((const char*)argname, arg_len, true);
    1.17 +    if (fuzzy_matched != NULL) {
    1.18 +      jio_fprintf(defaultStream::error_stream(),
    1.19 +                  "Did you mean '%s%s%s'?\n",
    1.20 +                  (fuzzy_matched->is_bool()) ? "(+/-)" : "",
    1.21 +                  fuzzy_matched->name,
    1.22 +                  (fuzzy_matched->is_bool()) ? "" : "=<value>");
    1.23 +    }
    1.24    }
    1.25  
    1.26    // allow for commandline "commenting out" options like -XX:#+Verbose
     2.1 --- a/src/share/vm/runtime/globals.cpp	Mon Jul 01 09:30:23 2013 -0700
     2.2 +++ b/src/share/vm/runtime/globals.cpp	Fri Jun 28 20:18:04 2013 -0700
     2.3 @@ -276,14 +276,14 @@
     2.4  Flag* Flag::flags = flagTable;
     2.5  size_t Flag::numFlags = (sizeof(flagTable) / sizeof(Flag));
     2.6  
     2.7 -inline bool str_equal(const char* s, char* q, size_t len) {
     2.8 +inline bool str_equal(const char* s, const char* q, size_t len) {
     2.9    // s is null terminated, q is not!
    2.10    if (strlen(s) != (unsigned int) len) return false;
    2.11    return strncmp(s, q, len) == 0;
    2.12  }
    2.13  
    2.14  // Search the flag table for a named flag
    2.15 -Flag* Flag::find_flag(char* name, size_t length, bool allow_locked) {
    2.16 +Flag* Flag::find_flag(const char* name, size_t length, bool allow_locked) {
    2.17    for (Flag* current = &flagTable[0]; current->name != NULL; current++) {
    2.18      if (str_equal(current->name, name, length)) {
    2.19        // Found a matching entry.  Report locked flags only if allowed.
    2.20 @@ -301,6 +301,52 @@
    2.21    return NULL;
    2.22  }
    2.23  
    2.24 +// Compute string similarity based on Dice's coefficient
    2.25 +static float str_similar(const char* str1, const char* str2, size_t len2) {
    2.26 +  int len1 = (int) strlen(str1);
    2.27 +  int total = len1 + (int) len2;
    2.28 +
    2.29 +  int hit = 0;
    2.30 +
    2.31 +  for (int i = 0; i < len1 -1; ++i) {
    2.32 +    for (int j = 0; j < (int) len2 -1; ++j) {
    2.33 +      if ((str1[i] == str2[j]) && (str1[i+1] == str2[j+1])) {
    2.34 +        ++hit;
    2.35 +        break;
    2.36 +      }
    2.37 +    }
    2.38 +  }
    2.39 +
    2.40 +  return 2.0f * (float) hit / (float) total;
    2.41 +}
    2.42 +
    2.43 +Flag* Flag::fuzzy_match(const char* name, size_t length, bool allow_locked) {
    2.44 +  float VMOptionsFuzzyMatchSimilarity = 0.7f;
    2.45 +  Flag* match = NULL;
    2.46 +  float score;
    2.47 +  float max_score = -1;
    2.48 +
    2.49 +  for (Flag* current = &flagTable[0]; current->name != NULL; current++) {
    2.50 +    score = str_similar(current->name, name, length);
    2.51 +    if (score > max_score) {
    2.52 +      max_score = score;
    2.53 +      match = current;
    2.54 +    }
    2.55 +  }
    2.56 +
    2.57 +  if (!(match->is_unlocked() || match->is_unlocker())) {
    2.58 +    if (!allow_locked) {
    2.59 +      return NULL;
    2.60 +    }
    2.61 +  }
    2.62 +
    2.63 +  if (max_score < VMOptionsFuzzyMatchSimilarity) {
    2.64 +    return NULL;
    2.65 +  }
    2.66 +
    2.67 +  return match;
    2.68 +}
    2.69 +
    2.70  // Returns the address of the index'th element
    2.71  static Flag* address_of_flag(CommandLineFlagWithType flag) {
    2.72    assert((size_t)flag < Flag::numFlags, "bad command line flag index");
     3.1 --- a/src/share/vm/runtime/globals.hpp	Mon Jul 01 09:30:23 2013 -0700
     3.2 +++ b/src/share/vm/runtime/globals.hpp	Fri Jun 28 20:18:04 2013 -0700
     3.3 @@ -220,7 +220,8 @@
     3.4    // number of flags
     3.5    static size_t numFlags;
     3.6  
     3.7 -  static Flag* find_flag(char* name, size_t length, bool allow_locked = false);
     3.8 +  static Flag* find_flag(const char* name, size_t length, bool allow_locked = false);
     3.9 +  static Flag* fuzzy_match(const char* name, size_t length, bool allow_locked = false);
    3.10  
    3.11    bool is_bool() const        { return strcmp(type, "bool") == 0; }
    3.12    bool get_bool() const       { return *((bool*) addr); }
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/test/gc/arguments/TestUnrecognizedVMOptionsHandling.java	Fri Jun 28 20:18:04 2013 -0700
     4.3 @@ -0,0 +1,69 @@
     4.4 +/*
     4.5 +* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
     4.6 +* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4.7 +*
     4.8 +* This code is free software; you can redistribute it and/or modify it
     4.9 +* under the terms of the GNU General Public License version 2 only, as
    4.10 +* published by the Free Software Foundation.
    4.11 +*
    4.12 +* This code is distributed in the hope that it will be useful, but WITHOUT
    4.13 +* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    4.14 +* FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    4.15 +* version 2 for more details (a copy is included in the LICENSE file that
    4.16 +* accompanied this code).
    4.17 +*
    4.18 +* You should have received a copy of the GNU General Public License version
    4.19 +* 2 along with this work; if not, write to the Free Software Foundation,
    4.20 +* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    4.21 +*
    4.22 +* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    4.23 +* or visit www.oracle.com if you need additional information or have any
    4.24 +* questions.
    4.25 +*/
    4.26 +
    4.27 +/*
    4.28 + * @test TestUnrecognizedVMOptionsHandling
    4.29 + * @key gc
    4.30 + * @bug 8017611
    4.31 + * @summary Tests handling unrecognized VM options
    4.32 + * @library /testlibrary
    4.33 + * @run main/othervm TestUnrecognizedVMOptionsHandling
    4.34 + */
    4.35 +
    4.36 +import com.oracle.java.testlibrary.*;
    4.37 +
    4.38 +public class TestUnrecognizedVMOptionsHandling {
    4.39 +
    4.40 +  public static void main(String args[]) throws Exception {
    4.41 +    // The first two JAVA processes are expected to fail, but with a correct VM option suggestion
    4.42 +    ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
    4.43 +      "-XX:+PrintGc",
    4.44 +      "-version"
    4.45 +      );
    4.46 +    OutputAnalyzer outputWithError = new OutputAnalyzer(pb.start());
    4.47 +    outputWithError.shouldContain("Did you mean '(+/-)PrintGC'?");
    4.48 +    if (outputWithError.getExitValue() == 0) {
    4.49 +      throw new RuntimeException("Not expected to get exit value 0");
    4.50 +    }
    4.51 +
    4.52 +    pb = ProcessTools.createJavaProcessBuilder(
    4.53 +      "-XX:MaxiumHeapSize=500m",
    4.54 +      "-version"
    4.55 +      );
    4.56 +    outputWithError = new OutputAnalyzer(pb.start());
    4.57 +    outputWithError.shouldContain("Did you mean 'MaxHeapSize=<value>'?");
    4.58 +    if (outputWithError.getExitValue() == 0) {
    4.59 +      throw new RuntimeException("Not expected to get exit value 0");
    4.60 +    }
    4.61 +
    4.62 +    // The last JAVA process should run successfully for the purpose of sanity check
    4.63 +    pb = ProcessTools.createJavaProcessBuilder(
    4.64 +      "-XX:+PrintGC",
    4.65 +      "-version"
    4.66 +      );
    4.67 +    OutputAnalyzer outputWithNoError = new OutputAnalyzer(pb.start());
    4.68 +    outputWithNoError.shouldNotContain("Did you mean '(+/-)PrintGC'?");
    4.69 +    outputWithNoError.shouldHaveExitValue(0);
    4.70 +  }
    4.71 +}
    4.72 +

mercurial