1 /* 2 * Copyright (c) 2017, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package jdk.experimental.bytecode; 25 26 import java.lang.invoke.MethodHandleInfo; 27 import java.util.ArrayList; 28 import java.util.List; 29 import java.util.Objects; 30 import java.util.function.Consumer; 31 import java.util.function.Function; 32 import java.util.function.ToIntBiFunction; 33 34 /** 35 * A helper for building and tracking constant pools whose entries are 36 * represented as byte arrays. 37 * 38 * @param <S> the type of the symbol representation 39 * @param <T> the type of type descriptors representation 40 */ 41 public class BytePoolHelper<S, T> implements PoolHelper<S, T, byte[]> { 42 43 GrowableByteBuffer pool = new GrowableByteBuffer(); 44 GrowableByteBuffer bsm_attr = new GrowableByteBuffer(); 45 //Map<PoolKey, PoolKey> indicesMap = new HashMap<>(); 46 int currentIndex = 1; 47 int currentBsmIndex = 0; 48 49 KeyMap<PoolKey> entries = new KeyMap<>(); 50 KeyMap<BsmKey> bootstraps = new KeyMap<>(); 51 PoolKey key = new PoolKey(); 52 BsmKey bsmKey = new BsmKey(); 53 54 Function<S, String> symbolToString; 55 Function<T, String> typeToString; 56 57 public BytePoolHelper(Function<S, String> symbolToString, Function<T, String> typeToString) { 58 this.symbolToString = symbolToString; 59 this.typeToString = typeToString; 60 } 61 62 static class KeyMap<K extends AbstractKey<K>> { 63 64 @SuppressWarnings("unchecked") 65 K[] table = (K[])new AbstractKey<?>[0x10]; 66 int nelems; 67 68 public void enter(K e) { 69 if (nelems * 3 >= (table.length - 1) * 2) 70 dble(); 71 int hash = getIndex(e); 72 K old = table[hash]; 73 if (old == null) { 74 nelems++; 75 } 76 e.next = old; 77 table[hash] = e; 78 } 79 80 protected K lookup(K other) { 81 K e = table[getIndex(other)]; 82 while (e != null && !e.equals(other)) 83 e = e.next; 84 return e; 85 } 86 87 /** 88 * Look for slot in the table. 89 * We use open addressing with double hashing. 90 */ 91 int getIndex(K e) { 92 int hashMask = table.length - 1; 93 int h = e.hashCode(); 94 int i = h & hashMask; 95 // The expression below is always odd, so it is guaranteed 96 // to be mutually prime with table.length, a power of 2. 97 int x = hashMask - ((h + (h >> 16)) << 1); 98 for (; ; ) { 99 K e2 = table[i]; 100 if (e2 == null) 101 return i; 102 else if (e.hash == e2.hash) 103 return i; 104 i = (i + x) & hashMask; 105 } 106 } 107 108 @SuppressWarnings("unchecked") 109 private void dble() { 110 K[] oldtable = table; 111 table = (K[])new AbstractKey<?>[oldtable.length * 2]; 112 int n = 0; 113 for (int i = oldtable.length; --i >= 0; ) { 114 K e = oldtable[i]; 115 if (e != null) { 116 table[getIndex(e)] = e; 117 n++; 118 } 119 } 120 // We don't need to update nelems for shared inherited scopes, 121 // since that gets handled by leave(). 122 nelems = n; 123 } 124 } 125 126 public static abstract class AbstractKey<K extends AbstractKey<K>> { 127 int hash; 128 int index = -1; 129 K next; 130 131 abstract K dup(); 132 133 public abstract boolean equals(Object o); 134 135 @Override 136 public int hashCode() { 137 return hash; 138 } 139 140 void at(int index) { 141 this.index = index; 142 } 143 } 144 145 public static class PoolKey extends AbstractKey<PoolKey> { 146 PoolTag tag; 147 Object o1; 148 Object o2; 149 Object o3; 150 Object o4; 151 int size = -1; 152 153 void setUtf8(CharSequence s) { 154 tag = PoolTag.CONSTANT_UTF8; 155 o1 = s; 156 size = 1; 157 hash = tag.tag | (s.hashCode() << 1); 158 } 159 160 void setClass(String clazz) { 161 tag = PoolTag.CONSTANT_CLASS; 162 o1 = clazz; 163 size = 1; 164 hash = tag.tag | (clazz.hashCode() << 1); 165 } 166 167 void setNameAndType(CharSequence name, String type) { 168 tag = PoolTag.CONSTANT_NAMEANDTYPE; 169 o1 = name; 170 o2 = type; 171 size = 2; 172 hash = tag.tag | ((name.hashCode() | type.hashCode()) << 1); 173 } 174 175 void setMemberRef(PoolTag poolTag, String owner, CharSequence name, String type) { 176 tag = poolTag; 177 o1 = owner; 178 o2 = name; 179 o3 = type; 180 size = 3; 181 hash = tag.tag | ((owner.hashCode() | name.hashCode() | type.hashCode()) << 1); 182 } 183 184 void setInvokeDynamic(int bsmIndex, CharSequence name, String type) { 185 tag = PoolTag.CONSTANT_INVOKEDYNAMIC; 186 o1 = bsmIndex; 187 o2 = name; 188 o3 = type; 189 size = 3; 190 hash = tag.tag | ((bsmIndex | name.hashCode() | type.hashCode()) << 1); 191 } 192 193 void setDynamicConstant(int bsmIndex, CharSequence name, String type) { 194 tag = PoolTag.CONSTANT_DYNAMIC; 195 o1 = bsmIndex; 196 o2 = name; 197 o3 = type; 198 size = 3; 199 hash = tag.tag | ((bsmIndex | name.hashCode() | type.hashCode()) << 1); 200 } 201 202 void setString(String s) { 203 tag = PoolTag.CONSTANT_STRING; 204 o1 = s; 205 size = 1; 206 hash = tag.tag | (s.hashCode() << 1); 207 } 208 209 void setInteger(Integer i) { 210 tag = PoolTag.CONSTANT_INTEGER; 211 o1 = i; 212 size = 1; 213 hash = tag.tag | (i.hashCode() << 1); 214 } 215 216 void setFloat(Float f) { 217 tag = PoolTag.CONSTANT_FLOAT; 218 o1 = f; 219 size = 1; 220 hash = tag.tag | (f.hashCode() << 1); 221 } 222 223 void setLong(Long l) { 224 tag = PoolTag.CONSTANT_LONG; 225 o1 = l; 226 size = 1; 227 hash = tag.tag | (l.hashCode() << 1); 228 } 229 230 void setDouble(Double d) { 231 tag = PoolTag.CONSTANT_DOUBLE; 232 o1 = d; 233 size = 1; 234 hash = tag.tag | (d.hashCode() << 1); 235 } 236 237 void setMethodType(String type) { 238 tag = PoolTag.CONSTANT_METHODTYPE; 239 o1 = type; 240 size = 1; 241 hash = tag.tag | (type.hashCode() << 1); 242 } 243 244 void setMethodHandle(int bsmKind, String owner, CharSequence name, String type) { 245 tag = PoolTag.CONSTANT_METHODHANDLE; 246 o1 = bsmKind; 247 o2 = owner; 248 o3 = name; 249 o4 = type; 250 size = 4; 251 hash = tag.tag | (bsmKind | owner.hashCode() | name.hashCode() | type.hashCode() << 1); 252 } 253 254 @Override 255 public boolean equals(Object obj) { 256 PoolKey that = (PoolKey) obj; 257 if (tag != that.tag) return false; 258 switch (size) { 259 case 1: 260 if (!o1.equals(that.o1)) { 261 return false; 262 } 263 break; 264 case 2: 265 if (!o2.equals(that.o2) || !o1.equals(that.o1)) { 266 return false; 267 } 268 break; 269 case 3: 270 if (!o3.equals(that.o3) || !o2.equals(that.o2) || !o1.equals(that.o1)) { 271 return false; 272 } 273 break; 274 case 4: 275 if (!o4.equals(that.o4) || !o3.equals(that.o3) || !o2.equals(that.o2) || !o1.equals(that.o1)) { 276 return false; 277 } 278 break; 279 } 280 return true; 281 } 282 283 PoolKey dup() { 284 PoolKey poolKey = new PoolKey(); 285 poolKey.tag = tag; 286 poolKey.size = size; 287 poolKey.hash = hash; 288 poolKey.o1 = o1; 289 poolKey.o2 = o2; 290 poolKey.o3 = o3; 291 poolKey.o4 = o4; 292 return poolKey; 293 } 294 } 295 296 static class BsmKey extends AbstractKey<BsmKey> { 297 String bsmClass; 298 CharSequence bsmName; 299 String bsmType; 300 List<Integer> bsmArgs; 301 302 void set(String bsmClass, CharSequence bsmName, String bsmType, List<Integer> bsmArgs) { 303 this.bsmClass = bsmClass; 304 this.bsmName = bsmName; 305 this.bsmType = bsmType; 306 this.bsmArgs = bsmArgs; 307 hash = bsmClass.hashCode() | bsmName.hashCode() | bsmType.hashCode() | Objects.hash(bsmArgs); 308 } 309 310 BsmKey dup() { 311 BsmKey bsmKey = new BsmKey(); 312 bsmKey.bsmClass = bsmClass; 313 bsmKey.bsmName = bsmName; 314 bsmKey.bsmType = bsmType; 315 bsmKey.bsmArgs = bsmArgs; 316 bsmKey.hash = hash; 317 return bsmKey; 318 } 319 320 @Override 321 public boolean equals(Object obj) { 322 if (obj instanceof BsmKey) { 323 BsmKey that = (BsmKey)obj; 324 return Objects.equals(bsmClass, that.bsmClass) && 325 Objects.equals(bsmName, that.bsmName) && 326 Objects.equals(bsmType, that.bsmType) && 327 Objects.deepEquals(bsmArgs, that.bsmArgs); 328 } else { 329 return false; 330 } 331 } 332 } 333 334 @Override 335 public int putClass(S symbol) { 336 return putClassInternal(symbolToString.apply(symbol)); 337 } 338 339 private int putClassInternal(String symbol) { 340 key.setClass(symbol); 341 PoolKey poolKey = entries.lookup(key); 342 if (poolKey == null) { 343 poolKey = key.dup(); 344 int utf8_idx = putUtf8(symbol); 345 poolKey.at(currentIndex++); 346 entries.enter(poolKey); 347 pool.writeByte(PoolTag.CONSTANT_CLASS.tag); 348 pool.writeChar(utf8_idx); 349 } 350 return poolKey.index; 351 } 352 353 @Override 354 public int putFieldRef(S owner, CharSequence name, T type) { 355 return putMemberRef(PoolTag.CONSTANT_FIELDREF, owner, name, type); 356 } 357 358 @Override 359 public int putMethodRef(S owner, CharSequence name, T type, boolean isInterface) { 360 return putMemberRef(isInterface ? PoolTag.CONSTANT_INTERFACEMETHODREF : PoolTag.CONSTANT_METHODREF, 361 owner, name, type); 362 } 363 364 int putMemberRef(PoolTag poolTag, S owner, CharSequence name, T type) { 365 return putMemberRefInternal(poolTag, symbolToString.apply(owner), name, typeToString.apply(type)); 366 } 367 368 int putMemberRefInternal(PoolTag poolTag, String owner, CharSequence name, String type) { 369 key.setMemberRef(poolTag, owner, name, type); 370 PoolKey poolKey = entries.lookup(key); 371 if (poolKey == null) { 372 poolKey = key.dup(); 373 int owner_idx = putClassInternal(owner); 374 int nameAndType_idx = putNameAndType(name, type); 375 poolKey.at(currentIndex++); 376 entries.enter(poolKey); 377 pool.writeByte(poolTag.tag); 378 pool.writeChar(owner_idx); 379 pool.writeChar(nameAndType_idx); 380 } 381 return poolKey.index; 382 } 383 384 @Override 385 public int putInt(int i) { 386 key.setInteger(i); 387 PoolKey poolKey = entries.lookup(key); 388 if (poolKey == null) { 389 poolKey = key.dup(); 390 poolKey.at(currentIndex++); 391 entries.enter(poolKey); 392 pool.writeByte(PoolTag.CONSTANT_INTEGER.tag); 393 pool.writeInt(i); 394 } 395 return poolKey.index; 396 } 397 398 @Override 399 public int putFloat(float f) { 400 key.setFloat(f); 401 PoolKey poolKey = entries.lookup(key); 402 if (poolKey == null) { 403 poolKey = key.dup(); 404 poolKey.at(currentIndex++); 405 entries.enter(poolKey); 406 pool.writeByte(PoolTag.CONSTANT_FLOAT.tag); 407 pool.writeFloat(f); 408 } 409 return poolKey.index; 410 } 411 412 @Override 413 public int putLong(long l) { 414 key.setLong(l); 415 PoolKey poolKey = entries.lookup(key); 416 if (poolKey == null) { 417 poolKey = key.dup(); 418 poolKey.at(currentIndex++); 419 entries.enter(poolKey); 420 pool.writeByte(PoolTag.CONSTANT_LONG.tag); 421 pool.writeLong(l); 422 currentIndex++; 423 } 424 return poolKey.index; 425 } 426 427 @Override 428 public int putDouble(double d) { 429 key.setDouble(d); 430 PoolKey poolKey = entries.lookup(key); 431 if (poolKey == null) { 432 poolKey = key.dup(); 433 poolKey.at(currentIndex++); 434 entries.enter(poolKey); 435 pool.writeByte(PoolTag.CONSTANT_DOUBLE.tag); 436 pool.writeDouble(d); 437 currentIndex++; 438 } 439 return poolKey.index; 440 } 441 442 443 @Override 444 public int putInvokeDynamic(CharSequence invokedName, T invokedType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) { 445 return putInvokeDynamicInternal(invokedName, typeToString.apply(invokedType), symbolToString.apply(bsmClass), bsmName, typeToString.apply(bsmType), staticArgs); 446 } 447 448 @Override 449 public int putDynamicConstant(CharSequence constName, T constType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) { 450 return putDynamicConstantInternal(constName, typeToString.apply(constType), symbolToString.apply(bsmClass), bsmName, typeToString.apply(bsmType), staticArgs); 451 } 452 453 private int putInvokeDynamicInternal(CharSequence invokedName, String invokedType, String bsmClass, CharSequence bsmName, String bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) { 454 int bsmIndex = putBsmInternal(bsmClass, bsmName, bsmType, staticArgs); 455 key.setInvokeDynamic(bsmIndex, invokedName, invokedType); 456 PoolKey poolKey = entries.lookup(key); 457 if (poolKey == null) { 458 poolKey = key.dup(); 459 int nameAndType_idx = putNameAndType(invokedName, invokedType); 460 poolKey.at(currentIndex++); 461 entries.enter(poolKey); 462 pool.writeByte(PoolTag.CONSTANT_INVOKEDYNAMIC.tag); 463 pool.writeChar(bsmIndex); 464 pool.writeChar(nameAndType_idx); 465 } 466 return poolKey.index; 467 } 468 469 private int putDynamicConstantInternal(CharSequence constName, String constType, String bsmClass, CharSequence bsmName, String bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) { 470 int bsmIndex = putBsmInternal(bsmClass, bsmName, bsmType, staticArgs); 471 key.setDynamicConstant(bsmIndex, constName, constType); 472 PoolKey poolKey = entries.lookup(key); 473 if (poolKey == null) { 474 poolKey = key.dup(); 475 int nameAndType_idx = putNameAndType(constName, constType); 476 poolKey.at(currentIndex++); 477 entries.enter(poolKey); 478 pool.writeByte(PoolTag.CONSTANT_DYNAMIC.tag); 479 pool.writeChar(bsmIndex); 480 pool.writeChar(nameAndType_idx); 481 } 482 return poolKey.index; 483 } 484 485 private int putBsmInternal(String bsmClass, CharSequence bsmName, String bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) { 486 ByteStaticArgListBuilder staticArgsBuilder = new ByteStaticArgListBuilder(); 487 staticArgs.accept(staticArgsBuilder); 488 List<Integer> static_idxs = staticArgsBuilder.indexes; 489 bsmKey.set(bsmClass, bsmName, bsmType, static_idxs); 490 BsmKey poolKey = bootstraps.lookup(bsmKey); 491 if (poolKey == null) { 492 poolKey = bsmKey.dup(); 493 // TODO the BSM could be a static method on an interface 494 int bsm_ref = putHandleInternal(MethodHandleInfo.REF_invokeStatic, bsmClass, bsmName, bsmType, false); 495 poolKey.at(currentBsmIndex++); 496 bootstraps.enter(poolKey); 497 bsm_attr.writeChar(bsm_ref); 498 bsm_attr.writeChar(static_idxs.size()); 499 for (int i : static_idxs) { 500 bsm_attr.writeChar(i); 501 } 502 } 503 return poolKey.index; 504 } 505 //where 506 class ByteStaticArgListBuilder implements StaticArgListBuilder<S, T, byte[]> { 507 508 List<Integer> indexes = new ArrayList<>(); 509 510 public ByteStaticArgListBuilder add(int i) { 511 indexes.add(putInt(i)); 512 return this; 513 } 514 public ByteStaticArgListBuilder add(float f) { 515 indexes.add(putFloat(f)); 516 return this; 517 } 518 public ByteStaticArgListBuilder add(long l) { 519 indexes.add(putLong(l)); 520 return this; 521 } 522 public ByteStaticArgListBuilder add(double d) { 523 indexes.add(putDouble(d)); 524 return this; 525 } 526 public ByteStaticArgListBuilder add(String s) { 527 indexes.add(putString(s)); 528 return this; 529 } 530 @Override 531 public StaticArgListBuilder<S, T, byte[]> add(int refKind, S owner, CharSequence name, T type) { 532 indexes.add(putHandle(refKind, owner, name, type)); 533 return this; 534 } 535 public <Z> ByteStaticArgListBuilder add(Z z, ToIntBiFunction<PoolHelper<S, T, byte[]>, Z> poolFunc) { 536 indexes.add(poolFunc.applyAsInt(BytePoolHelper.this, z)); 537 return this; 538 } 539 public ByteStaticArgListBuilder add(CharSequence constName, T constType, S bsmClass, CharSequence bsmName, T bsmType, Consumer<StaticArgListBuilder<S, T, byte[]>> staticArgs) { 540 indexes.add(putDynamicConstant(constName, constType, bsmClass, bsmName, bsmType, staticArgs)); 541 return this; 542 } 543 } 544 545 @Override 546 public int putMethodType(T s) { 547 return putMethodTypeInternal(typeToString.apply(s)); 548 } 549 550 private int putMethodTypeInternal(String s) { 551 key.setMethodType(s); 552 PoolKey poolKey = entries.lookup(key); 553 if (poolKey == null) { 554 poolKey = key.dup(); 555 int desc_idx = putUtf8(s); 556 poolKey.at(currentIndex++); 557 entries.enter(poolKey); 558 pool.writeByte(PoolTag.CONSTANT_METHODTYPE.tag); 559 pool.writeChar(desc_idx); 560 } 561 return poolKey.index; 562 } 563 564 @Override 565 public int putHandle(int refKind, S owner, CharSequence name, T type) { 566 return putHandleInternal(refKind, symbolToString.apply(owner), name, typeToString.apply(type), false); 567 } 568 569 @Override 570 public int putHandle(int refKind, S owner, CharSequence name, T type, boolean isInterface) { 571 return putHandleInternal(refKind, symbolToString.apply(owner), name, typeToString.apply(type), isInterface); 572 } 573 574 private int putHandleInternal(int refKind, String owner, CharSequence name, String type, boolean isInterface) { 575 key.setMethodHandle(refKind, owner, name, type); 576 PoolKey poolKey = entries.lookup(key); 577 if (poolKey == null) { 578 poolKey = key.dup(); 579 int ref_idx = putMemberRefInternal(fromKind(refKind, isInterface), owner, name, type); 580 poolKey.at(currentIndex++); 581 entries.enter(poolKey); 582 pool.writeByte(PoolTag.CONSTANT_METHODHANDLE.tag); 583 pool.writeByte(refKind); 584 pool.writeChar(ref_idx); 585 } 586 return poolKey.index; 587 } 588 589 PoolTag fromKind(int bsmKind, boolean isInterface) { 590 switch (bsmKind) { 591 case 1: // REF_getField 592 case 2: // REF_getStatic 593 case 3: // REF_putField 594 case 4: // REF_putStatic 595 return PoolTag.CONSTANT_FIELDREF; 596 case 5: // REF_invokeVirtual 597 case 6: // REF_invokeStatic 598 case 7: // REF_invokeSpecial 599 case 8: // REF_newInvokeSpecial 600 case 9: // REF_invokeInterface 601 return isInterface ? PoolTag.CONSTANT_INTERFACEMETHODREF : PoolTag.CONSTANT_METHODREF; 602 default: 603 throw new IllegalStateException(); 604 } 605 } 606 607 @Override 608 public int putType(T s) { 609 return putUtf8(typeToString.apply(s)); 610 } 611 612 public int putUtf8(CharSequence s) { 613 key.setUtf8(s); 614 PoolKey poolKey = entries.lookup(key); 615 if (poolKey == null) { 616 poolKey = key.dup(); 617 poolKey.at(currentIndex++); 618 entries.enter(poolKey); 619 pool.writeByte(PoolTag.CONSTANT_UTF8.tag); 620 putUTF8Internal(s); 621 } 622 return poolKey.index; 623 } 624 625 /** 626 * Puts an UTF8 string into this byte vector. The byte vector is 627 * automatically enlarged if necessary. 628 * 629 * @param s a String whose UTF8 encoded length must be less than 65536. 630 * @return this byte vector. 631 */ 632 void putUTF8Internal(final CharSequence s) { 633 int charLength = s.length(); 634 if (charLength > 65535) { 635 throw new IllegalArgumentException(); 636 } 637 // optimistic algorithm: instead of computing the byte length and then 638 // serializing the string (which requires two loops), we assume the byte 639 // length is equal to char length (which is the most frequent case), and 640 // we start serializing the string right away. During the serialization, 641 // if we find that this assumption is wrong, we continue with the 642 // general method. 643 pool.writeChar(charLength); 644 for (int i = 0; i < charLength; ++i) { 645 char c = s.charAt(i); 646 if (c >= '\001' && c <= '\177') { 647 pool.writeByte((byte) c); 648 } else { 649 encodeUTF8(s, i, 65535); 650 break; 651 } 652 } 653 } 654 655 /** 656 * Puts an UTF8 string into this byte vector. The byte vector is 657 * automatically enlarged if necessary. The string length is encoded in two 658 * bytes before the encoded characters, if there is space for that (i.e. if 659 * this.length - i - 2 >= 0). 660 * 661 * @param s the String to encode. 662 * @param i the index of the first character to encode. The previous 663 * characters are supposed to have already been encoded, using 664 * only one byte per character. 665 * @param maxByteLength the maximum byte length of the encoded string, including the 666 * already encoded characters. 667 * @return this byte vector. 668 */ 669 void encodeUTF8(final CharSequence s, int i, int maxByteLength) { 670 int charLength = s.length(); 671 int byteLength = i; 672 char c; 673 for (int j = i; j < charLength; ++j) { 674 c = s.charAt(j); 675 if (c >= '\001' && c <= '\177') { 676 byteLength++; 677 } else if (c > '\u07FF') { 678 byteLength += 3; 679 } else { 680 byteLength += 2; 681 } 682 } 683 if (byteLength > maxByteLength) { 684 throw new IllegalArgumentException(); 685 } 686 int byteLengthFinal = byteLength; 687 pool.withOffset(pool.offset - i - 2, buf -> buf.writeChar(byteLengthFinal)); 688 for (int j = i; j < charLength; ++j) { 689 c = s.charAt(j); 690 if (c >= '\001' && c <= '\177') { 691 pool.writeChar((byte) c); 692 } else if (c > '\u07FF') { 693 pool.writeChar((byte) (0xE0 | c >> 12 & 0xF)); 694 pool.writeChar((byte) (0x80 | c >> 6 & 0x3F)); 695 pool.writeChar((byte) (0x80 | c & 0x3F)); 696 } else { 697 pool.writeChar((byte) (0xC0 | c >> 6 & 0x1F)); 698 pool.writeChar((byte) (0x80 | c & 0x3F)); 699 } 700 } 701 } 702 703 @Override 704 public int putString(String s) { 705 key.setString(s); 706 PoolKey poolKey = entries.lookup(key); 707 if (poolKey == null) { 708 poolKey = key.dup(); 709 int utf8_index = putUtf8(s); 710 poolKey.at(currentIndex++); 711 entries.enter(poolKey); 712 pool.writeByte(PoolTag.CONSTANT_STRING.tag); 713 pool.writeChar(utf8_index); 714 } 715 return poolKey.index; 716 } 717 718 int putNameAndType(CharSequence name, String type) { 719 key.setNameAndType(name, type); 720 PoolKey poolKey = entries.lookup(key); 721 if (poolKey == null) { 722 poolKey = key.dup(); 723 int name_idx = putUtf8(name); 724 int type_idx = putUtf8(type); 725 poolKey.at(currentIndex++); 726 entries.enter(poolKey); 727 pool.writeByte(PoolTag.CONSTANT_NAMEANDTYPE.tag); 728 pool.writeChar(name_idx); 729 pool.writeChar(type_idx); 730 } 731 return poolKey.index; 732 } 733 734 @Override 735 public int size() { 736 return currentIndex - 1; 737 } 738 739 @Override 740 public byte[] entries() { 741 return pool.bytes(); 742 } 743 744 <Z extends ClassBuilder<S, T, Z>> void addAttributes(ClassBuilder<S , T, Z> cb) { 745 if (currentBsmIndex > 0) { 746 GrowableByteBuffer bsmAttrBuf = new GrowableByteBuffer(); 747 bsmAttrBuf.writeChar(currentBsmIndex); 748 bsmAttrBuf.writeBytes(bsm_attr); 749 cb.withAttribute("BootstrapMethods", bsmAttrBuf.bytes()); 750 } 751 } 752 }