nashorn/src/jdk.scripting.nashorn/share/classes/jdk/internal/dynalink/support/NameCodec.java
changeset 33864 009bfc0f3666
parent 33863 b29c231e0949
parent 33650 c99ead4a890b
child 33865 d5d2d1a08a71
equal deleted inserted replaced
33863:b29c231e0949 33864:009bfc0f3666
     1 /*
       
     2  * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 /*
       
    27  * This file is available under and governed by the GNU General Public
       
    28  * License version 2 only, as published by the Free Software Foundation.
       
    29  * However, the following notice accompanied the original version of this
       
    30  * file, and Oracle licenses the original version of this file under the BSD
       
    31  * license:
       
    32  */
       
    33 /*
       
    34    Copyright 2009-2013 Attila Szegedi
       
    35 
       
    36    Licensed under both the Apache License, Version 2.0 (the "Apache License")
       
    37    and the BSD License (the "BSD License"), with licensee being free to
       
    38    choose either of the two at their discretion.
       
    39 
       
    40    You may not use this file except in compliance with either the Apache
       
    41    License or the BSD License.
       
    42 
       
    43    If you choose to use this file in compliance with the Apache License, the
       
    44    following notice applies to you:
       
    45 
       
    46        You may obtain a copy of the Apache License at
       
    47 
       
    48            http://www.apache.org/licenses/LICENSE-2.0
       
    49 
       
    50        Unless required by applicable law or agreed to in writing, software
       
    51        distributed under the License is distributed on an "AS IS" BASIS,
       
    52        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
       
    53        implied. See the License for the specific language governing
       
    54        permissions and limitations under the License.
       
    55 
       
    56    If you choose to use this file in compliance with the BSD License, the
       
    57    following notice applies to you:
       
    58 
       
    59        Redistribution and use in source and binary forms, with or without
       
    60        modification, are permitted provided that the following conditions are
       
    61        met:
       
    62        * Redistributions of source code must retain the above copyright
       
    63          notice, this list of conditions and the following disclaimer.
       
    64        * Redistributions in binary form must reproduce the above copyright
       
    65          notice, this list of conditions and the following disclaimer in the
       
    66          documentation and/or other materials provided with the distribution.
       
    67        * Neither the name of the copyright holder nor the names of
       
    68          contributors may be used to endorse or promote products derived from
       
    69          this software without specific prior written permission.
       
    70 
       
    71        THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
       
    72        IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
       
    73        TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
       
    74        PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER
       
    75        BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
       
    76        CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
       
    77        SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
       
    78        BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
       
    79        WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
       
    80        OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
       
    81        ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    82 */
       
    83 
       
    84 package jdk.internal.dynalink.support;
       
    85 
       
    86 
       
    87 /**
       
    88  * Implements the name mangling and demangling as specified by John Rose's
       
    89  * <a href="https://blogs.oracle.com/jrose/entry/symbolic_freedom_in_the_vm"
       
    90  * target="_blank">"Symbolic Freedom in the VM"</a> article. Normally, you would
       
    91  * mangle the names in the call sites as you're generating bytecode, and then
       
    92  * demangle them when you receive them in bootstrap methods.
       
    93  */
       
    94 public final class NameCodec {
       
    95     private static final char ESCAPE_CHAR = '\\';
       
    96     private static final char EMPTY_ESCAPE = '=';
       
    97     private static final String EMPTY_NAME = new String(new char[] { ESCAPE_CHAR, EMPTY_ESCAPE });
       
    98     private static final char EMPTY_CHAR = 0xFEFF;
       
    99 
       
   100     private static final int MIN_ENCODING = '$';
       
   101     private static final int MAX_ENCODING = ']';
       
   102     private static final char[] ENCODING = new char[MAX_ENCODING - MIN_ENCODING + 1];
       
   103     private static final int MIN_DECODING = '!';
       
   104     private static final int MAX_DECODING = '}';
       
   105     private static final char[] DECODING = new char[MAX_DECODING - MIN_DECODING + 1];
       
   106 
       
   107     static {
       
   108         addEncoding('/', '|');
       
   109         addEncoding('.', ',');
       
   110         addEncoding(';', '?');
       
   111         addEncoding('$', '%');
       
   112         addEncoding('<', '^');
       
   113         addEncoding('>', '_');
       
   114         addEncoding('[', '{');
       
   115         addEncoding(']', '}');
       
   116         addEncoding(':', '!');
       
   117         addEncoding('\\', '-');
       
   118         DECODING[EMPTY_ESCAPE - MIN_DECODING] = EMPTY_CHAR;
       
   119     }
       
   120 
       
   121     private NameCodec() {
       
   122     }
       
   123 
       
   124     /**
       
   125      * Encodes ("mangles") an unencoded symbolic name.
       
   126      * @param name the symbolic name to mangle
       
   127      * @return the mangled form of the symbolic name.
       
   128      */
       
   129     public static String encode(final String name) {
       
   130         final int l = name.length();
       
   131         if(l == 0) {
       
   132             return EMPTY_NAME;
       
   133         }
       
   134         StringBuilder b = null;
       
   135         int lastEscape = -1;
       
   136         for(int i = 0; i < l; ++i) {
       
   137             final int encodeIndex = name.charAt(i) - MIN_ENCODING;
       
   138             if(encodeIndex >= 0 && encodeIndex < ENCODING.length) {
       
   139                 final char e = ENCODING[encodeIndex];
       
   140                 if(e != 0) {
       
   141                     if(b == null) {
       
   142                         b = new StringBuilder(name.length() + 3);
       
   143                         if(name.charAt(0) != ESCAPE_CHAR && i > 0) {
       
   144                             b.append(EMPTY_NAME);
       
   145                         }
       
   146                         b.append(name, 0, i);
       
   147                     } else {
       
   148                         b.append(name, lastEscape + 1, i);
       
   149                     }
       
   150                     b.append(ESCAPE_CHAR).append(e);
       
   151                     lastEscape = i;
       
   152                 }
       
   153             }
       
   154         }
       
   155         if(b == null) {
       
   156             return name;
       
   157         }
       
   158         assert lastEscape != -1;
       
   159         b.append(name, lastEscape + 1, l);
       
   160         return b.toString();
       
   161     }
       
   162 
       
   163     /**
       
   164      * Decodes ("demangles") an encoded symbolic name.
       
   165      * @param name the symbolic name to demangle
       
   166      * @return the demangled form of the symbolic name.
       
   167      */
       
   168     public static String decode(final String name) {
       
   169         if(name.isEmpty() || name.charAt(0) != ESCAPE_CHAR) {
       
   170             return name;
       
   171         }
       
   172         final int l = name.length();
       
   173         if(l == 2 && name.charAt(1) == EMPTY_CHAR) {
       
   174             return "";
       
   175         }
       
   176         final StringBuilder b = new StringBuilder(name.length());
       
   177         int lastEscape = -2;
       
   178         int lastBackslash = -1;
       
   179         for(;;) {
       
   180             final int nextBackslash = name.indexOf(ESCAPE_CHAR, lastBackslash + 1);
       
   181             if(nextBackslash == -1 || nextBackslash == l - 1) {
       
   182                 break;
       
   183             }
       
   184             final int decodeIndex = name.charAt(nextBackslash + 1) - MIN_DECODING;
       
   185             if(decodeIndex >= 0 && decodeIndex < DECODING.length) {
       
   186                 final char d = DECODING[decodeIndex];
       
   187                 if(d == EMPTY_CHAR) {
       
   188                     // "\=" is only valid at the beginning of a mangled string
       
   189                     if(nextBackslash == 0) {
       
   190                         lastEscape = 0;
       
   191                     }
       
   192                 } else if(d != 0) {
       
   193                     b.append(name, lastEscape + 2, nextBackslash).append(d);
       
   194                     lastEscape = nextBackslash;
       
   195                 }
       
   196             }
       
   197             lastBackslash = nextBackslash;
       
   198         }
       
   199         b.append(name, lastEscape + 2, l);
       
   200         return b.toString();
       
   201     }
       
   202 
       
   203     private static void addEncoding(final char from, final char to) {
       
   204         ENCODING[from - MIN_ENCODING] = to;
       
   205         DECODING[to - MIN_DECODING] = from;
       
   206     }
       
   207 }