1 /*
   2  * Permission is hereby granted, free of charge, to any person obtaining a copy of
   3  * this software and associated documentation files (the "Software"), to deal in
   4  * the Software without restriction, including without limitation the rights to
   5  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
   6  * of the Software, and to permit persons to whom the Software is furnished to do
   7  * so, subject to the following conditions:
   8  *
   9  * The above copyright notice and this permission notice shall be included in all
  10  * copies or substantial portions of the Software.
  11  *
  12  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  18  * SOFTWARE.
  19  */
  20 package jdk.nashorn.internal.runtime.regexp.joni;
  21 
  22 import jdk.nashorn.internal.runtime.regexp.joni.ast.CClassNode;
  23 import jdk.nashorn.internal.runtime.regexp.joni.constants.Arguments;
  24 import jdk.nashorn.internal.runtime.regexp.joni.constants.OPCode;
  25 import jdk.nashorn.internal.runtime.regexp.joni.constants.OPSize;
  26 import jdk.nashorn.internal.runtime.regexp.joni.exception.InternalException;
  27 
  28 class ByteCodePrinter {
  29     final int[]code;
  30     final int codeLength;
  31     final char[][] templates;
  32 
  33     Object[]operands;
  34     int operantCount;
  35     WarnCallback warnings;
  36 
  37     public ByteCodePrinter(Regex regex) {
  38         code = regex.code;
  39         codeLength = regex.codeLength;
  40         operands = regex.operands;
  41         operantCount = regex.operandLength;
  42 
  43         templates = regex.templates;
  44         warnings = regex.warnings;
  45     }
  46 
  47     public String byteCodeListToString() {
  48         return compiledByteCodeListToString();
  49     }
  50 
  51     private void pString(StringBuilder sb, int len, int s) {
  52         sb.append(":");
  53         while (len-- > 0) sb.append(new String(new byte[]{(byte)code[s++]}));
  54     }
  55 
  56     private void pStringFromTemplate(StringBuilder sb, int len, byte[]tm, int idx) {
  57         sb.append(":T:");
  58         while (len-- > 0) sb.append(new String(new byte[]{tm[idx++]}));
  59     }
  60 
  61     private void pLenString(StringBuilder sb, int len, int mbLen, int s) {
  62         int x = len * mbLen;
  63         sb.append(":" + len + ":");
  64         while (x-- > 0) sb.append(new String(new byte[]{(byte)code[s++]}));
  65     }
  66 
  67     private void pLenStringFromTemplate(StringBuilder sb, int len, int mbLen, char[] tm, int idx) {
  68         int x = len * mbLen;
  69         sb.append(":T:" + len + ":");
  70         while (x-- > 0) sb.append(new String(new byte[]{(byte)tm[idx++]}));
  71     }
  72 
  73     public int compiledByteCodeToString(StringBuilder sb, int bp) {
  74         int len, n, mem, addr, scn, cod;
  75         BitSet bs;
  76         CClassNode cc;
  77         int tm, idx;
  78 
  79         sb.append("[" + OPCode.OpCodeNames[code[bp]]);
  80         int argType = OPCode.OpCodeArgTypes[code[bp]];
  81         int ip = bp;
  82         if (argType != Arguments.SPECIAL) {
  83             bp++;
  84             switch (argType) {
  85             case Arguments.NON:
  86                 break;
  87 
  88             case Arguments.RELADDR:
  89                 sb.append(":(" + code[bp] + ")");
  90                 bp += OPSize.RELADDR;
  91                 break;
  92 
  93             case Arguments.ABSADDR:
  94                 sb.append(":(" + code[bp] + ")");
  95                 bp += OPSize.ABSADDR;
  96                 break;
  97 
  98             case Arguments.LENGTH:
  99                 sb.append(":" + code[bp]);
 100                 bp += OPSize.LENGTH;
 101                 break;
 102 
 103             case Arguments.MEMNUM:
 104                 sb.append(":" + code[bp]);
 105                 bp += OPSize.MEMNUM;
 106                 break;
 107 
 108             case Arguments.OPTION:
 109                 sb.append(":" + code[bp]);
 110                 bp += OPSize.OPTION;
 111                 break;
 112 
 113             case Arguments.STATE_CHECK:
 114                 sb.append(":" + code[bp]);
 115                 bp += OPSize.STATE_CHECK;
 116                 break;
 117             }
 118         } else {
 119             switch (code[bp++]) {
 120             case OPCode.EXACT1:
 121             case OPCode.ANYCHAR_STAR_PEEK_NEXT:
 122             case OPCode.ANYCHAR_ML_STAR_PEEK_NEXT:
 123             case OPCode.ANYCHAR_STAR_PEEK_NEXT_SB:
 124             case OPCode.ANYCHAR_ML_STAR_PEEK_NEXT_SB:
 125                 pString(sb, 1, bp++);
 126                 break;
 127 
 128             case OPCode.EXACT2:
 129                 pString(sb, 2, bp);
 130                 bp += 2;
 131                 break;
 132 
 133             case OPCode.EXACT3:
 134                 pString(sb, 3, bp);
 135                 bp += 3;
 136                 break;
 137 
 138             case OPCode.EXACT4:
 139                 pString(sb, 4, bp);
 140                 bp += 4;
 141                 break;
 142 
 143             case OPCode.EXACT5:
 144                 pString(sb, 5, bp);
 145                 bp += 5;
 146                 break;
 147 
 148             case OPCode.EXACTN:
 149                 len = code[bp];
 150                 bp += OPSize.LENGTH;
 151                 if (Config.USE_STRING_TEMPLATES) {
 152                     tm = code[bp];
 153                     bp += OPSize.INDEX;
 154                     idx = code[bp];
 155                     bp += OPSize.INDEX;
 156                     pLenStringFromTemplate(sb, len, 1, templates[tm], idx);
 157                 } else {
 158                     pLenString(sb, len, 1, bp);
 159                     bp += len;
 160                 }
 161                 break;
 162 
 163             case OPCode.EXACTMB2N1:
 164                 pString(sb, 2, bp);
 165                 bp += 2;
 166                 break;
 167 
 168             case OPCode.EXACTMB2N2:
 169                 pString(sb, 4, bp);
 170                 bp += 4;
 171                 break;
 172 
 173             case OPCode.EXACTMB2N3:
 174                 pString(sb, 6, bp);
 175                 bp += 6;
 176                 break;
 177 
 178             case OPCode.EXACTMB2N:
 179                 len = code[bp];
 180                 bp += OPSize.LENGTH;
 181                 if (Config.USE_STRING_TEMPLATES) {
 182                     tm = code[bp];
 183                     bp += OPSize.INDEX;
 184                     idx = code[bp];
 185                     bp += OPSize.INDEX;
 186                     pLenStringFromTemplate(sb, len, 2, templates[tm], idx);
 187                 } else {
 188                     pLenString(sb, len, 2, bp);
 189                     bp += len * 2;
 190                 }
 191                 break;
 192 
 193             case OPCode.EXACTMB3N:
 194                 len = code[bp];
 195                 bp += OPSize.LENGTH;
 196                 if (Config.USE_STRING_TEMPLATES) {
 197                     tm = code[bp];
 198                     bp += OPSize.INDEX;
 199                     idx = code[bp];
 200                     bp += OPSize.INDEX;
 201                     pLenStringFromTemplate(sb, len, 3, templates[tm], idx);
 202                 } else {
 203                     pLenString(sb, len, 3, bp);
 204                     bp += len * 3;
 205                 }
 206                 break;
 207 
 208             case OPCode.EXACTMBN:
 209                 int mbLen = code[bp];
 210                 bp += OPSize.LENGTH;
 211                 len = code[bp];
 212                 bp += OPSize.LENGTH;
 213                 n = len * mbLen;
 214 
 215                 if (Config.USE_STRING_TEMPLATES) {
 216                     tm = code[bp];
 217                     bp += OPSize.INDEX;
 218                     idx = code[bp];
 219                     bp += OPSize.INDEX;
 220                     sb.append(":T:" + mbLen + ":" + len + ":");
 221 
 222                     while (n-- > 0) sb.append(new String(new char[]{templates[tm][idx++]}));
 223                 } else {
 224                     sb.append(":" + mbLen + ":" + len + ":");
 225 
 226                     while (n-- > 0) sb.append(new String(new byte[]{(byte)code[bp++]}));
 227                 }
 228 
 229                 break;
 230 
 231             case OPCode.EXACT1_IC:
 232             case OPCode.EXACT1_IC_SB:
 233                 final int MAX_CHAR_LENGTH = 6;
 234                 byte[]bytes = new byte[MAX_CHAR_LENGTH];
 235                 for (int i = 0; bp + i < code.length && i < MAX_CHAR_LENGTH; i++) bytes[i] = (byte)code[bp + i];
 236                 pString(sb, 1, bp);
 237                 bp++;
 238                 break;
 239 
 240             case OPCode.EXACTN_IC:
 241             case OPCode.EXACTN_IC_SB:
 242                 len = code[bp];
 243                 bp += OPSize.LENGTH;
 244                 if (Config.USE_STRING_TEMPLATES) {
 245                     tm = code[bp];
 246                     bp += OPSize.INDEX;
 247                     idx = code[bp];
 248                     bp += OPSize.INDEX;
 249                     pLenStringFromTemplate(sb, len, 1, templates[tm], idx);
 250                 } else {
 251                     pLenString(sb, len, 1, bp);
 252                     bp += len;
 253                 }
 254                 break;
 255 
 256             case OPCode.CCLASS:
 257             case OPCode.CCLASS_SB:
 258                 bs = new BitSet();
 259                 System.arraycopy(code, bp, bs.bits, 0, BitSet.BITSET_SIZE);
 260                 n = bs.numOn();
 261                 bp += BitSet.BITSET_SIZE;
 262                 sb.append(":" + n);
 263                 break;
 264 
 265             case OPCode.CCLASS_NOT:
 266             case OPCode.CCLASS_NOT_SB:
 267                 bs = new BitSet();
 268                 System.arraycopy(code, bp, bs.bits, 0, BitSet.BITSET_SIZE);
 269                 n = bs.numOn();
 270                 bp += BitSet.BITSET_SIZE;
 271                 sb.append(":" + n);
 272                 break;
 273 
 274             case OPCode.CCLASS_MB:
 275             case OPCode.CCLASS_MB_NOT:
 276                 len = code[bp];
 277                 bp += OPSize.LENGTH;
 278                 cod = code[bp];
 279                 //bp += OPSize.CODE_POINT;
 280                 bp += len;
 281                 sb.append(":" + cod + ":" + len);
 282                 break;
 283 
 284             case OPCode.CCLASS_MIX:
 285             case OPCode.CCLASS_MIX_NOT:
 286                 bs = new BitSet();
 287                 System.arraycopy(code, bp, bs.bits, 0, BitSet.BITSET_SIZE);
 288                 n = bs.numOn();
 289                 bp += BitSet.BITSET_SIZE;
 290                 len = code[bp];
 291                 bp += OPSize.LENGTH;
 292                 cod = code[bp];
 293                 //bp += OPSize.CODE_POINT;
 294                 bp += len;
 295                 sb.append(":" + n + ":" + cod + ":" + len);
 296                 break;
 297 
 298             case OPCode.CCLASS_NODE:
 299                 cc = (CClassNode)operands[code[bp]];
 300                 bp += OPSize.POINTER;
 301                 n = cc.bs.numOn();
 302                 sb.append(":" + cc + ":" + n);
 303                 break;
 304 
 305             case OPCode.BACKREFN_IC:
 306                 mem = code[bp];
 307                 bp += OPSize.MEMNUM;
 308                 sb.append(":" + mem);
 309                 break;
 310 
 311             case OPCode.BACKREF_MULTI_IC:
 312             case OPCode.BACKREF_MULTI:
 313                 sb.append(" ");
 314                 len = code[bp];
 315                 bp += OPSize.LENGTH;
 316                 for (int i=0; i<len; i++) {
 317                     mem = code[bp];
 318                     bp += OPSize.MEMNUM;
 319                     if (i > 0) sb.append(", ");
 320                     sb.append(mem);
 321                 }
 322                 break;
 323 
 324             case OPCode.BACKREF_WITH_LEVEL: {
 325                 int option = code[bp];
 326                 bp += OPSize.OPTION;
 327                 sb.append(":" + option);
 328                 int level = code[bp];
 329                 bp += OPSize.LENGTH;
 330                 sb.append(":" + level);
 331                 sb.append(" ");
 332                 len = code[bp];
 333                 bp += OPSize.LENGTH;
 334                 for (int i=0; i<len; i++) {
 335                     mem = code[bp];
 336                     bp += OPSize.MEMNUM;
 337                     if (i > 0) sb.append(", ");
 338                     sb.append(mem);
 339                 }
 340                 break;
 341             }
 342 
 343             case OPCode.REPEAT:
 344             case OPCode.REPEAT_NG:
 345                 mem = code[bp];
 346                 bp += OPSize.MEMNUM;
 347                 addr = code[bp];
 348                 bp += OPSize.RELADDR;
 349                 sb.append(":" + mem + ":" + addr);
 350                 break;
 351 
 352             case OPCode.PUSH_OR_JUMP_EXACT1:
 353             case OPCode.PUSH_IF_PEEK_NEXT:
 354                 addr = code[bp];
 355                 bp += OPSize.RELADDR;
 356                 sb.append(":(" + addr + ")");
 357                 pString(sb, 1, bp);
 358                 bp++;
 359                 break;
 360 
 361             case OPCode.LOOK_BEHIND:
 362             case OPCode.LOOK_BEHIND_SB:
 363                 len = code[bp];
 364                 bp += OPSize.LENGTH;
 365                 sb.append(":" + len);
 366                 break;
 367 
 368             case OPCode.PUSH_LOOK_BEHIND_NOT:
 369                 addr = code[bp];
 370                 bp += OPSize.RELADDR;
 371                 len = code[bp];
 372                 bp += OPSize.LENGTH;
 373                 sb.append(":" + len + ":(" + addr + ")");
 374                 break;
 375 
 376             case OPCode.STATE_CHECK_PUSH:
 377             case OPCode.STATE_CHECK_PUSH_OR_JUMP:
 378                 scn = code[bp];
 379                 bp += OPSize.STATE_CHECK_NUM;
 380                 addr = code[bp];
 381                 bp += OPSize.RELADDR;
 382                 sb.append(":" + scn + ":(" + addr + ")");
 383                 break;
 384 
 385             default:
 386                 throw new InternalException("undefined code: " + code[--bp]);
 387             }
 388         }
 389 
 390         sb.append("]");
 391 
 392         // @opcode_address(opcode_size)
 393         if (Config.DEBUG_COMPILE_BYTE_CODE_INFO) sb.append("@" + ip + "(" + (bp - ip) + ")");
 394 
 395         return bp;
 396     }
 397 
 398     private String compiledByteCodeListToString() {
 399         StringBuilder sb = new StringBuilder();
 400         sb.append("code length: " + codeLength + "\n");
 401 
 402         int ncode = 0;
 403         int bp = 0;
 404         int end = codeLength;
 405 
 406         while (bp < end) {
 407             ncode++;
 408 
 409             if (bp > 0) sb.append(ncode % 5 == 0 ? "\n" : " ");
 410 
 411             bp = compiledByteCodeToString(sb, bp);
 412         }
 413         sb.append("\n");
 414         return sb.toString();
 415     }
 416 }