001/* 002 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package jdk.internal.jvmci.hotspot; 024 025import static jdk.internal.jvmci.common.UnsafeAccess.*; 026import static jdk.internal.jvmci.hotspot.HotSpotJVMCIRuntime.*; 027 028import java.lang.invoke.*; 029import java.util.*; 030 031import jdk.internal.jvmci.common.*; 032import jdk.internal.jvmci.meta.*; 033import jdk.internal.jvmci.options.*; 034 035/** 036 * Implementation of {@link ConstantPool} for HotSpot. 037 */ 038public class HotSpotConstantPool implements ConstantPool, HotSpotProxified { 039 040 public static class Options { 041 // @formatter:off 042 @Option(help = "Use Java code to access the constant pool cache and resolved references array", type = OptionType.Expert) 043 public static final OptionValue<Boolean> UseConstantPoolCacheJavaCode = new OptionValue<>(false); 044 // @formatter:on 045 } 046 047 /** 048 * Subset of JVM bytecode opcodes used by {@link HotSpotConstantPool}. 049 */ 050 public static class Bytecodes { 051 public static final int LDC = 18; // 0x12 052 public static final int LDC_W = 19; // 0x13 053 public static final int LDC2_W = 20; // 0x14 054 public static final int GETSTATIC = 178; // 0xB2 055 public static final int PUTSTATIC = 179; // 0xB3 056 public static final int GETFIELD = 180; // 0xB4 057 public static final int PUTFIELD = 181; // 0xB5 058 public static final int INVOKEVIRTUAL = 182; // 0xB6 059 public static final int INVOKESPECIAL = 183; // 0xB7 060 public static final int INVOKESTATIC = 184; // 0xB8 061 public static final int INVOKEINTERFACE = 185; // 0xB9 062 public static final int INVOKEDYNAMIC = 186; // 0xBA 063 public static final int NEW = 187; // 0xBB 064 public static final int NEWARRAY = 188; // 0xBC 065 public static final int ANEWARRAY = 189; // 0xBD 066 public static final int CHECKCAST = 192; // 0xC0 067 public static final int INSTANCEOF = 193; // 0xC1 068 public static final int MULTIANEWARRAY = 197; // 0xC5 069 070 static boolean isInvoke(int opcode) { 071 switch (opcode) { 072 case INVOKEVIRTUAL: 073 case INVOKESPECIAL: 074 case INVOKESTATIC: 075 case INVOKEINTERFACE: 076 case INVOKEDYNAMIC: 077 return true; 078 default: 079 return false; 080 } 081 } 082 083 /** 084 * See: {@code Rewriter::maybe_rewrite_invokehandle}. 085 */ 086 static boolean isInvokeHandleAlias(int opcode) { 087 switch (opcode) { 088 case INVOKEVIRTUAL: 089 case INVOKESPECIAL: 090 return true; 091 default: 092 return false; 093 } 094 } 095 } 096 097 /** 098 * Enum of all {@code JVM_CONSTANT} constants used in the VM. This includes the public and 099 * internal ones. 100 */ 101 private enum JVM_CONSTANT { 102 // @formatter:off 103 Utf8(config().jvmConstantUtf8), 104 Integer(config().jvmConstantInteger), 105 Long(config().jvmConstantLong), 106 Float(config().jvmConstantFloat), 107 Double(config().jvmConstantDouble), 108 Class(config().jvmConstantClass), 109 UnresolvedClass(config().jvmConstantUnresolvedClass), 110 UnresolvedClassInError(config().jvmConstantUnresolvedClassInError), 111 String(config().jvmConstantString), 112 Fieldref(config().jvmConstantFieldref), 113 MethodRef(config().jvmConstantMethodref), 114 InterfaceMethodref(config().jvmConstantInterfaceMethodref), 115 NameAndType(config().jvmConstantNameAndType), 116 MethodHandle(config().jvmConstantMethodHandle), 117 MethodHandleInError(config().jvmConstantMethodHandleInError), 118 MethodType(config().jvmConstantMethodType), 119 MethodTypeInError(config().jvmConstantMethodTypeInError), 120 InvokeDynamic(config().jvmConstantInvokeDynamic); 121 // @formatter:on 122 123 private final int tag; 124 125 private static final int ExternalMax = config().jvmConstantExternalMax; 126 private static final int InternalMin = config().jvmConstantInternalMin; 127 private static final int InternalMax = config().jvmConstantInternalMax; 128 129 private JVM_CONSTANT(int tag) { 130 this.tag = tag; 131 } 132 133 private static HotSpotVMConfig config() { 134 return runtime().getConfig(); 135 } 136 137 /** 138 * Maps JVM_CONSTANT tags to {@link JVM_CONSTANT} values. Using a separate class for lazy 139 * initialization. 140 */ 141 static class TagValueMap { 142 private static final JVM_CONSTANT[] table = new JVM_CONSTANT[ExternalMax + 1 + (InternalMax - InternalMin) + 1]; 143 144 static { 145 assert InternalMin > ExternalMax; 146 for (JVM_CONSTANT e : values()) { 147 table[indexOf(e.tag)] = e; 148 } 149 } 150 151 private static int indexOf(int tag) { 152 if (tag >= InternalMin) { 153 return tag - InternalMin + ExternalMax + 1; 154 } else { 155 assert tag <= ExternalMax; 156 } 157 return tag; 158 } 159 160 static JVM_CONSTANT get(int tag) { 161 JVM_CONSTANT res = table[indexOf(tag)]; 162 if (res != null) { 163 return res; 164 } 165 throw new JVMCIError("Unknown JVM_CONSTANT tag %s", tag); 166 } 167 } 168 169 public static JVM_CONSTANT getEnum(int tag) { 170 return TagValueMap.get(tag); 171 } 172 } 173 174 private static class LookupTypeCacheElement { 175 int lastCpi = Integer.MIN_VALUE; 176 JavaType javaType; 177 178 public LookupTypeCacheElement(int lastCpi, JavaType javaType) { 179 super(); 180 this.lastCpi = lastCpi; 181 this.javaType = javaType; 182 } 183 } 184 185 /** 186 * Reference to the C++ ConstantPool object. 187 */ 188 private final long metaspaceConstantPool; 189 private volatile LookupTypeCacheElement lastLookupType; 190 191 /** 192 * The constant pool cache of this constant pool. 193 */ 194 private final Cache cache; 195 196 /** 197 * Represents a {@code ConstantPoolCache}. The cache needs to be lazy since the constant pool 198 * cache is created when the methods of this class are rewritten and rewriting happens when the 199 * class is linked. 200 */ 201 private final class Cache { 202 203 private long address; 204 205 public Cache() { 206 // Maybe the constant pool cache already exists... 207 queryAddress(); 208 } 209 210 /** 211 * Queries the current value of {@code ConstantPool::_cache} if the current address is null. 212 */ 213 private void queryAddress() { 214 if (address == 0) { 215 address = unsafe.getAddress(metaspaceConstantPool + runtime().getConfig().constantPoolCacheOffset); 216 } 217 } 218 219 /** 220 * Returns whether a constant pool cache for this constant pool exists. 221 * 222 * @return true if it exists, false otherwise 223 */ 224 public boolean exists() { 225 queryAddress(); 226 return address != 0; 227 } 228 229 /** 230 * Represents a {@code ConstantPoolCacheEntry}. 231 */ 232 private final class Entry { 233 234 private final long address; 235 236 public Entry(final long address) { 237 this.address = address; 238 } 239 240 /** 241 * {@code ConstantPoolCacheEntry::_indices} is volatile of type {@code intx}. 242 * 243 * @return value of field {@code _indices} 244 */ 245 private long getIndices() { 246 assert runtime().getHostJVMCIBackend().getTarget().wordSize == 8 : "port to non-64-bit platform"; 247 return unsafe.getLongVolatile(null, address + runtime().getConfig().constantPoolCacheEntryIndicesOffset); 248 } 249 250 /** 251 * {@code ConstantPoolCacheEntry::_f1} is volatile of type {@code Metadata*}. 252 * 253 * @return value of field {@code _f1} 254 */ 255 private long getF1() { 256 assert runtime().getHostJVMCIBackend().getTarget().wordSize == 8 : "port to non-64-bit platform"; 257 return unsafe.getLongVolatile(null, address + runtime().getConfig().constantPoolCacheEntryF1Offset); 258 } 259 260 /** 261 * {@code ConstantPoolCacheEntry::_f2} is volatile of type {@code intx}. 262 * 263 * @return value of field {@code _f2} 264 */ 265 private long getF2() { 266 assert runtime().getHostJVMCIBackend().getTarget().wordSize == 8 : "port to non-64-bit platform"; 267 return unsafe.getLongVolatile(null, address + runtime().getConfig().constantPoolCacheEntryF2Offset); 268 } 269 270 /** 271 * {@code ConstantPoolCacheEntry::_flags} is volatile of type {@code intx}. 272 * 273 * @return flag bits 274 */ 275 private long flags() { 276 assert runtime().getHostJVMCIBackend().getTarget().wordSize == 8 : "port to non-64-bit platform"; 277 return unsafe.getLongVolatile(null, address + runtime().getConfig().constantPoolCacheEntryFlagsOffset); 278 } 279 280 private boolean isF1Null() { 281 final long f1 = getF1(); 282 return f1 == 0; 283 } 284 285 /** 286 * Returns the constant pool index for this entry. See 287 * {@code ConstantPoolCacheEntry::constant_pool_index()} 288 * 289 * @return the constant pool index for this entry 290 */ 291 public int getConstantPoolIndex() { 292 return ((int) getIndices()) & runtime().getConfig().constantPoolCacheEntryCpIndexMask; 293 } 294 295 /** 296 * See {@code ConstantPoolCache::has_appendix()}. 297 * 298 * @return true if there is an appendix, false otherwise 299 */ 300 private boolean hasAppendix() { 301 return (!isF1Null()) && (flags() & (1 << runtime().getConfig().constantPoolCacheEntryHasAppendixShift)) != 0; 302 } 303 304 /** 305 * See {@code ConstantPoolCache::appendix_if_resolved()}. 306 */ 307 public Object getAppendixIfResolved() { 308 if (!hasAppendix()) { 309 return null; 310 } 311 final int index = ((int) getF2()) + runtime().getConfig().constantPoolCacheEntryIndyResolvedReferencesAppendixOffset; 312 return resolvedReferences.getArray()[index]; 313 } 314 } 315 316 /** 317 * Get the constant pool cache entry at index {@code index}. 318 * 319 * @param index index of entry to return 320 * @return constant pool cache entry at given index 321 */ 322 public Entry getEntryAt(int index) { 323 queryAddress(); 324 assert exists(); 325 HotSpotVMConfig config = runtime().getConfig(); 326 return new Entry(address + config.constantPoolCacheSize + config.constantPoolCacheEntrySize * index); 327 } 328 329 /** 330 * Maps the constant pool cache index back to a constant pool index. See 331 * {@code ConstantPool::remap_instruction_operand_from_cache}. 332 * 333 * @param index the constant pool cache index 334 * @return constant pool index 335 */ 336 public int constantPoolCacheIndexToConstantPoolIndex(int index) { 337 final int cacheIndex = index - runtime().getConfig().constantPoolCpCacheIndexTag; 338 return getEntryAt(cacheIndex).getConstantPoolIndex(); 339 } 340 341 } 342 343 /** 344 * Resolved references of this constant pool. 345 */ 346 private final ResolvedReferences resolvedReferences = new ResolvedReferences(); 347 348 /** 349 * Hide the resolved references array in a private class so it cannot be accessed directly. The 350 * reason is the resolved references array is created when the constant pool cache is created. 351 * 352 * @see Cache 353 */ 354 private final class ResolvedReferences { 355 356 /** 357 * Pointer to the {@code ConstantPool::_resolved_references} array. 358 */ 359 private Object[] resolvedReferences; 360 361 /** 362 * Map of constant pool indexes to {@code ConstantPool::_resolved_references} indexes. 363 */ 364 private final HashMap<Integer, Integer> referenceMap = new HashMap<>(); 365 366 /** 367 * Returns the {@code ConstantPool::_resolved_references} array for this constant pool. 368 * 369 * @return resolved references array if exists, null otherwise 370 */ 371 public Object[] getArray() { 372 if (resolvedReferences == null) { 373 final long handle = unsafe.getAddress(metaspaceConstantPool + runtime().getConfig().constantPoolResolvedReferencesOffset); 374 if (handle != 0) { 375 resolvedReferences = (Object[]) runtime().getCompilerToVM().readUncompressedOop(handle + runtime().getConfig().handleHandleOffset); 376 fillReferenceMap(); 377 } 378 } 379 return resolvedReferences; 380 } 381 382 /** 383 * Fills the {@link #referenceMap} with all the values from 384 * {@code ConstantPool::_reference_map} for faster lookup. 385 */ 386 private void fillReferenceMap() { 387 // It is possible there is a resolved references array but no reference map. 388 final long address = unsafe.getAddress(metaspaceConstantPool + runtime().getConfig().constantPoolReferenceMapOffset); 389 if (address != 0) { 390 final int length = unsafe.getInt(null, address + runtime().getConfig().arrayU1LengthOffset); 391 for (int i = 0; i < length; i++) { 392 final int value = unsafe.getShort(address + runtime().getConfig().arrayU2DataOffset + i * Short.BYTES); 393 referenceMap.put(value, i); 394 } 395 } 396 } 397 398 /** 399 * See {@code ConstantPool::cp_to_object_index}. 400 * 401 * @param cpi constant pool index 402 * @return resolved references array index 403 */ 404 public int constantPoolIndexToResolvedReferencesIndex(int cpi) { 405 final Integer index = referenceMap.get(cpi); 406 // We might not find the index for jsr292 call. 407 return (index == null) ? -1 : index; 408 } 409 410 } 411 412 public HotSpotConstantPool(long metaspaceConstantPool) { 413 this.metaspaceConstantPool = metaspaceConstantPool; 414 415 // Cache constructor needs metaspaceConstantPool. 416 cache = new Cache(); 417 } 418 419 /** 420 * Gets the holder for this constant pool as {@link HotSpotResolvedObjectTypeImpl}. 421 * 422 * @return holder for this constant pool 423 */ 424 private HotSpotResolvedObjectType getHolder() { 425 final long metaspaceKlass = unsafe.getAddress(metaspaceConstantPool + runtime().getConfig().constantPoolHolderOffset); 426 return HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(metaspaceKlass); 427 } 428 429 /** 430 * Converts a raw index from the bytecodes to a constant pool index by adding a 431 * {@link HotSpotVMConfig#constantPoolCpCacheIndexTag constant}. 432 * 433 * @param rawIndex index from the bytecode 434 * @param opcode bytecode to convert the index for 435 * @return constant pool index 436 */ 437 private static int rawIndexToConstantPoolIndex(int rawIndex, int opcode) { 438 int index; 439 if (opcode == Bytecodes.INVOKEDYNAMIC) { 440 index = rawIndex; 441 // See: ConstantPool::is_invokedynamic_index 442 assert index < 0 : "not an invokedynamic constant pool index " + index; 443 } else { 444 assert opcode == Bytecodes.GETFIELD || opcode == Bytecodes.PUTFIELD || opcode == Bytecodes.GETSTATIC || opcode == Bytecodes.PUTSTATIC || opcode == Bytecodes.INVOKEINTERFACE || 445 opcode == Bytecodes.INVOKEVIRTUAL || opcode == Bytecodes.INVOKESPECIAL || opcode == Bytecodes.INVOKESTATIC : "unexpected invoke opcode " + opcode; 446 index = rawIndex + runtime().getConfig().constantPoolCpCacheIndexTag; 447 } 448 return index; 449 } 450 451 /** 452 * Decode a constant pool cache index to a constant pool index. 453 * 454 * See {@code ConstantPool::decode_cpcache_index}. 455 * 456 * @param index constant pool cache index 457 * @return decoded index 458 */ 459 private static int decodeConstantPoolCacheIndex(int index) { 460 if (isInvokedynamicIndex(index)) { 461 return decodeInvokedynamicIndex(index); 462 } else { 463 return index - runtime().getConfig().constantPoolCpCacheIndexTag; 464 } 465 } 466 467 /** 468 * See {@code ConstantPool::is_invokedynamic_index}. 469 */ 470 private static boolean isInvokedynamicIndex(int index) { 471 return index < 0; 472 } 473 474 /** 475 * See {@code ConstantPool::decode_invokedynamic_index}. 476 */ 477 private static int decodeInvokedynamicIndex(int i) { 478 assert isInvokedynamicIndex(i) : i; 479 return ~i; 480 } 481 482 /** 483 * Gets the constant pool tag at index {@code index}. 484 * 485 * @param index constant pool index 486 * @return constant pool tag 487 */ 488 private JVM_CONSTANT getTagAt(int index) { 489 assertBounds(index); 490 HotSpotVMConfig config = runtime().getConfig(); 491 final long metaspaceConstantPoolTags = unsafe.getAddress(metaspaceConstantPool + config.constantPoolTagsOffset); 492 final int tag = unsafe.getByteVolatile(null, metaspaceConstantPoolTags + config.arrayU1DataOffset + index); 493 if (tag == 0) { 494 return null; 495 } 496 return JVM_CONSTANT.getEnum(tag); 497 } 498 499 /** 500 * Gets the constant pool entry at index {@code index}. 501 * 502 * @param index constant pool index 503 * @return constant pool entry 504 */ 505 private long getEntryAt(int index) { 506 assertBounds(index); 507 return unsafe.getAddress(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); 508 } 509 510 /** 511 * Gets the integer constant pool entry at index {@code index}. 512 * 513 * @param index constant pool index 514 * @return integer constant pool entry at index 515 */ 516 private int getIntAt(int index) { 517 assertTag(index, JVM_CONSTANT.Integer); 518 return unsafe.getInt(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); 519 } 520 521 /** 522 * Gets the long constant pool entry at index {@code index}. 523 * 524 * @param index constant pool index 525 * @return long constant pool entry 526 */ 527 private long getLongAt(int index) { 528 assertTag(index, JVM_CONSTANT.Long); 529 return unsafe.getLong(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); 530 } 531 532 /** 533 * Gets the float constant pool entry at index {@code index}. 534 * 535 * @param index constant pool index 536 * @return float constant pool entry 537 */ 538 private float getFloatAt(int index) { 539 assertTag(index, JVM_CONSTANT.Float); 540 return unsafe.getFloat(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); 541 } 542 543 /** 544 * Gets the double constant pool entry at index {@code index}. 545 * 546 * @param index constant pool index 547 * @return float constant pool entry 548 */ 549 private double getDoubleAt(int index) { 550 assertTag(index, JVM_CONSTANT.Double); 551 return unsafe.getDouble(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); 552 } 553 554 /** 555 * Gets the {@code JVM_CONSTANT_NameAndType} constant pool entry at index {@code index}. 556 * 557 * @param index constant pool index 558 * @return {@code JVM_CONSTANT_NameAndType} constant pool entry 559 */ 560 private int getNameAndTypeAt(int index) { 561 assertTag(index, JVM_CONSTANT.NameAndType); 562 return unsafe.getInt(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); 563 } 564 565 /** 566 * Gets the {@code JVM_CONSTANT_NameAndType} reference index constant pool entry at index 567 * {@code index}. 568 * 569 * @param index constant pool index 570 * @return {@code JVM_CONSTANT_NameAndType} reference constant pool entry 571 */ 572 private int getNameAndTypeRefIndexAt(int index) { 573 return runtime().getCompilerToVM().lookupNameAndTypeRefIndexInPool(metaspaceConstantPool, index); 574 } 575 576 /** 577 * Gets the name of a {@code JVM_CONSTANT_NameAndType} constant pool entry at index 578 * {@code index}. 579 * 580 * @param index constant pool index 581 * @return name as {@link String} 582 */ 583 private String getNameRefAt(int index) { 584 if (Options.UseConstantPoolCacheJavaCode.getValue()) { 585 final int nameRefIndex = getNameRefIndexAt(getNameAndTypeRefIndexAt(index)); 586 return new HotSpotSymbol(getEntryAt(nameRefIndex)).asString(); 587 } else { 588 return runtime().getCompilerToVM().lookupNameRefInPool(metaspaceConstantPool, index); 589 } 590 } 591 592 /** 593 * Gets the name reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry at 594 * index {@code index}. 595 * 596 * @param index constant pool index 597 * @return name reference index 598 */ 599 private int getNameRefIndexAt(int index) { 600 final int refIndex = getNameAndTypeAt(index); 601 // name ref index is in the low 16-bits. 602 return refIndex & 0xFFFF; 603 } 604 605 /** 606 * Gets the signature of a {@code JVM_CONSTANT_NameAndType} constant pool entry at index 607 * {@code index}. 608 * 609 * @param index constant pool index 610 * @return signature as {@link String} 611 */ 612 private String getSignatureRefAt(int index) { 613 if (Options.UseConstantPoolCacheJavaCode.getValue()) { 614 final int signatureRefIndex = getSignatureRefIndexAt(getNameAndTypeRefIndexAt(index)); 615 return new HotSpotSymbol(getEntryAt(signatureRefIndex)).asString(); 616 } else { 617 return runtime().getCompilerToVM().lookupSignatureRefInPool(metaspaceConstantPool, index); 618 } 619 } 620 621 /** 622 * Gets the signature reference index of a {@code JVM_CONSTANT_NameAndType} constant pool entry 623 * at index {@code index}. 624 * 625 * @param index constant pool index 626 * @return signature reference index 627 */ 628 private int getSignatureRefIndexAt(int index) { 629 final int refIndex = getNameAndTypeAt(index); 630 // signature ref index is in the high 16-bits. 631 return refIndex >>> 16; 632 } 633 634 /** 635 * Gets the klass reference index constant pool entry at index {@code index}. See 636 * {@code ConstantPool::klass_ref_index_at}. 637 * 638 * @param index constant pool index 639 * @param cached whether to go through the constant pool cache 640 * @return klass reference index 641 */ 642 private int getKlassRefIndexAt(int index, boolean cached) { 643 int cpi = index; 644 if (cached && cache.exists()) { 645 // change byte-ordering and go via cache 646 cpi = cache.constantPoolCacheIndexToConstantPoolIndex(index); 647 } 648 assertTagIsFieldOrMethod(cpi); 649 final int refIndex = unsafe.getInt(metaspaceConstantPool + runtime().getConfig().constantPoolSize + cpi * runtime().getHostJVMCIBackend().getTarget().wordSize); 650 // klass ref index is in the low 16-bits. 651 return refIndex & 0xFFFF; 652 } 653 654 /** 655 * Gets the klass reference index constant pool entry at index {@code index}. See 656 * {@code ConstantPool::klass_ref_index_at}. 657 * 658 * @param index constant pool index 659 * @return klass reference index 660 */ 661 private int getKlassRefIndexAt(int index) { 662 if (Options.UseConstantPoolCacheJavaCode.getValue()) { 663 return getKlassRefIndexAt(index, true); 664 } else { 665 return runtime().getCompilerToVM().lookupKlassRefIndexInPool(metaspaceConstantPool, index); 666 } 667 } 668 669 /** 670 * Gets the uncached klass reference index constant pool entry at index {@code index}. See: 671 * {@code ConstantPool::uncached_klass_ref_index_at}. 672 * 673 * @param index constant pool index 674 * @return klass reference index 675 */ 676 private int getUncachedKlassRefIndexAt(int index) { 677 if (Options.UseConstantPoolCacheJavaCode.getValue()) { 678 return getKlassRefIndexAt(index, false); 679 } else { 680 assertTagIsFieldOrMethod(index); 681 final int refIndex = unsafe.getInt(metaspaceConstantPool + runtime().getConfig().constantPoolSize + index * runtime().getHostJVMCIBackend().getTarget().wordSize); 682 // klass ref index is in the low 16-bits. 683 return refIndex & 0xFFFF; 684 } 685 } 686 687 /** 688 * Asserts that the constant pool index {@code index} is in the bounds of the constant pool. 689 * 690 * @param index constant pool index 691 */ 692 private void assertBounds(int index) { 693 assert 0 <= index && index < length() : "index " + index + " not between 0 and " + length(); 694 } 695 696 /** 697 * Asserts that the constant pool tag at index {@code index} is equal to {@code tag}. 698 * 699 * @param index constant pool index 700 * @param tag expected tag 701 */ 702 private void assertTag(int index, JVM_CONSTANT tag) { 703 final JVM_CONSTANT tagAt = getTagAt(index); 704 assert tagAt == tag : "constant pool tag at index " + index + " is " + tagAt + " but expected " + tag; 705 } 706 707 /** 708 * Asserts that the constant pool tag at index {@code index} is a {@link JVM_CONSTANT#Fieldref}, 709 * or a {@link JVM_CONSTANT#MethodRef}, or a {@link JVM_CONSTANT#InterfaceMethodref}. 710 * 711 * @param index constant pool index 712 */ 713 private void assertTagIsFieldOrMethod(int index) { 714 final JVM_CONSTANT tagAt = getTagAt(index); 715 assert tagAt == JVM_CONSTANT.Fieldref || tagAt == JVM_CONSTANT.MethodRef || tagAt == JVM_CONSTANT.InterfaceMethodref : tagAt; 716 } 717 718 @Override 719 public int length() { 720 return unsafe.getInt(metaspaceConstantPool + runtime().getConfig().constantPoolLengthOffset); 721 } 722 723 @Override 724 public Object lookupConstant(int cpi) { 725 assert cpi != 0; 726 final JVM_CONSTANT tag = getTagAt(cpi); 727 switch (tag) { 728 case Integer: 729 return JavaConstant.forInt(getIntAt(cpi)); 730 case Long: 731 return JavaConstant.forLong(getLongAt(cpi)); 732 case Float: 733 return JavaConstant.forFloat(getFloatAt(cpi)); 734 case Double: 735 return JavaConstant.forDouble(getDoubleAt(cpi)); 736 case Class: 737 case UnresolvedClass: 738 case UnresolvedClassInError: 739 final int opcode = -1; // opcode is not used 740 return lookupType(cpi, opcode); 741 case String: 742 /* 743 * Normally, we would expect a String here, but anonymous classes can have 744 * "pseudo strings" (arbitrary live objects) patched into a String entry. Such 745 * entries do not have a symbol in the constant pool slot. 746 */ 747 Object string; 748 if (Options.UseConstantPoolCacheJavaCode.getValue()) { 749 // See: ConstantPool::resolve_constant_at_impl 750 /* 751 * Note: Call getArray() before constantPoolIndexToResolvedReferencesIndex() 752 * because it fills the map if the array exists. 753 */ 754 Object[] localResolvedReferences = resolvedReferences.getArray(); 755 final int index = resolvedReferences.constantPoolIndexToResolvedReferencesIndex(cpi); 756 assert index >= 0; 757 // See: ConstantPool::string_at_impl 758 string = localResolvedReferences[index]; 759 if (string != null) { 760 assert string instanceof String || getEntryAt(index) == 0L; 761 return HotSpotObjectConstantImpl.forObject(string); 762 } else { 763 final long metaspaceSymbol = getEntryAt(cpi); 764 if (metaspaceSymbol != 0L) { 765 HotSpotSymbol symbol = new HotSpotSymbol(metaspaceSymbol); 766 string = symbol.asString().intern(); 767 // See: ConstantPool::string_at_put 768 localResolvedReferences[index] = string; 769 } 770 } 771 } else { 772 string = runtime().getCompilerToVM().resolvePossiblyCachedConstantInPool(metaspaceConstantPool, cpi); 773 } 774 return HotSpotObjectConstantImpl.forObject(string); 775 case MethodHandle: 776 case MethodHandleInError: 777 case MethodType: 778 case MethodTypeInError: 779 Object obj = runtime().getCompilerToVM().resolveConstantInPool(metaspaceConstantPool, cpi); 780 return HotSpotObjectConstantImpl.forObject(obj); 781 default: 782 throw new JVMCIError("Unknown constant pool tag %s", tag); 783 } 784 } 785 786 @Override 787 public String lookupUtf8(int cpi) { 788 assertTag(cpi, JVM_CONSTANT.Utf8); 789 String s; 790 if (Options.UseConstantPoolCacheJavaCode.getValue()) { 791 HotSpotSymbol symbol = new HotSpotSymbol(getEntryAt(cpi)); 792 s = symbol.asString(); 793 // It shouldn't but just in case something went wrong... 794 if (s == null) { 795 throw JVMCIError.shouldNotReachHere("malformed UTF-8 string in constant pool"); 796 } 797 } else { 798 s = runtime().getCompilerToVM().getSymbol(getEntryAt(cpi)); 799 } 800 return s; 801 } 802 803 @Override 804 public Signature lookupSignature(int cpi) { 805 return new HotSpotSignature(runtime(), lookupUtf8(cpi)); 806 } 807 808 @Override 809 public JavaConstant lookupAppendix(int cpi, int opcode) { 810 assert Bytecodes.isInvoke(opcode); 811 final int index = rawIndexToConstantPoolIndex(cpi, opcode); 812 813 Object appendix = null; 814 815 if (Options.UseConstantPoolCacheJavaCode.getValue()) { 816 if (!cache.exists()) { 817 // Nothing to load yet. 818 return null; 819 } 820 final int cacheIndex = decodeConstantPoolCacheIndex(index); 821 Cache.Entry entry = cache.getEntryAt(cacheIndex); 822 appendix = entry.getAppendixIfResolved(); 823 } else { 824 appendix = runtime().getCompilerToVM().lookupAppendixInPool(metaspaceConstantPool, index); 825 } 826 827 if (appendix == null) { 828 return null; 829 } else { 830 return HotSpotObjectConstantImpl.forObject(appendix); 831 } 832 } 833 834 /** 835 * Gets a {@link JavaType} corresponding a given metaspace Klass or a metaspace Symbol depending 836 * on the {@link HotSpotVMConfig#compilerToVMKlassTag tag}. 837 * 838 * @param metaspacePointer either a metaspace Klass or a metaspace Symbol 839 */ 840 private static JavaType getJavaType(final long metaspacePointer) { 841 HotSpotJVMCIRuntime runtime = runtime(); 842 HotSpotVMConfig config = runtime.getConfig(); 843 if ((metaspacePointer & config.compilerToVMSymbolTag) != 0) { 844 final long metaspaceSymbol = metaspacePointer & ~config.compilerToVMSymbolTag; 845 String name; 846 if (Options.UseConstantPoolCacheJavaCode.getValue()) { 847 HotSpotSymbol symbol = new HotSpotSymbol(metaspaceSymbol); 848 name = symbol.asString(); 849 // It shouldn't but just in case something went wrong... 850 if (name == null) { 851 throw JVMCIError.shouldNotReachHere("malformed UTF-8 string in constant pool"); 852 } 853 } else { 854 name = runtime.getCompilerToVM().getSymbol(metaspaceSymbol); 855 } 856 return HotSpotUnresolvedJavaType.create(runtime(), "L" + name + ";"); 857 } else { 858 assert (metaspacePointer & config.compilerToVMKlassTag) == 0; 859 return HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(metaspacePointer); 860 } 861 } 862 863 @Override 864 public JavaMethod lookupMethod(int cpi, int opcode) { 865 final int index = rawIndexToConstantPoolIndex(cpi, opcode); 866 final long metaspaceMethod = runtime().getCompilerToVM().lookupMethodInPool(metaspaceConstantPool, index, (byte) opcode); 867 if (metaspaceMethod != 0L) { 868 HotSpotResolvedJavaMethod result = HotSpotResolvedJavaMethodImpl.fromMetaspace(metaspaceMethod); 869 return result; 870 } else { 871 // Get the method's name and signature. 872 String name = getNameRefAt(index); 873 HotSpotSignature signature = new HotSpotSignature(runtime(), getSignatureRefAt(index)); 874 if (opcode == Bytecodes.INVOKEDYNAMIC) { 875 HotSpotResolvedObjectType holder = HotSpotResolvedObjectTypeImpl.fromObjectClass(MethodHandle.class); 876 return new HotSpotMethodUnresolved(name, signature, holder); 877 } else { 878 final int klassIndex = getKlassRefIndexAt(index); 879 final long metaspacePointer = runtime().getCompilerToVM().lookupKlassInPool(metaspaceConstantPool, klassIndex); 880 JavaType holder = getJavaType(metaspacePointer); 881 return new HotSpotMethodUnresolved(name, signature, holder); 882 } 883 } 884 } 885 886 @Override 887 public JavaType lookupType(int cpi, int opcode) { 888 final LookupTypeCacheElement elem = this.lastLookupType; 889 if (elem != null && elem.lastCpi == cpi) { 890 return elem.javaType; 891 } else { 892 final long metaspacePointer = runtime().getCompilerToVM().lookupKlassInPool(metaspaceConstantPool, cpi); 893 JavaType result = getJavaType(metaspacePointer); 894 if (result instanceof ResolvedJavaType) { 895 this.lastLookupType = new LookupTypeCacheElement(cpi, result); 896 } 897 return result; 898 } 899 } 900 901 @Override 902 public JavaField lookupField(int cpi, int opcode) { 903 final int index = rawIndexToConstantPoolIndex(cpi, opcode); 904 final int nameAndTypeIndex = getNameAndTypeRefIndexAt(index); 905 final int nameIndex = getNameRefIndexAt(nameAndTypeIndex); 906 String name = lookupUtf8(nameIndex); 907 final int typeIndex = getSignatureRefIndexAt(nameAndTypeIndex); 908 String typeName = lookupUtf8(typeIndex); 909 JavaType type = runtime().lookupType(typeName, getHolder(), false); 910 911 final int holderIndex = getKlassRefIndexAt(index); 912 JavaType holder = lookupType(holderIndex, opcode); 913 914 if (holder instanceof HotSpotResolvedObjectTypeImpl) { 915 long[] info = new long[2]; 916 long metaspaceKlass; 917 try { 918 metaspaceKlass = runtime().getCompilerToVM().resolveField(metaspaceConstantPool, index, (byte) opcode, info); 919 } catch (Throwable t) { 920 /* 921 * If there was an exception resolving the field we give up and return an unresolved 922 * field. 923 */ 924 return new HotSpotUnresolvedField(holder, name, type); 925 } 926 HotSpotResolvedObjectTypeImpl resolvedHolder = HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(metaspaceKlass); 927 final int flags = (int) info[0]; 928 final long offset = info[1]; 929 HotSpotResolvedJavaField result = resolvedHolder.createField(name, type, offset, flags); 930 return result; 931 } else { 932 return new HotSpotUnresolvedField(holder, name, type); 933 } 934 } 935 936 @Override 937 public void loadReferencedType(int cpi, int opcode) { 938 int index; 939 switch (opcode) { 940 case Bytecodes.CHECKCAST: 941 case Bytecodes.INSTANCEOF: 942 case Bytecodes.NEW: 943 case Bytecodes.ANEWARRAY: 944 case Bytecodes.MULTIANEWARRAY: 945 case Bytecodes.LDC: 946 case Bytecodes.LDC_W: 947 case Bytecodes.LDC2_W: 948 index = cpi; 949 break; 950 case Bytecodes.INVOKEDYNAMIC: { 951 // invokedynamic instructions point to a constant pool cache entry. 952 if (Options.UseConstantPoolCacheJavaCode.getValue()) { 953 // index = decodeConstantPoolCacheIndex(cpi) + 954 // runtime().getConfig().constantPoolCpCacheIndexTag; 955 // index = cache.constantPoolCacheIndexToConstantPoolIndex(index); 956 final int cacheIndex = cpi; 957 index = cache.getEntryAt(decodeInvokedynamicIndex(cacheIndex)).getConstantPoolIndex(); 958 // JVMCIError.guarantee(index == x, index + " != " + x); 959 } else { 960 index = decodeConstantPoolCacheIndex(cpi) + runtime().getConfig().constantPoolCpCacheIndexTag; 961 index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, index); 962 } 963 break; 964 } 965 case Bytecodes.GETSTATIC: 966 case Bytecodes.PUTSTATIC: 967 case Bytecodes.GETFIELD: 968 case Bytecodes.PUTFIELD: 969 case Bytecodes.INVOKEVIRTUAL: 970 case Bytecodes.INVOKESPECIAL: 971 case Bytecodes.INVOKESTATIC: 972 case Bytecodes.INVOKEINTERFACE: { 973 // invoke and field instructions point to a constant pool cache entry. 974 if (Options.UseConstantPoolCacheJavaCode.getValue()) { 975 // index = rawIndexToConstantPoolIndex(cpi, opcode); 976 // index = cache.constantPoolCacheIndexToConstantPoolIndex(index); 977 final int cacheIndex = cpi; 978 index = cache.getEntryAt(cacheIndex).getConstantPoolIndex(); 979 // JVMCIError.guarantee(index == x, index + " != " + x); 980 } else { 981 index = rawIndexToConstantPoolIndex(cpi, opcode); 982 index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, index); 983 } 984 break; 985 } 986 default: 987 throw JVMCIError.shouldNotReachHere("Unexpected opcode " + opcode); 988 } 989 990 final JVM_CONSTANT tag = getTagAt(index); 991 if (tag == null) { 992 assert getTagAt(index - 1) == JVM_CONSTANT.Double || getTagAt(index - 1) == JVM_CONSTANT.Long; 993 return; 994 } 995 switch (tag) { 996 case MethodRef: 997 case Fieldref: 998 case InterfaceMethodref: 999 index = getUncachedKlassRefIndexAt(index); 1000 // Read the tag only once because it could change between multiple reads. 1001 final JVM_CONSTANT klassTag = getTagAt(index); 1002 assert klassTag == JVM_CONSTANT.Class || klassTag == JVM_CONSTANT.UnresolvedClass || klassTag == JVM_CONSTANT.UnresolvedClassInError : klassTag; 1003 // fall through 1004 case Class: 1005 case UnresolvedClass: 1006 case UnresolvedClassInError: 1007 final long metaspaceKlass = runtime().getCompilerToVM().constantPoolKlassAt(metaspaceConstantPool, index); 1008 HotSpotResolvedObjectTypeImpl type = HotSpotResolvedObjectTypeImpl.fromMetaspaceKlass(metaspaceKlass); 1009 Class<?> klass = type.mirror(); 1010 if (!klass.isPrimitive() && !klass.isArray()) { 1011 unsafe.ensureClassInitialized(klass); 1012 } 1013 switch (tag) { 1014 case MethodRef: 1015 if (Bytecodes.isInvokeHandleAlias(opcode)) { 1016 final int methodRefCacheIndex = rawIndexToConstantPoolIndex(cpi, opcode); 1017 if (isInvokeHandle(methodRefCacheIndex, type)) { 1018 runtime().getCompilerToVM().resolveInvokeHandle(metaspaceConstantPool, methodRefCacheIndex); 1019 } 1020 } 1021 } 1022 break; 1023 case InvokeDynamic: 1024 if (isInvokedynamicIndex(cpi)) { 1025 runtime().getCompilerToVM().resolveInvokeDynamic(metaspaceConstantPool, cpi); 1026 } 1027 break; 1028 default: 1029 // nothing 1030 break; 1031 } 1032 } 1033 1034 private boolean isInvokeHandle(int methodRefCacheIndex, HotSpotResolvedObjectTypeImpl klass) { 1035 int index; 1036 if (Options.UseConstantPoolCacheJavaCode.getValue()) { 1037 index = cache.constantPoolCacheIndexToConstantPoolIndex(methodRefCacheIndex); 1038 } else { 1039 index = runtime().getCompilerToVM().constantPoolRemapInstructionOperandFromCache(metaspaceConstantPool, methodRefCacheIndex); 1040 } 1041 assertTag(index, JVM_CONSTANT.MethodRef); 1042 return ResolvedJavaMethod.isSignaturePolymorphic(klass, getNameRefAt(methodRefCacheIndex), runtime().getHostJVMCIBackend().getMetaAccess()); 1043 } 1044 1045 @Override 1046 public String toString() { 1047 HotSpotResolvedObjectType holder = getHolder(); 1048 return "HotSpotConstantPool<" + holder.toJavaName() + ">"; 1049 } 1050}