lkml.org 
[lkml]   [2020]   [Apr]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 3/3] perf jvmti: Fix demangling Java symbols
    Date
    For a Java method signature like:

    Ljava/lang/AbstractStringBuilder;appendChars(Ljava/lang/String;II)V

    The demangler produces:

    void class java.lang.AbstractStringBuilder.appendChars(class java.lang., shorttring., int, int)

    The arguments should be (java.lang.String, int, int) but the demangler
    interprets the "S" in String as the type code for "short". Correct this
    and two other minor things:

    - There is no "bool" type in Java, should be "boolean".

    - The demangler prepends "class" to every Java class name. This is not
    standard Java syntax and it wastes a lot of horizontal space if the
    signature is long. Remove this as there isn't any ambiguity between
    class names and primitives.

    Also added a test case.

    Signed-off-by: Nick Gasson <nick.gasson@arm.com>
    ---
    tools/perf/tests/Build | 1 +
    tools/perf/tests/builtin-test.c | 4 +++
    tools/perf/tests/demangle-java-test.c | 42 +++++++++++++++++++++++++++
    tools/perf/tests/tests.h | 1 +
    tools/perf/util/demangle-java.c | 13 +++++----
    5 files changed, 55 insertions(+), 6 deletions(-)
    create mode 100644 tools/perf/tests/demangle-java-test.c

    diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
    index 1692529639b0..2c45ac4a9581 100644
    --- a/tools/perf/tests/Build
    +++ b/tools/perf/tests/Build
    @@ -55,6 +55,7 @@ perf-y += mem2node.o
    perf-y += maps.o
    perf-y += time-utils-test.o
    perf-y += genelf.o
    +perf-y += demangle-java-test.o

    $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build
    $(call rule_mkdir)
    diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
    index 54d9516c9839..03b362b37f97 100644
    --- a/tools/perf/tests/builtin-test.c
    +++ b/tools/perf/tests/builtin-test.c
    @@ -309,6 +309,10 @@ static struct test generic_tests[] = {
    .desc = "maps__merge_in",
    .func = test__maps__merge_in,
    },
    + {
    + .desc = "Demangle Java",
    + .func = test__demangle_java,
    + },
    {
    .func = NULL,
    },
    diff --git a/tools/perf/tests/demangle-java-test.c b/tools/perf/tests/demangle-java-test.c
    new file mode 100644
    index 000000000000..8f3b90832fb0
    --- /dev/null
    +++ b/tools/perf/tests/demangle-java-test.c
    @@ -0,0 +1,42 @@
    +// SPDX-License-Identifier: GPL-2.0
    +#include <string.h>
    +#include <stdlib.h>
    +#include <stdio.h>
    +#include "tests.h"
    +#include "session.h"
    +#include "debug.h"
    +#include "demangle-java.h"
    +
    +int test__demangle_java(struct test *test __maybe_unused, int subtest __maybe_unused)
    +{
    + int ret = TEST_OK;
    + char *buf = NULL;
    + size_t i;
    +
    + struct {
    + const char *mangled, *demangled;
    + } test_cases[] = {
    + { "Ljava/lang/StringLatin1;equals([B[B)Z",
    + "boolean java.lang.StringLatin1.equals(byte[], byte[])" },
    + { "Ljava/util/zip/ZipUtils;CENSIZ([BI)J",
    + "long java.util.zip.ZipUtils.CENSIZ(byte[], int)" },
    + { "Ljava/util/regex/Pattern$BmpCharProperty;match(Ljava/util/regex/Matcher;ILjava/lang/CharSequence;)Z",
    + "boolean java.util.regex.Pattern$BmpCharProperty.match(java.util.regex.Matcher, int, java.lang.CharSequence)" },
    + { "Ljava/lang/AbstractStringBuilder;appendChars(Ljava/lang/String;II)V",
    + "void java.lang.AbstractStringBuilder.appendChars(java.lang.String, int, int)" },
    + { "Ljava/lang/Object;<init>()V",
    + "void java.lang.Object<init>()" },
    + };
    +
    + for (i = 0; i < sizeof(test_cases) / sizeof(test_cases[0]); i++) {
    + buf = java_demangle_sym(test_cases[i].mangled, 0);
    + if (strcmp(buf, test_cases[i].demangled)) {
    + pr_debug("FAILED: %s: %s != %s\n", test_cases[i].mangled,
    + buf, test_cases[i].demangled);
    + ret = TEST_FAIL;
    + }
    + free(buf);
    + }
    +
    + return ret;
    +}
    diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
    index 9a160fef47c9..49b791d978f6 100644
    --- a/tools/perf/tests/tests.h
    +++ b/tools/perf/tests/tests.h
    @@ -111,6 +111,7 @@ int test__mem2node(struct test *t, int subtest);
    int test__maps__merge_in(struct test *t, int subtest);
    int test__time_utils(struct test *t, int subtest);
    int test__jit_write_elf(struct test *test, int subtest);
    +int test__demangle_java(struct test *test, int subtest);

    bool test__bp_signal_is_supported(void);
    bool test__bp_account_is_supported(void);
    diff --git a/tools/perf/util/demangle-java.c b/tools/perf/util/demangle-java.c
    index 6fb7f34c0814..39c05200ed65 100644
    --- a/tools/perf/util/demangle-java.c
    +++ b/tools/perf/util/demangle-java.c
    @@ -15,7 +15,7 @@ enum {
    MODE_CLASS = 1,
    MODE_FUNC = 2,
    MODE_TYPE = 3,
    - MODE_CTYPE = 3, /* class arg */
    + MODE_CTYPE = 4, /* class arg */
    };

    #define BASE_ENT(c, n) [c - 'A']=n
    @@ -27,7 +27,7 @@ static const char *base_types['Z' - 'A' + 1] = {
    BASE_ENT('I', "int" ),
    BASE_ENT('J', "long" ),
    BASE_ENT('S', "short" ),
    - BASE_ENT('Z', "bool" ),
    + BASE_ENT('Z', "boolean" ),
    };

    /*
    @@ -59,15 +59,16 @@ __demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int

    switch (*q) {
    case 'L':
    - if (mode == MODE_PREFIX || mode == MODE_CTYPE) {
    - if (mode == MODE_CTYPE) {
    + if (mode == MODE_PREFIX || mode == MODE_TYPE) {
    + if (mode == MODE_TYPE) {
    if (narg)
    rlen += scnprintf(buf + rlen, maxlen - rlen, ", ");
    narg++;
    }
    - rlen += scnprintf(buf + rlen, maxlen - rlen, "class ");
    if (mode == MODE_PREFIX)
    mode = MODE_CLASS;
    + else
    + mode = MODE_CTYPE;
    } else
    buf[rlen++] = *q;
    break;
    @@ -120,7 +121,7 @@ __demangle_java_sym(const char *str, const char *end, char *buf, int maxlen, int
    if (mode != MODE_CLASS && mode != MODE_CTYPE)
    goto error;
    /* safe because at least one other char to process */
    - if (isalpha(*(q + 1)))
    + if (isalpha(*(q + 1)) && mode == MODE_CLASS)
    rlen += scnprintf(buf + rlen, maxlen - rlen, ".");
    if (mode == MODE_CLASS)
    mode = MODE_FUNC;
    --
    2.26.1
    \
     
     \ /
      Last update: 2020-04-27 08:17    [W:2.915 / U:0.048 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site