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