ssssssss45


C:\hotspot-69087d08d473\src\share\vm/oops/constantPool.cpp
#include "precompiled.hpp"
#include "classfile/classLoaderData.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/metadataOnStackMark.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "interpreter/linkResolver.hpp"
#include "memory/heapInspection.hpp"
#include "memory/metadataFactory.hpp"
#include "memory/oopFactory.hpp"
#include "oops/constantPool.hpp"
#include "oops/instanceKlass.hpp"
#include "oops/objArrayKlass.hpp"
#include "runtime/fieldType.hpp"
#include "runtime/init.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/signature.hpp"
#include "runtime/vframe.hpp"
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
ConstantPool* ConstantPool::allocate(ClassLoaderData* loader_data, int length, TRAPS) {
  Array<u1>* tags = MetadataFactory::new_writeable_array<u1>(loader_data, length, 0, CHECK_NULL);
  int size = ConstantPool::size(length);
  return new (loader_data, size, false, MetaspaceObj::ConstantPoolType, THREAD) ConstantPool(tags);
}
ConstantPool::ConstantPool(Array<u1>* tags) {
  set_length(tags->length());
  set_tags(NULL);
  set_cache(NULL);
  set_reference_map(NULL);
  set_resolved_references(NULL);
  set_operands(NULL);
  set_pool_holder(NULL);
  set_flags(0);
  set_version(0);
  set_lock(new Monitor(Monitor::nonleaf + 2, "A constant pool lock"));
  int length = tags->length();
  for (int index = 0; index < length; index++) {
    tags->at_put(index, JVM_CONSTANT_Invalid);
  }
  set_tags(tags);
}
void ConstantPool::deallocate_contents(ClassLoaderData* loader_data) {
  MetadataFactory::free_metadata(loader_data, cache());
  set_cache(NULL);
  MetadataFactory::free_array<u2>(loader_data, reference_map());
  set_reference_map(NULL);
  MetadataFactory::free_array<jushort>(loader_data, operands());
  set_operands(NULL);
  release_C_heap_structures();
  MetadataFactory::free_array<u1>(loader_data, tags());
  set_tags(NULL);
}
void ConstantPool::release_C_heap_structures() {
  unreference_symbols();
  delete _lock;
  set_lock(NULL);
}
objArrayOop ConstantPool::resolved_references() const {
  return (objArrayOop)JNIHandles::resolve(_resolved_references);
}
objArrayOop ConstantPool::resolved_references_or_null() const {
  if (_cache == NULL) {
    return NULL;
  } else {
    return (objArrayOop)JNIHandles::resolve(_resolved_references);
  }
}
void ConstantPool::initialize_resolved_references(ClassLoaderData* loader_data,
                                                  intStack reference_map,
                                                  int constant_pool_map_length,
                                                  TRAPS) {
  int map_length = reference_map.length();
  if (map_length > 0) {
    if (constant_pool_map_length > 0) {
      Array<u2>* om = MetadataFactory::new_array<u2>(loader_data, constant_pool_map_length, CHECK);
      for (int i = 0; i < constant_pool_map_length; i++) {
        int x = reference_map.at(i);
        assert(x == (int)(jushort) x, "klass index is too big");
        om->at_put(i, (jushort)x);
      }
      set_reference_map(om);
    }
    objArrayOop stom = oopFactory::new_objArray(SystemDictionary::Object_klass(), map_length, CHECK);
    Handle refs_handle (THREAD, (oop)stom);  // must handleize.
    set_resolved_references(loader_data->add_handle(refs_handle));
  }
}
void ConstantPool::restore_unshareable_info(TRAPS) {
  if (resolved_references() != NULL) return;
  restore_vtable();
  if (SystemDictionary::Object_klass_loaded()) {
    int map_length = resolved_reference_length();
    if (map_length > 0) {
      objArrayOop stom = oopFactory::new_objArray(SystemDictionary::Object_klass(), map_length, CHECK);
      Handle refs_handle (THREAD, (oop)stom);  // must handleize.
      ClassLoaderData* loader_data = pool_holder()->class_loader_data();
      set_resolved_references(loader_data->add_handle(refs_handle));
    }
    set_lock(new Monitor(Monitor::nonleaf + 2, "A constant pool lock"));
  }
}
void ConstantPool::remove_unshareable_info() {
  set_resolved_reference_length(
    resolved_references() != NULL ? resolved_references()->length() : 0);
  set_resolved_references(NULL);
  set_lock(NULL);
}
int ConstantPool::cp_to_object_index(int cp_index) {
  int i = reference_map()->find(cp_index);
  return (i < 0) ? _no_index_sentinel : i;
}
Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS) {
  CPSlot entry = this_oop->slot_at(which);
  if (entry.is_resolved()) {
    assert(entry.get_klass()->is_klass(), "must be");
    return entry.get_klass();
  }
  assert(THREAD->is_Java_thread(), "must be a Java thread");
  bool do_resolve = false;
  bool in_error = false;
  Handle mirror_handle;
  Symbol* name = NULL;
  Handle       loader;
  {  MonitorLockerEx ml(this_oop->lock());
    if (this_oop->tag_at(which).is_unresolved_klass()) {
      if (this_oop->tag_at(which).is_unresolved_klass_in_error()) {
        in_error = true;
      } else {
        do_resolve = true;
        name   = this_oop->unresolved_klass_at(which);
        loader = Handle(THREAD, this_oop->pool_holder()->class_loader());
      }
    }
  } // unlocking constantPool
  if (in_error) {
    throw_resolution_error(this_oop, which, CHECK_0);
  }
  if (do_resolve) {
    oop protection_domain = this_oop->pool_holder()->protection_domain();
    Handle h_prot (THREAD, protection_domain);
    Klass* k_oop = SystemDictionary::resolve_or_fail(name, loader, h_prot, true, THREAD);
    KlassHandle k;
    if (!HAS_PENDING_EXCEPTION) {
      k = KlassHandle(THREAD, k_oop);
      mirror_handle = Handle(THREAD, k_oop->java_mirror());
      verify_constant_pool_resolve(this_oop, k, THREAD);
    }
    if (HAS_PENDING_EXCEPTION) {
        MonitorLockerEx ml(this_oop->lock());
        if (this_oop->tag_at(which).is_klass()) {
          CLEAR_PENDING_EXCEPTION;
          entry = this_oop->resolved_klass_at(which);
          return entry.get_klass();
        }
        save_and_throw_exception(this_oop, which, constantTag(JVM_CONSTANT_UnresolvedClass), CHECK_0);
    }
    if (TraceClassResolution && !k()->oop_is_array()) {
      ResourceMark rm;
      int line_number = -1;
      const char * source_file = NULL;
      if (JavaThread::current()->has_last_Java_frame()) {
        vframeStream vfst(JavaThread::current());
        if (!vfst.at_end()) {
          line_number = vfst.method()->line_number_from_bci(vfst.bci());
          Symbol* s = vfst.method()->method_holder()->source_file_name();
          if (s != NULL) {
            source_file = s->as_C_string();
          }
        }
      }
      if (k() != this_oop->pool_holder()) {
        if (source_file != NULL) {
          tty->print("RESOLVE %s %s %s:%d\n",
                     this_oop->pool_holder()->external_name(),
                     InstanceKlass::cast(k())->external_name(), source_file, line_number);
        } else {
          tty->print("RESOLVE %s %s\n",
                     this_oop->pool_holder()->external_name(),
                     InstanceKlass::cast(k())->external_name());
        }
      }
      return k();
    } else {
      MonitorLockerEx ml(this_oop->lock());
      do_resolve = this_oop->tag_at(which).is_unresolved_klass();
      if (do_resolve) {
        this_oop->klass_at_put(which, k());
      }
    }
  }
  entry = this_oop->resolved_klass_at(which);
  assert(entry.is_resolved() && entry.get_klass()->is_klass(), "must be resolved at this point");
  return entry.get_klass();
}
Klass* ConstantPool::klass_at_if_loaded(constantPoolHandle this_oop, int which) {
  CPSlot entry = this_oop->slot_at(which);
  if (entry.is_resolved()) {
    assert(entry.get_klass()->is_klass(), "must be");
    return entry.get_klass();
  } else {
    assert(entry.is_unresolved(), "must be either symbol or klass");
    Thread *thread = Thread::current();
    Symbol* name = entry.get_symbol();
    oop loader = this_oop->pool_holder()->class_loader();
    oop protection_domain = this_oop->pool_holder()->protection_domain();
    Handle h_prot (thread, protection_domain);
    Handle h_loader (thread, loader);
    Klass* k = SystemDictionary::find(name, h_loader, h_prot, thread);
    if (k != NULL) {
      EXCEPTION_MARK;
      KlassHandle klass(THREAD, k);
      verify_constant_pool_resolve(this_oop, klass, THREAD);
      if (HAS_PENDING_EXCEPTION) {
        CLEAR_PENDING_EXCEPTION;
        return NULL;
      }
      return klass();
    } else {
      return k;
    }
  }
}
Klass* ConstantPool::klass_ref_at_if_loaded(constantPoolHandle this_oop, int which) {
  return klass_at_if_loaded(this_oop, this_oop->klass_ref_index_at(which));
}
Method* ConstantPool::method_at_if_loaded(constantPoolHandle cpool,
                                                   int which) {
  if (cpool->cache() == NULL)  return NULL;  // nothing to load yet
  int cache_index = decode_cpcache_index(which, true);
  if (!(cache_index >= 0 && cache_index < cpool->cache()->length())) {
    if (PrintMiscellaneous && (Verbose||WizardMode)) {
      tty->print_cr("bad operand %d in:", which); cpool->print();
    }
    return NULL;
  }
  ConstantPoolCacheEntry* e = cpool->cache()->entry_at(cache_index);
  return e->method_if_resolved(cpool);
}
bool ConstantPool::has_appendix_at_if_loaded(constantPoolHandle cpool, int which) {
  if (cpool->cache() == NULL)  return false;  // nothing to load yet
  int cache_index = decode_cpcache_index(which, true);
  ConstantPoolCacheEntry* e = cpool->cache()->entry_at(cache_index);
  return e->has_appendix();
}
oop ConstantPool::appendix_at_if_loaded(constantPoolHandle cpool, int which) {
  if (cpool->cache() == NULL)  return NULL;  // nothing to load yet
  int cache_index = decode_cpcache_index(which, true);
  ConstantPoolCacheEntry* e = cpool->cache()->entry_at(cache_index);
  return e->appendix_if_resolved(cpool);
}
bool ConstantPool::has_method_type_at_if_loaded(constantPoolHandle cpool, int which) {
  if (cpool->cache() == NULL)  return false;  // nothing to load yet
  int cache_index = decode_cpcache_index(which, true);
  ConstantPoolCacheEntry* e = cpool->cache()->entry_at(cache_index);
  return e->has_method_type();
}
oop ConstantPool::method_type_at_if_loaded(constantPoolHandle cpool, int which) {
  if (cpool->cache() == NULL)  return NULL;  // nothing to load yet
  int cache_index = decode_cpcache_index(which, true);
  ConstantPoolCacheEntry* e = cpool->cache()->entry_at(cache_index);
  return e->method_type_if_resolved(cpool);
}
Symbol* ConstantPool::impl_name_ref_at(int which, bool uncached) {
  int name_index = name_ref_index_at(impl_name_and_type_ref_index_at(which, uncached));
  return symbol_at(name_index);
}
Symbol* ConstantPool::impl_signature_ref_at(int which, bool uncached) {
  int signature_index = signature_ref_index_at(impl_name_and_type_ref_index_at(which, uncached));
  return symbol_at(signature_index);
}
int ConstantPool::impl_name_and_type_ref_index_at(int which, bool uncached) {
  int i = which;
  if (!uncached && cache() != NULL) {
    if (ConstantPool::is_invokedynamic_index(which)) {
      int pool_index = invokedynamic_cp_cache_entry_at(which)->constant_pool_index();
      pool_index = invoke_dynamic_name_and_type_ref_index_at(pool_index);
      assert(tag_at(pool_index).is_name_and_type(), "");
      return pool_index;
    }
    i = remap_instruction_operand_from_cache(which);
  } else {
    if (tag_at(which).is_invoke_dynamic()) {
      int pool_index = invoke_dynamic_name_and_type_ref_index_at(which);
      assert(tag_at(pool_index).is_name_and_type(), "");
      return pool_index;
    }
  }
  assert(tag_at(i).is_field_or_method(), "Corrupted constant pool");
  assert(!tag_at(i).is_invoke_dynamic(), "Must be handled above");
  jint ref_index = *int_at_addr(i);
  return extract_high_short_from_int(ref_index);
}
int ConstantPool::impl_klass_ref_index_at(int which, bool uncached) {
  guarantee(!ConstantPool::is_invokedynamic_index(which),
            "an invokedynamic instruction does not have a klass");
  int i = which;
  if (!uncached && cache() != NULL) {
    i = remap_instruction_operand_from_cache(which);
  }
  assert(tag_at(i).is_field_or_method(), "Corrupted constant pool");
  jint ref_index = *int_at_addr(i);
  return extract_low_short_from_int(ref_index);
}
int ConstantPool::remap_instruction_operand_from_cache(int operand) {
  int cpc_index = operand;
  DEBUG_ONLY(cpc_index -= CPCACHE_INDEX_TAG);
  assert((int)(u2)cpc_index == cpc_index, "clean u2");
  int member_index = cache()->entry_at(cpc_index)->constant_pool_index();
  return member_index;
}
void ConstantPool::verify_constant_pool_resolve(constantPoolHandle this_oop, KlassHandle k, TRAPS) {
 if (k->oop_is_instance() || k->oop_is_objArray()) {
    instanceKlassHandle holder (THREAD, this_oop->pool_holder());
    Klass* elem_oop = k->oop_is_instance() ? k() : ObjArrayKlass::cast(k())->bottom_klass();
    KlassHandle element (THREAD, elem_oop);
    if (element->oop_is_instance()) {
      LinkResolver::check_klass_accessability(holder, element, CHECK);
    }
  }
}
int ConstantPool::name_ref_index_at(int which_nt) {
  jint ref_index = name_and_type_at(which_nt);
  return extract_low_short_from_int(ref_index);
}
int ConstantPool::signature_ref_index_at(int which_nt) {
  jint ref_index = name_and_type_at(which_nt);
  return extract_high_short_from_int(ref_index);
}
Klass* ConstantPool::klass_ref_at(int which, TRAPS) {
  return klass_at(klass_ref_index_at(which), THREAD);
}
Symbol* ConstantPool::klass_name_at(int which) const {
  assert(tag_at(which).is_unresolved_klass() || tag_at(which).is_klass(),
         "Corrupted constant pool");
  CPSlot entry = slot_at(which);
  if (entry.is_resolved()) {
    assert(entry.get_klass()->is_klass(), "must be");
    return entry.get_klass()->name();
  } else {
    assert(entry.is_unresolved(), "must be either symbol or klass");
    return entry.get_symbol();
  }
}
Symbol* ConstantPool::klass_ref_at_noresolve(int which) {
  jint ref_index = klass_ref_index_at(which);
  return klass_at_noresolve(ref_index);
}
Symbol* ConstantPool::uncached_klass_ref_at_noresolve(int which) {
  jint ref_index = uncached_klass_ref_index_at(which);
  return klass_at_noresolve(ref_index);
}
char* ConstantPool::string_at_noresolve(int which) {
  Symbol* s = unresolved_string_at(which);
  if (s == NULL) {
    return (char*)"<pseudo-string>";
  } else {
    return unresolved_string_at(which)->as_C_string();
  }
}
BasicType ConstantPool::basic_type_for_signature_at(int which) {
  return FieldType::basic_type(symbol_at(which));
}
void ConstantPool::resolve_string_constants_impl(constantPoolHandle this_oop, TRAPS) {
  for (int index = 1; index < this_oop->length(); index++) { // Index 0 is unused
    if (this_oop->tag_at(index).is_string()) {
      this_oop->string_at(index, CHECK);
    }
  }
}
bool ConstantPool::resolve_class_constants(TRAPS) {
  constantPoolHandle cp(THREAD, this);
  for (int index = 1; index < length(); index++) { // Index 0 is unused
    if (tag_at(index).is_unresolved_klass() &&
        klass_at_if_loaded(cp, index) == NULL) {
      return false;
  }
  }
  return true;
}
Symbol* ConstantPool::exception_message(constantPoolHandle this_oop, int which, constantTag tag, oop pending_exception) {
  Symbol* message = java_lang_Throwable::detail_message(pending_exception);
  if (message != NULL) {
    return message;
  }
  switch (tag.value()) {
  case JVM_CONSTANT_UnresolvedClass:
    message = this_oop->unresolved_klass_at(which);
    break;
  case JVM_CONSTANT_MethodHandle:
    message = this_oop->method_handle_name_ref_at(which);
    break;
  case JVM_CONSTANT_MethodType:
    message = this_oop->method_type_signature_at(which);
    break;
  default:
    ShouldNotReachHere();
  }
  return message;
}
void ConstantPool::throw_resolution_error(constantPoolHandle this_oop, int which, TRAPS) {
  Symbol* message = NULL;
  Symbol* error = SystemDictionary::find_resolution_error(this_oop, which, &message);
  assert(error != NULL && message != NULL, "checking");
  CLEAR_PENDING_EXCEPTION;
  ResourceMark rm;
  THROW_MSG(error, message->as_C_string());
}
void ConstantPool::save_and_throw_exception(constantPoolHandle this_oop, int which,
                                            constantTag tag, TRAPS) {
  assert(this_oop->lock()->is_locked(), "constant pool lock should be held");
  Symbol* error = PENDING_EXCEPTION->klass()->name();
  int error_tag = tag.error_value();
  if (!PENDING_EXCEPTION->
    is_a(SystemDictionary::LinkageError_klass())) {
  } else if (this_oop->tag_at(which).value() != error_tag) {
    Symbol* message = exception_message(this_oop, which, tag, PENDING_EXCEPTION);
    SystemDictionary::add_resolution_error(this_oop, which, error, message);
    this_oop->tag_at_put(which, error_tag);
  } else {
    throw_resolution_error(this_oop, which, CHECK);
  }
  assert(HAS_PENDING_EXCEPTION, "should not be cleared");
}
oop ConstantPool::resolve_constant_at_impl(constantPoolHandle this_oop, int index, int cache_index, TRAPS) {
  oop result_oop = NULL;
  Handle throw_exception;
  if (cache_index == _possible_index_sentinel) {
    assert(index > 0, "valid index");
    cache_index = this_oop->cp_to_object_index(index);
  }
  assert(cache_index == _no_index_sentinel || cache_index >= 0, "");
  assert(index == _no_index_sentinel || index >= 0, "");
  if (cache_index >= 0) {
    result_oop = this_oop->resolved_references()->obj_at(cache_index);
    if (result_oop != NULL) {
      return result_oop;
    }
    index = this_oop->object_to_cp_index(cache_index);
  }
  jvalue prim_value;  // temp used only in a few cases below
  constantTag tag = this_oop->tag_at(index);
  switch (tag.value()) {
  case JVM_CONSTANT_UnresolvedClass:
  case JVM_CONSTANT_UnresolvedClassInError:
  case JVM_CONSTANT_Class:
    {
      assert(cache_index == _no_index_sentinel, "should not have been set");
      Klass* resolved = klass_at_impl(this_oop, index, CHECK_NULL);
      result_oop = resolved->java_mirror();
      break;
    }
  case JVM_CONSTANT_String:
    assert(cache_index != _no_index_sentinel, "should have been set");
    if (this_oop->is_pseudo_string_at(index)) {
      result_oop = this_oop->pseudo_string_at(index, cache_index);
      break;
    }
    result_oop = string_at_impl(this_oop, index, cache_index, CHECK_NULL);
    break;
  case JVM_CONSTANT_MethodHandleInError:
  case JVM_CONSTANT_MethodTypeInError:
    {
      throw_resolution_error(this_oop, index, CHECK_NULL);
      break;
    }
  case JVM_CONSTANT_MethodHandle:
    {
      int ref_kind                 = this_oop->method_handle_ref_kind_at(index);
      int callee_index             = this_oop->method_handle_klass_index_at(index);
      Symbol*  name =      this_oop->method_handle_name_ref_at(index);
      Symbol*  signature = this_oop->method_handle_signature_ref_at(index);
      if (PrintMiscellaneous)
        tty->print_cr("resolve JVM_CONSTANT_MethodHandle:%d [%d/%d/%d] %s.%s",
                      ref_kind, index, this_oop->method_handle_index_at(index),
                      callee_index, name->as_C_string(), signature->as_C_string());
      KlassHandle callee;
      { Klass* k = klass_at_impl(this_oop, callee_index, CHECK_NULL);
        callee = KlassHandle(THREAD, k);
      }
      KlassHandle klass(THREAD, this_oop->pool_holder());
      Handle value = SystemDictionary::link_method_handle_constant(klass, ref_kind,
                                                                   callee, name, signature,
                                                                   THREAD);
      result_oop = value();
      if (HAS_PENDING_EXCEPTION) {
        MonitorLockerEx ml(this_oop->lock());  // lock cpool to change tag.
        save_and_throw_exception(this_oop, index, tag, CHECK_NULL);
      }
      break;
    }
  case JVM_CONSTANT_MethodType:
    {
      Symbol*  signature = this_oop->method_type_signature_at(index);
      if (PrintMiscellaneous)
        tty->print_cr("resolve JVM_CONSTANT_MethodType [%d/%d] %s",
                      index, this_oop->method_type_index_at(index),
                      signature->as_C_string());
      KlassHandle klass(THREAD, this_oop->pool_holder());
      Handle value = SystemDictionary::find_method_handle_type(signature, klass, THREAD);
      result_oop = value();
      if (HAS_PENDING_EXCEPTION) {
        MonitorLockerEx ml(this_oop->lock());  // lock cpool to change tag.
        save_and_throw_exception(this_oop, index, tag, CHECK_NULL);
      }
      break;
    }
  case JVM_CONSTANT_Integer:
    assert(cache_index == _no_index_sentinel, "should not have been set");
    prim_value.i = this_oop->int_at(index);
    result_oop = java_lang_boxing_object::create(T_INT, &prim_value, CHECK_NULL);
    break;
  case JVM_CONSTANT_Float:
    assert(cache_index == _no_index_sentinel, "should not have been set");
    prim_value.f = this_oop->float_at(index);
    result_oop = java_lang_boxing_object::create(T_FLOAT, &prim_value, CHECK_NULL);
    break;
  case JVM_CONSTANT_Long:
    assert(cache_index == _no_index_sentinel, "should not have been set");
    prim_value.j = this_oop->long_at(index);
    result_oop = java_lang_boxing_object::create(T_LONG, &prim_value, CHECK_NULL);
    break;
  case JVM_CONSTANT_Double:
    assert(cache_index == _no_index_sentinel, "should not have been set");
    prim_value.d = this_oop->double_at(index);
    result_oop = java_lang_boxing_object::create(T_DOUBLE, &prim_value, CHECK_NULL);
    break;
  default:
    DEBUG_ONLY( tty->print_cr("*** %p: tag at CP[%d/%d] = %d",
                              this_oop(), index, cache_index, tag.value()));
    assert(false, "unexpected constant tag");
    break;
  }
  if (cache_index >= 0) {
    Handle result_handle(THREAD, result_oop);
    MonitorLockerEx ml(this_oop->lock());  // don't know if we really need this
    oop result = this_oop->resolved_references()->obj_at(cache_index);
    if (result == NULL) {
      this_oop->resolved_references()->obj_at_put(cache_index, result_handle());
      return result_handle();
    } else {
      return result;
    }
  } else {
    return result_oop;
  }
}
oop ConstantPool::uncached_string_at(int which, TRAPS) {
  Symbol* sym = unresolved_string_at(which);
  oop str = StringTable::intern(sym, CHECK_(NULL));
  assert(java_lang_String::is_instance(str), "must be string");
  return str;
}
oop ConstantPool::resolve_bootstrap_specifier_at_impl(constantPoolHandle this_oop, int index, TRAPS) {
  assert(this_oop->tag_at(index).is_invoke_dynamic(), "Corrupted constant pool");
  Handle bsm;
  int argc;
  {
    int bsm_index = this_oop->invoke_dynamic_bootstrap_method_ref_index_at(index);
    oop bsm_oop = this_oop->resolve_possibly_cached_constant_at(bsm_index, CHECK_NULL);
    if (!java_lang_invoke_MethodHandle::is_instance(bsm_oop)) {
      THROW_MSG_NULL(vmSymbols::java_lang_LinkageError(), "BSM not an MethodHandle");
    }
    argc = this_oop->invoke_dynamic_argument_count_at(index);
    if (argc == 0)  return bsm_oop;
    bsm = Handle(THREAD, bsm_oop);
  }
  objArrayHandle info;
  {
    objArrayOop info_oop = oopFactory::new_objArray(SystemDictionary::Object_klass(), 1+argc, CHECK_NULL);
    info = objArrayHandle(THREAD, info_oop);
  }
  info->obj_at_put(0, bsm());
  for (int i = 0; i < argc; i++) {
    int arg_index = this_oop->invoke_dynamic_argument_index_at(index, i);
    oop arg_oop = this_oop->resolve_possibly_cached_constant_at(arg_index, CHECK_NULL);
    info->obj_at_put(1+i, arg_oop);
  }
  return info();
}
oop ConstantPool::string_at_impl(constantPoolHandle this_oop, int which, int obj_index, TRAPS) {
  oop str = this_oop->resolved_references()->obj_at(obj_index);
  if (str != NULL) return str;
  Symbol* sym = this_oop->unresolved_string_at(which);
  str = StringTable::intern(sym, CHECK_(NULL));
  this_oop->string_at_put(which, obj_index, str);
  assert(java_lang_String::is_instance(str), "must be string");
  return str;
}
bool ConstantPool::klass_name_at_matches(instanceKlassHandle k,
                                                int which) {
  Symbol* cp_name = klass_name_at(which);
  return (cp_name == k->name());
}
void ConstantPool::unreference_symbols() {
  for (int index = 1; index < length(); index++) { // Index 0 is unused
    constantTag tag = tag_at(index);
    if (tag.is_symbol()) {
      symbol_at(index)->decrement_refcount();
    }
  }
}
bool ConstantPool::compare_entry_to(int index1, constantPoolHandle cp2,
       int index2, TRAPS) {
  jbyte t1 = tag_at(index1).non_error_value();
  jbyte t2 = cp2->tag_at(index2).non_error_value();
  if (t1 != t2) {
    return false;
  }
  switch (t1) {
  case JVM_CONSTANT_Class:
  {
    Klass* k1 = klass_at(index1, CHECK_false);
    Klass* k2 = cp2->klass_at(index2, CHECK_false);
    if (k1 == k2) {
      return true;
    }
  } break;
  case JVM_CONSTANT_ClassIndex:
  {
    int recur1 = klass_index_at(index1);
    int recur2 = cp2->klass_index_at(index2);
    bool match = compare_entry_to(recur1, cp2, recur2, CHECK_false);
    if (match) {
      return true;
    }
  } break;
  case JVM_CONSTANT_Double:
  {
    jdouble d1 = double_at(index1);
    jdouble d2 = cp2->double_at(index2);
    if (d1 == d2) {
      return true;
    }
  } break;
  case JVM_CONSTANT_Fieldref:
  case JVM_CONSTANT_InterfaceMethodref:
  case JVM_CONSTANT_Methodref:
  {
    int recur1 = uncached_klass_ref_index_at(index1);
    int recur2 = cp2->uncached_klass_ref_index_at(index2);
    bool match = compare_entry_to(recur1, cp2, recur2, CHECK_false);
    if (match) {
      recur1 = uncached_name_and_type_ref_index_at(index1);
      recur2 = cp2->uncached_name_and_type_ref_index_at(index2);
      match = compare_entry_to(recur1, cp2, recur2, CHECK_false);
      if (match) {
        return true;
      }
    }
  } break;
  case JVM_CONSTANT_Float:
  {
    jfloat f1 = float_at(index1);
    jfloat f2 = cp2->float_at(index2);
    if (f1 == f2) {
      return true;
    }
  } break;
  case JVM_CONSTANT_Integer:
  {
    jint i1 = int_at(index1);
    jint i2 = cp2->int_at(index2);
    if (i1 == i2) {
      return true;
    }
  } break;
  case JVM_CONSTANT_Long:
  {
    jlong l1 = long_at(index1);
    jlong l2 = cp2->long_at(index2);
    if (l1 == l2) {
      return true;
    }
  } break;
  case JVM_CONSTANT_NameAndType:
  {
    int recur1 = name_ref_index_at(index1);
    int recur2 = cp2->name_ref_index_at(index2);
    bool match = compare_entry_to(recur1, cp2, recur2, CHECK_false);
    if (match) {
      recur1 = signature_ref_index_at(index1);
      recur2 = cp2->signature_ref_index_at(index2);
      match = compare_entry_to(recur1, cp2, recur2, CHECK_false);
      if (match) {
        return true;
      }
    }
  } break;
  case JVM_CONSTANT_StringIndex:
  {
    int recur1 = string_index_at(index1);
    int recur2 = cp2->string_index_at(index2);
    bool match = compare_entry_to(recur1, cp2, recur2, CHECK_false);
    if (match) {
      return true;
    }
  } break;
  case JVM_CONSTANT_UnresolvedClass:
  {
    Symbol* k1 = unresolved_klass_at(index1);
    Symbol* k2 = cp2->unresolved_klass_at(index2);
    if (k1 == k2) {
      return true;
    }
  } break;
  case JVM_CONSTANT_MethodType:
  {
    int k1 = method_type_index_at_error_ok(index1);
    int k2 = cp2->method_type_index_at_error_ok(index2);
    bool match = compare_entry_to(k1, cp2, k2, CHECK_false);
    if (match) {
      return true;
    }
  } break;
  case JVM_CONSTANT_MethodHandle:
  {
    int k1 = method_handle_ref_kind_at_error_ok(index1);
    int k2 = cp2->method_handle_ref_kind_at_error_ok(index2);
    if (k1 == k2) {
      int i1 = method_handle_index_at_error_ok(index1);
      int i2 = cp2->method_handle_index_at_error_ok(index2);
      bool match = compare_entry_to(i1, cp2, i2, CHECK_false);
      if (match) {
        return true;
      }
    }
  } break;
  case JVM_CONSTANT_InvokeDynamic:
  {
    int k1 = invoke_dynamic_name_and_type_ref_index_at(index1);
    int k2 = cp2->invoke_dynamic_name_and_type_ref_index_at(index2);
    int i1 = invoke_dynamic_bootstrap_specifier_index(index1);
    int i2 = cp2->invoke_dynamic_bootstrap_specifier_index(index2);
    bool match_entry = compare_entry_to(k1, cp2, k2, CHECK_false);
    bool match_operand = compare_operand_to(i1, cp2, i2, CHECK_false);
    return (match_entry && match_operand);
  } break;
  case JVM_CONSTANT_String:
  {
    Symbol* s1 = unresolved_string_at(index1);
    Symbol* s2 = cp2->unresolved_string_at(index2);
    if (s1 == s2) {
      return true;
    }
  } break;
  case JVM_CONSTANT_Utf8:
  {
    Symbol* s1 = symbol_at(index1);
    Symbol* s2 = cp2->symbol_at(index2);
    if (s1 == s2) {
      return true;
    }
  } break;
  case JVM_CONSTANT_Invalid: // fall through
  default:
    ShouldNotReachHere();
    break;
  }
  return false;
} // end compare_entry_to()
void ConstantPool::resize_operands(int delta_len, int delta_size, TRAPS) {
  int old_len  = operand_array_length(operands());
  int new_len  = old_len + delta_len;
  int min_len  = (delta_len > 0) ? old_len : new_len;
  int old_size = operands()->length();
  int new_size = old_size + delta_size;
  int min_size = (delta_size > 0) ? old_size : new_size;
  ClassLoaderData* loader_data = pool_holder()->class_loader_data();
  Array<u2>* new_ops = MetadataFactory::new_array<u2>(loader_data, new_size, CHECK);
  for (int idx = 0; idx < min_len; idx++) {
    int offset = operand_offset_at(idx);                       // offset in original array
    operand_offset_at_put(new_ops, idx, offset + 2*delta_len); // offset in resized array
  }
  Copy::conjoint_memory_atomic(operands()->adr_at(2*old_len),
                               new_ops->adr_at(2*new_len),
                               (min_size - 2*min_len) * sizeof(u2));
  if ( operands() != NULL) { // the safety check
    MetadataFactory::free_array<u2>(loader_data, operands());
  }
  set_operands(new_ops);
} // end resize_operands()
void ConstantPool::extend_operands(constantPoolHandle ext_cp, TRAPS) {
  int delta_len = operand_array_length(ext_cp->operands());
  if (delta_len == 0) {
    return; // nothing to do
  }
  int delta_size = ext_cp->operands()->length();
  assert(delta_len  > 0 && delta_size > 0, "extended operands array must be bigger");
  if (operand_array_length(operands()) == 0) {
    ClassLoaderData* loader_data = pool_holder()->class_loader_data();
    Array<u2>* new_ops = MetadataFactory::new_array<u2>(loader_data, delta_size, CHECK);
    operand_offset_at_put(new_ops, 0, 2*delta_len); // offset in new array
    set_operands(new_ops);
  } else {
    resize_operands(delta_len, delta_size, CHECK);
  }
} // end extend_operands()
void ConstantPool::shrink_operands(int new_len, TRAPS) {
  int old_len = operand_array_length(operands());
  if (new_len == old_len) {
    return; // nothing to do
  }
  assert(new_len < old_len, "shrunken operands array must be smaller");
  int free_base  = operand_next_offset_at(new_len - 1);
  int delta_len  = new_len - old_len;
  int delta_size = 2*delta_len + free_base - operands()->length();
  resize_operands(delta_len, delta_size, CHECK);
} // end shrink_operands()
void ConstantPool::copy_operands(constantPoolHandle from_cp,
                                 constantPoolHandle to_cp,
                                 TRAPS) {
  int from_oplen = operand_array_length(from_cp->operands());
  int old_oplen  = operand_array_length(to_cp->operands());
  if (from_oplen != 0) {
    ClassLoaderData* loader_data = to_cp->pool_holder()->class_loader_data();
    if (old_oplen == 0) {
      int len = from_cp->operands()->length();
      Array<u2>* new_ops = MetadataFactory::new_array<u2>(loader_data, len, CHECK);
      Copy::conjoint_memory_atomic(
          from_cp->operands()->adr_at(0), new_ops->adr_at(0), len * sizeof(u2));
      to_cp->set_operands(new_ops);
    } else {
      int old_len  = to_cp->operands()->length();
      int from_len = from_cp->operands()->length();
      int old_off  = old_oplen * sizeof(u2);
      int from_off = from_oplen * sizeof(u2);
      Array<u2>* new_operands = MetadataFactory::new_array<u2>(loader_data, old_len + from_len, CHECK);
      int fillp = 0, len = 0;
      Copy::conjoint_memory_atomic(to_cp->operands()->adr_at(0),
                                   new_operands->adr_at(fillp),
                                   (len = old_off) * sizeof(u2));
      fillp += len;
      Copy::conjoint_memory_atomic(from_cp->operands()->adr_at(0),
                                   new_operands->adr_at(fillp),
                                   (len = from_off) * sizeof(u2));
      fillp += len;
      Copy::conjoint_memory_atomic(to_cp->operands()->adr_at(old_off),
                                   new_operands->adr_at(fillp),
                                   (len = old_len - old_off) * sizeof(u2));
      fillp += len;
      Copy::conjoint_memory_atomic(from_cp->operands()->adr_at(from_off),
                                   new_operands->adr_at(fillp),
                                   (len = from_len - from_off) * sizeof(u2));
      fillp += len;
      assert(fillp == new_operands->length(), "");
      for (int j = 0; j < from_oplen; j++) {
        int offset = operand_offset_at(new_operands, old_oplen + j);
        assert(offset == operand_offset_at(from_cp->operands(), j), "correct copy");
        offset += old_len;  // every new tuple is preceded by old_len extra u2's
        operand_offset_at_put(new_operands, old_oplen + j, offset);
      }
      to_cp->set_operands(new_operands);
    }
  }
} // end copy_operands()
void ConstantPool::copy_cp_to_impl(constantPoolHandle from_cp, int start_i, int end_i,
       constantPoolHandle to_cp, int to_i, TRAPS) {
  int dest_i = to_i;  // leave original alone for debug purposes
  for (int src_i = start_i; src_i <= end_i; /* see loop bottom */ ) {
    copy_entry_to(from_cp, src_i, to_cp, dest_i, CHECK);
    switch (from_cp->tag_at(src_i).value()) {
    case JVM_CONSTANT_Double:
    case JVM_CONSTANT_Long:
      src_i += 2;
      dest_i += 2;
      break;
    default:
      src_i++;
      dest_i++;
      break;
    }
  }
  copy_operands(from_cp, to_cp, CHECK);
} // end copy_cp_to_impl()
void ConstantPool::copy_entry_to(constantPoolHandle from_cp, int from_i,
                                        constantPoolHandle to_cp, int to_i,
                                        TRAPS) {
  int tag = from_cp->tag_at(from_i).value();
  switch (tag) {
  case JVM_CONSTANT_Class:
  {
    Klass* k = from_cp->klass_at(from_i, CHECK);
    to_cp->klass_at_put(to_i, k);
  } break;
  case JVM_CONSTANT_ClassIndex:
  {
    jint ki = from_cp->klass_index_at(from_i);
    to_cp->klass_index_at_put(to_i, ki);
  } break;
  case JVM_CONSTANT_Double:
  {
    jdouble d = from_cp->double_at(from_i);
    to_cp->double_at_put(to_i, d);
    to_cp->tag_at_put(to_i + 1, JVM_CONSTANT_Invalid);
  } break;
  case JVM_CONSTANT_Fieldref:
  {
    int class_index = from_cp->uncached_klass_ref_index_at(from_i);
    int name_and_type_index = from_cp->uncached_name_and_type_ref_index_at(from_i);
    to_cp->field_at_put(to_i, class_index, name_and_type_index);
  } break;
  case JVM_CONSTANT_Float:
  {
    jfloat f = from_cp->float_at(from_i);
    to_cp->float_at_put(to_i, f);
  } break;
  case JVM_CONSTANT_Integer:
  {
    jint i = from_cp->int_at(from_i);
    to_cp->int_at_put(to_i, i);
  } break;
  case JVM_CONSTANT_InterfaceMethodref:
  {
    int class_index = from_cp->uncached_klass_ref_index_at(from_i);
    int name_and_type_index = from_cp->uncached_name_and_type_ref_index_at(from_i);
    to_cp->interface_method_at_put(to_i, class_index, name_and_type_index);
  } break;
  case JVM_CONSTANT_Long:
  {
    jlong l = from_cp->long_at(from_i);
    to_cp->long_at_put(to_i, l);
    to_cp->tag_at_put(to_i + 1, JVM_CONSTANT_Invalid);
  } break;
  case JVM_CONSTANT_Methodref:
  {
    int class_index = from_cp->uncached_klass_ref_index_at(from_i);
    int name_and_type_index = from_cp->uncached_name_and_type_ref_index_at(from_i);
    to_cp->method_at_put(to_i, class_index, name_and_type_index);
  } break;
  case JVM_CONSTANT_NameAndType:
  {
    int name_ref_index = from_cp->name_ref_index_at(from_i);
    int signature_ref_index = from_cp->signature_ref_index_at(from_i);
    to_cp->name_and_type_at_put(to_i, name_ref_index, signature_ref_index);
  } break;
  case JVM_CONSTANT_StringIndex:
  {
    jint si = from_cp->string_index_at(from_i);
    to_cp->string_index_at_put(to_i, si);
  } break;
  case JVM_CONSTANT_UnresolvedClass:
  case JVM_CONSTANT_UnresolvedClassInError:
  {
    CPSlot entry = from_cp->slot_at(from_i);
    if (entry.is_resolved()) {
      assert(entry.get_klass()->is_klass(), "must be");
      to_cp->klass_at_put(to_i, entry.get_klass());
    } else {
      to_cp->unresolved_klass_at_put(to_i, entry.get_symbol());
    }
  } break;
  case JVM_CONSTANT_String:
  {
    Symbol* s = from_cp->unresolved_string_at(from_i);
    to_cp->unresolved_string_at_put(to_i, s);
  } break;
  case JVM_CONSTANT_Utf8:
  {
    Symbol* s = from_cp->symbol_at(from_i);
    s->increment_refcount();
    to_cp->symbol_at_put(to_i, s);
  } break;
  case JVM_CONSTANT_MethodType:
  case JVM_CONSTANT_MethodTypeInError:
  {
    jint k = from_cp->method_type_index_at_error_ok(from_i);
    to_cp->method_type_index_at_put(to_i, k);
  } break;
  case JVM_CONSTANT_MethodHandle:
  case JVM_CONSTANT_MethodHandleInError:
  {
    int k1 = from_cp->method_handle_ref_kind_at_error_ok(from_i);
    int k2 = from_cp->method_handle_index_at_error_ok(from_i);
    to_cp->method_handle_index_at_put(to_i, k1, k2);
  } break;
  case JVM_CONSTANT_InvokeDynamic:
  {
    int k1 = from_cp->invoke_dynamic_bootstrap_specifier_index(from_i);
    int k2 = from_cp->invoke_dynamic_name_and_type_ref_index_at(from_i);
    k1 += operand_array_length(to_cp->operands());  // to_cp might already have operands
    to_cp->invoke_dynamic_at_put(to_i, k1, k2);
  } break;
  case JVM_CONSTANT_Invalid: // fall through
  default:
  {
    ShouldNotReachHere();
  } break;
  }
} // end copy_entry_to()
int ConstantPool::find_matching_entry(int pattern_i,
      constantPoolHandle search_cp, TRAPS) {
  for (int i = 1; i < search_cp->length(); i++) {
    bool found = compare_entry_to(pattern_i, search_cp, i, CHECK_0);
    if (found) {
      return i;
    }
  }
  return 0;  // entry not found; return unused index zero (0)
} // end find_matching_entry()
bool ConstantPool::compare_operand_to(int idx1, constantPoolHandle cp2, int idx2, TRAPS) {
  int k1 = operand_bootstrap_method_ref_index_at(idx1);
  int k2 = cp2->operand_bootstrap_method_ref_index_at(idx2);
  bool match = compare_entry_to(k1, cp2, k2, CHECK_false);
  if (!match) {
    return false;
  }
  int argc = operand_argument_count_at(idx1);
  if (argc == cp2->operand_argument_count_at(idx2)) {
    for (int j = 0; j < argc; j++) {
      k1 = operand_argument_index_at(idx1, j);
      k2 = cp2->operand_argument_index_at(idx2, j);
      match = compare_entry_to(k1, cp2, k2, CHECK_false);
      if (!match) {
        return false;
      }
    }
    return true;           // got through loop; all elements equal
  }
  return false;
} // end compare_operand_to()
int ConstantPool::find_matching_operand(int pattern_i,
                    constantPoolHandle search_cp, int search_len, TRAPS) {
  for (int i = 0; i < search_len; i++) {
    bool found = compare_operand_to(pattern_i, search_cp, i, CHECK_(-1));
    if (found) {
      return i;
    }
  }
  return -1;  // bootstrap specifier not found; return unused index (-1)
} // end find_matching_operand()
#ifndef PRODUCT
const char* ConstantPool::printable_name_at(int which) {
  constantTag tag = tag_at(which);
  if (tag.is_string()) {
    return string_at_noresolve(which);
  } else if (tag.is_klass() || tag.is_unresolved_klass()) {
    return klass_name_at(which)->as_C_string();
  } else if (tag.is_symbol()) {
    return symbol_at(which)->as_C_string();
  }
  return "";
}
#endif // PRODUCT
const bool debug_cpool = false;
#define DBG(code) do { if (debug_cpool) { (code); } } while(0)
static void print_cpool_bytes(jint cnt, u1 *bytes) {
  const char* WARN_MSG = "Must not be such entry!";
  jint size = 0;
  u2   idx1, idx2;
  for (jint idx = 1; idx < cnt; idx++) {
    jint ent_size = 0;
    u1   tag  = *bytes++;
    size++;                       // count tag
    printf("const #%03d, tag: %02d ", idx, tag);
    switch(tag) {
      case JVM_CONSTANT_Invalid: {
        printf("Invalid");
        break;
      }
      case JVM_CONSTANT_Unicode: {
        printf("Unicode      %s", WARN_MSG);
        break;
      }
      case JVM_CONSTANT_Utf8: {
        u2 len = Bytes::get_Java_u2(bytes);
        char str[128];
        if (len > 127) {
           len = 127;
        }
        strncpy(str, (char *) (bytes+2), len);
        str[len] = '\0';
        printf("Utf8          \"%s\"", str);
        ent_size = 2 + len;
        break;
      }
      case JVM_CONSTANT_Integer: {
        u4 val = Bytes::get_Java_u4(bytes);
        printf("int          %d", *(int *) &val);
        ent_size = 4;
        break;
      }
      case JVM_CONSTANT_Float: {
        u4 val = Bytes::get_Java_u4(bytes);
        printf("float        %5.3ff", *(float *) &val);
        ent_size = 4;
        break;
      }
      case JVM_CONSTANT_Long: {
        u8 val = Bytes::get_Java_u8(bytes);
        printf("long         " INT64_FORMAT, (int64_t) *(jlong *) &val);
        ent_size = 8;
        idx++; // Long takes two cpool slots
        break;
      }
      case JVM_CONSTANT_Double: {
        u8 val = Bytes::get_Java_u8(bytes);
        printf("double       %5.3fd", *(jdouble *)&val);
        ent_size = 8;
        idx++; // Double takes two cpool slots
        break;
      }
      case JVM_CONSTANT_Class: {
        idx1 = Bytes::get_Java_u2(bytes);
        printf("class        #%03d", idx1);
        ent_size = 2;
        break;
      }
      case JVM_CONSTANT_String: {
        idx1 = Bytes::get_Java_u2(bytes);
        printf("String       #%03d", idx1);
        ent_size = 2;
        break;
      }
      case JVM_CONSTANT_Fieldref: {
        idx1 = Bytes::get_Java_u2(bytes);
        idx2 = Bytes::get_Java_u2(bytes+2);
        printf("Field        #%03d, #%03d", (int) idx1, (int) idx2);
        ent_size = 4;
        break;
      }
      case JVM_CONSTANT_Methodref: {
        idx1 = Bytes::get_Java_u2(bytes);
        idx2 = Bytes::get_Java_u2(bytes+2);
        printf("Method       #%03d, #%03d", idx1, idx2);
        ent_size = 4;
        break;
      }
      case JVM_CONSTANT_InterfaceMethodref: {
        idx1 = Bytes::get_Java_u2(bytes);
        idx2 = Bytes::get_Java_u2(bytes+2);
        printf("InterfMethod #%03d, #%03d", idx1, idx2);
        ent_size = 4;
        break;
      }
      case JVM_CONSTANT_NameAndType: {
        idx1 = Bytes::get_Java_u2(bytes);
        idx2 = Bytes::get_Java_u2(bytes+2);
        printf("NameAndType  #%03d, #%03d", idx1, idx2);
        ent_size = 4;
        break;
      }
      case JVM_CONSTANT_ClassIndex: {
        printf("ClassIndex  %s", WARN_MSG);
        break;
      }
      case JVM_CONSTANT_UnresolvedClass: {
        printf("UnresolvedClass: %s", WARN_MSG);
        break;
      }
      case JVM_CONSTANT_UnresolvedClassInError: {
        printf("UnresolvedClassInErr: %s", WARN_MSG);
        break;
      }
      case JVM_CONSTANT_StringIndex: {
        printf("StringIndex: %s", WARN_MSG);
        break;
      }
    }
    printf(";\n");
    bytes += ent_size;
    size  += ent_size;
  }
  printf("Cpool size: %d\n", size);
  fflush(0);
  return;
} /* end print_cpool_bytes */
jint ConstantPool::cpool_entry_size(jint idx) {
  switch(tag_at(idx).value()) {
    case JVM_CONSTANT_Invalid:
    case JVM_CONSTANT_Unicode:
      return 1;
    case JVM_CONSTANT_Utf8:
      return 3 + symbol_at(idx)->utf8_length();
    case JVM_CONSTANT_Class:
    case JVM_CONSTANT_String:
    case JVM_CONSTANT_ClassIndex:
    case JVM_CONSTANT_UnresolvedClass:
    case JVM_CONSTANT_UnresolvedClassInError:
    case JVM_CONSTANT_StringIndex:
    case JVM_CONSTANT_MethodType:
    case JVM_CONSTANT_MethodTypeInError:
      return 3;
    case JVM_CONSTANT_MethodHandle:
    case JVM_CONSTANT_MethodHandleInError:
      return 4; //tag, ref_kind, ref_index
    case JVM_CONSTANT_Integer:
    case JVM_CONSTANT_Float:
    case JVM_CONSTANT_Fieldref:
    case JVM_CONSTANT_Methodref:
    case JVM_CONSTANT_InterfaceMethodref:
    case JVM_CONSTANT_NameAndType:
      return 5;
    case JVM_CONSTANT_InvokeDynamic:
      return 5;
    case JVM_CONSTANT_Long:
    case JVM_CONSTANT_Double:
      return 9;
  }
  assert(false, "cpool_entry_size: Invalid constant pool entry tag");
  return 1;
} /* end cpool_entry_size */
jint ConstantPool::hash_entries_to(SymbolHashMap *symmap,
                                          SymbolHashMap *classmap) {
  jint size = 0;
  for (u2 idx = 1; idx < length(); idx++) {
    u2 tag = tag_at(idx).value();
    size += cpool_entry_size(idx);
    switch(tag) {
      case JVM_CONSTANT_Utf8: {
        Symbol* sym = symbol_at(idx);
        symmap->add_entry(sym, idx);
        DBG(printf("adding symbol entry %s = %d\n", sym->as_utf8(), idx));
        break;
      }
      case JVM_CONSTANT_Class:
      case JVM_CONSTANT_UnresolvedClass:
      case JVM_CONSTANT_UnresolvedClassInError: {
        Symbol* sym = klass_name_at(idx);
        classmap->add_entry(sym, idx);
        DBG(printf("adding class entry %s = %d\n", sym->as_utf8(), idx));
        break;
      }
      case JVM_CONSTANT_Long:
      case JVM_CONSTANT_Double: {
        idx++; // Both Long and Double take two cpool slots
        break;
      }
    }
  }
  return size;
} /* end hash_utf8_entries_to */
int ConstantPool::copy_cpool_bytes(int cpool_size,
                                          SymbolHashMap* tbl,
                                          unsigned char *bytes) {
  u2   idx1, idx2;
  jint size  = 0;
  jint cnt   = length();
  unsigned char *start_bytes = bytes;
  for (jint idx = 1; idx < cnt; idx++) {
    u1   tag      = tag_at(idx).value();
    jint ent_size = cpool_entry_size(idx);
    assert(size + ent_size <= cpool_size, "Size mismatch");
    DBG(printf("#%03hd tag=%03hd, ", idx, tag));
    switch(tag) {
      case JVM_CONSTANT_Invalid: {
        DBG(printf("JVM_CONSTANT_Invalid"));
        break;
      }
      case JVM_CONSTANT_Unicode: {
        assert(false, "Wrong constant pool tag: JVM_CONSTANT_Unicode");
        DBG(printf("JVM_CONSTANT_Unicode"));
        break;
      }
      case JVM_CONSTANT_Utf8: {
        Symbol* sym = symbol_at(idx);
        char*     str = sym->as_utf8();
        int       len = (int) strlen(str);
        Bytes::put_Java_u2((address) (bytes+1), (u2) len);
        for (int i = 0; i < len; i++) {
            bytes[3+i] = (u1) str[i];
        }
        DBG(printf("JVM_CONSTANT_Utf8: %s ", str));
        break;
      }
      case JVM_CONSTANT_Integer: {
        jint val = int_at(idx);
        Bytes::put_Java_u4((address) (bytes+1), *(u4*)&val);
        break;
      }
      case JVM_CONSTANT_Float: {
        jfloat val = float_at(idx);
        Bytes::put_Java_u4((address) (bytes+1), *(u4*)&val);
        break;
      }
      case JVM_CONSTANT_Long: {
        jlong val = long_at(idx);
        Bytes::put_Java_u8((address) (bytes+1), *(u8*)&val);
        idx++;             // Long takes two cpool slots
        break;
      }
      case JVM_CONSTANT_Double: {
        jdouble val = double_at(idx);
        Bytes::put_Java_u8((address) (bytes+1), *(u8*)&val);
        idx++;             // Double takes two cpool slots
        break;
      }
      case JVM_CONSTANT_Class:
      case JVM_CONSTANT_UnresolvedClass:
      case JVM_CONSTANT_UnresolvedClassInError: {
        Symbol* sym = klass_name_at(idx);
        idx1 = tbl->symbol_to_value(sym);
        assert(idx1 != 0, "Have not found a hashtable entry");
        Bytes::put_Java_u2((address) (bytes+1), idx1);
        DBG(printf("JVM_CONSTANT_Class: idx=#%03hd, %s", idx1, sym->as_utf8()));
        break;
      }
      case JVM_CONSTANT_String: {
        Symbol* sym = unresolved_string_at(idx);
        idx1 = tbl->symbol_to_value(sym);
        assert(idx1 != 0, "Have not found a hashtable entry");
        Bytes::put_Java_u2((address) (bytes+1), idx1);
        DBG(printf("JVM_CONSTANT_String: idx=#%03hd, %s", idx1, sym->as_utf8()));
        break;
      }
      case JVM_CONSTANT_Fieldref:
      case JVM_CONSTANT_Methodref:
      case JVM_CONSTANT_InterfaceMethodref: {
        idx1 = uncached_klass_ref_index_at(idx);
        idx2 = uncached_name_and_type_ref_index_at(idx);
        Bytes::put_Java_u2((address) (bytes+1), idx1);
        Bytes::put_Java_u2((address) (bytes+3), idx2);
        DBG(printf("JVM_CONSTANT_Methodref: %hd %hd", idx1, idx2));
        break;
      }
      case JVM_CONSTANT_NameAndType: {
        idx1 = name_ref_index_at(idx);
        idx2 = signature_ref_index_at(idx);
        Bytes::put_Java_u2((address) (bytes+1), idx1);
        Bytes::put_Java_u2((address) (bytes+3), idx2);
        DBG(printf("JVM_CONSTANT_NameAndType: %hd %hd", idx1, idx2));
        break;
      }
      case JVM_CONSTANT_ClassIndex: {
        idx1 = klass_index_at(idx);
        Bytes::put_Java_u2((address) (bytes+1), idx1);
        DBG(printf("JVM_CONSTANT_ClassIndex: %hd", idx1));
        break;
      }
      case JVM_CONSTANT_StringIndex: {
        idx1 = string_index_at(idx);
        Bytes::put_Java_u2((address) (bytes+1), idx1);
        DBG(printf("JVM_CONSTANT_StringIndex: %hd", idx1));
        break;
      }
      case JVM_CONSTANT_MethodHandle:
      case JVM_CONSTANT_MethodHandleInError: {
        int kind = method_handle_ref_kind_at_error_ok(idx);
        idx1 = method_handle_index_at_error_ok(idx);
        Bytes::put_Java_u2((address) (bytes+2), idx1);
        DBG(printf("JVM_CONSTANT_MethodHandle: %d %hd", kind, idx1));
        break;
      }
      case JVM_CONSTANT_MethodType:
      case JVM_CONSTANT_MethodTypeInError: {
        idx1 = method_type_index_at_error_ok(idx);
        Bytes::put_Java_u2((address) (bytes+1), idx1);
        DBG(printf("JVM_CONSTANT_MethodType: %hd", idx1));
        break;
      }
      case JVM_CONSTANT_InvokeDynamic: {
        idx1 = extract_low_short_from_int(*int_at_addr(idx));
        idx2 = extract_high_short_from_int(*int_at_addr(idx));
        assert(idx2 == invoke_dynamic_name_and_type_ref_index_at(idx), "correct half of u4");
        Bytes::put_Java_u2((address) (bytes+1), idx1);
        Bytes::put_Java_u2((address) (bytes+3), idx2);
        DBG(printf("JVM_CONSTANT_InvokeDynamic: %hd %hd", idx1, idx2));
        break;
      }
    }
    DBG(printf("\n"));
    bytes += ent_size;
    size  += ent_size;
  }
  assert(size == cpool_size, "Size mismatch");
  DBG(print_cpool_bytes(cnt, start_bytes));
  return (int)(bytes - start_bytes);
} /* end copy_cpool_bytes */
#undef DBG
void ConstantPool::set_on_stack(const bool value) {
  if (value) {
    int old_flags = *const_cast<volatile int *>(&_flags);
    while ((old_flags & _on_stack) == 0) {
      int new_flags = old_flags | _on_stack;
      int result = Atomic::cmpxchg(new_flags, &_flags, old_flags);
      if (result == old_flags) {
        MetadataOnStackMark::record(this, Thread::current());
        return;
      }
      old_flags = result;
    }
  } else {
    _flags &= ~_on_stack;
  }
}
void ConstantPool::patch_resolved_references(
                                            GrowableArray<Handle>* cp_patches) {
  assert(EnableInvokeDynamic, "");
  for (int index = 1; index < cp_patches->length(); index++) { // Index 0 is unused
    Handle patch = cp_patches->at(index);
    if (patch.not_null()) {
      assert (tag_at(index).is_string(), "should only be string left");
      int obj_index = cp_to_object_index(index);
      pseudo_string_at_put(index, obj_index, patch());
      DEBUG_ONLY(cp_patches->at_put(index, Handle());)
    }
  }
#ifdef ASSERT
  for (int index = 0; index < cp_patches->length(); index++) {
    assert(cp_patches->at(index).is_null(),
           err_msg("Unused constant pool patch at %d in class file %s",
                   index,
                   pool_holder()->external_name()));
  }
#endif // ASSERT
}
#ifndef PRODUCT
void ConstantPool::preload_and_initialize_all_classes(ConstantPool* obj, TRAPS) {
  guarantee(obj->is_constantPool(), "object must be constant pool");
  constantPoolHandle cp(THREAD, (ConstantPool*)obj);
  guarantee(cp->pool_holder() != NULL, "must be fully loaded");
  for (int i = 0; i< cp->length();  i++) {
    if (cp->tag_at(i).is_unresolved_klass()) {
      Klass* klass = cp->klass_at(i, CHECK);
      if (klass->oop_is_instance()) {
        InstanceKlass::cast(klass)->initialize(CHECK);
      }
    }
  }
}
#endif
void ConstantPool::print_on(outputStream* st) const {
  EXCEPTION_MARK;
  assert(is_constantPool(), "must be constantPool");
  st->print_cr("%s", internal_name());
  if (flags() != 0) {
    st->print(" - flags: 0x%x", flags());
    if (has_preresolution()) st->print(" has_preresolution");
    if (on_stack()) st->print(" on_stack");
    st->cr();
  }
  if (pool_holder() != NULL) {
    st->print_cr(" - holder: " INTPTR_FORMAT, pool_holder());
  }
  st->print_cr(" - cache: " INTPTR_FORMAT, cache());
  st->print_cr(" - resolved_references: " INTPTR_FORMAT, (void *)resolved_references());
  st->print_cr(" - reference_map: " INTPTR_FORMAT, reference_map());
  for (int index = 1; index < length(); index++) {      // Index 0 is unused
    ((ConstantPool*)this)->print_entry_on(index, st);
    switch (tag_at(index).value()) {
      case JVM_CONSTANT_Long :
      case JVM_CONSTANT_Double :
        index++;   // Skip entry following eigth-byte constant
    }
  }
  st->cr();
}
void ConstantPool::print_entry_on(const int index, outputStream* st) {
  EXCEPTION_MARK;
  st->print(" - %3d : ", index);
  tag_at(index).print_on(st);
  st->print(" : ");
  switch (tag_at(index).value()) {
    case JVM_CONSTANT_Class :
      { Klass* k = klass_at(index, CATCH);
        guarantee(k != NULL, "need klass");
        k->print_value_on(st);
        st->print(" {0x%lx}", (address)k);
      }
      break;
    case JVM_CONSTANT_Fieldref :
    case JVM_CONSTANT_Methodref :
    case JVM_CONSTANT_InterfaceMethodref :
      st->print("klass_index=%d", uncached_klass_ref_index_at(index));
      st->print(" name_and_type_index=%d", uncached_name_and_type_ref_index_at(index));
      break;
    case JVM_CONSTANT_String :
      if (is_pseudo_string_at(index)) {
        oop anObj = pseudo_string_at(index);
        anObj->print_value_on(st);
        st->print(" {0x%lx}", (address)anObj);
      } else {
        unresolved_string_at(index)->print_value_on(st);
      }
      break;
    case JVM_CONSTANT_Integer :
      st->print("%d", int_at(index));
      break;
    case JVM_CONSTANT_Float :
      st->print("%f", float_at(index));
      break;
    case JVM_CONSTANT_Long :
      st->print_jlong(long_at(index));
      break;
    case JVM_CONSTANT_Double :
      st->print("%lf", double_at(index));
      break;
    case JVM_CONSTANT_NameAndType :
      st->print("name_index=%d", name_ref_index_at(index));
      st->print(" signature_index=%d", signature_ref_index_at(index));
      break;
    case JVM_CONSTANT_Utf8 :
      symbol_at(index)->print_value_on(st);
      break;
    case JVM_CONSTANT_UnresolvedClass :               // fall-through
    case JVM_CONSTANT_UnresolvedClassInError: {
      CPSlot entry = slot_at(index);
      if (entry.is_resolved()) {
        entry.get_klass()->print_value_on(st);
      } else {
        entry.get_symbol()->print_value_on(st);
      }
      }
      break;
    case JVM_CONSTANT_MethodHandle :
    case JVM_CONSTANT_MethodHandleInError :
      st->print("ref_kind=%d", method_handle_ref_kind_at_error_ok(index));
      st->print(" ref_index=%d", method_handle_index_at_error_ok(index));
      break;
    case JVM_CONSTANT_MethodType :
    case JVM_CONSTANT_MethodTypeInError :
      st->print("signature_index=%d", method_type_index_at_error_ok(index));
      break;
    case JVM_CONSTANT_InvokeDynamic :
      {
        st->print("bootstrap_method_index=%d", invoke_dynamic_bootstrap_method_ref_index_at(index));
        st->print(" name_and_type_index=%d", invoke_dynamic_name_and_type_ref_index_at(index));
        int argc = invoke_dynamic_argument_count_at(index);
        if (argc > 0) {
          for (int arg_i = 0; arg_i < argc; arg_i++) {
            int arg = invoke_dynamic_argument_index_at(index, arg_i);
            st->print((arg_i == 0 ? " arguments={%d" : ", %d"), arg);
          }
          st->print("}");
        }
      }
      break;
    default:
      ShouldNotReachHere();
      break;
  }
  st->cr();
}
void ConstantPool::print_value_on(outputStream* st) const {
  assert(is_constantPool(), "must be constantPool");
  st->print("constant pool [%d]", length());
  if (has_preresolution()) st->print("/preresolution");
  if (operands() != NULL)  st->print("/operands[%d]", operands()->length());
  print_address_on(st);
  st->print(" for ");
  pool_holder()->print_value_on(st);
  if (pool_holder() != NULL) {
    bool extra = (pool_holder()->constants() != this);
    if (extra)  st->print(" (extra)");
  }
  if (cache() != NULL) {
    st->print(" cache=" PTR_FORMAT, cache());
  }
}
#if INCLUDE_SERVICES
void ConstantPool::collect_statistics(KlassSizeStats *sz) const {
  sz->_cp_all_bytes += (sz->_cp_bytes          = sz->count(this));
  sz->_cp_all_bytes += (sz->_cp_tags_bytes     = sz->count_array(tags()));
  sz->_cp_all_bytes += (sz->_cp_cache_bytes    = sz->count(cache()));
  sz->_cp_all_bytes += (sz->_cp_operands_bytes = sz->count_array(operands()));
  sz->_cp_all_bytes += (sz->_cp_refmap_bytes   = sz->count_array(reference_map()));
  sz->_ro_bytes += sz->_cp_operands_bytes + sz->_cp_tags_bytes +
                   sz->_cp_refmap_bytes;
  sz->_rw_bytes += sz->_cp_bytes + sz->_cp_cache_bytes;
}
#endif // INCLUDE_SERVICES
void ConstantPool::verify_on(outputStream* st) {
  guarantee(is_constantPool(), "object must be constant pool");
  for (int i = 0; i< length();  i++) {
    constantTag tag = tag_at(i);
    CPSlot entry = slot_at(i);
    if (tag.is_klass()) {
      if (entry.is_resolved()) {
        guarantee(entry.get_klass()->is_klass(),    "should be klass");
      }
    } else if (tag.is_unresolved_klass()) {
      if (entry.is_resolved()) {
        guarantee(entry.get_klass()->is_klass(),    "should be klass");
      }
    } else if (tag.is_symbol()) {
      guarantee(entry.get_symbol()->refcount() != 0, "should have nonzero reference count");
    } else if (tag.is_string()) {
      guarantee(entry.get_symbol()->refcount() != 0, "should have nonzero reference count");
    }
  }
  if (cache() != NULL) {
    guarantee(cache()->is_constantPoolCache(), "should be constant pool cache");
  }
  if (pool_holder() != NULL) {
    guarantee(pool_holder()->is_klass(),    "should be klass");
  }
}
void SymbolHashMap::add_entry(Symbol* sym, u2 value) {
  char *str = sym->as_utf8();
  unsigned int hash = compute_hash(str, sym->utf8_length());
  unsigned int index = hash % table_size();
  for (SymbolHashMapEntry *en = bucket(index); en != NULL; en = en->next()) {
    assert(en->symbol() != NULL, "SymbolHashMapEntry symbol is NULL");
    if (en->hash() == hash && en->symbol() == sym) {
        return;  // already there
    }
  }
  SymbolHashMapEntry* entry = new SymbolHashMapEntry(hash, sym, value);
  entry->set_next(bucket(index));
  _buckets[index].set_entry(entry);
  assert(entry->symbol() != NULL, "SymbolHashMapEntry symbol is NULL");
}
SymbolHashMapEntry* SymbolHashMap::find_entry(Symbol* sym) {
  assert(sym != NULL, "SymbolHashMap::find_entry - symbol is NULL");
  char *str = sym->as_utf8();
  int   len = sym->utf8_length();
  unsigned int hash = SymbolHashMap::compute_hash(str, len);
  unsigned int index = hash % table_size();
  for (SymbolHashMapEntry *en = bucket(index); en != NULL; en = en->next()) {
    assert(en->symbol() != NULL, "SymbolHashMapEntry symbol is NULL");
    if (en->hash() == hash && en->symbol() == sym) {
      return en;
    }
  }
  return NULL;
}
C:\hotspot-69087d08d473\src\share\vm/oops/constantPool.hpp
#ifndef SHARE_VM_OOPS_CONSTANTPOOLOOP_HPP
#define SHARE_VM_OOPS_CONSTANTPOOLOOP_HPP
#include "oops/arrayOop.hpp"
#include "oops/cpCache.hpp"
#include "oops/objArrayOop.hpp"
#include "oops/symbol.hpp"
#include "oops/typeArrayOop.hpp"
#include "runtime/handles.hpp"
#include "utilities/constantTag.hpp"
#ifdef TARGET_ARCH_x86
# include "bytes_x86.hpp"
#endif
#ifdef TARGET_ARCH_aarch64
# include "bytes_aarch64.hpp"
#endif
#ifdef TARGET_ARCH_sparc
# include "bytes_sparc.hpp"
#endif
#ifdef TARGET_ARCH_zero
# include "bytes_zero.hpp"
#endif
#ifdef TARGET_ARCH_arm
# include "bytes_arm.hpp"
#endif
#ifdef TARGET_ARCH_ppc
# include "bytes_ppc.hpp"
#endif
class SymbolHashMap;
class CPSlot VALUE_OBJ_CLASS_SPEC {
  intptr_t _ptr;
 public:
  CPSlot(intptr_t ptr): _ptr(ptr) {}
  CPSlot(Klass* ptr): _ptr((intptr_t)ptr) {}
  CPSlot(Symbol* ptr): _ptr((intptr_t)ptr | 1) {}
  intptr_t value()   { return _ptr; }
  bool is_resolved()   { return (_ptr & 1) == 0; }
  bool is_unresolved() { return (_ptr & 1) == 1; }
  Symbol* get_symbol() {
    assert(is_unresolved(), "bad call");
    return (Symbol*)(_ptr & ~1);
  }
  Klass* get_klass() {
    assert(is_resolved(), "bad call");
    return (Klass*)_ptr;
  }
};
class KlassSizeStats;
class ConstantPool : public Metadata {
  friend class VMStructs;
  friend class BytecodeInterpreter;  // Directly extracts an oop in the pool for fast instanceof/checkcast
  friend class Universe;             // For null constructor
 private:
  Array<u1>*           _tags;        // the tag array describing the constant pool's contents
  ConstantPoolCache*   _cache;       // the cache holding interpreter runtime information
  InstanceKlass*       _pool_holder; // the corresponding class
  Array<u2>*           _operands;    // for variable-sized (InvokeDynamic) nodes, usually empty
  jobject              _resolved_references;
  Array<u2>*           _reference_map;
  enum {
    _has_preresolution = 1,           // Flags
    _on_stack          = 2
  };
  int                  _flags;  // old fashioned bit twiddling
  int                  _length; // number of elements in the array
  union {
    int                _resolved_reference_length;
    int                _version;
  } _saved;
  Monitor*             _lock;
  void set_tags(Array<u1>* tags)               { _tags = tags; }
  void tag_at_put(int which, jbyte t)          { tags()->at_put(which, t); }
  void release_tag_at_put(int which, jbyte t)  { tags()->release_at_put(which, t); }
  void set_operands(Array<u2>* operands)       { _operands = operands; }
  int flags() const                            { return _flags; }
  void set_flags(int f)                        { _flags = f; }
 private:
  intptr_t* base() const { return (intptr_t*) (((char*) this) + sizeof(ConstantPool)); }
  CPSlot slot_at(int which) const {
    assert(is_within_bounds(which), "index out of bounds");
    volatile intptr_t adr = (intptr_t)OrderAccess::load_ptr_acquire(obj_at_addr_raw(which));
    assert(adr != 0 || which == 0, "cp entry for klass should not be zero");
    return CPSlot(adr);
  }
  void slot_at_put(int which, CPSlot s) const {
    assert(is_within_bounds(which), "index out of bounds");
    assert(s.value() != 0, "Caught something");
  }
  intptr_t* obj_at_addr_raw(int which) const {
    assert(is_within_bounds(which), "index out of bounds");
    return (intptr_t*) &base()[which];
  }
  jint* int_at_addr(int which) const {
    assert(is_within_bounds(which), "index out of bounds");
    return (jint*) &base()[which];
  }
  jlong* long_at_addr(int which) const {
    assert(is_within_bounds(which), "index out of bounds");
    return (jlong*) &base()[which];
  }
  jfloat* float_at_addr(int which) const {
    assert(is_within_bounds(which), "index out of bounds");
    return (jfloat*) &base()[which];
  }
  jdouble* double_at_addr(int which) const {
    assert(is_within_bounds(which), "index out of bounds");
    return (jdouble*) &base()[which];
  }
  ConstantPool(Array<u1>* tags);
  ConstantPool() { assert(DumpSharedSpaces || UseSharedSpaces, "only for CDS"); }
 public:
  static ConstantPool* allocate(ClassLoaderData* loader_data, int length, TRAPS);
  bool is_constantPool() const volatile     { return true; }
  Array<u1>* tags() const                   { return _tags; }
  Array<u2>* operands() const               { return _operands; }
  bool has_preresolution() const            { return (_flags & _has_preresolution) != 0; }
  void set_has_preresolution()              { _flags |= _has_preresolution; }
  bool on_stack() const                      { return (_flags &_on_stack) != 0; }
  void set_on_stack(const bool value);
  InstanceKlass* pool_holder() const      { return _pool_holder; }
  void set_pool_holder(InstanceKlass* k)  { _pool_holder = k; }
  InstanceKlass** pool_holder_addr()      { return &_pool_holder; }
  ConstantPoolCache* cache() const        { return _cache; }
  void set_cache(ConstantPoolCache* cache){ _cache = cache; }
  void initialize_resolved_references(ClassLoaderData* loader_data,
                                      intStack reference_map,
                                      int constant_pool_map_length,
                                      TRAPS);
  objArrayOop resolved_references()  const;
  objArrayOop resolved_references_or_null()  const;
  int object_to_cp_index(int index)         { return _reference_map->at(index); }
  int cp_to_object_index(int index);
  static bool is_invokedynamic_index(int i) { return (i < 0); }
  static int  decode_invokedynamic_index(int i) { assert(is_invokedynamic_index(i),  ""); return ~i; }
  static int  encode_invokedynamic_index(int i) { assert(!is_invokedynamic_index(i), ""); return ~i; }
  int invokedynamic_cp_cache_index(int index) const {
    assert (is_invokedynamic_index(index), "should be a invokedynamic index");
    int cache_index = decode_invokedynamic_index(index);
    return cache_index;
  }
  ConstantPoolCacheEntry* invokedynamic_cp_cache_entry_at(int index) const {
    int cp_cache_index = invokedynamic_cp_cache_index(index);
    return cache()->entry_at(cp_cache_index);
  }
  static int tags_offset_in_bytes()         { return offset_of(ConstantPool, _tags); }
  static int cache_offset_in_bytes()        { return offset_of(ConstantPool, _cache); }
  static int pool_holder_offset_in_bytes()  { return offset_of(ConstantPool, _pool_holder); }
  static int resolved_references_offset_in_bytes() { return offset_of(ConstantPool, _resolved_references); }
  void klass_at_put(int which, Klass* k) {
    assert(k != NULL, "resolved class shouldn't be null");
    assert(is_within_bounds(which), "index out of bounds");
    OrderAccess::release_store_ptr((Klass* volatile *)obj_at_addr_raw(which), k);
    release_tag_at_put(which, JVM_CONSTANT_Class);
  }
  void klass_index_at_put(int which, int name_index) {
    tag_at_put(which, JVM_CONSTANT_ClassIndex);
  }
  void unresolved_klass_at_put(int which, Symbol* s) {
    release_tag_at_put(which, JVM_CONSTANT_UnresolvedClass);
    slot_at_put(which, s);
  }
  void method_handle_index_at_put(int which, int ref_kind, int ref_index) {
    tag_at_put(which, JVM_CONSTANT_MethodHandle);
  }
  void method_type_index_at_put(int which, int ref_index) {
    tag_at_put(which, JVM_CONSTANT_MethodType);
  }
  void invoke_dynamic_at_put(int which, int bootstrap_specifier_index, int name_and_type_index) {
    tag_at_put(which, JVM_CONSTANT_InvokeDynamic);
  }
  void unresolved_string_at_put(int which, Symbol* s) {
    release_tag_at_put(which, JVM_CONSTANT_String);
  }
  void int_at_put(int which, jint i) {
    tag_at_put(which, JVM_CONSTANT_Integer);
  }
  void long_at_put(int which, jlong l) {
    tag_at_put(which, JVM_CONSTANT_Long);
    Bytes::put_native_u8((address)long_at_addr(which), *((u8*) &l));
  }
  void float_at_put(int which, jfloat f) {
    tag_at_put(which, JVM_CONSTANT_Float);
  }
  void double_at_put(int which, jdouble d) {
    tag_at_put(which, JVM_CONSTANT_Double);
    Bytes::put_native_u8((address) double_at_addr(which), *((u8*) &d));
  }
  Symbol** symbol_at_addr(int which) const {
    assert(is_within_bounds(which), "index out of bounds");
    return (Symbol**) &base()[which];
  }
  void symbol_at_put(int which, Symbol* s) {
    assert(s->refcount() != 0, "should have nonzero refcount");
    tag_at_put(which, JVM_CONSTANT_Utf8);
  }
  void string_at_put(int which, int obj_index, oop str) {
    resolved_references()->obj_at_put(obj_index, str);
  }
  void string_index_at_put(int which, int string_index) {
    tag_at_put(which, JVM_CONSTANT_StringIndex);
  }
  void field_at_put(int which, int class_index, int name_and_type_index) {
    tag_at_put(which, JVM_CONSTANT_Fieldref);
  }
  void method_at_put(int which, int class_index, int name_and_type_index) {
    tag_at_put(which, JVM_CONSTANT_Methodref);
  }
  void interface_method_at_put(int which, int class_index, int name_and_type_index) {
    tag_at_put(which, JVM_CONSTANT_InterfaceMethodref);
  }
  void name_and_type_at_put(int which, int name_index, int signature_index) {
    tag_at_put(which, JVM_CONSTANT_NameAndType);
  }
  constantTag tag_at(int which) const { return (constantTag)tags()->at_acquire(which); }
  Klass* klass_at(int which, TRAPS) {
    constantPoolHandle h_this(THREAD, this);
    return klass_at_impl(h_this, which, THREAD);
  }
  Symbol* klass_name_at(int which) const;  // Returns the name, w/o resolving.
  Klass* resolved_klass_at(int which) const {  // Used by Compiler
    guarantee(tag_at(which).is_klass(), "Corrupted constant pool");
    return CPSlot((Klass*)OrderAccess::load_ptr_acquire(obj_at_addr_raw(which))).get_klass();
  }
  Symbol* unresolved_klass_at(int which) {     // Temporary until actual use
    Symbol* s = CPSlot((Symbol*)OrderAccess::load_ptr_acquire(obj_at_addr_raw(which))).get_symbol();
    assert(tag_at(which).is_unresolved_klass(), "Corrupted constant pool");
    return s;
  }
  Symbol* klass_at_noresolve(int which) { return klass_name_at(which); }
  jint int_at(int which) {
    assert(tag_at(which).is_int(), "Corrupted constant pool");
    return *int_at_addr(which);
  }
  jlong long_at(int which) {
    assert(tag_at(which).is_long(), "Corrupted constant pool");
    u8 tmp = Bytes::get_native_u8((address)&base()[which]);
    return *((jlong*)&tmp);
  }
  jfloat float_at(int which) {
    assert(tag_at(which).is_float(), "Corrupted constant pool");
    return *float_at_addr(which);
  }
  jdouble double_at(int which) {
    assert(tag_at(which).is_double(), "Corrupted constant pool");
    u8 tmp = Bytes::get_native_u8((address)&base()[which]);
    return *((jdouble*)&tmp);
  }
  Symbol* symbol_at(int which) {
    assert(tag_at(which).is_utf8(), "Corrupted constant pool");
    return *symbol_at_addr(which);
  }
  oop string_at(int which, int obj_index, TRAPS) {
    constantPoolHandle h_this(THREAD, this);
    return string_at_impl(h_this, which, obj_index, THREAD);
  }
  oop string_at(int which, TRAPS) {
    int obj_index = cp_to_object_index(which);
    return string_at(which, obj_index, THREAD);
  }
  oop uncached_string_at(int which, TRAPS);
  bool is_pseudo_string_at(int which) {
    return unresolved_string_at(which) == NULL;
  }
  oop pseudo_string_at(int which, int obj_index) {
    assert(tag_at(which).is_string(), "Corrupted constant pool");
    assert(unresolved_string_at(which) == NULL, "shouldn't have symbol");
    oop s = resolved_references()->obj_at(obj_index);
    return s;
  }
  oop pseudo_string_at(int which) {
    assert(tag_at(which).is_string(), "Corrupted constant pool");
    assert(unresolved_string_at(which) == NULL, "shouldn't have symbol");
    int obj_index = cp_to_object_index(which);
    oop s = resolved_references()->obj_at(obj_index);
    return s;
  }
  void pseudo_string_at_put(int which, int obj_index, oop x) {
    assert(EnableInvokeDynamic, "");
    assert(tag_at(which).is_string(), "Corrupted constant pool");
    unresolved_string_at_put(which, NULL); // indicates patched string
    string_at_put(which, obj_index, x);    // this works just fine
  }
  oop resolved_string_at(int which) {
    assert(tag_at(which).is_string(), "Corrupted constant pool");
    int obj_index = cp_to_object_index(which);
    return resolved_references()->obj_at(obj_index);
  }
  Symbol* unresolved_string_at(int which) {
    assert(tag_at(which).is_string(), "Corrupted constant pool");
    Symbol* s = *symbol_at_addr(which);
    return s;
  }
  char* string_at_noresolve(int which);
  jint name_and_type_at(int which) {
    assert(tag_at(which).is_name_and_type(), "Corrupted constant pool");
    return *int_at_addr(which);
  }
 private:
  int method_handle_ref_kind_at(int which, bool error_ok) {
    assert(tag_at(which).is_method_handle() ||
           (error_ok && tag_at(which).is_method_handle_in_error()), "Corrupted constant pool");
    return extract_low_short_from_int(*int_at_addr(which));  // mask out unwanted ref_index bits
  }
  int method_handle_index_at(int which, bool error_ok) {
    assert(tag_at(which).is_method_handle() ||
           (error_ok && tag_at(which).is_method_handle_in_error()), "Corrupted constant pool");
    return extract_high_short_from_int(*int_at_addr(which));  // shift out unwanted ref_kind bits
  }
  int method_type_index_at(int which, bool error_ok) {
    assert(tag_at(which).is_method_type() ||
           (error_ok && tag_at(which).is_method_type_in_error()), "Corrupted constant pool");
    return *int_at_addr(which);
  }
 public:
  int method_handle_ref_kind_at(int which) {
    return method_handle_ref_kind_at(which, false);
  }
  int method_handle_ref_kind_at_error_ok(int which) {
    return method_handle_ref_kind_at(which, true);
  }
  int method_handle_index_at(int which) {
    return method_handle_index_at(which, false);
  }
  int method_handle_index_at_error_ok(int which) {
    return method_handle_index_at(which, true);
  }
  int method_type_index_at(int which) {
    return method_type_index_at(which, false);
  }
  int method_type_index_at_error_ok(int which) {
    return method_type_index_at(which, true);
  }
  Symbol* method_handle_name_ref_at(int which) {
    int member = method_handle_index_at(which);
    return impl_name_ref_at(member, true);
  }
  Symbol* method_handle_signature_ref_at(int which) {
    int member = method_handle_index_at(which);
    return impl_signature_ref_at(member, true);
  }
  int method_handle_klass_index_at(int which) {
    int member = method_handle_index_at(which);
    return impl_klass_ref_index_at(member, true);
  }
  Symbol* method_type_signature_at(int which) {
    int sym = method_type_index_at(which);
    return symbol_at(sym);
  }
  int invoke_dynamic_name_and_type_ref_index_at(int which) {
    assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
    return extract_high_short_from_int(*int_at_addr(which));
  }
  int invoke_dynamic_bootstrap_specifier_index(int which) {
    assert(tag_at(which).value() == JVM_CONSTANT_InvokeDynamic, "Corrupted constant pool");
    return extract_low_short_from_int(*int_at_addr(which));
  }
  int invoke_dynamic_operand_base(int which) {
    int bootstrap_specifier_index = invoke_dynamic_bootstrap_specifier_index(which);
    return operand_offset_at(operands(), bootstrap_specifier_index);
  }
  static int operand_offset_at(Array<u2>* operands, int bootstrap_specifier_index) {
    int n = (bootstrap_specifier_index * 2);
    assert(n >= 0 && n+2 <= operands->length(), "oob");
    DEBUG_ONLY(int second_part = build_int_from_shorts(operands->at(0),
                                                       operands->at(1)));
    assert(second_part == 0 || n+2 <= second_part, "oob (2)");
    int offset = build_int_from_shorts(operands->at(n+0),
                                       operands->at(n+1));
    assert(offset == 0 || offset >= second_part && offset <= operands->length(), "oob (3)");
    return offset;
  }
  static void operand_offset_at_put(Array<u2>* operands, int bootstrap_specifier_index, int offset) {
    int n = bootstrap_specifier_index * 2;
    assert(n >= 0 && n+2 <= operands->length(), "oob");
    operands->at_put(n+0, extract_low_short_from_int(offset));
    operands->at_put(n+1, extract_high_short_from_int(offset));
  }
  static int operand_array_length(Array<u2>* operands) {
    if (operands == NULL || operands->length() == 0)  return 0;
    int second_part = operand_offset_at(operands, 0);
    return (second_part / 2);
  }
#ifdef ASSERT
  static int operand_limit_at(Array<u2>* operands, int bootstrap_specifier_index) {
    int nextidx = bootstrap_specifier_index + 1;
    if (nextidx == operand_array_length(operands))
      return operands->length();
    else
      return operand_offset_at(operands, nextidx);
  }
  int invoke_dynamic_operand_limit(int which) {
    int bootstrap_specifier_index = invoke_dynamic_bootstrap_specifier_index(which);
    return operand_limit_at(operands(), bootstrap_specifier_index);
  }
#endif //ASSERT
  enum {
         _indy_bsm_offset  = 0,  // CONSTANT_MethodHandle bsm
         _indy_argc_offset = 1,  // u2 argc
         _indy_argv_offset = 2   // u2 argv[argc]
  };
  int operand_offset_at(int bootstrap_specifier_index) {
    assert(0 <= bootstrap_specifier_index &&
           bootstrap_specifier_index < operand_array_length(operands()),
           "Corrupted CP operands");
    return operand_offset_at(operands(), bootstrap_specifier_index);
  }
  int operand_bootstrap_method_ref_index_at(int bootstrap_specifier_index) {
    int offset = operand_offset_at(bootstrap_specifier_index);
    return operands()->at(offset + _indy_bsm_offset);
  }
  int operand_argument_count_at(int bootstrap_specifier_index) {
    int offset = operand_offset_at(bootstrap_specifier_index);
    int argc = operands()->at(offset + _indy_argc_offset);
    return argc;
  }
  int operand_argument_index_at(int bootstrap_specifier_index, int j) {
    int offset = operand_offset_at(bootstrap_specifier_index);
    return operands()->at(offset + _indy_argv_offset + j);
  }
  int operand_next_offset_at(int bootstrap_specifier_index) {
    int offset = operand_offset_at(bootstrap_specifier_index) + _indy_argv_offset
                   + operand_argument_count_at(bootstrap_specifier_index);
    return offset;
  }
  bool compare_operand_to(int bootstrap_specifier_index1, constantPoolHandle cp2,
                          int bootstrap_specifier_index2, TRAPS);
  int find_matching_operand(int bootstrap_specifier_index, constantPoolHandle search_cp,
                            int operands_cur_len, TRAPS);
  void resize_operands(int delta_len, int delta_size, TRAPS);
  void extend_operands(constantPoolHandle ext_cp, TRAPS);
  void shrink_operands(int new_len, TRAPS);
  int invoke_dynamic_bootstrap_method_ref_index_at(int which) {
    assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
    int op_base = invoke_dynamic_operand_base(which);
    return operands()->at(op_base + _indy_bsm_offset);
  }
  int invoke_dynamic_argument_count_at(int which) {
    assert(tag_at(which).is_invoke_dynamic(), "Corrupted constant pool");
    int op_base = invoke_dynamic_operand_base(which);
    int argc = operands()->at(op_base + _indy_argc_offset);
    DEBUG_ONLY(int end_offset = op_base + _indy_argv_offset + argc;
               int next_offset = invoke_dynamic_operand_limit(which));
    assert(end_offset == next_offset, "matched ending");
    return argc;
  }
  int invoke_dynamic_argument_index_at(int which, int j) {
    int op_base = invoke_dynamic_operand_base(which);
    DEBUG_ONLY(int argc = operands()->at(op_base + _indy_argc_offset));
    assert((uint)j < (uint)argc, "oob");
    return operands()->at(op_base + _indy_argv_offset + j);
  }
  Klass* klass_ref_at(int which, TRAPS);
  Symbol* klass_ref_at_noresolve(int which);
  Symbol* name_ref_at(int which)                { return impl_name_ref_at(which, false); }
  Symbol* signature_ref_at(int which)           { return impl_signature_ref_at(which, false); }
  int klass_ref_index_at(int which)               { return impl_klass_ref_index_at(which, false); }
  int name_and_type_ref_index_at(int which)       { return impl_name_and_type_ref_index_at(which, false); }
  int name_ref_index_at(int which_nt);            // ==  low-order jshort of name_and_type_at(which_nt)
  int signature_ref_index_at(int which_nt);       // == high-order jshort of name_and_type_at(which_nt)
  BasicType basic_type_for_signature_at(int which);
  void resolve_string_constants(TRAPS) {
    constantPoolHandle h_this(THREAD, this);
    resolve_string_constants_impl(h_this, CHECK);
  }
  void remove_unshareable_info();
  void restore_unshareable_info(TRAPS);
  bool resolve_class_constants(TRAPS);
  void restore_vtable() { guarantee(is_constantPool(), "vtable restored by this call"); }
 private:
  enum { _no_index_sentinel = -1, _possible_index_sentinel = -2 };
 public:
  oop resolve_constant_at(int index, TRAPS) {
    constantPoolHandle h_this(THREAD, this);
    return resolve_constant_at_impl(h_this, index, _no_index_sentinel, THREAD);
  }
  oop resolve_cached_constant_at(int cache_index, TRAPS) {
    constantPoolHandle h_this(THREAD, this);
    return resolve_constant_at_impl(h_this, _no_index_sentinel, cache_index, THREAD);
  }
  oop resolve_possibly_cached_constant_at(int pool_index, TRAPS) {
    constantPoolHandle h_this(THREAD, this);
    return resolve_constant_at_impl(h_this, pool_index, _possible_index_sentinel, THREAD);
  }
  oop resolve_bootstrap_specifier_at(int index, TRAPS) {
    constantPoolHandle h_this(THREAD, this);
    return resolve_bootstrap_specifier_at_impl(h_this, index, THREAD);
  }
  bool klass_name_at_matches(instanceKlassHandle k, int which);
  int length() const                   { return _length; }
  void set_length(int length)          { _length = length; }
  bool is_within_bounds(int index) const {
    return 0 <= index && index < length();
  }
  static int header_size()             { return sizeof(ConstantPool)/HeapWordSize; }
  static int size(int length)          { return align_object_size(header_size() + length); }
  int size() const                     { return size(length()); }
#if INCLUDE_SERVICES
  void collect_statistics(KlassSizeStats *sz) const;
#endif
  friend class ClassFileParser;
  friend class SystemDictionary;
  static Method*          method_at_if_loaded      (constantPoolHandle this_oop, int which);
  static bool       has_appendix_at_if_loaded      (constantPoolHandle this_oop, int which);
  static oop            appendix_at_if_loaded      (constantPoolHandle this_oop, int which);
  static bool    has_method_type_at_if_loaded      (constantPoolHandle this_oop, int which);
  static oop         method_type_at_if_loaded      (constantPoolHandle this_oop, int which);
  static Klass*            klass_at_if_loaded      (constantPoolHandle this_oop, int which);
  static Klass*        klass_ref_at_if_loaded      (constantPoolHandle this_oop, int which);
  Symbol* uncached_klass_ref_at_noresolve(int which);
  Symbol* uncached_name_ref_at(int which)                 { return impl_name_ref_at(which, true); }
  Symbol* uncached_signature_ref_at(int which)            { return impl_signature_ref_at(which, true); }
  int       uncached_klass_ref_index_at(int which)          { return impl_klass_ref_index_at(which, true); }
  int       uncached_name_and_type_ref_index_at(int which)  { return impl_name_and_type_ref_index_at(which, true); }
  int pre_resolve_shared_klasses(TRAPS);
  const char* printable_name_at(int which) PRODUCT_RETURN0;
#ifdef ASSERT
  enum { CPCACHE_INDEX_TAG = 0x10000 };  // helps keep CP cache indices distinct from CP indices
#else
  enum { CPCACHE_INDEX_TAG = 0 };        // in product mode, this zero value is a no-op
#endif //ASSERT
  static int decode_cpcache_index(int raw_index, bool invokedynamic_ok = false) {
    if (invokedynamic_ok && is_invokedynamic_index(raw_index))
      return decode_invokedynamic_index(raw_index);
    else
      return raw_index - CPCACHE_INDEX_TAG;
  }
 private:
  void set_resolved_references(jobject s) { _resolved_references = s; }
  Array<u2>* reference_map() const        { return _reference_map; }
  void set_reference_map(Array<u2>* o)    { _reference_map = o; }
  void patch_resolved_references(GrowableArray<Handle>* cp_patches);
  Symbol* impl_name_ref_at(int which, bool uncached);
  Symbol* impl_signature_ref_at(int which, bool uncached);
  int       impl_klass_ref_index_at(int which, bool uncached);
  int       impl_name_and_type_ref_index_at(int which, bool uncached);
  int remap_instruction_operand_from_cache(int operand);  // operand must be biased by CPCACHE_INDEX_TAG
  jint klass_index_at(int which) {
    assert(tag_at(which).is_klass_index(), "Corrupted constant pool");
    return *int_at_addr(which);
  }
  jint string_index_at(int which) {
    assert(tag_at(which).is_string_index(), "Corrupted constant pool");
    return *int_at_addr(which);
  }
  static void verify_constant_pool_resolve(constantPoolHandle this_oop, KlassHandle klass, TRAPS);
  static Klass* klass_at_impl(constantPoolHandle this_oop, int which, TRAPS);
  static oop string_at_impl(constantPoolHandle this_oop, int which, int obj_index, TRAPS);
  static void resolve_string_constants_impl(constantPoolHandle this_oop, TRAPS);
  static oop resolve_constant_at_impl(constantPoolHandle this_oop, int index, int cache_index, TRAPS);
  static oop resolve_bootstrap_specifier_at_impl(constantPoolHandle this_oop, int index, TRAPS);
  static void throw_resolution_error(constantPoolHandle this_oop, int which, TRAPS);
  static Symbol* exception_message(constantPoolHandle this_oop, int which, constantTag tag, oop pending_exception);
  static void save_and_throw_exception(constantPoolHandle this_oop, int which, constantTag tag, TRAPS);
 public:
  bool compare_entry_to(int index1, constantPoolHandle cp2, int index2, TRAPS);
  void copy_cp_to(int start_i, int end_i, constantPoolHandle to_cp, int to_i, TRAPS) {
    constantPoolHandle h_this(THREAD, this);
    copy_cp_to_impl(h_this, start_i, end_i, to_cp, to_i, THREAD);
  }
  static void copy_cp_to_impl(constantPoolHandle from_cp, int start_i, int end_i, constantPoolHandle to_cp, int to_i, TRAPS);
  static void copy_entry_to(constantPoolHandle from_cp, int from_i, constantPoolHandle to_cp, int to_i, TRAPS);
  static void copy_operands(constantPoolHandle from_cp, constantPoolHandle to_cp, TRAPS);
  int  find_matching_entry(int pattern_i, constantPoolHandle search_cp, TRAPS);
  int  version() const                    { return _saved._version; }
  void set_version(int version)           { _saved._version = version; }
  void increment_and_save_version(int version) {
    _saved._version = version >= 0 ? (version + 1) : version;  // keep overflow
  }
  void set_resolved_reference_length(int length) { _saved._resolved_reference_length = length; }
  int  resolved_reference_length() const  { return _saved._resolved_reference_length; }
  void set_lock(Monitor* lock)            { _lock = lock; }
  Monitor* lock()                         { return _lock; }
  void unreference_symbols();
  void deallocate_contents(ClassLoaderData* loader_data);
  void release_C_heap_structures();
  friend class JvmtiConstantPoolReconstituter;
 private:
  jint cpool_entry_size(jint idx);
  jint hash_entries_to(SymbolHashMap *symmap, SymbolHashMap *classmap);
  int  copy_cpool_bytes(int cpool_size,
                        SymbolHashMap* tbl,
                        unsigned char *bytes);
 public:
  void verify_on(outputStream* st);
  void print_on(outputStream* st) const;
  void print_value_on(outputStream* st) const;
  void print_entry_on(int index, outputStream* st);
  const char* internal_name() const { return "{constant pool}"; }
#ifndef PRODUCT
  static void preload_and_initialize_all_classes(ConstantPool* constant_pool, TRAPS);
#endif
};
class SymbolHashMapEntry : public CHeapObj<mtSymbol> {
 private:
  unsigned int        _hash;   // 32-bit hash for item
  SymbolHashMapEntry* _next;   // Next element in the linked list for this bucket
  Symbol*             _symbol; // 1-st part of the mapping: symbol => value
  u2                  _value;  // 2-nd part of the mapping: symbol => value
 public:
  unsigned   int hash() const             { return _hash;   }
  void       set_hash(unsigned int hash)  { _hash = hash;   }
  SymbolHashMapEntry* next() const        { return _next;   }
  void set_next(SymbolHashMapEntry* next) { _next = next;   }
  Symbol*    symbol() const               { return _symbol; }
  void       set_symbol(Symbol* sym)      { _symbol = sym;  }
  u2         value() const                {  return _value; }
  void       set_value(u2 value)          { _value = value; }
  SymbolHashMapEntry(unsigned int hash, Symbol* symbol, u2 value)
    : _hash(hash), _symbol(symbol), _value(value), _next(NULL) {}
}; // End SymbolHashMapEntry class
class SymbolHashMapBucket : public CHeapObj<mtSymbol> {
private:
  SymbolHashMapEntry*    _entry;
public:
  SymbolHashMapEntry* entry() const         {  return _entry; }
  void set_entry(SymbolHashMapEntry* entry) { _entry = entry; }
  void clear()                              { _entry = NULL;  }
}; // End SymbolHashMapBucket class
class SymbolHashMap: public CHeapObj<mtSymbol> {
 private:
  enum SymbolHashMap_Constants {
    _Def_HashMap_Size = 256
  };
  int                   _table_size;
  SymbolHashMapBucket*  _buckets;
  void initialize_table(int table_size) {
    _table_size = table_size;
    _buckets = NEW_C_HEAP_ARRAY(SymbolHashMapBucket, table_size, mtSymbol);
    for (int index = 0; index < table_size; index++) {
      _buckets[index].clear();
    }
  }
 public:
  int table_size() const        { return _table_size; }
  SymbolHashMap()               { initialize_table(_Def_HashMap_Size); }
  SymbolHashMap(int table_size) { initialize_table(table_size); }
  static unsigned int compute_hash(const char* str, int len) {
    unsigned int hash = 0;
    while (len-- > 0) {
      hash = 31*hash + (unsigned) *str;
      str++;
    }
    return hash;
  }
  SymbolHashMapEntry* bucket(int i) {
    return _buckets[i].entry();
  }
  void add_entry(Symbol* sym, u2 value);
  SymbolHashMapEntry* find_entry(Symbol* sym);
  u2 symbol_to_value(Symbol* sym) {
    SymbolHashMapEntry *entry = find_entry(sym);
    return (entry == NULL) ? 0 : entry->value();
  }
  ~SymbolHashMap() {
    SymbolHashMapEntry* next;
    for (int i = 0; i < _table_size; i++) {
      for (SymbolHashMapEntry* cur = bucket(i); cur != NULL; cur = next) {
        next = cur->next();
        delete(cur);
      }
    }
    FREE_C_HEAP_ARRAY(SymbolHashMapBucket, _buckets, mtSymbol);
  }
}; // End SymbolHashMap class
#endif // SHARE_VM_OOPS_CONSTANTPOOLOOP_HPP
C:\hotspot-69087d08d473\src\share\vm/oops/constMethod.cpp
#include "precompiled.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/gcLocker.hpp"
#include "memory/heapInspection.hpp"
#include "memory/metadataFactory.hpp"
#include "oops/constMethod.hpp"
#include "oops/method.hpp"
const u2 ConstMethod::MAX_IDNUM   = 0xFFFE;
const u2 ConstMethod::UNSET_IDNUM = 0xFFFF;
ConstMethod* ConstMethod::allocate(ClassLoaderData* loader_data,
                                   int byte_code_size,
                                   InlineTableSizes* sizes,
                                   MethodType method_type,
                                   TRAPS) {
  int size = ConstMethod::size(byte_code_size, sizes);
  return new (loader_data, size, true, MetaspaceObj::ConstMethodType, THREAD) ConstMethod(
      byte_code_size, sizes, method_type, size);
}
ConstMethod::ConstMethod(int byte_code_size,
                         InlineTableSizes* sizes,
                         MethodType method_type,
                         int size) {
  No_Safepoint_Verifier no_safepoint;
  init_fingerprint();
  set_constants(NULL);
  set_stackmap_data(NULL);
  set_code_size(byte_code_size);
  set_constMethod_size(size);
  set_inlined_tables_length(sizes); // sets _flags
  set_method_type(method_type);
  assert(this->size() == size, "wrong size for object");
  set_name_index(0);
  set_signature_index(0);
  set_constants(NULL);
  set_max_stack(0);
  set_max_locals(0);
  set_method_idnum(0);
  set_size_of_parameters(0);
  set_result_type(T_VOID);
}
void ConstMethod::copy_stackmap_data(ClassLoaderData* loader_data,
                                     u1* sd, int length, TRAPS) {
  _stackmap_data = MetadataFactory::new_array<u1>(loader_data, length, CHECK);
  memcpy((void*)_stackmap_data->adr_at(0), (void*)sd, length);
}
void ConstMethod::deallocate_contents(ClassLoaderData* loader_data) {
  if (stackmap_data() != NULL) {
    MetadataFactory::free_array<u1>(loader_data, stackmap_data());
  }
  set_stackmap_data(NULL);
  if (has_method_annotations())
    MetadataFactory::free_array<u1>(loader_data, method_annotations());
  if (has_parameter_annotations())
    MetadataFactory::free_array<u1>(loader_data, parameter_annotations());
  if (has_type_annotations())
    MetadataFactory::free_array<u1>(loader_data, type_annotations());
  if (has_default_annotations())
    MetadataFactory::free_array<u1>(loader_data, default_annotations());
}
int ConstMethod::size(int code_size,
                      InlineTableSizes* sizes) {
  int extra_bytes = code_size;
  if (sizes->compressed_linenumber_size() > 0) {
    extra_bytes += sizes->compressed_linenumber_size();
  }
  if (sizes->checked_exceptions_length() > 0) {
    extra_bytes += sizeof(u2);
    extra_bytes += sizes->checked_exceptions_length() * sizeof(CheckedExceptionElement);
  }
  if (sizes->localvariable_table_length() > 0) {
    extra_bytes += sizeof(u2);
    extra_bytes +=
              sizes->localvariable_table_length() * sizeof(LocalVariableTableElement);
  }
  if (sizes->exception_table_length() > 0) {
    extra_bytes += sizeof(u2);
    extra_bytes += sizes->exception_table_length() * sizeof(ExceptionTableElement);
  }
  if (sizes->generic_signature_index() != 0) {
    extra_bytes += sizeof(u2);
  }
  if (sizes->method_parameters_length() > 0) {
    extra_bytes += sizeof(u2);
    extra_bytes += sizes->method_parameters_length() * sizeof(MethodParametersElement);
  }
  extra_bytes = align_size_up(extra_bytes, BytesPerWord);
  if (sizes->method_annotations_length() > 0) {
    extra_bytes += sizeof(AnnotationArray*);
  }
  if (sizes->parameter_annotations_length() > 0) {
    extra_bytes += sizeof(AnnotationArray*);
  }
  if (sizes->type_annotations_length() > 0) {
    extra_bytes += sizeof(AnnotationArray*);
  }
  if (sizes->default_annotations_length() > 0) {
    extra_bytes += sizeof(AnnotationArray*);
  }
  int extra_words = align_size_up(extra_bytes, BytesPerWord) / BytesPerWord;
  assert(extra_words == extra_bytes/BytesPerWord, "should already be aligned");
  return align_object_size(header_size() + extra_words);
}
Method* ConstMethod::method() const {
    return _constants->pool_holder()->method_with_idnum(_method_idnum);
  }
u_char* ConstMethod::compressed_linenumber_table() const {
  assert(has_linenumber_table(), "called only if table is present");
  return code_end();
}
u2* ConstMethod::last_u2_element() const {
  int offset = 0;
  if (has_method_annotations()) offset++;
  if (has_parameter_annotations()) offset++;
  if (has_type_annotations()) offset++;
  if (has_default_annotations()) offset++;
  return (u2*)((AnnotationArray**)constMethod_end() - offset) - 1;
}
u2* ConstMethod::generic_signature_index_addr() const {
  assert(has_generic_signature(), "called only if generic signature exists");
  return last_u2_element();
}
u2* ConstMethod::method_parameters_length_addr() const {
  assert(has_method_parameters(), "called only if table is present");
  return has_generic_signature() ? (last_u2_element() - 1) :
                                    last_u2_element();
}
u2* ConstMethod::checked_exceptions_length_addr() const {
  assert(has_checked_exceptions(), "called only if table is present");
  if(has_method_parameters()) {
    return (u2*)method_parameters_start() - 1;
  } else {
    return has_generic_signature() ? (last_u2_element() - 1) :
                                     last_u2_element();
  }
}
u2* ConstMethod::exception_table_length_addr() const {
  assert(has_exception_handler(), "called only if table is present");
  if (has_checked_exceptions()) {
    return (u2*) checked_exceptions_start() - 1;
  } else {
    if(has_method_parameters()) {
      return (u2*)method_parameters_start() - 1;
    } else {
      return has_generic_signature() ? (last_u2_element() - 1) :
                                        last_u2_element();
    }
  }
}
u2* ConstMethod::localvariable_table_length_addr() const {
  assert(has_localvariable_table(), "called only if table is present");
  if (has_exception_handler()) {
    return (u2*) exception_table_start() - 1;
  } else {
    if (has_checked_exceptions()) {
      return (u2*) checked_exceptions_start() - 1;
    } else {
      if(has_method_parameters()) {
        return (u2*)method_parameters_start() - 1;
      } else {
      return has_generic_signature() ? (last_u2_element() - 1) :
                                        last_u2_element();
      }
    }
  }
}
void ConstMethod::set_inlined_tables_length(InlineTableSizes* sizes) {
  _flags = 0;
  if (sizes->compressed_linenumber_size() > 0)
    _flags |= _has_linenumber_table;
  if (sizes->generic_signature_index() != 0)
    _flags |= _has_generic_signature;
  if (sizes->method_parameters_length() > 0)
    _flags |= _has_method_parameters;
  if (sizes->checked_exceptions_length() > 0)
    _flags |= _has_checked_exceptions;
  if (sizes->exception_table_length() > 0)
    _flags |= _has_exception_table;
  if (sizes->localvariable_table_length() > 0)
    _flags |= _has_localvariable_table;
  if (sizes->method_annotations_length() > 0)
    _flags |= _has_method_annotations;
  if (sizes->parameter_annotations_length() > 0)
    _flags |= _has_parameter_annotations;
  if (sizes->type_annotations_length() > 0)
    _flags |= _has_type_annotations;
  if (sizes->default_annotations_length() > 0)
    _flags |= _has_default_annotations;
  if (sizes->generic_signature_index() != 0)
  if (sizes->method_parameters_length() > 0)
  if (sizes->checked_exceptions_length() > 0)
  if (sizes->exception_table_length() > 0)
  if (sizes->localvariable_table_length() > 0)
}
int ConstMethod::method_parameters_length() const {
  return has_method_parameters() ? *(method_parameters_length_addr()) : 0;
}
MethodParametersElement* ConstMethod::method_parameters_start() const {
  u2* addr = method_parameters_length_addr();
  u2 length = *addr;
  assert(length > 0, "should only be called if table is present");
  addr -= length * sizeof(MethodParametersElement) / sizeof(u2);
  return (MethodParametersElement*) addr;
}
int ConstMethod::checked_exceptions_length() const {
  return has_checked_exceptions() ? *(checked_exceptions_length_addr()) : 0;
}
CheckedExceptionElement* ConstMethod::checked_exceptions_start() const {
  u2* addr = checked_exceptions_length_addr();
  u2 length = *addr;
  assert(length > 0, "should only be called if table is present");
  addr -= length * sizeof(CheckedExceptionElement) / sizeof(u2);
  return (CheckedExceptionElement*) addr;
}
int ConstMethod::localvariable_table_length() const {
  return has_localvariable_table() ? *(localvariable_table_length_addr()) : 0;
}
LocalVariableTableElement* ConstMethod::localvariable_table_start() const {
  u2* addr = localvariable_table_length_addr();
  u2 length = *addr;
  assert(length > 0, "should only be called if table is present");
  addr -= length * sizeof(LocalVariableTableElement) / sizeof(u2);
  return (LocalVariableTableElement*) addr;
}
int ConstMethod::exception_table_length() const {
  return has_exception_handler() ? *(exception_table_length_addr()) : 0;
}
ExceptionTableElement* ConstMethod::exception_table_start() const {
  u2* addr = exception_table_length_addr();
  u2 length = *addr;
  assert(length > 0, "should only be called if table is present");
  addr -= length * sizeof(ExceptionTableElement) / sizeof(u2);
  return (ExceptionTableElement*)addr;
}
AnnotationArray** ConstMethod::method_annotations_addr() const {
  assert(has_method_annotations(), "should only be called if method annotations are present");
  return (AnnotationArray**)constMethod_end() - 1;
}
AnnotationArray** ConstMethod::parameter_annotations_addr() const {
  assert(has_parameter_annotations(), "should only be called if method parameter annotations are present");
  int offset = 1;
  if (has_method_annotations()) offset++;
  return (AnnotationArray**)constMethod_end() - offset;
}
AnnotationArray** ConstMethod::type_annotations_addr() const {
  assert(has_type_annotations(), "should only be called if method type annotations are present");
  int offset = 1;
  if (has_method_annotations()) offset++;
  if (has_parameter_annotations()) offset++;
  return (AnnotationArray**)constMethod_end() - offset;
}
AnnotationArray** ConstMethod::default_annotations_addr() const {
  assert(has_default_annotations(), "should only be called if method default annotations are present");
  int offset = 1;
  if (has_method_annotations()) offset++;
  if (has_parameter_annotations()) offset++;
  if (has_type_annotations()) offset++;
  return (AnnotationArray**)constMethod_end() - offset;
}
void ConstMethod::copy_annotations_from(ConstMethod* cm) {
  if (cm->has_method_annotations()) {
    assert(has_method_annotations(), "should be allocated already");
    set_method_annotations(cm->method_annotations());
  }
  if (cm->has_parameter_annotations()) {
    assert(has_parameter_annotations(), "should be allocated already");
    set_parameter_annotations(cm->parameter_annotations());
  }
  if (cm->has_type_annotations()) {
    assert(has_type_annotations(), "should be allocated already");
    set_type_annotations(cm->type_annotations());
  }
  if (cm->has_default_annotations()) {
    assert(has_default_annotations(), "should be allocated already");
    set_default_annotations(cm->default_annotations());
  }
}
void ConstMethod::print_on(outputStream* st) const {
  ResourceMark rm;
  assert(is_constMethod(), "must be constMethod");
  st->print_cr("%s", internal_name());
  Method* m = method();
  st->print(" - method:       " INTPTR_FORMAT " ", p2i((address)m));
  if (m != NULL) {
    m->print_value_on(st);
  }
  st->cr();
  if (has_stackmap_table()) {
    st->print(" - stackmap data:       ");
    stackmap_data()->print_value_on(st);
    st->cr();
  }
}
void ConstMethod::print_value_on(outputStream* st) const {
  assert(is_constMethod(), "must be constMethod");
  st->print(" const part of method " );
  Method* m = method();
  if (m != NULL) {
    m->print_value_on(st);
  } else {
    st->print("NULL");
  }
}
#if INCLUDE_SERVICES
void ConstMethod::collect_statistics(KlassSizeStats *sz) const {
  int n1, n2, n3;
  sz->_const_method_bytes += (n1 = sz->count(this));
  sz->_bytecode_bytes     += (n2 = code_size());
  sz->_stackmap_bytes     += (n3 = sz->count_array(stackmap_data()));
  int a1 = 0, a2 = 0, a3 = 0, a4 = 0;
  if (has_method_annotations()) {
    sz->_methods_annotations_bytes += (a1 = sz->count_array(method_annotations()));
  }
  if (has_parameter_annotations()) {
    sz->_methods_parameter_annotations_bytes += (a2 = sz->count_array(parameter_annotations()));
  }
  if (has_type_annotations()) {
    sz->_methods_type_annotations_bytes += (a3 = sz->count_array(type_annotations()));
  }
  if (has_default_annotations()) {
    sz->_methods_default_annotations_bytes += (a4 = sz->count_array(default_annotations()));
  }
  int size_annotations = a1 + a2 + a3 + a4;
  sz->_method_all_bytes += n1 + n3 + size_annotations; // note: n2 is part of n3
  sz->_ro_bytes += n1 + n3 + size_annotations;
}
#endif // INCLUDE_SERVICES
void ConstMethod::verify_on(outputStream* st) {
  guarantee(is_constMethod(), "object must be constMethod");
  guarantee(method() != NULL && method()->is_method(), "should be method");
  address m_end = (address)((intptr_t) this + size());
  address compressed_table_start = code_end();
  guarantee(compressed_table_start <= m_end, "invalid method layout");
  address compressed_table_end = compressed_table_start;
  if (has_linenumber_table()) {
    CompressedLineNumberReadStream stream(compressed_linenumber_table());
    while (stream.read_pair()) {
      guarantee(stream.bci() >= 0 && stream.bci() <= code_size(), "invalid bci in line number table");
    }
    compressed_table_end += stream.position();
  }
  guarantee(compressed_table_end <= m_end, "invalid method layout");
  if (has_method_parameters()) {
    u2* addr = method_parameters_length_addr();
    guarantee(*addr > 0 && (address) addr >= compressed_table_end && (address) addr < m_end, "invalid method layout");
  }
  if (has_checked_exceptions()) {
    u2* addr = checked_exceptions_length_addr();
    guarantee(*addr > 0 && (address) addr >= compressed_table_end && (address) addr < m_end, "invalid method layout");
  }
  if (has_exception_handler()) {
    u2* addr = exception_table_length_addr();
     guarantee(*addr > 0 && (address) addr >= compressed_table_end && (address) addr < m_end, "invalid method layout");
  }
  if (has_localvariable_table()) {
    u2* addr = localvariable_table_length_addr();
    guarantee(*addr > 0 && (address) addr >= compressed_table_end && (address) addr < m_end, "invalid method layout");
  }
  u2* uncompressed_table_start;
  if (has_localvariable_table()) {
    uncompressed_table_start = (u2*) localvariable_table_start();
  } else if (has_exception_handler()) {
    uncompressed_table_start = (u2*) exception_table_start();
  } else if (has_checked_exceptions()) {
      uncompressed_table_start = (u2*) checked_exceptions_start();
  } else if (has_method_parameters()) {
      uncompressed_table_start = (u2*) method_parameters_start();
  } else {
      uncompressed_table_start = (u2*) m_end;
  }
  int gap = (intptr_t) uncompressed_table_start - (intptr_t) compressed_table_end;
  int max_gap = align_object_size(1)*BytesPerWord;
  guarantee(gap >= 0 && gap < max_gap, "invalid method layout");
}
C:\hotspot-69087d08d473\src\share\vm/oops/constMethod.hpp
#ifndef SHARE_VM_OOPS_CONSTMETHODOOP_HPP
#define SHARE_VM_OOPS_CONSTMETHODOOP_HPP
#include "oops/oop.hpp"
class CheckedExceptionElement VALUE_OBJ_CLASS_SPEC {
 public:
  u2 class_cp_index;
};
class LocalVariableTableElement VALUE_OBJ_CLASS_SPEC {
 public:
  u2 start_bci;
  u2 length;
  u2 name_cp_index;
  u2 descriptor_cp_index;
  u2 signature_cp_index;
  u2 slot;
};
class ExceptionTableElement VALUE_OBJ_CLASS_SPEC {
 public:
  u2 start_pc;
  u2 end_pc;
  u2 handler_pc;
  u2 catch_type_index;
};
class MethodParametersElement VALUE_OBJ_CLASS_SPEC {
 public:
  u2 name_cp_index;
  u2 flags;
};
class KlassSizeStats;
#define INLINE_TABLES_DO(do_element)            \
  do_element(localvariable_table_length)        \
  do_element(compressed_linenumber_size)        \
  do_element(exception_table_length)            \
  do_element(checked_exceptions_length)         \
  do_element(method_parameters_length)          \
  do_element(generic_signature_index)           \
  do_element(method_annotations_length)         \
  do_element(parameter_annotations_length)      \
  do_element(type_annotations_length)           \
  do_element(default_annotations_length)
#define INLINE_TABLE_DECLARE(sym)    int _##sym;
#define INLINE_TABLE_PARAM(sym)      int sym,
#define INLINE_TABLE_INIT(sym)       _##sym(sym),
#define INLINE_TABLE_NULL(sym)       _##sym(0),
#define INLINE_TABLE_ACCESSOR(sym)   int sym() const { return _##sym; }
class InlineTableSizes : StackObj {
  INLINE_TABLES_DO(INLINE_TABLE_DECLARE)
  int _end;
 public:
  InlineTableSizes(
      INLINE_TABLES_DO(INLINE_TABLE_PARAM)
      int end) :
      INLINE_TABLES_DO(INLINE_TABLE_INIT)
      _end(end) {}
  InlineTableSizes() :
      INLINE_TABLES_DO(INLINE_TABLE_NULL)
      _end(0) {}
  INLINE_TABLES_DO(INLINE_TABLE_ACCESSOR)
};
#undef INLINE_TABLE_ACCESSOR
#undef INLINE_TABLE_NULL
#undef INLINE_TABLE_INIT
#undef INLINE_TABLE_PARAM
#undef INLINE_TABLE_DECLARE
class ConstMethod : public MetaspaceObj {
  friend class VMStructs;
public:
  typedef enum { NORMAL, OVERPASS } MethodType;
private:
  enum {
    _has_linenumber_table = 0x0001,
    _has_checked_exceptions = 0x0002,
    _has_localvariable_table = 0x0004,
    _has_exception_table = 0x0008,
    _has_generic_signature = 0x0010,
    _has_method_parameters = 0x0020,
    _is_overpass = 0x0040,
    _has_method_annotations = 0x0080,
    _has_parameter_annotations = 0x0100,
    _has_type_annotations = 0x0200,
    _has_default_annotations = 0x0400
  };
  volatile uint64_t _fingerprint;
  ConstantPool*     _constants;                  // Constant pool
  Array<u1>*        _stackmap_data;
  int               _constMethod_size;
  u2                _flags;
  u1                _result_type;                 // BasicType of result
  u2                _code_size;
  u2                _name_index;                 // Method name (index in constant pool)
  u2                _signature_index;            // Method signature (index in constant pool)
  u2                _method_idnum;               // unique identification number for the method within the class
  u2                _max_stack;                  // Maximum number of entries on the expression stack
  u2                _max_locals;                 // Number of local variables used by this method
  u2                _size_of_parameters;         // size of the parameter block (receiver + arguments) in words
  u2                _orig_method_idnum;          // Original unique identification number for the method
  ConstMethod(int byte_code_size,
              InlineTableSizes* sizes,
              MethodType is_overpass,
              int size);
public:
  static ConstMethod* allocate(ClassLoaderData* loader_data,
                               int byte_code_size,
                               InlineTableSizes* sizes,
                               MethodType mt,
                               TRAPS);
  bool is_constMethod() const { return true; }
  void set_inlined_tables_length(InlineTableSizes* sizes);
  bool has_generic_signature() const
    { return (_flags & _has_generic_signature) != 0; }
  bool has_linenumber_table() const
    { return (_flags & _has_linenumber_table) != 0; }
  bool has_checked_exceptions() const
    { return (_flags & _has_checked_exceptions) != 0; }
  bool has_localvariable_table() const
    { return (_flags & _has_localvariable_table) != 0; }
  bool has_exception_handler() const
    { return (_flags & _has_exception_table) != 0; }
  bool has_method_parameters() const
    { return (_flags & _has_method_parameters) != 0; }
  MethodType method_type() const {
    return ((_flags & _is_overpass) == 0) ? NORMAL : OVERPASS;
  }
  void set_method_type(MethodType mt) {
    if (mt == NORMAL) {
      _flags &= ~(_is_overpass);
    } else {
      _flags |= _is_overpass;
    }
  }
  ConstantPool* constants() const        { return _constants; }
  void set_constants(ConstantPool* c)    { _constants = c; }
  Method* method() const;
  Array<u1>* stackmap_data() const { return _stackmap_data; }
  void set_stackmap_data(Array<u1>* sd) { _stackmap_data = sd; }
  void copy_stackmap_data(ClassLoaderData* loader_data, u1* sd, int length, TRAPS);
  bool has_stackmap_table() const { return _stackmap_data != NULL; }
  void init_fingerprint() {
    const uint64_t initval = CONST64(0x8000000000000000);
    _fingerprint = initval;
  }
  uint64_t fingerprint() const                   {
    uint high_fp = (uint)(_fingerprint >> 32);
    if ((int) _fingerprint == 0 || high_fp == 0x80000000) {
      return 0L;
    } else {
      return _fingerprint;
    }
  }
  uint64_t set_fingerprint(uint64_t new_fingerprint) {
#ifdef ASSERT
    uint64_t oldfp = fingerprint();
#endif // ASSERT
    _fingerprint = new_fingerprint;
    assert(oldfp == 0L || new_fingerprint == oldfp,
           "fingerprint cannot change");
    assert(((new_fingerprint >> 32) != 0x80000000) && (int)new_fingerprint !=0,
           "fingerprint should call init to set initial value");
    return new_fingerprint;
  }
  int name_index() const                         { return _name_index; }
  void set_name_index(int index)                 { _name_index = index; }
  int signature_index() const                    { return _signature_index; }
  void set_signature_index(int index)            { _signature_index = index; }
  int generic_signature_index() const            {
    if (has_generic_signature()) {
      return *generic_signature_index_addr();
    } else {
      return 0;
    }
  }
  void set_generic_signature_index(u2 index)    {
    assert(has_generic_signature(), "");
    u2* addr = generic_signature_index_addr();
  }
  static int header_size() {
    return sizeof(ConstMethod)/HeapWordSize;
  }
  static int size(int code_size, InlineTableSizes* sizes);
  int size() const                    { return _constMethod_size;}
  void set_constMethod_size(int size)     { _constMethod_size = size; }
#if INCLUDE_SERVICES
  void collect_statistics(KlassSizeStats *sz) const;
#endif
  int code_size() const                          { return _code_size; }
  void set_code_size(int size) {
    assert(max_method_code_size < (1 << 16),
           "u2 is too small to hold method code size in general");
    assert(0 <= size && size <= max_method_code_size, "invalid code size");
    _code_size = size;
  }
  u_char* compressed_linenumber_table() const;         // not preserved by gc
  u2* generic_signature_index_addr() const;
  u2* checked_exceptions_length_addr() const;
  u2* localvariable_table_length_addr() const;
  u2* exception_table_length_addr() const;
  u2* method_parameters_length_addr() const;
  int checked_exceptions_length() const;
  CheckedExceptionElement* checked_exceptions_start() const;
  int localvariable_table_length() const;
  LocalVariableTableElement* localvariable_table_start() const;
  int exception_table_length() const;
  ExceptionTableElement* exception_table_start() const;
  int method_parameters_length() const;
  MethodParametersElement* method_parameters_start() const;
  bool has_method_annotations() const
    { return (_flags & _has_method_annotations) != 0; }
  bool has_parameter_annotations() const
    { return (_flags & _has_parameter_annotations) != 0; }
  bool has_type_annotations() const
    { return (_flags & _has_type_annotations) != 0; }
  bool has_default_annotations() const
    { return (_flags & _has_default_annotations) != 0; }
  AnnotationArray** method_annotations_addr() const;
  AnnotationArray* method_annotations() const  {
    return has_method_annotations() ? *(method_annotations_addr()) : NULL;
  }
  void set_method_annotations(AnnotationArray* anno) {
  }
  AnnotationArray** parameter_annotations_addr() const;
  AnnotationArray* parameter_annotations() const {
    return has_parameter_annotations() ? *(parameter_annotations_addr()) : NULL;
  }
  void set_parameter_annotations(AnnotationArray* anno) {
  }
  AnnotationArray** type_annotations_addr() const;
  AnnotationArray* type_annotations() const {
    return has_type_annotations() ? *(type_annotations_addr()) : NULL;
  }
  void set_type_annotations(AnnotationArray* anno) {
  }
  AnnotationArray** default_annotations_addr() const;
  AnnotationArray* default_annotations() const {
    return has_default_annotations() ? *(default_annotations_addr()) : NULL;
  }
  void set_default_annotations(AnnotationArray* anno) {
  }
  int method_annotations_length() const {
    return has_method_annotations() ? method_annotations()->length() : 0;
  }
  int parameter_annotations_length() const {
    return has_parameter_annotations() ? parameter_annotations()->length() : 0;
  }
  int type_annotations_length() const {
    return has_type_annotations() ? type_annotations()->length() : 0;
  }
  int default_annotations_length() const {
    return has_default_annotations() ? default_annotations()->length() : 0;
  }
  void copy_annotations_from(ConstMethod* cm);
  void    set_code(address code) {
    if (code_size() > 0) {
      memcpy(code_base(), code, code_size());
    }
  }
  address code_base() const            { return (address) (this+1); }
  address code_end() const             { return code_base() + code_size(); }
  bool    contains(address bcp) const  { return code_base() <= bcp
                                                     && bcp < code_end(); }
  static ByteSize codes_offset()
                            { return in_ByteSize(sizeof(ConstMethod)); }
  static ByteSize constants_offset()
                            { return byte_offset_of(ConstMethod, _constants); }
  static ByteSize max_stack_offset()
                            { return byte_offset_of(ConstMethod, _max_stack); }
  static ByteSize size_of_locals_offset()
                            { return byte_offset_of(ConstMethod, _max_locals); }
  static ByteSize size_of_parameters_offset()
                            { return byte_offset_of(ConstMethod, _size_of_parameters); }
  static ByteSize result_type_offset()
                            { return byte_offset_of(ConstMethod, _result_type); }
  static const u2 MAX_IDNUM;
  static const u2 UNSET_IDNUM;
  u2 method_idnum() const                        { return _method_idnum; }
  void set_method_idnum(u2 idnum)                { _method_idnum = idnum; }
  u2 orig_method_idnum() const                   { return _orig_method_idnum; }
  void set_orig_method_idnum(u2 idnum)           { _orig_method_idnum = idnum; }
  int  max_stack() const                         { return _max_stack; }
  void set_max_stack(int size)                   { _max_stack = size; }
  int  max_locals() const                        { return _max_locals; }
  void set_max_locals(int size)                  { _max_locals = size; }
  int  size_of_parameters() const                { return _size_of_parameters; }
  void set_size_of_parameters(int size)          { _size_of_parameters = size; }
  void set_result_type(BasicType rt)             { assert(rt < 16, "result type too large");
                                                   _result_type = (u1)rt; }
  void deallocate_contents(ClassLoaderData* loader_data);
  bool is_klass() const { return false; }
  DEBUG_ONLY(bool on_stack() { return false; })
private:
  address constMethod_end() const
                          { return (address)((intptr_t*)this + _constMethod_size); }
  u2* last_u2_element() const;
 public:
  void print_on      (outputStream* st) const;
  void print_value_on(outputStream* st) const;
  const char* internal_name() const { return "{constMethod}"; }
  void verify_on(outputStream* st);
};
#endif // SHARE_VM_OOPS_CONSTMETHODOOP_HPP
C:\hotspot-69087d08d473\src\share\vm/oops/cpCache.cpp
#include "precompiled.hpp"
#include "gc_implementation/shared/markSweep.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/rewriter.hpp"
#include "memory/universe.inline.hpp"
#include "oops/cpCache.hpp"
#include "oops/objArrayOop.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiRedefineClassesTrace.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/orderAccess.inline.hpp"
#include "utilities/macros.hpp"
#if INCLUDE_ALL_GCS
# include "gc_implementation/parallelScavenge/psPromotionManager.hpp"
#endif // INCLUDE_ALL_GCS
PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
void ConstantPoolCacheEntry::initialize_entry(int index) {
  assert(0 < index && index < 0x10000, "sanity check");
  _indices = index;
  _f1 = NULL;
  _f2 = _flags = 0;
  assert(constant_pool_index() == index, "");
}
int ConstantPoolCacheEntry::make_flags(TosState state,
                                       int option_bits,
                                       int field_index_or_method_params) {
  assert(state < number_of_states, "Invalid state in make_flags");
  int f = ((int)state << tos_state_shift) | option_bits | field_index_or_method_params;
#ifdef ASSERT
  TosState old_state = flag_state();
  assert(old_state == (TosState)0 || old_state == state,
         "inconsistent cpCache flags state");
#endif
  return (_flags | f) ;
}
void ConstantPoolCacheEntry::set_bytecode_1(Bytecodes::Code code) {
#ifdef ASSERT
  volatile Bytecodes::Code c = bytecode_1();
  assert(c == 0 || c == code || code == 0, "update must be consistent");
#endif
  OrderAccess::release_store_ptr(&_indices, _indices | ((u_char)code << bytecode_1_shift));
}
void ConstantPoolCacheEntry::set_bytecode_2(Bytecodes::Code code) {
#ifdef ASSERT
  volatile Bytecodes::Code c = bytecode_2();
  assert(c == 0 || c == code || code == 0, "update must be consistent");
#endif
  OrderAccess::release_store_ptr(&_indices, _indices | ((u_char)code << bytecode_2_shift));
}
void ConstantPoolCacheEntry::release_set_f1(Metadata* f1) {
  assert(f1 != NULL, "");
  OrderAccess::release_store_ptr((HeapWord*) &_f1, f1);
}
bool ConstantPoolCacheEntry::init_flags_atomic(intptr_t flags) {
  intptr_t result = Atomic::cmpxchg_ptr(flags, &_flags, 0);
  return (result == 0);
}
void ConstantPoolCacheEntry::set_field(Bytecodes::Code get_code,
                                       Bytecodes::Code put_code,
                                       KlassHandle field_holder,
                                       int field_index,
                                       int field_offset,
                                       TosState field_type,
                                       bool is_final,
                                       bool is_volatile,
                                       Klass* root_klass) {
  set_f1(field_holder());
  set_f2(field_offset);
  assert((field_index & field_index_mask) == field_index,
         "field index does not fit in low flag bits");
  set_field_flags(field_type,
                  ((is_volatile ? 1 : 0) << is_volatile_shift) |
                  ((is_final    ? 1 : 0) << is_final_shift),
                  field_index);
  set_bytecode_1(get_code);
  set_bytecode_2(put_code);
  NOT_PRODUCT(verify(tty));
}
void ConstantPoolCacheEntry::set_parameter_size(int value) {
  assert(_flags == 0 || parameter_size() == 0 || parameter_size() == value,
         err_msg("size must not change: parameter_size=%d, value=%d", parameter_size(), value));
  if (_flags == 0) {
    Atomic::cmpxchg_ptr((value & parameter_size_mask), &_flags, 0);
  }
  guarantee(parameter_size() == value,
            err_msg("size must not change: parameter_size=%d, value=%d", parameter_size(), value));
}
void ConstantPoolCacheEntry::set_direct_or_vtable_call(Bytecodes::Code invoke_code,
                                                       methodHandle method,
                                                       int vtable_index,
                                                       bool sender_is_interface) {
  bool is_vtable_call = (vtable_index >= 0);  // FIXME: split this method on this boolean
  assert(method->interpreter_entry() != NULL, "should have been set at this point");
  assert(!method->is_obsolete(),  "attempt to write obsolete method to cpCache");
  int byte_no = -1;
  bool change_to_virtual = false;
  switch (invoke_code) {
    case Bytecodes::_invokeinterface:
      change_to_virtual = true;
    case Bytecodes::_invokevirtual:
      {
        if (!is_vtable_call) {
          assert(method->can_be_statically_bound(), "");
          set_method_flags(as_TosState(method->result_type()),
                           (                             1      << is_vfinal_shift) |
                           ((method->is_final_method() ? 1 : 0) << is_final_shift)  |
                           ((change_to_virtual         ? 1 : 0) << is_forced_virtual_shift),
                           method()->size_of_parameters());
          set_f2_as_vfinal_method(method());
        } else {
          assert(!method->can_be_statically_bound(), "");
          assert(vtable_index >= 0, "valid index");
          assert(!method->is_final_method(), "sanity");
          set_method_flags(as_TosState(method->result_type()),
                           ((change_to_virtual ? 1 : 0) << is_forced_virtual_shift),
                           method()->size_of_parameters());
          set_f2(vtable_index);
        }
        byte_no = 2;
        break;
      }
    case Bytecodes::_invokespecial:
    case Bytecodes::_invokestatic:
      assert(!is_vtable_call, "");
      set_method_flags(as_TosState(method->result_type()),
                       ((is_vfinal()               ? 1 : 0) << is_vfinal_shift) |
                       ((method->is_final_method() ? 1 : 0) << is_final_shift),
                       method()->size_of_parameters());
      set_f1(method());
      byte_no = 1;
      break;
    default:
      ShouldNotReachHere();
      break;
  }
  if (byte_no == 1) {
    assert(invoke_code != Bytecodes::_invokevirtual &&
           invoke_code != Bytecodes::_invokeinterface, "");
    bool do_resolve = true;
    if (invoke_code == Bytecodes::_invokespecial && sender_is_interface &&
        method->name() != vmSymbols::object_initializer_name()) {
      do_resolve = false;
    }
    if (invoke_code == Bytecodes::_invokestatic && !method->method_holder()->is_initialized()) {
      do_resolve = false;
    }
    if (do_resolve) {
        set_bytecode_1(invoke_code);
    }
  } else if (byte_no == 2)  {
    if (change_to_virtual) {
      assert(invoke_code == Bytecodes::_invokeinterface, "");
    } else {
      assert(invoke_code == Bytecodes::_invokevirtual, "");
    }
    set_bytecode_2(Bytecodes::_invokevirtual);
  } else {
    ShouldNotReachHere();
  }
  NOT_PRODUCT(verify(tty));
}
void ConstantPoolCacheEntry::set_direct_call(Bytecodes::Code invoke_code, methodHandle method,
                                             bool sender_is_interface) {
  int index = Method::nonvirtual_vtable_index;
  set_direct_or_vtable_call(invoke_code, method, index, sender_is_interface);
}
void ConstantPoolCacheEntry::set_vtable_call(Bytecodes::Code invoke_code, methodHandle method, int index) {
  assert(method->method_holder()->is_interface() || method->method_holder()->verify_vtable_index(index), "");
  set_direct_or_vtable_call(invoke_code, method, index, false);
}
void ConstantPoolCacheEntry::set_itable_call(Bytecodes::Code invoke_code,
                                                        KlassHandle referenced_klass,
                                                        methodHandle method, int index) {
  assert(method->method_holder()->verify_itable_index(index), "");
  assert(invoke_code == Bytecodes::_invokeinterface, "");
  InstanceKlass* interf = method->method_holder();
  assert(interf->is_interface(), "must be an interface");
  assert(!method->is_final_method(), "interfaces do not have final methods; cannot link to one here");
  set_f1(referenced_klass());
  set_f2((intx)method());
  set_method_flags(as_TosState(method->result_type()),
                   0,  // no option bits
                   method()->size_of_parameters());
  set_bytecode_1(Bytecodes::_invokeinterface);
}
void ConstantPoolCacheEntry::set_method_handle(constantPoolHandle cpool, const CallInfo &call_info) {
  set_method_handle_common(cpool, Bytecodes::_invokehandle, call_info);
}
void ConstantPoolCacheEntry::set_dynamic_call(constantPoolHandle cpool, const CallInfo &call_info) {
  set_method_handle_common(cpool, Bytecodes::_invokedynamic, call_info);
}
void ConstantPoolCacheEntry::set_method_handle_common(constantPoolHandle cpool,
                                                      Bytecodes::Code invoke_code,
                                                      const CallInfo &call_info) {
  MonitorLockerEx ml(cpool->lock());
  if (!is_f1_null()) {
    return;
  }
  const methodHandle adapter = call_info.resolved_method();
  const Handle appendix      = call_info.resolved_appendix();
  const Handle method_type   = call_info.resolved_method_type();
  const bool has_appendix    = appendix.not_null();
  const bool has_method_type = method_type.not_null();
  set_method_flags(as_TosState(adapter->result_type()),
                   ((has_appendix    ? 1 : 0) << has_appendix_shift   ) |
                   ((has_method_type ? 1 : 0) << has_method_type_shift) |
                   (                   1      << is_final_shift       ),
                   adapter->size_of_parameters());
  if (TraceInvokeDynamic) {
    tty->print_cr("set_method_handle bc=%d appendix=" PTR_FORMAT "%s method_type=" PTR_FORMAT "%s method=" PTR_FORMAT " ",
                  invoke_code,
                  (void *)appendix(),    (has_appendix    ? "" : " (unused)"),
                  (void *)method_type(), (has_method_type ? "" : " (unused)"),
                  (intptr_t)adapter());
    adapter->print();
    if (has_appendix)  appendix()->print();
  }
  objArrayHandle resolved_references = cpool->resolved_references();
  if (has_appendix) {
    const int appendix_index = f2_as_index() + _indy_resolved_references_appendix_offset;
    assert(appendix_index >= 0 && appendix_index < resolved_references->length(), "oob");
    assert(resolved_references->obj_at(appendix_index) == NULL, "init just once");
    resolved_references->obj_at_put(appendix_index, appendix());
  }
  if (has_method_type) {
    const int method_type_index = f2_as_index() + _indy_resolved_references_method_type_offset;
    assert(method_type_index >= 0 && method_type_index < resolved_references->length(), "oob");
    assert(resolved_references->obj_at(method_type_index) == NULL, "init just once");
    resolved_references->obj_at_put(method_type_index, method_type());
  }
  release_set_f1(adapter());  // This must be the last one to set (see NOTE above)!
  set_bytecode_1(invoke_code);
  NOT_PRODUCT(verify(tty));
  if (TraceInvokeDynamic) {
    this->print(tty, 0);
  }
}
Method* ConstantPoolCacheEntry::method_if_resolved(constantPoolHandle cpool) {
  Bytecodes::Code invoke_code = bytecode_1();
  if (invoke_code != (Bytecodes::Code)0) {
    Metadata* f1 = f1_ord();
    if (f1 != NULL) {
      switch (invoke_code) {
      case Bytecodes::_invokeinterface:
        assert(f1->is_klass(), "");
        return klassItable::method_for_itable_index((Klass*)f1, f2_as_index());
      case Bytecodes::_invokestatic:
      case Bytecodes::_invokespecial:
        assert(!has_appendix(), "");
      case Bytecodes::_invokehandle:
      case Bytecodes::_invokedynamic:
        assert(f1->is_method(), "");
        return (Method*)f1;
      }
    }
  }
  invoke_code = bytecode_2();
  if (invoke_code != (Bytecodes::Code)0) {
    switch (invoke_code) {
    case Bytecodes::_invokevirtual:
      if (is_vfinal()) {
        Method* m = f2_as_vfinal_method();
        assert(m->is_method(), "");
        return m;
      } else {
        int holder_index = cpool->uncached_klass_ref_index_at(constant_pool_index());
        if (cpool->tag_at(holder_index).is_klass()) {
          Klass* klass = cpool->resolved_klass_at(holder_index);
          if (!klass->oop_is_instance())
            klass = SystemDictionary::Object_klass();
          return InstanceKlass::cast(klass)->method_at_vtable(f2_as_index());
        }
      }
      break;
    }
  }
  return NULL;
}
oop ConstantPoolCacheEntry::appendix_if_resolved(constantPoolHandle cpool) {
  if (!has_appendix())
    return NULL;
  const int ref_index = f2_as_index() + _indy_resolved_references_appendix_offset;
  objArrayOop resolved_references = cpool->resolved_references();
  return resolved_references->obj_at(ref_index);
}
oop ConstantPoolCacheEntry::method_type_if_resolved(constantPoolHandle cpool) {
  if (!has_method_type())
    return NULL;
  const int ref_index = f2_as_index() + _indy_resolved_references_method_type_offset;
  objArrayOop resolved_references = cpool->resolved_references();
  return resolved_references->obj_at(ref_index);
}
#if INCLUDE_JVMTI
void log_adjust(const char* entry_type, Method* old_method, Method* new_method, bool* trace_name_printed) {
  if (RC_TRACE_IN_RANGE(0x00100000, 0x00400000)) {
    if (!(*trace_name_printed)) {
      RC_TRACE_MESG(("adjust: name=%s",
        old_method->method_holder()->external_name()));
    }
    RC_TRACE(0x00400000, ("cpc %s entry update: %s(%s)",
      entry_type,
      new_method->name()->as_C_string(),
      new_method->signature()->as_C_string()));
  }
}
void ConstantPoolCacheEntry::adjust_method_entry(Method* old_method,
       Method* new_method, bool * trace_name_printed) {
  if (is_vfinal()) {
    if (f2_as_vfinal_method() == old_method) {
      _f2 = (intptr_t)new_method;
    }
    return;
  }
  assert (_f1 != NULL, "should not call with uninteresting entry");
  if (!(_f1->is_method())) {
    if (f2_as_interface_method() == old_method) {
      _f2 = (intptr_t)new_method;
      log_adjust("interface", old_method, new_method, trace_name_printed);
    }
  } else if (_f1 == old_method) {
    _f1 = new_method;
    log_adjust("special, static or dynamic", old_method, new_method, trace_name_printed);
  }
}
bool ConstantPoolCacheEntry::check_no_old_or_obsolete_entries() {
  Method* m = get_interesting_method_entry(NULL);
  if (m != NULL) {
    assert(m->is_valid() && m->is_method(), "m is a valid method");
    return !m->is_old() && !m->is_obsolete(); // old is always set for old and obsolete
  } else {
    return true;
  }
}
Method* ConstantPoolCacheEntry::get_interesting_method_entry(Klass* k) {
  if (!is_method_entry()) {
    return NULL;
  }
  Method* m = NULL;
  if (is_vfinal()) {
    m = f2_as_vfinal_method();
  } else if (is_f1_null()) {
    return NULL;
  } else {
    if (!(_f1->is_method())) {
      m = f2_as_interface_method();
    } else {
      m = f1_as_method();
    }
  }
  assert(m != NULL && m->is_method(), "sanity check");
  if (m == NULL || !m->is_method() || (k != NULL && m->method_holder() != k)) {
    return NULL;
  }
  return m;
}
#endif // INCLUDE_JVMTI
void ConstantPoolCacheEntry::print(outputStream* st, int index) const {
  if (index == 0) st->print_cr("                 -------------");
  st->print("%3d  (" PTR_FORMAT ")  ", index, (intptr_t)this);
  st->print_cr("[%02x|%02x|%5d]", bytecode_2(), bytecode_1(),
               constant_pool_index());
  st->print_cr("                 [   " PTR_FORMAT "]", (intptr_t)_f1);
  st->print_cr("                 [   " PTR_FORMAT "]", (intptr_t)_f2);
  st->print_cr("                 [   " PTR_FORMAT "]", (intptr_t)_flags);
  st->print_cr("                 -------------");
}
void ConstantPoolCacheEntry::verify(outputStream* st) const {
}
ConstantPoolCache* ConstantPoolCache::allocate(ClassLoaderData* loader_data,
                                     const intStack& index_map,
                                     const intStack& invokedynamic_index_map,
                                     const intStack& invokedynamic_map, TRAPS) {
  const int length = index_map.length() + invokedynamic_index_map.length();
  int size = ConstantPoolCache::size(length);
  return new (loader_data, size, false, MetaspaceObj::ConstantPoolCacheType, THREAD)
    ConstantPoolCache(length, index_map, invokedynamic_index_map, invokedynamic_map);
}
void ConstantPoolCache::initialize(const intArray& inverse_index_map,
                                   const intArray& invokedynamic_inverse_index_map,
                                   const intArray& invokedynamic_references_map) {
  for (int i = 0; i < inverse_index_map.length(); i++) {
    ConstantPoolCacheEntry* e = entry_at(i);
    int original_index = inverse_index_map[i];
    e->initialize_entry(original_index);
    assert(entry_at(i) == e, "sanity");
  }
  int invokedynamic_offset = inverse_index_map.length();
  for (int i = 0; i < invokedynamic_inverse_index_map.length(); i++) {
    int offset = i + invokedynamic_offset;
    ConstantPoolCacheEntry* e = entry_at(offset);
    int original_index = invokedynamic_inverse_index_map[i];
    e->initialize_entry(original_index);
    assert(entry_at(offset) == e, "sanity");
  }
  for (int ref = 0; ref < invokedynamic_references_map.length(); ref++) {
    const int cpci = invokedynamic_references_map[ref];
    if (cpci >= 0) {
#ifdef ASSERT
      for (int entry = 1; entry < ConstantPoolCacheEntry::_indy_resolved_references_entries; entry++) {
        const int cpci_next = invokedynamic_references_map[ref + entry];
        assert(cpci == cpci_next, err_msg_res("%d == %d", cpci, cpci_next));
      }
#endif
      entry_at(cpci)->initialize_resolved_reference_index(ref);
      ref += ConstantPoolCacheEntry::_indy_resolved_references_entries - 1;  // skip extra entries
    }
  }
}
#if INCLUDE_JVMTI
void ConstantPoolCache::adjust_method_entries(InstanceKlass* holder, bool * trace_name_printed) {
  for (int i = 0; i < length(); i++) {
    ConstantPoolCacheEntry* entry = entry_at(i);
    Method* old_method = entry->get_interesting_method_entry(holder);
    if (old_method == NULL || !old_method->is_old()) {
      continue; // skip uninteresting entries
    }
    if (old_method->is_deleted()) {
      entry->initialize_entry(entry->constant_pool_index());
      continue;
    }
    Method* new_method = holder->method_with_idnum(old_method->orig_method_idnum());
    assert(new_method != NULL, "method_with_idnum() should not be NULL");
    assert(old_method != new_method, "sanity check");
    entry_at(i)->adjust_method_entry(old_method, new_method, trace_name_printed);
  }
}
bool ConstantPoolCache::check_no_old_or_obsolete_entries() {
  for (int i = 1; i < length(); i++) {
    if (entry_at(i)->get_interesting_method_entry(NULL) != NULL &&
        !entry_at(i)->check_no_old_or_obsolete_entries()) {
      return false;
    }
  }
  return true;
}
void ConstantPoolCache::dump_cache() {
  for (int i = 1; i < length(); i++) {
    if (entry_at(i)->get_interesting_method_entry(NULL) != NULL) {
      entry_at(i)->print(tty, i);
    }
  }
}
#endif // INCLUDE_JVMTI
void ConstantPoolCache::print_on(outputStream* st) const {
  assert(is_constantPoolCache(), "obj must be constant pool cache");
  st->print_cr("%s", internal_name());
  for (int i = 0; i < length(); i++) entry_at(i)->print(st, i);
}
void ConstantPoolCache::print_value_on(outputStream* st) const {
  assert(is_constantPoolCache(), "obj must be constant pool cache");
  st->print("cache [%d]", length());
  print_address_on(st);
  st->print(" for ");
  constant_pool()->print_value_on(st);
}
void ConstantPoolCache::verify_on(outputStream* st) {
  guarantee(is_constantPoolCache(), "obj must be constant pool cache");
  for (int i = 0; i < length(); i++) entry_at(i)->verify(st);
}
C:\hotspot-69087d08d473\src\share\vm/oops/cpCache.hpp
#ifndef SHARE_VM_OOPS_CPCACHEOOP_HPP
#define SHARE_VM_OOPS_CPCACHEOOP_HPP
#include "interpreter/bytecodes.hpp"
#include "memory/allocation.hpp"
#include "runtime/orderAccess.hpp"
#include "utilities/array.hpp"
class PSPromotionManager;
class CallInfo;
class ConstantPoolCacheEntry VALUE_OBJ_CLASS_SPEC {
  friend class VMStructs;
  friend class constantPoolCacheKlass;
  friend class ConstantPool;
  friend class InterpreterRuntime;
 private:
  volatile intx     _indices;  // constant pool index & rewrite bytecodes
  volatile Metadata*   _f1;       // entry specific metadata field
  volatile intx        _f2;       // entry specific int/metadata field
  volatile intx     _flags;    // flags
  void set_bytecode_1(Bytecodes::Code code);
  void set_bytecode_2(Bytecodes::Code code);
  void set_f1(Metadata* f1) {
    Metadata* existing_f1 = (Metadata*)_f1; // read once
    assert(existing_f1 == NULL || existing_f1 == f1, "illegal field change");
    _f1 = f1;
  }
  void release_set_f1(Metadata* f1);
  void set_f2(intx f2) {
    intx existing_f2 = _f2; // read once
    assert(existing_f2 == 0 || existing_f2 == f2, "illegal field change");
    _f2 = f2;
  }
  void set_f2_as_vfinal_method(Method* f2) {
    assert(is_vfinal(), "flags must be set");
    set_f2((intx)f2);
  }
  int make_flags(TosState state, int option_bits, int field_index_or_method_params);
  void set_flags(intx flags)                     { _flags = flags; }
  bool init_flags_atomic(intx flags);
  void set_field_flags(TosState field_type, int option_bits, int field_index) {
    assert((field_index & field_index_mask) == field_index, "field_index in range");
    set_flags(make_flags(field_type, option_bits | (1 << is_field_entry_shift), field_index));
  }
  void set_method_flags(TosState return_type, int option_bits, int method_params) {
    assert((method_params & parameter_size_mask) == method_params, "method_params in range");
    set_flags(make_flags(return_type, option_bits, method_params));
  }
  bool init_method_flags_atomic(TosState return_type, int option_bits, int method_params) {
    assert((method_params & parameter_size_mask) == method_params, "method_params in range");
    return init_flags_atomic(make_flags(return_type, option_bits, method_params));
  }
 public:
  enum {
    tos_state_bits             = 4,
    tos_state_mask             = right_n_bits(tos_state_bits),
    tos_state_shift            = BitsPerInt - tos_state_bits,  // see verify_tos_state_shift below
    is_field_entry_shift       = 26,  // (F) is it a field or a method?
    has_method_type_shift      = 25,  // (M) does the call site have a MethodType?
    has_appendix_shift         = 24,  // (A) does the call site have an appendix argument?
    is_forced_virtual_shift    = 23,  // (I) is the interface reference forced to virtual mode?
    is_final_shift             = 22,  // (f) is the field or method final?
    is_volatile_shift          = 21,  // (v) is the field volatile?
    is_vfinal_shift            = 20,  // (vf) did the call resolve to a final method?
    field_index_bits           = 16,
    field_index_mask           = right_n_bits(field_index_bits),
    parameter_size_bits        = 8,  // subset of field_index_mask, range is 0..255
    parameter_size_mask        = right_n_bits(parameter_size_bits),
    option_bits_mask           = ~(((-1) << tos_state_shift) | (field_index_mask | parameter_size_mask))
  };
  enum {
    cp_index_bits              = 2*BitsPerByte,
    cp_index_mask              = right_n_bits(cp_index_bits),
    bytecode_1_shift           = cp_index_bits,
    bytecode_1_mask            = right_n_bits(BitsPerByte), // == (u1)0xFF
    bytecode_2_shift           = cp_index_bits + BitsPerByte,
    bytecode_2_mask            = right_n_bits(BitsPerByte)  // == (u1)0xFF
  };
  void initialize_entry(int original_index);     // initialize primary entry
  void initialize_resolved_reference_index(int ref_index) {
    assert(_f2 == 0, "set once");  // note: ref_index might be zero also
    _f2 = ref_index;
  }
  void set_field(                                // sets entry to resolved field state
    Bytecodes::Code get_code,                    // the bytecode used for reading the field
    Bytecodes::Code put_code,                    // the bytecode used for writing the field
    KlassHandle     field_holder,                // the object/klass holding the field
    int             orig_field_index,            // the original field index in the field holder
    int             field_offset,                // the field offset in words in the field holder
    TosState        field_type,                  // the (machine) field type
    bool            is_final,                     // the field is final
    bool            is_volatile,                 // the field is volatile
    Klass*          root_klass                   // needed by the GC to dirty the klass
  );
 private:
  void set_direct_or_vtable_call(
    Bytecodes::Code invoke_code,                 // the bytecode used for invoking the method
    methodHandle    method,                      // the method/prototype if any (NULL, otherwise)
    int             vtable_index,                // the vtable index if any, else negative
    bool            sender_is_interface
  );
 public:
  void set_direct_call(                          // sets entry to exact concrete method entry
    Bytecodes::Code invoke_code,                 // the bytecode used for invoking the method
    methodHandle    method,                      // the method to call
    bool            sender_is_interface
  );
  void set_vtable_call(                          // sets entry to vtable index
    Bytecodes::Code invoke_code,                 // the bytecode used for invoking the method
    methodHandle    method,                      // resolved method which declares the vtable index
    int             vtable_index                 // the vtable index
  );
  void set_itable_call(
    Bytecodes::Code invoke_code,                 // the bytecode used; must be invokeinterface
    KlassHandle referenced_klass,                // the referenced klass in the InterfaceMethodref
    methodHandle method,                         // the resolved interface method
    int itable_index                             // index into itable for the method
  );
  void set_method_handle(
    constantPoolHandle cpool,                    // holding constant pool (required for locking)
    const CallInfo &call_info                    // Call link information
  );
  void set_dynamic_call(
    constantPoolHandle cpool,                    // holding constant pool (required for locking)
    const CallInfo &call_info                    // Call link information
  );
  void set_method_handle_common(
    constantPoolHandle cpool,                    // holding constant pool (required for locking)
    Bytecodes::Code invoke_code,                 // _invokehandle or _invokedynamic
    const CallInfo &call_info                    // Call link information
  );
  enum {
    _indy_resolved_references_appendix_offset    = 0,
    _indy_resolved_references_method_type_offset = 1,
    _indy_resolved_references_entries
  };
  Method*      method_if_resolved(constantPoolHandle cpool);
  oop        appendix_if_resolved(constantPoolHandle cpool);
  oop     method_type_if_resolved(constantPoolHandle cpool);
  void set_parameter_size(int value);
  static int bytecode_number(Bytecodes::Code code) {
    switch (code) {
      case Bytecodes::_getstatic       :    // fall through
      case Bytecodes::_getfield        :    // fall through
      case Bytecodes::_invokespecial   :    // fall through
      case Bytecodes::_invokestatic    :    // fall through
      case Bytecodes::_invokehandle    :    // fall through
      case Bytecodes::_invokedynamic   :    // fall through
      case Bytecodes::_invokeinterface : return 1;
      case Bytecodes::_putstatic       :    // fall through
      case Bytecodes::_putfield        :    // fall through
      case Bytecodes::_invokevirtual   : return 2;
      default                          : break;
    }
    return -1;
  }
  bool is_resolved(Bytecodes::Code code) const {
    switch (bytecode_number(code)) {
      case 1:  return (bytecode_1() == code);
      case 2:  return (bytecode_2() == code);
    }
    return false;      // default: not resolved
  }
  int indices() const                            { return _indices; }
  int indices_ord() const                        { return (intx)OrderAccess::load_ptr_acquire(&_indices); }
  int constant_pool_index() const                { return (indices() & cp_index_mask); }
  Bytecodes::Code bytecode_1() const             { return Bytecodes::cast((indices_ord() >> bytecode_1_shift) & bytecode_1_mask); }
  Bytecodes::Code bytecode_2() const             { return Bytecodes::cast((indices_ord() >> bytecode_2_shift) & bytecode_2_mask); }
  Metadata* f1_ord() const                       { return (Metadata *)OrderAccess::load_ptr_acquire(&_f1); }
  Method*   f1_as_method() const                 { Metadata* f1 = f1_ord(); assert(f1 == NULL || f1->is_method(), ""); return (Method*)f1; }
  Klass*    f1_as_klass() const                  { Metadata* f1 = f1_ord(); assert(f1 == NULL || f1->is_klass(), ""); return (Klass*)f1; }
  bool      is_f1_null() const                   { Metadata* f1 = f1_ord(); return f1 == NULL; }  // classifies a CPC entry as unbound
  int       f2_as_index() const                  { assert(!is_vfinal(), ""); return (int) _f2; }
  Method*   f2_as_vfinal_method() const          { assert(is_vfinal(), ""); return (Method*)_f2; }
  Method*   f2_as_interface_method() const       { assert(bytecode_1() == Bytecodes::_invokeinterface, ""); return (Method*)_f2; }
  int  field_index() const                       { assert(is_field_entry(),  ""); return (_flags & field_index_mask); }
  int  parameter_size() const                    { assert(is_method_entry(), ""); return (_flags & parameter_size_mask); }
  bool is_volatile() const                       { return (_flags & (1 << is_volatile_shift))       != 0; }
  bool is_final() const                          { return (_flags & (1 << is_final_shift))          != 0; }
  bool is_forced_virtual() const                 { return (_flags & (1 << is_forced_virtual_shift)) != 0; }
  bool is_vfinal() const                         { return (_flags & (1 << is_vfinal_shift))         != 0; }
  bool has_appendix() const                      { return (!is_f1_null()) && (_flags & (1 << has_appendix_shift))      != 0; }
  bool has_method_type() const                   { return (!is_f1_null()) && (_flags & (1 << has_method_type_shift))   != 0; }
  bool is_method_entry() const                   { return (_flags & (1 << is_field_entry_shift))    == 0; }
  bool is_field_entry() const                    { return (_flags & (1 << is_field_entry_shift))    != 0; }
  bool is_long() const                           { return flag_state() == ltos; }
  bool is_double() const                         { return flag_state() == dtos; }
  TosState flag_state() const                    { assert((uint)number_of_states <= (uint)tos_state_mask+1, "");
                                                   return (TosState)((_flags >> tos_state_shift) & tos_state_mask); }
  static WordSize size()                         { return in_WordSize(sizeof(ConstantPoolCacheEntry) / HeapWordSize); }
  static ByteSize size_in_bytes()                { return in_ByteSize(sizeof(ConstantPoolCacheEntry)); }
  static ByteSize indices_offset()               { return byte_offset_of(ConstantPoolCacheEntry, _indices); }
  static ByteSize f1_offset()                    { return byte_offset_of(ConstantPoolCacheEntry, _f1); }
  static ByteSize f2_offset()                    { return byte_offset_of(ConstantPoolCacheEntry, _f2); }
  static ByteSize flags_offset()                 { return byte_offset_of(ConstantPoolCacheEntry, _flags); }
#if INCLUDE_JVMTI
  void adjust_method_entry(Method* old_method, Method* new_method,
         bool* trace_name_printed);
  bool check_no_old_or_obsolete_entries();
  Method* get_interesting_method_entry(Klass* k);
#endif // INCLUDE_JVMTI
  void print (outputStream* st, int index) const;
  void verify(outputStream* st) const;
  static void verify_tos_state_shift() {
    assert((((u4)-1 >> tos_state_shift) & ~tos_state_mask) == 0, "no need for tos_state mask");
  }
};
class ConstantPoolCache: public MetaspaceObj {
  friend class VMStructs;
  friend class MetadataFactory;
 private:
  int             _length;
  ConstantPool*   _constant_pool;          // the corresponding constant pool
  debug_only(friend class ClassVerifier;)
  ConstantPoolCache(int length,
                    const intStack& inverse_index_map,
                    const intStack& invokedynamic_inverse_index_map,
                    const intStack& invokedynamic_references_map) :
                          _length(length),
                          _constant_pool(NULL) {
    initialize(inverse_index_map, invokedynamic_inverse_index_map,
               invokedynamic_references_map);
    for (int i = 0; i < length; i++) {
      assert(entry_at(i)->is_f1_null(), "Failed to clear?");
    }
  }
  void initialize(const intArray& inverse_index_map,
                  const intArray& invokedynamic_inverse_index_map,
                  const intArray& invokedynamic_references_map);
 public:
  static ConstantPoolCache* allocate(ClassLoaderData* loader_data,
                                     const intStack& cp_cache_map,
                                     const intStack& invokedynamic_cp_cache_map,
                                     const intStack& invokedynamic_references_map, TRAPS);
  bool is_constantPoolCache() const { return true; }
  int length() const                             { return _length; }
 private:
  void set_length(int length)                    { _length = length; }
  static int header_size()                       { return sizeof(ConstantPoolCache) / HeapWordSize; }
  static int size(int length)                    { return align_object_size(header_size() + length * in_words(ConstantPoolCacheEntry::size())); }
 public:
  int size() const                               { return size(length()); }
 private:
  ConstantPool**        constant_pool_addr()   { return &_constant_pool; }
  ConstantPoolCacheEntry* base() const           { return (ConstantPoolCacheEntry*)((address)this + in_bytes(base_offset())); }
  friend class constantPoolCacheKlass;
  friend class ConstantPoolCacheEntry;
 public:
  void set_constant_pool(ConstantPool* pool)   { _constant_pool = pool; }
  ConstantPool* constant_pool() const          { return _constant_pool; }
  ConstantPoolCacheEntry* entry_at(int i) const {
    assert(0 <= i && i < length(), "index out of bounds");
    return base() + i;
  }
  static ByteSize base_offset()                  { return in_ByteSize(sizeof(ConstantPoolCache)); }
  static ByteSize entry_offset(int raw_index) {
    int index = raw_index;
    return (base_offset() + ConstantPoolCacheEntry::size_in_bytes() * index);
  }
#if INCLUDE_JVMTI
  void adjust_method_entries(InstanceKlass* holder, bool* trace_name_printed);
  bool check_no_old_or_obsolete_entries();
  void dump_cache();
#endif // INCLUDE_JVMTI
  DEBUG_ONLY(bool on_stack() { return false; })
  void deallocate_contents(ClassLoaderData* data) {}
  bool is_klass() const { return false; }
  void print_on(outputStream* st) const;
  void print_value_on(outputStream* st) const;
  const char* internal_name() const { return "{constant pool cache}"; }
  void verify_on(outputStream* st);
};
#endif // SHARE_VM_OOPS_CPCACHEOOP_HPP
C:\hotspot-69087d08d473\src\share\vm/oops/fieldInfo.hpp
#ifndef SHARE_VM_OOPS_FIELDINFO_HPP
#define SHARE_VM_OOPS_FIELDINFO_HPP
#include "oops/constantPool.hpp"
#include "oops/typeArrayOop.hpp"
#include "classfile/vmSymbols.hpp"
class FieldInfo VALUE_OBJ_CLASS_SPEC {
  friend class fieldDescriptor;
  friend class JavaFieldStream;
  friend class ClassFileParser;
 public:
#define FIELDINFO_TAG_SIZE             2
#define FIELDINFO_TAG_BLANK            0
#define FIELDINFO_TAG_OFFSET           1
#define FIELDINFO_TAG_TYPE_PLAIN       2
#define FIELDINFO_TAG_TYPE_CONTENDED   3
#define FIELDINFO_TAG_MASK             3
  enum FieldOffset {
    access_flags_offset      = 0,
    name_index_offset        = 1,
    signature_index_offset   = 2,
    initval_index_offset     = 3,
    low_packed_offset        = 4,
    high_packed_offset       = 5,
    field_slots              = 6
  };
 private:
  u2 _shorts[field_slots];
  void set_name_index(u2 val)                    { _shorts[name_index_offset] = val;         }
  void set_signature_index(u2 val)               { _shorts[signature_index_offset] = val;    }
  void set_initval_index(u2 val)                 { _shorts[initval_index_offset] = val;      }
  u2 name_index() const                          { return _shorts[name_index_offset];        }
  u2 signature_index() const                     { return _shorts[signature_index_offset];   }
  u2 initval_index() const                       { return _shorts[initval_index_offset];     }
 public:
  static FieldInfo* from_field_array(Array<u2>* fields, int index) {
    return ((FieldInfo*)fields->adr_at(index * field_slots));
  }
  static FieldInfo* from_field_array(u2* fields, int index) {
    return ((FieldInfo*)(fields + index * field_slots));
  }
  void initialize(u2 access_flags,
                  u2 name_index,
                  u2 signature_index,
                  u2 initval_index) {
    _shorts[access_flags_offset] = access_flags;
    _shorts[name_index_offset] = name_index;
    _shorts[signature_index_offset] = signature_index;
    _shorts[initval_index_offset] = initval_index;
    _shorts[low_packed_offset] = 0;
    _shorts[high_packed_offset] = 0;
  }
  u2 access_flags() const                        { return _shorts[access_flags_offset];            }
  u4 offset() const {
    u2 lo = _shorts[low_packed_offset];
    switch(lo & FIELDINFO_TAG_MASK) {
      case FIELDINFO_TAG_OFFSET:
        return build_int_from_shorts(_shorts[low_packed_offset], _shorts[high_packed_offset]) >> FIELDINFO_TAG_SIZE;
#ifndef PRODUCT
      case FIELDINFO_TAG_TYPE_PLAIN:
        fatal("Asking offset for the plain type field");
      case FIELDINFO_TAG_TYPE_CONTENDED:
        fatal("Asking offset for the contended type field");
      case FIELDINFO_TAG_BLANK:
        fatal("Asking offset for the blank field");
#endif
    }
    ShouldNotReachHere();
    return 0;
  }
  bool is_contended() const {
    u2 lo = _shorts[low_packed_offset];
    switch(lo & FIELDINFO_TAG_MASK) {
      case FIELDINFO_TAG_TYPE_PLAIN:
        return false;
      case FIELDINFO_TAG_TYPE_CONTENDED:
        return true;
#ifndef PRODUCT
      case FIELDINFO_TAG_OFFSET:
        fatal("Asking contended flag for the field with offset");
      case FIELDINFO_TAG_BLANK:
        fatal("Asking contended flag for the blank field");
#endif
    }
    ShouldNotReachHere();
    return false;
  }
  u2 contended_group() const {
    u2 lo = _shorts[low_packed_offset];
    switch(lo & FIELDINFO_TAG_MASK) {
      case FIELDINFO_TAG_TYPE_PLAIN:
        return 0;
      case FIELDINFO_TAG_TYPE_CONTENDED:
        return _shorts[high_packed_offset];
#ifndef PRODUCT
      case FIELDINFO_TAG_OFFSET:
        fatal("Asking the contended group for the field with offset");
      case FIELDINFO_TAG_BLANK:
        fatal("Asking the contended group for the blank field");
#endif
    }
    ShouldNotReachHere();
    return 0;
 }
  u2 allocation_type() const {
    u2 lo = _shorts[low_packed_offset];
    switch(lo & FIELDINFO_TAG_MASK) {
      case FIELDINFO_TAG_TYPE_PLAIN:
      case FIELDINFO_TAG_TYPE_CONTENDED:
        return (lo >> FIELDINFO_TAG_SIZE);
#ifndef PRODUCT
      case FIELDINFO_TAG_OFFSET:
        fatal("Asking the field type for field with offset");
      case FIELDINFO_TAG_BLANK:
        fatal("Asking the field type for the blank field");
#endif
    }
    ShouldNotReachHere();
    return 0;
  }
  bool is_offset_set() const {
    return (_shorts[low_packed_offset] & FIELDINFO_TAG_MASK) == FIELDINFO_TAG_OFFSET;
  }
  Symbol* name(constantPoolHandle cp) const {
    int index = name_index();
    if (is_internal()) {
      return lookup_symbol(index);
    }
    return cp->symbol_at(index);
  }
  Symbol* signature(constantPoolHandle cp) const {
    int index = signature_index();
    if (is_internal()) {
      return lookup_symbol(index);
    }
    return cp->symbol_at(index);
  }
  void set_access_flags(u2 val)                  { _shorts[access_flags_offset] = val;             }
  void set_offset(u4 val)                        {
    val = val << FIELDINFO_TAG_SIZE; // make room for tag
    _shorts[low_packed_offset] = extract_low_short_from_int(val) | FIELDINFO_TAG_OFFSET;
    _shorts[high_packed_offset] = extract_high_short_from_int(val);
  }
  void set_allocation_type(int type) {
    u2 lo = _shorts[low_packed_offset];
    switch(lo & FIELDINFO_TAG_MASK) {
      case FIELDINFO_TAG_BLANK:
        _shorts[low_packed_offset] = ((type << FIELDINFO_TAG_SIZE)) & 0xFFFF;
        _shorts[low_packed_offset] &= ~FIELDINFO_TAG_MASK;
        _shorts[low_packed_offset] |= FIELDINFO_TAG_TYPE_PLAIN;
        return;
#ifndef PRODUCT
      case FIELDINFO_TAG_TYPE_PLAIN:
      case FIELDINFO_TAG_TYPE_CONTENDED:
      case FIELDINFO_TAG_OFFSET:
        fatal("Setting the field type with overwriting");
#endif
    }
    ShouldNotReachHere();
  }
  void set_contended_group(u2 val) {
    u2 lo = _shorts[low_packed_offset];
    switch(lo & FIELDINFO_TAG_MASK) {
      case FIELDINFO_TAG_TYPE_PLAIN:
        _shorts[low_packed_offset] |= FIELDINFO_TAG_TYPE_CONTENDED;
        _shorts[high_packed_offset] = val;
        return;
#ifndef PRODUCT
      case FIELDINFO_TAG_TYPE_CONTENDED:
        fatal("Overwriting contended group");
      case FIELDINFO_TAG_BLANK:
        fatal("Setting contended group for the blank field");
      case FIELDINFO_TAG_OFFSET:
        fatal("Setting contended group for field with offset");
#endif
    }
    ShouldNotReachHere();
  }
  bool is_internal() const {
    return (access_flags() & JVM_ACC_FIELD_INTERNAL) != 0;
  }
  bool is_stable() const {
    return (access_flags() & JVM_ACC_FIELD_STABLE) != 0;
  }
  void set_stable(bool z) {
    if (z) _shorts[access_flags_offset] |=  JVM_ACC_FIELD_STABLE;
    else   _shorts[access_flags_offset] &= ~JVM_ACC_FIELD_STABLE;
  }
  Symbol* lookup_symbol(int symbol_index) const {
    assert(is_internal(), "only internal fields");
    return vmSymbols::symbol_at((vmSymbols::SID)symbol_index);
  }
};
#endif // SHARE_VM_OOPS_FIELDINFO_HPP
C:\hotspot-69087d08d473\src\share\vm/oops/fieldStreams.hpp
#ifndef SHARE_VM_OOPS_FIELDSTREAMS_HPP
#define SHARE_VM_OOPS_FIELDSTREAMS_HPP
#include "oops/instanceKlass.hpp"
#include "oops/fieldInfo.hpp"
#include "runtime/fieldDescriptor.hpp"
class FieldStreamBase : public StackObj {
 protected:
  Array<u2>*          _fields;
  constantPoolHandle  _constants;
  int                 _index;
  int                 _limit;
  int                 _generic_signature_slot;
  fieldDescriptor     _fd_buf;
  FieldInfo* field() const { return FieldInfo::from_field_array(_fields, _index); }
  InstanceKlass* field_holder() const { return _constants->pool_holder(); }
  int init_generic_signature_start_slot() {
    int length = _fields->length();
    int num_fields = 0;
    int skipped_generic_signature_slots = 0;
    FieldInfo* fi;
    AccessFlags flags;
       signature slots for field[0] to field[_index - 1]. */
    for (int i = 0; i < _index; i++) {
      fi = FieldInfo::from_field_array(_fields, i);
      flags.set_flags(fi->access_flags());
      if (flags.field_has_generic_signature()) {
        length --;
        skipped_generic_signature_slots ++;
      }
    }
    for (int i = _index; i*FieldInfo::field_slots < length; i++) {
      fi = FieldInfo::from_field_array(_fields, i);
      flags.set_flags(fi->access_flags());
      if (flags.field_has_generic_signature()) {
        length --;
      }
      num_fields ++;
    }
    _generic_signature_slot = length + skipped_generic_signature_slots;
    assert(_generic_signature_slot <= _fields->length(), "");
    return num_fields;
  }
  FieldStreamBase(Array<u2>* fields, constantPoolHandle constants, int start, int limit) {
    _fields = fields;
    _constants = constants;
    _index = start;
    int num_fields = init_generic_signature_start_slot();
    if (limit < start) {
      _limit = num_fields;
    } else {
      _limit = limit;
    }
  }
  FieldStreamBase(Array<u2>* fields, constantPoolHandle constants) {
    _fields = fields;
    _constants = constants;
    _index = 0;
    _limit = init_generic_signature_start_slot();
  }
 public:
  FieldStreamBase(InstanceKlass* klass) {
    _fields = klass->fields();
    _constants = klass->constants();
    _index = 0;
    _limit = klass->java_fields_count();
    init_generic_signature_start_slot();
    assert(klass == field_holder(), "");
  }
  FieldStreamBase(instanceKlassHandle klass) {
    _fields = klass->fields();
    _constants = klass->constants();
    _index = 0;
    _limit = klass->java_fields_count();
    init_generic_signature_start_slot();
    assert(klass == field_holder(), "");
  }
  int index() const                 { return _index; }
  void next() {
    if (access_flags().field_has_generic_signature()) {
      _generic_signature_slot ++;
      assert(_generic_signature_slot <= _fields->length(), "");
    }
    _index += 1;
  }
  bool done() const { return _index >= _limit; }
  AccessFlags access_flags() const {
    AccessFlags flags;
    flags.set_flags(field()->access_flags());
    return flags;
  }
  void set_access_flags(u2 flags) const {
    field()->set_access_flags(flags);
  }
  void set_access_flags(AccessFlags flags) const {
    set_access_flags(flags.as_short());
  }
  Symbol* name() const {
    return field()->name(_constants);
  }
  Symbol* signature() const {
    return field()->signature(_constants);
  }
  Symbol* generic_signature() const {
    if (access_flags().field_has_generic_signature()) {
      assert(_generic_signature_slot < _fields->length(), "out of bounds");
      int index = _fields->at(_generic_signature_slot);
      return _constants->symbol_at(index);
    } else {
      return NULL;
    }
  }
  int offset() const {
    return field()->offset();
  }
  int allocation_type() const {
    return field()->allocation_type();
  }
  void set_offset(int offset) {
    field()->set_offset(offset);
  }
  bool is_offset_set() const {
    return field()->is_offset_set();
  }
  bool is_contended() const {
    return field()->is_contended();
  }
  int contended_group() const {
    return field()->contended_group();
  }
  fieldDescriptor& field_descriptor() const {
    fieldDescriptor& field = const_cast<fieldDescriptor&>(_fd_buf);
    field.reinitialize(field_holder(), _index);
    return field;
  }
};
class JavaFieldStream : public FieldStreamBase {
 public:
  JavaFieldStream(instanceKlassHandle k): FieldStreamBase(k->fields(), k->constants(), 0, k->java_fields_count()) {}
  int name_index() const {
    assert(!field()->is_internal(), "regular only");
    return field()->name_index();
  }
  void set_name_index(int index) {
    assert(!field()->is_internal(), "regular only");
    field()->set_name_index(index);
  }
  int signature_index() const {
    assert(!field()->is_internal(), "regular only");
    return field()->signature_index();
  }
  void set_signature_index(int index) {
    assert(!field()->is_internal(), "regular only");
    field()->set_signature_index(index);
  }
  int generic_signature_index() const {
    assert(!field()->is_internal(), "regular only");
    if (access_flags().field_has_generic_signature()) {
      assert(_generic_signature_slot < _fields->length(), "out of bounds");
      return _fields->at(_generic_signature_slot);
    } else {
      return 0;
    }
  }
  void set_generic_signature_index(int index) {
    assert(!field()->is_internal(), "regular only");
    if (access_flags().field_has_generic_signature()) {
      assert(_generic_signature_slot < _fields->length(), "out of bounds");
      _fields->at_put(_generic_signature_slot, index);
    }
  }
  int initval_index() const {
    assert(!field()->is_internal(), "regular only");
    return field()->initval_index();
  }
  void set_initval_index(int index) {
    assert(!field()->is_internal(), "regular only");
    return field()->set_initval_index(index);
  }
};
class InternalFieldStream : public FieldStreamBase {
 public:
  InternalFieldStream(InstanceKlass* k):      FieldStreamBase(k->fields(), k->constants(), k->java_fields_count(), 0) {}
  InternalFieldStream(instanceKlassHandle k): FieldStreamBase(k->fields(), k->constants(), k->java_fields_count(), 0) {}
};
class AllFieldStream : public FieldStreamBase {
 public:
  AllFieldStream(Array<u2>* fields, constantPoolHandle constants): FieldStreamBase(fields, constants) {}
  AllFieldStream(InstanceKlass* k):      FieldStreamBase(k->fields(), k->constants()) {}
  AllFieldStream(instanceKlassHandle k): FieldStreamBase(k->fields(), k->constants()) {}
};
#endif // SHARE_VM_OOPS_FIELDSTREAMS_HPP
C:\hotspot-69087d08d473\src\share\vm/oops/generateOopMap.cpp
#include "precompiled.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "oops/generateOopMap.hpp"
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/os.hpp"
#include "runtime/relocator.hpp"
#include "utilities/bitMap.inline.hpp"
#include "prims/methodHandles.hpp"
class ComputeCallStack : public SignatureIterator {
  CellTypeState *_effect;
  int _idx;
  void setup();
  void set(CellTypeState state)         { _effect[_idx++] = state; }
  int  length()                         { return _idx; };
  virtual void do_bool  ()              { set(CellTypeState::value); };
  virtual void do_char  ()              { set(CellTypeState::value); };
  virtual void do_float ()              { set(CellTypeState::value); };
  virtual void do_byte  ()              { set(CellTypeState::value); };
  virtual void do_short ()              { set(CellTypeState::value); };
  virtual void do_int   ()              { set(CellTypeState::value); };
  virtual void do_void  ()              { set(CellTypeState::bottom);};
  virtual void do_object(int begin, int end)  { set(CellTypeState::ref); };
  virtual void do_array (int begin, int end)  { set(CellTypeState::ref); };
  void do_double()                      { set(CellTypeState::value);
                                          set(CellTypeState::value); }
  void do_long  ()                      { set(CellTypeState::value);
                                           set(CellTypeState::value); }
public:
  ComputeCallStack(Symbol* signature) : SignatureIterator(signature) {};
  int compute_for_parameters(bool is_static, CellTypeState *effect) {
    _idx    = 0;
    _effect = effect;
    if (!is_static)
      effect[_idx++] = CellTypeState::ref;
    iterate_parameters();
    return length();
  };
  int compute_for_returntype(CellTypeState *effect) {
    _idx    = 0;
    _effect = effect;
    iterate_returntype();
    set(CellTypeState::bottom);  // Always terminate with a bottom state, so ppush works
    return length();
  }
};
class ComputeEntryStack : public SignatureIterator {
  CellTypeState *_effect;
  int _idx;
  void setup();
  void set(CellTypeState state)         { _effect[_idx++] = state; }
  int  length()                         { return _idx; };
  virtual void do_bool  ()              { set(CellTypeState::value); };
  virtual void do_char  ()              { set(CellTypeState::value); };
  virtual void do_float ()              { set(CellTypeState::value); };
  virtual void do_byte  ()              { set(CellTypeState::value); };
  virtual void do_short ()              { set(CellTypeState::value); };
  virtual void do_int   ()              { set(CellTypeState::value); };
  virtual void do_void  ()              { set(CellTypeState::bottom);};
  virtual void do_object(int begin, int end)  { set(CellTypeState::make_slot_ref(_idx)); }
  virtual void do_array (int begin, int end)  { set(CellTypeState::make_slot_ref(_idx)); }
  void do_double()                      { set(CellTypeState::value);
                                          set(CellTypeState::value); }
  void do_long  ()                      { set(CellTypeState::value);
                                          set(CellTypeState::value); }
public:
  ComputeEntryStack(Symbol* signature) : SignatureIterator(signature) {};
  int compute_for_parameters(bool is_static, CellTypeState *effect) {
    _idx    = 0;
    _effect = effect;
    if (!is_static)
      effect[_idx++] = CellTypeState::make_slot_ref(0);
    iterate_parameters();
    return length();
  };
  int compute_for_returntype(CellTypeState *effect) {
    _idx    = 0;
    _effect = effect;
    iterate_returntype();
    set(CellTypeState::bottom);  // Always terminate with a bottom state, so ppush works
    return length();
  }
};
int RetTable::_init_nof_entries = 10;
int RetTableEntry::_init_nof_jsrs = 5;
void RetTableEntry::add_delta(int bci, int delta) {
  if (_target_bci > bci) _target_bci += delta;
  for (int k = 0; k < _jsrs->length(); k++) {
    int jsr = _jsrs->at(k);
    if (jsr > bci) _jsrs->at_put(k, jsr+delta);
  }
}
void RetTable::compute_ret_table(methodHandle method) {
  BytecodeStream i(method);
  Bytecodes::Code bytecode;
  while( (bytecode = i.next()) >= 0) {
    switch (bytecode) {
      case Bytecodes::_jsr:
        add_jsr(i.next_bci(), i.dest());
        break;
      case Bytecodes::_jsr_w:
        add_jsr(i.next_bci(), i.dest_w());
        break;
    }
  }
}
void RetTable::add_jsr(int return_bci, int target_bci) {
  RetTableEntry* entry = _first;
  for (;entry && entry->target_bci() != target_bci; entry = entry->next());
  if (!entry) {
    entry = new RetTableEntry(target_bci, _first);
    _first = entry;
  }
  entry->add_jsr(return_bci);
}
RetTableEntry* RetTable::find_jsrs_for_target(int targBci) {
  RetTableEntry *cur = _first;
  while(cur) {
    assert(cur->target_bci() != -1, "sanity check");
    if (cur->target_bci() == targBci)  return cur;
    cur = cur->next();
  }
  ShouldNotReachHere();
  return NULL;
}
void RetTable::update_ret_table(int bci, int delta) {
  RetTableEntry *cur = _first;
  while(cur) {
    cur->add_delta(bci, delta);
    cur = cur->next();
  }
}
CellTypeState CellTypeState::bottom      = CellTypeState::make_bottom();
CellTypeState CellTypeState::uninit      = CellTypeState::make_any(uninit_value);
CellTypeState CellTypeState::ref         = CellTypeState::make_any(ref_conflict);
CellTypeState CellTypeState::value       = CellTypeState::make_any(val_value);
CellTypeState CellTypeState::refUninit   = CellTypeState::make_any(ref_conflict | uninit_value);
CellTypeState CellTypeState::top         = CellTypeState::make_top();
CellTypeState CellTypeState::addr        = CellTypeState::make_any(addr_conflict);
static CellTypeState epsilonCTS[1] = { CellTypeState::bottom };
static CellTypeState   refCTS   = CellTypeState::ref;
static CellTypeState   valCTS   = CellTypeState::value;
static CellTypeState    vCTS[2] = { CellTypeState::value, CellTypeState::bottom };
static CellTypeState    rCTS[2] = { CellTypeState::ref,   CellTypeState::bottom };
static CellTypeState   rrCTS[3] = { CellTypeState::ref,   CellTypeState::ref,   CellTypeState::bottom };
static CellTypeState   vrCTS[3] = { CellTypeState::value, CellTypeState::ref,   CellTypeState::bottom };
static CellTypeState   vvCTS[3] = { CellTypeState::value, CellTypeState::value, CellTypeState::bottom };
static CellTypeState  rvrCTS[4] = { CellTypeState::ref,   CellTypeState::value, CellTypeState::ref,   CellTypeState::bottom };
static CellTypeState  vvrCTS[4] = { CellTypeState::value, CellTypeState::value, CellTypeState::ref,   CellTypeState::bottom };
static CellTypeState  vvvCTS[4] = { CellTypeState::value, CellTypeState::value, CellTypeState::value, CellTypeState::bottom };
static CellTypeState vvvrCTS[5] = { CellTypeState::value, CellTypeState::value, CellTypeState::value, CellTypeState::ref,   CellTypeState::bottom };
static CellTypeState vvvvCTS[5] = { CellTypeState::value, CellTypeState::value, CellTypeState::value, CellTypeState::value, CellTypeState::bottom };
char CellTypeState::to_char() const {
  if (can_be_reference()) {
    if (can_be_value() || can_be_address())
      return '#';    // Conflict that needs to be rewritten
    else
      return 'r';
  } else if (can_be_value())
    return 'v';
  else if (can_be_address())
    return 'p';
  else if (can_be_uninit())
    return ' ';
  else
    return '@';
}
void CellTypeState::print(outputStream *os) {
  if (can_be_address()) {
    os->print("(p");
  } else {
    os->print("( ");
  }
  if (can_be_reference()) {
    os->print("r");
  } else {
    os->print(" ");
  }
  if (can_be_value()) {
    os->print("v");
  } else {
    os->print(" ");
  }
  if (can_be_uninit()) {
    os->print("u|");
  } else {
    os->print(" |");
  }
  if (is_info_top()) {
    os->print("Top)");
  } else if (is_info_bottom()) {
    os->print("Bot)");
  } else {
    if (is_reference()) {
      int info = get_info();
      int data = info & ~(ref_not_lock_bit | ref_slot_bit);
      if (info & ref_not_lock_bit) {
        if (info & ref_slot_bit) {
          os->print("slot%d)", data);
        } else {
          os->print("line%d)", data);
        }
      } else {
        os->print("lock%d)", data);
      }
    } else {
      os->print("%d)", get_info());
    }
  }
}
void GenerateOopMap ::initialize_bb() {
  _gc_points = 0;
  _bb_count  = 0;
  _bb_hdr_bits.clear();
  _bb_hdr_bits.resize(method()->code_size());
}
void GenerateOopMap::bb_mark_fct(GenerateOopMap *c, int bci, int *data) {
  assert(bci>= 0 && bci < c->method()->code_size(), "index out of bounds");
  if (c->is_bb_header(bci))
     return;
  if (TraceNewOopMapGeneration) {
     tty->print_cr("Basicblock#%d begins at: %d", c->_bb_count, bci);
  }
  c->set_bbmark_bit(bci);
  c->_bb_count++;
}
void GenerateOopMap::mark_bbheaders_and_count_gc_points() {
  initialize_bb();
  bool fellThrough = false;  // False to get first BB marked.
  ExceptionTable excps(method());
  for(int i = 0; i < excps.length(); i ++) {
    bb_mark_fct(this, excps.handler_pc(i), NULL);
  }
  BytecodeStream bcs(_method);
  Bytecodes::Code bytecode;
  while( (bytecode = bcs.next()) >= 0) {
    int bci = bcs.bci();
    if (!fellThrough)
        bb_mark_fct(this, bci, NULL);
    fellThrough = jump_targets_do(&bcs, &GenerateOopMap::bb_mark_fct, NULL);
    switch (bytecode) {
      case Bytecodes::_jsr:
        assert(!fellThrough, "should not happen");
        bb_mark_fct(this, bci + Bytecodes::length_for(bytecode), NULL);
        break;
      case Bytecodes::_jsr_w:
        assert(!fellThrough, "should not happen");
        bb_mark_fct(this, bci + Bytecodes::length_for(bytecode), NULL);
        break;
    }
    if (possible_gc_point(&bcs))
      _gc_points++;
  }
}
void GenerateOopMap::reachable_basicblock(GenerateOopMap *c, int bci, int *data) {
  assert(bci>= 0 && bci < c->method()->code_size(), "index out of bounds");
  BasicBlock* bb = c->get_basic_block_at(bci);
  if (bb->is_dead()) {
    bb->mark_as_alive();
  }
}
void GenerateOopMap::mark_reachable_code() {
  int change = 1; // int to get function pointers to work
  _basic_blocks[0].mark_as_alive();
  ExceptionTable excps(method());
  for(int i = 0; i < excps.length(); i++) {
    BasicBlock *bb = get_basic_block_at(excps.handler_pc(i));
    if (bb->is_dead()) bb->mark_as_alive();
  }
  BytecodeStream bcs(_method);
  while (change) {
    change = 0;
    for (int i = 0; i < _bb_count; i++) {
      BasicBlock *bb = &_basic_blocks[i];
      if (bb->is_alive()) {
        bcs.set_start(bb->_end_bci);
        bcs.next();
        Bytecodes::Code bytecode = bcs.code();
        int bci = bcs.bci();
        assert(bci == bb->_end_bci, "wrong bci");
        bool fell_through = jump_targets_do(&bcs, &GenerateOopMap::reachable_basicblock, &change);
        switch (bytecode) {
          case Bytecodes::_jsr:
          case Bytecodes::_jsr_w:
            assert(!fell_through, "should not happen");
            reachable_basicblock(this, bci + Bytecodes::length_for(bytecode), &change);
            break;
        }
        if (fell_through) {
          if (bb[1].is_dead()) {
            bb[1].mark_as_alive();
            change = 1;
          }
        }
      }
    }
  }
}
   returns "true".  Otherwise, calls "jmpFct" one or more times, with
   "c", an appropriate "pcDelta", and "data" as arguments, then
   returns "false".  There is one exception: if the current
   instruction is a "ret", returns "false" without calling "jmpFct".
   Arrangements for tracking the control flow of a "ret" must be made
   externally. */
bool GenerateOopMap::jump_targets_do(BytecodeStream *bcs, jmpFct_t jmpFct, int *data) {
  int bci = bcs->bci();
  switch (bcs->code()) {
    case Bytecodes::_ifeq:
    case Bytecodes::_ifne:
    case Bytecodes::_iflt:
    case Bytecodes::_ifge:
    case Bytecodes::_ifgt:
    case Bytecodes::_ifle:
    case Bytecodes::_if_icmpeq:
    case Bytecodes::_if_icmpne:
    case Bytecodes::_if_icmplt:
    case Bytecodes::_if_icmpge:
    case Bytecodes::_if_icmpgt:
    case Bytecodes::_if_icmple:
    case Bytecodes::_if_acmpeq:
    case Bytecodes::_if_acmpne:
    case Bytecodes::_ifnull:
    case Bytecodes::_ifnonnull:
      (*jmpFct)(this, bcs->dest(), data);
      (*jmpFct)(this, bci + 3, data);
      break;
    case Bytecodes::_goto:
      (*jmpFct)(this, bcs->dest(), data);
      break;
    case Bytecodes::_goto_w:
      (*jmpFct)(this, bcs->dest_w(), data);
      break;
    case Bytecodes::_tableswitch:
      { Bytecode_tableswitch tableswitch(method(), bcs->bcp());
        int len = tableswitch.length();
        (*jmpFct)(this, bci + tableswitch.default_offset(), data); /* Default. jump address */
        while (--len >= 0) {
          (*jmpFct)(this, bci + tableswitch.dest_offset_at(len), data);
        }
        break;
      }
    case Bytecodes::_lookupswitch:
      { Bytecode_lookupswitch lookupswitch(method(), bcs->bcp());
        int npairs = lookupswitch.number_of_pairs();
        (*jmpFct)(this, bci + lookupswitch.default_offset(), data); /* Default. */
        while(--npairs >= 0) {
          LookupswitchPair pair = lookupswitch.pair_at(npairs);
          (*jmpFct)(this, bci + pair.offset(), data);
        }
        break;
      }
    case Bytecodes::_jsr:
      assert(bcs->is_wide()==false, "sanity check");
      (*jmpFct)(this, bcs->dest(), data);
      break;
    case Bytecodes::_jsr_w:
      (*jmpFct)(this, bcs->dest_w(), data);
      break;
    case Bytecodes::_wide:
      ShouldNotReachHere();
      return true;
      break;
    case Bytecodes::_athrow:
    case Bytecodes::_ireturn:
    case Bytecodes::_lreturn:
    case Bytecodes::_freturn:
    case Bytecodes::_dreturn:
    case Bytecodes::_areturn:
    case Bytecodes::_return:
    case Bytecodes::_ret:
      break;
    default:
      return true;
  }
  return false;
}
   block. */
BasicBlock *GenerateOopMap::get_basic_block_at(int bci) const {
  BasicBlock* bb = get_basic_block_containing(bci);
  assert(bb->_bci == bci, "should have found BB");
  return bb;
}
BasicBlock  *GenerateOopMap::get_basic_block_containing(int bci) const {
  BasicBlock *bbs = _basic_blocks;
  int lo = 0, hi = _bb_count - 1;
  while (lo <= hi) {
    int m = (lo + hi) / 2;
    int mbci = bbs[m]._bci;
    int nbci;
    if ( m == _bb_count-1) {
      assert( bci >= mbci && bci < method()->code_size(), "sanity check failed");
      return bbs+m;
    } else {
      nbci = bbs[m+1]._bci;
    }
    if ( mbci <= bci && bci < nbci) {
      return bbs+m;
    } else if (mbci < bci) {
      lo = m + 1;
    } else {
      assert(mbci > bci, "sanity check");
      hi = m - 1;
    }
  }
  fatal("should have found BB");
  return NULL;
}
void GenerateOopMap::restore_state(BasicBlock *bb)
{
  memcpy(_state, bb->_state, _state_len*sizeof(CellTypeState));
  _stack_top = bb->_stack_top;
  _monitor_top = bb->_monitor_top;
}
int GenerateOopMap::next_bb_start_pc(BasicBlock *bb) {
 int bbNum = bb - _basic_blocks + 1;
 if (bbNum == _bb_count)
    return method()->code_size();
 return _basic_blocks[bbNum]._bci;
}
#define ALLOC_RESOURCE_ARRAY(var, type, count) \
  var = NEW_RESOURCE_ARRAY_RETURN_NULL(type, count);              \
  if (var == NULL) {                                              \
    report_error("Cannot reserve enough memory to analyze this method"); \
    return;                                                       \
  }
void GenerateOopMap::init_state() {
  _state_len     = _max_locals + _max_stack + _max_monitors;
  ALLOC_RESOURCE_ARRAY(_state, CellTypeState, _state_len);
  memset(_state, 0, _state_len * sizeof(CellTypeState));
  int count = MAX3(_max_locals, _max_stack, _max_monitors) + 1/*for null terminator char */;
  ALLOC_RESOURCE_ARRAY(_state_vec_buf, char, count);
}
void GenerateOopMap::make_context_uninitialized() {
  CellTypeState* vs = vars();
  for (int i = 0; i < _max_locals; i++)
      vs[i] = CellTypeState::uninit;
  _stack_top = 0;
  _monitor_top = 0;
}
int GenerateOopMap::methodsig_to_effect(Symbol* signature, bool is_static, CellTypeState* effect) {
  ComputeEntryStack ces(signature);
  return ces.compute_for_parameters(is_static, effect);
}
CellTypeState CellTypeState::merge(CellTypeState cts, int slot) const {
  CellTypeState result;
  assert(!is_bottom() && !cts.is_bottom(),
         "merge of bottom values is handled elsewhere");
  result._state = _state | cts._state;
  if (!result.is_info_top()) {
    assert((result.can_be_address() || result.can_be_reference()),
           "only addresses and references have non-top info");
    if (!equal(cts)) {
      if (result.is_reference()) {
        result = CellTypeState::make_slot_ref(slot);
      } else {
        result._state |= info_conflict;
      }
    }
  }
  assert(result.is_valid_state(), "checking that CTS merge maintains legal state");
  return result;
}
bool GenerateOopMap::merge_local_state_vectors(CellTypeState* cts,
                                               CellTypeState* bbts) {
  int i;
  int len = _max_locals + _stack_top;
  bool change = false;
  for (i = len - 1; i >= 0; i--) {
    CellTypeState v = cts[i].merge(bbts[i], i);
    change = change || !v.equal(bbts[i]);
    bbts[i] = v;
  }
  return change;
}
bool GenerateOopMap::merge_monitor_state_vectors(CellTypeState* cts,
                                                 CellTypeState* bbts) {
  bool change = false;
  if (_max_monitors > 0 && _monitor_top != bad_monitors) {
    int base = _max_locals + _max_stack;
    int len = base + _monitor_top;
    for (int i = len - 1; i >= base; i--) {
      CellTypeState v = cts[i].merge(bbts[i], i);
      change = change || !v.equal(bbts[i]);
      bbts[i] = v;
    }
  }
  return change;
}
void GenerateOopMap::copy_state(CellTypeState *dst, CellTypeState *src) {
  int len = _max_locals + _stack_top;
  for (int i = 0; i < len; i++) {
    if (src[i].is_nonlock_reference()) {
      dst[i] = CellTypeState::make_slot_ref(i);
    } else {
      dst[i] = src[i];
    }
  }
  if (_max_monitors > 0 && _monitor_top != bad_monitors) {
    int base = _max_locals + _max_stack;
    len = base + _monitor_top;
    for (int i = base; i < len; i++) {
      dst[i] = src[i];
    }
  }
}
void GenerateOopMap::merge_state_into_bb(BasicBlock *bb) {
  guarantee(bb != NULL, "null basicblock");
  assert(bb->is_alive(), "merging state into a dead basicblock");
  if (_stack_top == bb->_stack_top) {
    if (merge_local_state_vectors(_state, bb->_state)) {
      bb->set_changed(true);
    }
    if (_monitor_top == bb->_monitor_top) {
      if (merge_monitor_state_vectors(_state, bb->_state)) {
        bb->set_changed(true);
      }
    } else {
      if (TraceMonitorMismatch) {
        report_monitor_mismatch("monitor stack height merge conflict");
      }
      bb->_monitor_top = bad_monitors;
      bb->set_changed(true);
      _monitor_safe = false;
    }
  } else if (!bb->is_reachable()) {
    copy_state(bb->_state, _state);
    bb->_stack_top = _stack_top;
    bb->_monitor_top = _monitor_top;
    bb->set_changed(true);
  } else {
    verify_error("stack height conflict: %d vs. %d",  _stack_top, bb->_stack_top);
  }
}
void GenerateOopMap::merge_state(GenerateOopMap *gom, int bci, int* data) {
   gom->merge_state_into_bb(gom->get_basic_block_at(bci));
}
void GenerateOopMap::set_var(int localNo, CellTypeState cts) {
  assert(cts.is_reference() || cts.is_value() || cts.is_address(),
         "wrong celltypestate");
  if (localNo < 0 || localNo > _max_locals) {
    verify_error("variable write error: r%d", localNo);
    return;
  }
  vars()[localNo] = cts;
}
CellTypeState GenerateOopMap::get_var(int localNo) {
  assert(localNo < _max_locals + _nof_refval_conflicts, "variable read error");
  if (localNo < 0 || localNo > _max_locals) {
    verify_error("variable read error: r%d", localNo);
    return valCTS; // just to pick something;
  }
  return vars()[localNo];
}
CellTypeState GenerateOopMap::pop() {
  if ( _stack_top <= 0) {
    verify_error("stack underflow");
    return valCTS; // just to pick something
  }
  return  stack()[--_stack_top];
}
void GenerateOopMap::push(CellTypeState cts) {
  if ( _stack_top >= _max_stack) {
    verify_error("stack overflow");
    return;
  }
  stack()[_stack_top++] = cts;
}
CellTypeState GenerateOopMap::monitor_pop() {
  assert(_monitor_top != bad_monitors, "monitor_pop called on error monitor stack");
  if (_monitor_top == 0) {
    _monitor_safe = false;
     _monitor_top = bad_monitors;
    if (TraceMonitorMismatch) {
      report_monitor_mismatch("monitor stack underflow");
    }
    return CellTypeState::ref; // just to keep the analysis going.
  }
  return  monitors()[--_monitor_top];
}
void GenerateOopMap::monitor_push(CellTypeState cts) {
  assert(_monitor_top != bad_monitors, "monitor_push called on error monitor stack");
  if (_monitor_top >= _max_monitors) {
    _monitor_safe = false;
    _monitor_top = bad_monitors;
    if (TraceMonitorMismatch) {
      report_monitor_mismatch("monitor stack overflow");
    }
    return;
  }
  monitors()[_monitor_top++] = cts;
}
void GenerateOopMap::do_interpretation()
{
  int i = 0;
  do {
#ifndef PRODUCT
    if (TraceNewOopMapGeneration) {
      tty->print("\n\nIteration #%d of do_interpretation loop, method:\n", i);
      method()->print_name(tty);
      tty->print("\n\n");
    }
#endif
    _conflict = false;
    _monitor_safe = true;
    if (!_got_error) init_basic_blocks();
    if (!_got_error) setup_method_entry_state();
    if (!_got_error) interp_all();
    if (!_got_error) rewrite_refval_conflicts();
    i++;
  } while (_conflict && !_got_error);
}
void GenerateOopMap::init_basic_blocks() {
  ALLOC_RESOURCE_ARRAY(_basic_blocks, BasicBlock, _bb_count);
  BytecodeStream j(_method);
  Bytecodes::Code bytecode;
  int bbNo = 0;
  int monitor_count = 0;
  int prev_bci = -1;
  while( (bytecode = j.next()) >= 0) {
    if (j.code() == Bytecodes::_monitorenter) {
      monitor_count++;
    }
    int bci = j.bci();
    if (is_bb_header(bci)) {
      BasicBlock *bb   = _basic_blocks + bbNo;
      bb->_bci         = bci;
      bb->_max_locals  = _max_locals;
      bb->_max_stack   = _max_stack;
      bb->set_changed(false);
      bb->_stack_top   = BasicBlock::_dead_basic_block; // Initialize all basicblocks are dead.
      bb->_monitor_top = bad_monitors;
      if (bbNo > 0) {
        _basic_blocks[bbNo - 1]._end_bci = prev_bci;
      }
      bbNo++;
    }
    prev_bci = bci;
  }
  _basic_blocks[bbNo-1]._end_bci = prev_bci;
  if (bbNo !=_bb_count) {
    if (bbNo < _bb_count) {
      verify_error("jump into the middle of instruction?");
      return;
    } else {
      verify_error("extra basic blocks - should not happen?");
      return;
    }
  }
  _max_monitors = monitor_count;
  init_state();
  if ((unsigned)bbNo > UINTPTR_MAX / sizeof(CellTypeState) / _state_len) {
    report_error("The amount of memory required to analyze this method "
                 "exceeds addressable range");
    return;
  }
  CellTypeState *basicBlockState;
  ALLOC_RESOURCE_ARRAY(basicBlockState, CellTypeState, bbNo * _state_len);
  memset(basicBlockState, 0, bbNo * _state_len * sizeof(CellTypeState));
  for (int blockNum=0; blockNum < bbNo; blockNum++) {
    BasicBlock *bb = _basic_blocks + blockNum;
    bb->_state = basicBlockState + blockNum * _state_len;
#ifdef ASSERT
    if (blockNum + 1 < bbNo) {
      address bcp = _method->bcp_from(bb->_end_bci);
      int bc_len = Bytecodes::java_length_at(_method(), bcp);
      assert(bb->_end_bci + bc_len == bb[1]._bci, "unmatched bci info in basicblock");
    }
#endif
  }
#ifdef ASSERT
  { BasicBlock *bb = &_basic_blocks[bbNo-1];
    address bcp = _method->bcp_from(bb->_end_bci);
    int bc_len = Bytecodes::java_length_at(_method(), bcp);
    assert(bb->_end_bci + bc_len == _method->code_size(), "wrong end bci");
  }
#endif
  mark_reachable_code();
}
void GenerateOopMap::setup_method_entry_state() {
    make_context_uninitialized();
    methodsig_to_effect(method()->signature(), method()->is_static(), vars());
    initialize_vars();
    merge_state_into_bb(&_basic_blocks[0]);
    assert(_basic_blocks[0].changed(), "we are not getting off the ground");
}
void GenerateOopMap::update_basic_blocks(int bci, int delta,
                                         int new_method_size) {
  assert(new_method_size >= method()->code_size() + delta,
         "new method size is too small");
  BitMap::bm_word_t* new_bb_hdr_bits =
    NEW_RESOURCE_ARRAY(BitMap::bm_word_t,
                       BitMap::word_align_up(new_method_size));
  _bb_hdr_bits.set_map(new_bb_hdr_bits);
  _bb_hdr_bits.set_size(new_method_size);
  _bb_hdr_bits.clear();
  for(int k = 0; k < _bb_count; k++) {
    if (_basic_blocks[k]._bci > bci) {
      _basic_blocks[k]._bci     += delta;
      _basic_blocks[k]._end_bci += delta;
    }
    _bb_hdr_bits.at_put(_basic_blocks[k]._bci, true);
  }
}
void GenerateOopMap::initialize_vars() {
  for (int k = 0; k < _init_vars->length(); k++)
    _state[_init_vars->at(k)] = CellTypeState::make_slot_ref(k);
}
void GenerateOopMap::add_to_ref_init_set(int localNo) {
  if (TraceNewOopMapGeneration)
    tty->print_cr("Added init vars: %d", localNo);
  if (_init_vars->contains(localNo) )
    return;
   _init_vars->append(localNo);
}
void GenerateOopMap::interp_all() {
  bool change = true;
  while (change && !_got_error) {
    change = false;
    for (int i = 0; i < _bb_count && !_got_error; i++) {
      BasicBlock *bb = &_basic_blocks[i];
      if (bb->changed()) {
         if (_got_error) return;
         change = true;
         bb->set_changed(false);
         interp_bb(bb);
      }
    }
  }
}
void GenerateOopMap::interp_bb(BasicBlock *bb) {
  assert(bb->is_reachable(), "should be reachable or deadcode exist");
  restore_state(bb);
  BytecodeStream itr(_method);
  int lim_bci = next_bb_start_pc(bb);
  itr.set_interval(bb->_bci, lim_bci);
  assert(lim_bci != bb->_bci, "must be at least one instruction in a basicblock");
  itr.next(); // read first instruction
  while(itr.next_bci() < lim_bci && !_got_error) {
    if (_has_exceptions || _monitor_top != 0) {
      do_exception_edge(&itr);
    }
    interp1(&itr);
    itr.next();
  }
  if (!_got_error) {
    assert(itr.next_bci() == lim_bci, "must point to end");
    if (_has_exceptions || _monitor_top != 0) {
      do_exception_edge(&itr);
    }
    interp1(&itr);
    bool fall_through = jump_targets_do(&itr, GenerateOopMap::merge_state, NULL);
    if (_got_error)  return;
    if (itr.code() == Bytecodes::_ret) {
      assert(!fall_through, "cannot be set if ret instruction");
      ret_jump_targets_do(&itr, GenerateOopMap::merge_state, itr.get_index(), NULL);
    } else if (fall_through) {
     if (lim_bci != bb[1]._bci) {
       verify_error("bytecodes fell through last instruction");
       return;
     }
     merge_state_into_bb(bb + 1);
    }
  }
}
void GenerateOopMap::do_exception_edge(BytecodeStream* itr) {
  if (!Bytecodes::can_trap(itr->code())) return;
  switch (itr->code()) {
    case Bytecodes::_aload_0:
      return;
    case Bytecodes::_ireturn:
    case Bytecodes::_lreturn:
    case Bytecodes::_freturn:
    case Bytecodes::_dreturn:
    case Bytecodes::_areturn:
    case Bytecodes::_return:
      if (_monitor_top == 0) {
        return;
      }
      break;
    case Bytecodes::_monitorexit:
      if (_monitor_top != bad_monitors && _monitor_top != 0) {
        return;
      }
      break;
  }
  if (_has_exceptions) {
    int bci = itr->bci();
    ExceptionTable exct(method());
    for(int i = 0; i< exct.length(); i++) {
      int start_pc   = exct.start_pc(i);
      int end_pc     = exct.end_pc(i);
      int handler_pc = exct.handler_pc(i);
      int catch_type = exct.catch_type_index(i);
      if (start_pc <= bci && bci < end_pc) {
        BasicBlock *excBB = get_basic_block_at(handler_pc);
        guarantee(excBB != NULL, "no basic block for exception");
        CellTypeState *excStk = excBB->stack();
        CellTypeState *cOpStck = stack();
        CellTypeState cOpStck_0 = cOpStck[0];
        int cOpStackTop = _stack_top;
        assert(method()->max_stack() > 0, "sanity check");
        cOpStck[0] = CellTypeState::make_slot_ref(_max_locals);
        _stack_top = 1;
        merge_state_into_bb(excBB);
        cOpStck[0] = cOpStck_0;
        _stack_top = cOpStackTop;
        if (catch_type == 0) {
          return;
        }
      }
    }
  }
  if (_monitor_top == 0) {
    return;
  }
  if (TraceMonitorMismatch && _monitor_safe) {
    report_monitor_mismatch("non-empty monitor stack at exceptional exit");
  }
  _monitor_safe = false;
}
void GenerateOopMap::report_monitor_mismatch(const char *msg) {
#ifndef PRODUCT
  tty->print("    Monitor mismatch in method ");
  method()->print_short_name(tty);
  tty->print_cr(": %s", msg);
#endif
}
void GenerateOopMap::print_states(outputStream *os,
                                  CellTypeState* vec, int num) {
  for (int i = 0; i < num; i++) {
    vec[i].print(tty);
  }
}
void GenerateOopMap::print_current_state(outputStream   *os,
                                         BytecodeStream *currentBC,
                                         bool            detailed) {
  if (detailed) {
    os->print("     %4d vars     = ", currentBC->bci());
    print_states(os, vars(), _max_locals);
    os->print("    %s", Bytecodes::name(currentBC->code()));
    switch(currentBC->code()) {
      case Bytecodes::_invokevirtual:
      case Bytecodes::_invokespecial:
      case Bytecodes::_invokestatic:
      case Bytecodes::_invokedynamic:
      case Bytecodes::_invokeinterface:
        int idx = currentBC->has_index_u4() ? currentBC->get_index_u4() : currentBC->get_index_u2_cpcache();
        ConstantPool* cp      = method()->constants();
        int nameAndTypeIdx    = cp->name_and_type_ref_index_at(idx);
        int signatureIdx      = cp->signature_ref_index_at(nameAndTypeIdx);
        Symbol* signature     = cp->symbol_at(signatureIdx);
        os->print("%s", signature->as_C_string());
    }
    os->cr();
    os->print("          stack    = ");
    print_states(os, stack(), _stack_top);
    os->cr();
    if (_monitor_top != bad_monitors) {
      os->print("          monitors = ");
      print_states(os, monitors(), _monitor_top);
    } else {
      os->print("          [bad monitor stack]");
    }
    os->cr();
  } else {
    os->print("    %4d  vars = '%s' ", currentBC->bci(),  state_vec_to_string(vars(), _max_locals));
    os->print("     stack = '%s' ", state_vec_to_string(stack(), _stack_top));
    if (_monitor_top != bad_monitors) {
      os->print("  monitors = '%s'  \t%s", state_vec_to_string(monitors(), _monitor_top), Bytecodes::name(currentBC->code()));
    } else {
      os->print("  [bad monitor stack]");
    }
    switch(currentBC->code()) {
      case Bytecodes::_invokevirtual:
      case Bytecodes::_invokespecial:
      case Bytecodes::_invokestatic:
      case Bytecodes::_invokedynamic:
      case Bytecodes::_invokeinterface:
        int idx = currentBC->has_index_u4() ? currentBC->get_index_u4() : currentBC->get_index_u2_cpcache();
        ConstantPool* cp      = method()->constants();
        int nameAndTypeIdx    = cp->name_and_type_ref_index_at(idx);
        int signatureIdx      = cp->signature_ref_index_at(nameAndTypeIdx);
        Symbol* signature     = cp->symbol_at(signatureIdx);
        os->print("%s", signature->as_C_string());
    }
    os->cr();
  }
}
void GenerateOopMap::interp1(BytecodeStream *itr) {
  if (TraceNewOopMapGeneration) {
    print_current_state(tty, itr, TraceNewOopMapGenerationDetailed);
  }
  if (_report_result == true) {
    switch(itr->code()) {
      case Bytecodes::_invokevirtual:
      case Bytecodes::_invokespecial:
      case Bytecodes::_invokestatic:
      case Bytecodes::_invokedynamic:
      case Bytecodes::_invokeinterface:
        _itr_send = itr;
        _report_result_for_send = true;
        break;
      default:
       fill_stackmap_for_opcodes(itr, vars(), stack(), _stack_top);
       break;
    }
  }
  switch(itr->code()) {
    case Bytecodes::_nop:                                           break;
    case Bytecodes::_goto:                                          break;
    case Bytecodes::_goto_w:                                        break;
    case Bytecodes::_iinc:                                          break;
    case Bytecodes::_return:            do_return_monitor_check();
                                        break;
    case Bytecodes::_aconst_null:
    case Bytecodes::_new:               ppush1(CellTypeState::make_line_ref(itr->bci()));
                                        break;
    case Bytecodes::_iconst_m1:
    case Bytecodes::_iconst_0:
    case Bytecodes::_iconst_1:
    case Bytecodes::_iconst_2:
    case Bytecodes::_iconst_3:
    case Bytecodes::_iconst_4:
    case Bytecodes::_iconst_5:
    case Bytecodes::_fconst_0:
    case Bytecodes::_fconst_1:
    case Bytecodes::_fconst_2:
    case Bytecodes::_bipush:
    case Bytecodes::_sipush:            ppush1(valCTS);             break;
    case Bytecodes::_lconst_0:
    case Bytecodes::_lconst_1:
    case Bytecodes::_dconst_0:
    case Bytecodes::_dconst_1:          ppush(vvCTS);               break;
    case Bytecodes::_ldc2_w:            ppush(vvCTS);               break;
    case Bytecodes::_ldc:               // fall through:
    case Bytecodes::_ldc_w:             do_ldc(itr->bci());         break;
    case Bytecodes::_iload:
    case Bytecodes::_fload:             ppload(vCTS, itr->get_index()); break;
    case Bytecodes::_lload:
    case Bytecodes::_dload:             ppload(vvCTS,itr->get_index()); break;
    case Bytecodes::_aload:             ppload(rCTS, itr->get_index()); break;
    case Bytecodes::_iload_0:
    case Bytecodes::_fload_0:           ppload(vCTS, 0);            break;
    case Bytecodes::_iload_1:
    case Bytecodes::_fload_1:           ppload(vCTS, 1);            break;
    case Bytecodes::_iload_2:
    case Bytecodes::_fload_2:           ppload(vCTS, 2);            break;
    case Bytecodes::_iload_3:
    case Bytecodes::_fload_3:           ppload(vCTS, 3);            break;
    case Bytecodes::_lload_0:
    case Bytecodes::_dload_0:           ppload(vvCTS, 0);           break;
    case Bytecodes::_lload_1:
    case Bytecodes::_dload_1:           ppload(vvCTS, 1);           break;
    case Bytecodes::_lload_2:
    case Bytecodes::_dload_2:           ppload(vvCTS, 2);           break;
    case Bytecodes::_lload_3:
    case Bytecodes::_dload_3:           ppload(vvCTS, 3);           break;
    case Bytecodes::_aload_0:           ppload(rCTS, 0);            break;
    case Bytecodes::_aload_1:           ppload(rCTS, 1);            break;
    case Bytecodes::_aload_2:           ppload(rCTS, 2);            break;
    case Bytecodes::_aload_3:           ppload(rCTS, 3);            break;
    case Bytecodes::_iaload:
    case Bytecodes::_faload:
    case Bytecodes::_baload:
    case Bytecodes::_caload:
    case Bytecodes::_saload:            pp(vrCTS, vCTS); break;
    case Bytecodes::_laload:            pp(vrCTS, vvCTS);  break;
    case Bytecodes::_daload:            pp(vrCTS, vvCTS); break;
    case Bytecodes::_aaload:            pp_new_ref(vrCTS, itr->bci()); break;
    case Bytecodes::_istore:
    case Bytecodes::_fstore:            ppstore(vCTS, itr->get_index()); break;
    case Bytecodes::_lstore:
    case Bytecodes::_dstore:            ppstore(vvCTS, itr->get_index()); break;
    case Bytecodes::_astore:            do_astore(itr->get_index());     break;
    case Bytecodes::_istore_0:
    case Bytecodes::_fstore_0:          ppstore(vCTS, 0);           break;
    case Bytecodes::_istore_1:
    case Bytecodes::_fstore_1:          ppstore(vCTS, 1);           break;
    case Bytecodes::_istore_2:
    case Bytecodes::_fstore_2:          ppstore(vCTS, 2);           break;
    case Bytecodes::_istore_3:
    case Bytecodes::_fstore_3:          ppstore(vCTS, 3);           break;
    case Bytecodes::_lstore_0:
    case Bytecodes::_dstore_0:          ppstore(vvCTS, 0);          break;
    case Bytecodes::_lstore_1:
    case Bytecodes::_dstore_1:          ppstore(vvCTS, 1);          break;
    case Bytecodes::_lstore_2:
    case Bytecodes::_dstore_2:          ppstore(vvCTS, 2);          break;
    case Bytecodes::_lstore_3:
    case Bytecodes::_dstore_3:          ppstore(vvCTS, 3);          break;
    case Bytecodes::_astore_0:          do_astore(0);               break;
    case Bytecodes::_astore_1:          do_astore(1);               break;
    case Bytecodes::_astore_2:          do_astore(2);               break;
    case Bytecodes::_astore_3:          do_astore(3);               break;
    case Bytecodes::_iastore:
    case Bytecodes::_fastore:
    case Bytecodes::_bastore:
    case Bytecodes::_castore:
    case Bytecodes::_sastore:           ppop(vvrCTS);               break;
    case Bytecodes::_lastore:
    case Bytecodes::_dastore:           ppop(vvvrCTS);              break;
    case Bytecodes::_aastore:           ppop(rvrCTS);               break;
    case Bytecodes::_pop:               ppop_any(1);                break;
    case Bytecodes::_pop2:              ppop_any(2);                break;
    case Bytecodes::_dup:               ppdupswap(1, "11");         break;
    case Bytecodes::_dup_x1:            ppdupswap(2, "121");        break;
    case Bytecodes::_dup_x2:            ppdupswap(3, "1321");       break;
    case Bytecodes::_dup2:              ppdupswap(2, "2121");       break;
    case Bytecodes::_dup2_x1:           ppdupswap(3, "21321");      break;
    case Bytecodes::_dup2_x2:           ppdupswap(4, "214321");     break;
    case Bytecodes::_swap:              ppdupswap(2, "12");         break;
    case Bytecodes::_iadd:
    case Bytecodes::_fadd:
    case Bytecodes::_isub:
    case Bytecodes::_fsub:
    case Bytecodes::_imul:
    case Bytecodes::_fmul:
    case Bytecodes::_idiv:
    case Bytecodes::_fdiv:
    case Bytecodes::_irem:
    case Bytecodes::_frem:
    case Bytecodes::_ishl:
    case Bytecodes::_ishr:
    case Bytecodes::_iushr:
    case Bytecodes::_iand:
    case Bytecodes::_ior:
    case Bytecodes::_ixor:
    case Bytecodes::_l2f:
    case Bytecodes::_l2i:
    case Bytecodes::_d2f:
    case Bytecodes::_d2i:
    case Bytecodes::_fcmpl:
    case Bytecodes::_fcmpg:             pp(vvCTS, vCTS); break;
    case Bytecodes::_ladd:
    case Bytecodes::_dadd:
    case Bytecodes::_lsub:
    case Bytecodes::_dsub:
    case Bytecodes::_lmul:
    case Bytecodes::_dmul:
    case Bytecodes::_ldiv:
    case Bytecodes::_ddiv:
    case Bytecodes::_lrem:
    case Bytecodes::_drem:
    case Bytecodes::_land:
    case Bytecodes::_lor:
    case Bytecodes::_lxor:              pp(vvvvCTS, vvCTS); break;
    case Bytecodes::_ineg:
    case Bytecodes::_fneg:
    case Bytecodes::_i2f:
    case Bytecodes::_f2i:
    case Bytecodes::_i2c:
    case Bytecodes::_i2s:
    case Bytecodes::_i2b:               pp(vCTS, vCTS); break;
    case Bytecodes::_lneg:
    case Bytecodes::_dneg:
    case Bytecodes::_l2d:
    case Bytecodes::_d2l:               pp(vvCTS, vvCTS); break;
    case Bytecodes::_lshl:
    case Bytecodes::_lshr:
    case Bytecodes::_lushr:             pp(vvvCTS, vvCTS); break;
    case Bytecodes::_i2l:
    case Bytecodes::_i2d:
    case Bytecodes::_f2l:
    case Bytecodes::_f2d:               pp(vCTS, vvCTS); break;
    case Bytecodes::_lcmp:              pp(vvvvCTS, vCTS); break;
    case Bytecodes::_dcmpl:
    case Bytecodes::_dcmpg:             pp(vvvvCTS, vCTS); break;
    case Bytecodes::_ifeq:
    case Bytecodes::_ifne:
    case Bytecodes::_iflt:
    case Bytecodes::_ifge:
    case Bytecodes::_ifgt:
    case Bytecodes::_ifle:
    case Bytecodes::_tableswitch:       ppop1(valCTS);
                                        break;
    case Bytecodes::_ireturn:
    case Bytecodes::_freturn:           do_return_monitor_check();
                                        ppop1(valCTS);
                                        break;
    case Bytecodes::_if_icmpeq:
    case Bytecodes::_if_icmpne:
    case Bytecodes::_if_icmplt:
    case Bytecodes::_if_icmpge:
    case Bytecodes::_if_icmpgt:
    case Bytecodes::_if_icmple:         ppop(vvCTS);
                                        break;
    case Bytecodes::_lreturn:           do_return_monitor_check();
                                        ppop(vvCTS);
                                        break;
    case Bytecodes::_dreturn:           do_return_monitor_check();
                                        ppop(vvCTS);
                                        break;
    case Bytecodes::_if_acmpeq:
    case Bytecodes::_if_acmpne:         ppop(rrCTS);                 break;
    case Bytecodes::_jsr:               do_jsr(itr->dest());         break;
    case Bytecodes::_jsr_w:             do_jsr(itr->dest_w());       break;
    case Bytecodes::_getstatic:         do_field(true,  true,  itr->get_index_u2_cpcache(), itr->bci()); break;
    case Bytecodes::_putstatic:         do_field(false, true,  itr->get_index_u2_cpcache(), itr->bci()); break;
    case Bytecodes::_getfield:          do_field(true,  false, itr->get_index_u2_cpcache(), itr->bci()); break;
    case Bytecodes::_putfield:          do_field(false, false, itr->get_index_u2_cpcache(), itr->bci()); break;
    case Bytecodes::_invokevirtual:
    case Bytecodes::_invokespecial:     do_method(false, false, itr->get_index_u2_cpcache(), itr->bci()); break;
    case Bytecodes::_invokestatic:      do_method(true,  false, itr->get_index_u2_cpcache(), itr->bci()); break;
    case Bytecodes::_invokedynamic:     do_method(true,  false, itr->get_index_u4(),         itr->bci()); break;
    case Bytecodes::_invokeinterface:   do_method(false, true,  itr->get_index_u2_cpcache(), itr->bci()); break;
    case Bytecodes::_newarray:
    case Bytecodes::_anewarray:         pp_new_ref(vCTS, itr->bci()); break;
    case Bytecodes::_checkcast:         do_checkcast(); break;
    case Bytecodes::_arraylength:
    case Bytecodes::_instanceof:        pp(rCTS, vCTS); break;
    case Bytecodes::_monitorenter:      do_monitorenter(itr->bci()); break;
    case Bytecodes::_monitorexit:       do_monitorexit(itr->bci()); break;
    case Bytecodes::_athrow:            // handled by do_exception_edge() BUT ...
                                        if ((!_has_exceptions) && (_monitor_top > 0)) {
                                          _monitor_safe = false;
                                        }
                                        break;
    case Bytecodes::_areturn:           do_return_monitor_check();
                                        ppop1(refCTS);
                                        break;
    case Bytecodes::_ifnull:
    case Bytecodes::_ifnonnull:         ppop1(refCTS); break;
    case Bytecodes::_multianewarray:    do_multianewarray(*(itr->bcp()+3), itr->bci()); break;
    case Bytecodes::_wide:              fatal("Iterator should skip this bytecode"); break;
    case Bytecodes::_ret:                                           break;
    case Bytecodes::_lookupswitch:      ppop1(valCTS);             break;
    default:
         tty->print("unexpected opcode: %d\n", itr->code());
         ShouldNotReachHere();
    break;
  }
}
void GenerateOopMap::check_type(CellTypeState expected, CellTypeState actual) {
  if (!expected.equal_kind(actual)) {
    verify_error("wrong type on stack (found: %c expected: %c)", actual.to_char(), expected.to_char());
  }
}
void GenerateOopMap::ppstore(CellTypeState *in, int loc_no) {
  while(!(*in).is_bottom()) {
    CellTypeState expected =*in++;
    CellTypeState actual   = pop();
    check_type(expected, actual);
    assert(loc_no >= 0, "sanity check");
    set_var(loc_no++, actual);
  }
}
void GenerateOopMap::ppload(CellTypeState *out, int loc_no) {
  while(!(*out).is_bottom()) {
    CellTypeState out1 = *out++;
    CellTypeState vcts = get_var(loc_no);
    assert(out1.can_be_reference() || out1.can_be_value(),
           "can only load refs. and values.");
    if (out1.is_reference()) {
      assert(loc_no>=0, "sanity check");
      if (!vcts.is_reference()) {
        _conflict = true;
        if (vcts.can_be_uninit()) {
          add_to_ref_init_set(loc_no);
          vcts = out1;
        } else {
          record_refval_conflict(loc_no);
          vcts = out1;
        }
        push(out1); // recover...
      } else {
        push(vcts); // preserve reference.
      }
    } else {
      push(out1); // handle val/init conflict
    }
    loc_no++;
  }
}
void GenerateOopMap::ppdupswap(int poplen, const char *out) {
  CellTypeState actual[5];
  assert(poplen < 5, "this must be less than length of actual vector");
  for(int i = 0; i < poplen; i++) actual[i] = pop();
  char push_ch = *out++;
  while (push_ch != '\0') {
    int idx = push_ch - '1';
    assert(idx >= 0 && idx < poplen, "wrong arguments");
    push(actual[idx]);
    push_ch = *out++;
  }
}
void GenerateOopMap::ppop1(CellTypeState out) {
  CellTypeState actual = pop();
  check_type(out, actual);
}
void GenerateOopMap::ppop(CellTypeState *out) {
  while (!(*out).is_bottom()) {
    ppop1(*out++);
  }
}
void GenerateOopMap::ppush1(CellTypeState in) {
  assert(in.is_reference() | in.is_value(), "sanity check");
  push(in);
}
void GenerateOopMap::ppush(CellTypeState *in) {
  while (!(*in).is_bottom()) {
    ppush1(*in++);
  }
}
void GenerateOopMap::pp(CellTypeState *in, CellTypeState *out) {
  ppop(in);
  ppush(out);
}
void GenerateOopMap::pp_new_ref(CellTypeState *in, int bci) {
  ppop(in);
  ppush1(CellTypeState::make_line_ref(bci));
}
void GenerateOopMap::ppop_any(int poplen) {
  if (_stack_top >= poplen) {
    _stack_top -= poplen;
  } else {
    verify_error("stack underflow");
  }
}
void GenerateOopMap::replace_all_CTS_matches(CellTypeState match,
                                             CellTypeState replace) {
  int i;
  int len = _max_locals + _stack_top;
  bool change = false;
  for (i = len - 1; i >= 0; i--) {
    if (match.equal(_state[i])) {
      _state[i] = replace;
    }
  }
  if (_monitor_top > 0) {
    int base = _max_locals + _max_stack;
    len = base + _monitor_top;
    for (i = len - 1; i >= base; i--) {
      if (match.equal(_state[i])) {
        _state[i] = replace;
      }
    }
  }
}
void GenerateOopMap::do_checkcast() {
  CellTypeState actual = pop();
  check_type(refCTS, actual);
  push(actual);
}
void GenerateOopMap::do_monitorenter(int bci) {
  CellTypeState actual = pop();
  if (_monitor_top == bad_monitors) {
    return;
  }
  if (actual.is_lock_reference()) {
    _monitor_top = bad_monitors;
    _monitor_safe = false;
    if (TraceMonitorMismatch) {
      report_monitor_mismatch("nested redundant lock -- bailout...");
    }
    return;
  }
  CellTypeState lock = CellTypeState::make_lock_ref(bci);
  check_type(refCTS, actual);
  if (!actual.is_info_top()) {
    replace_all_CTS_matches(actual, lock);
    monitor_push(lock);
  }
}
void GenerateOopMap::do_monitorexit(int bci) {
  CellTypeState actual = pop();
  if (_monitor_top == bad_monitors) {
    return;
  }
  check_type(refCTS, actual);
  CellTypeState expected = monitor_pop();
  if (!actual.is_lock_reference() || !expected.equal(actual)) {
    _monitor_top = bad_monitors;
    _monitor_safe = false;
    BasicBlock* bb = get_basic_block_containing(bci);
    guarantee(bb != NULL, "no basic block for bci");
    bb->set_changed(true);
    bb->_monitor_top = bad_monitors;
    if (TraceMonitorMismatch) {
      report_monitor_mismatch("improper monitor pair");
    }
  } else {
    replace_all_CTS_matches(actual, CellTypeState::make_line_ref(bci));
  }
}
void GenerateOopMap::do_return_monitor_check() {
  if (_monitor_top > 0) {
    _monitor_safe = false;
    if (TraceMonitorMismatch) {
      report_monitor_mismatch("non-empty monitor stack at return");
    }
  }
}
void GenerateOopMap::do_jsr(int targ_bci) {
  push(CellTypeState::make_addr(targ_bci));
}
void GenerateOopMap::do_ldc(int bci) {
  Bytecode_loadconstant ldc(method(), bci);
  ConstantPool* cp  = method()->constants();
  constantTag tag = cp->tag_at(ldc.pool_index()); // idx is index in resolved_references
  BasicType       bt  = ldc.result_type();
  CellTypeState   cts;
  if (tag.basic_type() == T_OBJECT) {
    assert(!tag.is_string_index() && !tag.is_klass_index(), "Unexpected index tag");
    assert(bt == T_OBJECT, "Guard is incorrect");
    cts = CellTypeState::make_line_ref(bci);
  } else {
    assert(bt != T_OBJECT, "Guard is incorrect");
    cts = valCTS;
  }
  ppush1(cts);
}
void GenerateOopMap::do_multianewarray(int dims, int bci) {
  assert(dims >= 1, "sanity check");
  for(int i = dims -1; i >=0; i--) {
    ppop1(valCTS);
  }
  ppush1(CellTypeState::make_line_ref(bci));
}
void GenerateOopMap::do_astore(int idx) {
  CellTypeState r_or_p = pop();
  if (!r_or_p.is_address() && !r_or_p.is_reference()) {
    verify_error("wrong type on stack (found: %c, expected: {pr})", r_or_p.to_char());
    return;
  }
  set_var(idx, r_or_p);
}
int GenerateOopMap::copy_cts(CellTypeState *dst, CellTypeState *src) {
  int idx = 0;
  while (!src[idx].is_bottom()) {
    dst[idx] = src[idx];
    idx++;
  }
  return idx;
}
void GenerateOopMap::do_field(int is_get, int is_static, int idx, int bci) {
  ConstantPool* cp     = method()->constants();
  int nameAndTypeIdx     = cp->name_and_type_ref_index_at(idx);
  int signatureIdx       = cp->signature_ref_index_at(nameAndTypeIdx);
  Symbol* signature      = cp->symbol_at(signatureIdx);
  assert(signature->utf8_length() > 0, "field signatures cannot have zero length");
  char sigch = (char)*(signature->base());
  CellTypeState temp[4];
  CellTypeState *eff  = sigchar_to_effect(sigch, bci, temp);
  CellTypeState in[4];
  CellTypeState *out;
  int i =  0;
  if (is_get) {
    out = eff;
  } else {
    out = epsilonCTS;
    i   = copy_cts(in, eff);
  }
  if (!is_static) in[i++] = CellTypeState::ref;
  in[i] = CellTypeState::bottom;
  assert(i<=3, "sanity check");
  pp(in, out);
}
void GenerateOopMap::do_method(int is_static, int is_interface, int idx, int bci) {
  ConstantPool* cp  = _method->constants();
  Symbol* signature   = cp->signature_ref_at(idx);
  CellTypeState out[4];
  CellTypeState in[MAXARGSIZE+1];   // Includes result
  ComputeCallStack cse(signature);
  int res_length=  cse.compute_for_returntype(out);
  if (out[0].equal(CellTypeState::ref) && out[1].equal(CellTypeState::bottom)) {
    out[0] = CellTypeState::make_line_ref(bci);
  }
  assert(res_length<=4, "max value should be vv");
  int arg_length = cse.compute_for_parameters(is_static != 0, in);
  assert(arg_length<=MAXARGSIZE, "too many locals");
  for (int i = arg_length - 1; i >= 0; i--) ppop1(in[i]);// Do args in reverse order.
  if (_report_result_for_send == true) {
     fill_stackmap_for_opcodes(_itr_send, vars(), stack(), _stack_top);
     _report_result_for_send = false;
  }
  ppush(out);
}
CellTypeState *GenerateOopMap::sigchar_to_effect(char sigch, int bci, CellTypeState *out) {
  if (sigch=='L' || sigch=='[') {
    out[0] = CellTypeState::make_line_ref(bci);
    out[1] = CellTypeState::bottom;
    return out;
  }
  if (sigch == 'J' || sigch == 'D' ) return vvCTS;  // Long and Double
  if (sigch == 'V' ) return epsilonCTS;             // Void
  return vCTS;                                      // Otherwise
}
long GenerateOopMap::_total_byte_count = 0;
elapsedTimer GenerateOopMap::_total_oopmap_time;
void GenerateOopMap::ret_jump_targets_do(BytecodeStream *bcs, jmpFct_t jmpFct, int varNo, int *data) {
  CellTypeState ra = vars()[varNo];
  if (!ra.is_good_address()) {
    verify_error("ret returns from two jsr subroutines?");
    return;
  }
  int target = ra.get_info();
  RetTableEntry* rtEnt = _rt.find_jsrs_for_target(target);
  int bci = bcs->bci();
  for (int i = 0; i < rtEnt->nof_jsrs(); i++) {
    int target_bci = rtEnt->jsrs(i);
    BasicBlock* jsr_bb    = get_basic_block_containing(target_bci - 1);
    debug_only(BasicBlock* target_bb = &jsr_bb[1];)
    assert(target_bb  == get_basic_block_at(target_bci), "wrong calc. of successor basicblock");
    bool alive = jsr_bb->is_alive();
    if (TraceNewOopMapGeneration) {
      tty->print("pc = %d, ret -> %d alive: %s\n", bci, target_bci, alive ? "true" : "false");
    }
    if (alive) jmpFct(this, target_bci, data);
  }
}
char* GenerateOopMap::state_vec_to_string(CellTypeState* vec, int len) {
#ifdef ASSERT
  int checklen = MAX3(_max_locals, _max_stack, _max_monitors) + 1;
  assert(len < checklen, "state_vec_buf overflow");
#endif
  for (int i = 0; i < len; i++) _state_vec_buf[i] = vec[i].to_char();
  _state_vec_buf[len] = 0;
  return _state_vec_buf;
}
void GenerateOopMap::print_time() {
  tty->print_cr ("Accumulated oopmap times:");
  tty->print_cr ("---------------------------");
  tty->print_cr ("  Total : %3.3f sec.", GenerateOopMap::_total_oopmap_time.seconds());
  tty->print_cr ("  (%3.0f bytecodes per sec) ",
  GenerateOopMap::_total_byte_count / GenerateOopMap::_total_oopmap_time.seconds());
}
GenerateOopMap::GenerateOopMap(methodHandle method) {
  _method = method;
  _max_locals=0;
  _init_vars = NULL;
#ifndef PRODUCT
  if (TraceNewOopMapGenerationDetailed) {
    TraceNewOopMapGeneration = true;
  }
#endif
}
void GenerateOopMap::compute_map(TRAPS) {
#ifndef PRODUCT
  if (TimeOopMap2) {
    method()->print_short_name(tty);
    tty->print("  ");
  }
  if (TimeOopMap) {
    _total_byte_count += method()->code_size();
  }
#endif
  TraceTime t_single("oopmap time", TimeOopMap2);
  TraceTime t_all(NULL, &_total_oopmap_time, TimeOopMap);
  _got_error      = false;
  _conflict       = false;
  _max_locals     = method()->max_locals();
  _max_stack      = method()->max_stack();
  _has_exceptions = (method()->has_exception_handler());
  _nof_refval_conflicts = 0;
  _init_vars      = new GrowableArray<intptr_t>(5);  // There are seldom more than 5 init_vars
  _report_result  = false;
  _report_result_for_send = false;
  _new_var_map    = NULL;
  _ret_adr_tos    = new GrowableArray<intptr_t>(5);  // 5 seems like a good number;
  _did_rewriting  = false;
  _did_relocation = false;
  if (TraceNewOopMapGeneration) {
    tty->print("Method name: %s\n", method()->name()->as_C_string());
    if (Verbose) {
      _method->print_codes();
      tty->print_cr("Exception table:");
      ExceptionTable excps(method());
      for(int i = 0; i < excps.length(); i ++) {
        tty->print_cr("[%d - %d] -> %d",
                      excps.start_pc(i), excps.end_pc(i), excps.handler_pc(i));
      }
    }
  }
  if (method()->code_size() == 0 || _max_locals + method()->max_stack() == 0) {
    fill_stackmap_prolog(0);
    fill_stackmap_epilog();
    return;
  }
  if (!_got_error)
    _rt.compute_ret_table(_method);
  if (!_got_error)
    mark_bbheaders_and_count_gc_points();
  if (!_got_error)
    do_interpretation();
  if (!_got_error && report_results())
     report_result();
  if (_got_error) {
    THROW_HANDLE(_exception);
  }
}
void GenerateOopMap::error_work(const char *format, va_list ap) {
  _got_error = true;
  char msg_buffer[512];
  os::vsnprintf(msg_buffer, sizeof(msg_buffer), format, ap);
  char msg_buffer2[512];
  os::snprintf(msg_buffer2, sizeof(msg_buffer2), "%s in method %s", msg_buffer, method()->name()->as_C_string());
  _exception = Exceptions::new_exception(Thread::current(),
                vmSymbols::java_lang_LinkageError(), msg_buffer2);
}
void GenerateOopMap::report_error(const char *format, ...) {
  va_list ap;
  va_start(ap, format);
  error_work(format, ap);
}
void GenerateOopMap::verify_error(const char *format, ...) {
  const char *msg = "Illegal class file encountered. Try running with -Xverify:all";
  _got_error = true;
  char msg_buffer2[512];
  os::snprintf(msg_buffer2, sizeof(msg_buffer2), "%s in method %s", msg,
               method()->name()->as_C_string());
  _exception = Exceptions::new_exception(Thread::current(),
                vmSymbols::java_lang_LinkageError(), msg_buffer2);
}
void GenerateOopMap::report_result() {
  if (TraceNewOopMapGeneration) tty->print_cr("Report result pass");
  _report_result = true;
  fill_stackmap_prolog(_gc_points);
  for (int i = 0; i<_bb_count; i++) {
    if (_basic_blocks[i].is_reachable()) {
      _basic_blocks[i].set_changed(true);
      interp_bb(&_basic_blocks[i]);
    }
  }
  fill_stackmap_epilog();
  fill_init_vars(_init_vars);
  _report_result = false;
}
void GenerateOopMap::result_for_basicblock(int bci) {
 if (TraceNewOopMapGeneration) tty->print_cr("Report result pass for basicblock");
  _report_result = true;
  BasicBlock* bb = get_basic_block_containing(bci);
  guarantee(bb != NULL, "no basic block for bci");
  assert(bb->is_reachable(), "getting result from unreachable basicblock");
  bb->set_changed(true);
  interp_bb(bb);
}
void GenerateOopMap::record_refval_conflict(int varNo) {
  assert(varNo>=0 && varNo< _max_locals, "index out of range");
  if (TraceOopMapRewrites) {
     tty->print("### Conflict detected (local no: %d)\n", varNo);
  }
  if (!_new_var_map) {
    _new_var_map = NEW_RESOURCE_ARRAY(int, _max_locals);
    for (int k = 0; k < _max_locals; k++)  _new_var_map[k] = k;
  }
  if ( _new_var_map[varNo] == varNo) {
    if (_max_locals + _nof_refval_conflicts >= MAX_LOCAL_VARS) {
      report_error("Rewriting exceeded local variable limit");
      return;
    }
    _new_var_map[varNo] = _max_locals + _nof_refval_conflicts;
    _nof_refval_conflicts++;
  }
}
void GenerateOopMap::rewrite_refval_conflicts()
{
  int nof_conflicts = 0;              // Used for debugging only
  if ( _nof_refval_conflicts == 0 )
     return;
  if (!allow_rewrites() && !IgnoreRewrites) {
    fatal("Rewriting method not allowed at this stage");
  }
  if (IgnoreRewrites) {
    if (Verbose) {
       tty->print("rewrites suppressed for local no. ");
       for (int l = 0; l < _max_locals; l++) {
         if (_new_var_map[l] != l) {
           tty->print("%d ", l);
           vars()[l] = CellTypeState::value;
         }
       }
       tty->cr();
    }
    _new_var_map = NULL;
    _nof_refval_conflicts = 0;
    _conflict = false;
    return;
  }
  _did_rewriting = true;
  if (TraceOopMapRewrites) {
    tty->print_cr("ref/value conflict for method %s - bytecodes are getting rewritten", method()->name()->as_C_string());
    method()->print();
    method()->print_codes();
  }
  assert(_new_var_map!=NULL, "nothing to rewrite");
  assert(_conflict==true, "We should not be here");
  compute_ret_adr_at_TOS();
  if (!_got_error) {
    for (int k = 0; k < _max_locals && !_got_error; k++) {
      if (_new_var_map[k] != k) {
        if (TraceOopMapRewrites) {
          tty->print_cr("Rewriting: %d -> %d", k, _new_var_map[k]);
        }
        rewrite_refval_conflict(k, _new_var_map[k]);
        if (_got_error) return;
        nof_conflicts++;
      }
    }
  }
  assert(nof_conflicts == _nof_refval_conflicts, "sanity check");
  method()->set_max_locals(_max_locals+_nof_refval_conflicts);
  _max_locals += _nof_refval_conflicts;
  _new_var_map = NULL;
  _nof_refval_conflicts = 0;
}
void GenerateOopMap::rewrite_refval_conflict(int from, int to) {
  bool startOver;
  do {
    BytecodeStream bcs(_method);
    startOver = false;
    while( !startOver && !_got_error &&
           bcs.next() >=0) {
      startOver = rewrite_refval_conflict_inst(&bcs, from, to);
    }
  } while (startOver && !_got_error);
}
   in a ref way, change it to use "to". There's a subtle reason why we
   renumber the ref uses and not the non-ref uses: non-ref uses may be
   2 slots wide (double, long) which would necessitate keeping track of
   whether we should add one or two variables to the method. If the change
   affected the width of some instruction, returns "TRUE"; otherwise, returns "FALSE".
   Another reason for moving ref's value is for solving (addr, ref) conflicts, which
   both uses aload/astore methods.
bool GenerateOopMap::rewrite_refval_conflict_inst(BytecodeStream *itr, int from, int to) {
  Bytecodes::Code bc = itr->code();
  int index;
  int bci = itr->bci();
  if (is_aload(itr, &index) && index == from) {
    if (TraceOopMapRewrites) {
      tty->print_cr("Rewriting aload at bci: %d", bci);
    }
    return rewrite_load_or_store(itr, Bytecodes::_aload, Bytecodes::_aload_0, to);
  }
  if (is_astore(itr, &index) && index == from) {
    if (!stack_top_holds_ret_addr(bci)) {
      if (TraceOopMapRewrites) {
        tty->print_cr("Rewriting astore at bci: %d", bci);
      }
      return rewrite_load_or_store(itr, Bytecodes::_astore, Bytecodes::_astore_0, to);
    } else {
      if (TraceOopMapRewrites) {
        tty->print_cr("Supress rewriting of astore at bci: %d", bci);
      }
    }
  }
  return false;
}
bool GenerateOopMap::rewrite_load_or_store(BytecodeStream *bcs, Bytecodes::Code bcN, Bytecodes::Code bc0, unsigned int varNo) {
  assert(bcN == Bytecodes::_astore   || bcN == Bytecodes::_aload,   "wrong argument (bcN)");
  assert(bc0 == Bytecodes::_astore_0 || bc0 == Bytecodes::_aload_0, "wrong argument (bc0)");
  int ilen = Bytecodes::length_at(_method(), bcs->bcp());
  int newIlen;
  if (ilen == 4) {
    newIlen = 4;
  } else if (varNo < 4)
     newIlen = 1;
  else if (varNo >= 256)
     newIlen = 4;
  else
     newIlen = 2;
  assert(newIlen <= 4, "sanity check");
  u_char inst_buffer[4]; // Max. instruction size is 4.
  address bcp;
  if (newIlen != ilen) {
    bcp = (address)inst_buffer;
  } else {
    bcp = _method->bcp_from(bcs->bci());
  }
  if (newIlen == 1) {
    assert(varNo < 4, "varNo too large");
  } else if (newIlen == 2) {
    assert(varNo < 256, "2-byte index needed!");
  } else {
    assert(newIlen == 4, "Wrong instruction length");
    Bytes::put_Java_u2(bcp+2, varNo);
  }
  if (newIlen != ilen) {
    expand_current_instr(bcs->bci(), ilen, newIlen, inst_buffer);
  }
  return (newIlen != ilen);
}
class RelocCallback : public RelocatorListener {
 private:
  GenerateOopMap* _gom;
 public:
   RelocCallback(GenerateOopMap* gom) { _gom = gom; };
  virtual void relocated(int bci, int delta, int new_code_length) {
    _gom->update_basic_blocks  (bci, delta, new_code_length);
    _gom->update_ret_adr_at_TOS(bci, delta);
    _gom->_rt.update_ret_table (bci, delta);
  }
};
void GenerateOopMap::expand_current_instr(int bci, int ilen, int newIlen, u_char inst_buffer[]) {
  Thread *THREAD = Thread::current();  // Could really have TRAPS argument.
  RelocCallback rcb(this);
  Relocator rc(_method, &rcb);
  methodHandle m= rc.insert_space_at(bci, newIlen, inst_buffer, THREAD);
  if (m.is_null() || HAS_PENDING_EXCEPTION) {
    report_error("could not rewrite method - exception occurred or bytecode buffer overflow");
    return;
  }
  _did_relocation = true;
  _method = m;
}
bool GenerateOopMap::is_astore(BytecodeStream *itr, int *index) {
  Bytecodes::Code bc = itr->code();
  switch(bc) {
    case Bytecodes::_astore_0:
    case Bytecodes::_astore_1:
    case Bytecodes::_astore_2:
    case Bytecodes::_astore_3:
      return true;
    case Bytecodes::_astore:
      return true;
  }
  return false;
}
bool GenerateOopMap::is_aload(BytecodeStream *itr, int *index) {
  Bytecodes::Code bc = itr->code();
  switch(bc) {
    case Bytecodes::_aload_0:
    case Bytecodes::_aload_1:
    case Bytecodes::_aload_2:
    case Bytecodes::_aload_3:
      return true;
    case Bytecodes::_aload:
      return true;
  }
  return false;
}
bool GenerateOopMap::stack_top_holds_ret_addr(int bci) {
  for(int i = 0; i < _ret_adr_tos->length(); i++) {
    if (_ret_adr_tos->at(i) == bci)
      return true;
  }
  return false;
}
void GenerateOopMap::compute_ret_adr_at_TOS() {
  assert(_ret_adr_tos != NULL, "must be initialized");
  _ret_adr_tos->clear();
  for (int i = 0; i < bb_count(); i++) {
    BasicBlock* bb = &_basic_blocks[i];
    if (bb->is_reachable()) {
      BytecodeStream bcs(_method);
      bcs.set_interval(bb->_bci, next_bb_start_pc(bb));
      restore_state(bb);
      while (bcs.next()>=0 && !_got_error) {
        if (_stack_top > 0 && stack()[_stack_top-1].is_address()) {
          _ret_adr_tos->append(bcs.bci());
          if (TraceNewOopMapGeneration) {
            tty->print_cr("Ret_adr TOS at bci: %d", bcs.bci());
          }
        }
        interp1(&bcs);
      }
    }
  }
}
void GenerateOopMap::update_ret_adr_at_TOS(int bci, int delta) {
  for(int i = 0; i < _ret_adr_tos->length(); i++) {
    int v = _ret_adr_tos->at(i);
    if (v > bci)  _ret_adr_tos->at_put(i, v + delta);
  }
}
#ifndef PRODUCT
int ResolveOopMapConflicts::_nof_invocations  = 0;
int ResolveOopMapConflicts::_nof_rewrites     = 0;
int ResolveOopMapConflicts::_nof_relocations  = 0;
#endif
methodHandle ResolveOopMapConflicts::do_potential_rewrite(TRAPS) {
  compute_map(CHECK_(methodHandle()));
#ifndef PRODUCT
  if (PrintRewrites) {
    _nof_invocations++;
    if (did_rewriting()) {
      _nof_rewrites++;
      if (did_relocation()) _nof_relocations++;
      tty->print("Method was rewritten %s: ", (did_relocation()) ? "and relocated" : "");
      method()->print_value(); tty->cr();
      tty->print_cr("Cand.: %d rewrts: %d (%d%%) reloc.: %d (%d%%)",
          _nof_invocations,
          _nof_rewrites,    (_nof_rewrites    * 100) / _nof_invocations,
          _nof_relocations, (_nof_relocations * 100) / _nof_invocations);
    }
  }
#endif
  return methodHandle(THREAD, method());
}
C:\hotspot-69087d08d473\src\share\vm/oops/generateOopMap.hpp
#ifndef SHARE_VM_OOPS_GENERATEOOPMAP_HPP
#define SHARE_VM_OOPS_GENERATEOOPMAP_HPP
#include "interpreter/bytecodeStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/universe.inline.hpp"
#include "oops/method.hpp"
#include "oops/oopsHierarchy.hpp"
#include "runtime/signature.hpp"
class GenerateOopMap;
class BasicBlock;
class CellTypeState;
class StackMap;
#define MAXARGSIZE      256      // This should be enough
#define MAX_LOCAL_VARS  65536    // 16-bit entry
typedef void (*jmpFct_t)(GenerateOopMap *c, int bcpDelta, int* data);
class RetTableEntry : public ResourceObj {
 private:
  static int _init_nof_jsrs;                      // Default size of jsrs list
  int _target_bci;                                // Target PC address of jump (bytecode index)
  GrowableArray<intptr_t> * _jsrs;                     // List of return addresses  (bytecode index)
  RetTableEntry *_next;                           // Link to next entry
 public:
   RetTableEntry(int target, RetTableEntry *next)  { _target_bci=target; _jsrs = new GrowableArray<intptr_t>(_init_nof_jsrs); _next = next;  }
  int target_bci() const                      { return _target_bci; }
  int nof_jsrs() const                        { return _jsrs->length(); }
  int jsrs(int i) const                       { assert(i>=0 && i<nof_jsrs(), "Index out of bounds"); return _jsrs->at(i); }
  void add_jsr    (int return_bci)            { _jsrs->append(return_bci); }
  void add_delta  (int bci, int delta);
  RetTableEntry * next()  const               { return _next; }
};
class RetTable VALUE_OBJ_CLASS_SPEC {
 private:
  RetTableEntry *_first;
  static int _init_nof_entries;
  void add_jsr(int return_bci, int target_bci);   // Adds entry to list
 public:
  RetTable()                                                  { _first = NULL; }
  void compute_ret_table(methodHandle method);
  void update_ret_table(int bci, int delta);
  RetTableEntry* find_jsrs_for_target(int targBci);
};
class CellTypeState VALUE_OBJ_CLASS_SPEC {
 private:
  unsigned int _state;
  enum { info_mask            = right_n_bits(28),
         bits_mask            = (int)(~info_mask) };
  enum { uninit_bit           = (int)(nth_bit(31)),
         ref_bit              = nth_bit(30),
         val_bit              = nth_bit(29),
         addr_bit             = nth_bit(28),
         live_bits_mask       = (int)(bits_mask & ~uninit_bit) };
  enum { top_info_bit         = nth_bit(27),
         not_bottom_info_bit  = nth_bit(26),
         info_data_mask       = right_n_bits(26),
         info_conflict        = info_mask };
  enum { ref_not_lock_bit     = nth_bit(25),  // 0 if this reference is locked as a monitor
         ref_slot_bit         = nth_bit(24),  // 1 if this reference is a "slot" reference,
         ref_data_mask        = right_n_bits(24) };
  enum { bottom_value         = 0,
         uninit_value         = (int)(uninit_bit | info_conflict),
         ref_value            = ref_bit,
         ref_conflict         = ref_bit | info_conflict,
         val_value            = val_bit | info_conflict,
         addr_value           = addr_bit,
         addr_conflict        = addr_bit | info_conflict };
 public:
  static CellTypeState make_any(int state) {
    CellTypeState s;
    s._state = state;
    return s;
  }
  static CellTypeState make_bottom() {
    return make_any(0);
  }
  static CellTypeState make_top() {
    return make_any(AllBits);
  }
  static CellTypeState make_addr(int bci) {
    assert((bci >= 0) && (bci < info_data_mask), "check to see if ret addr is valid");
    return make_any(addr_bit | not_bottom_info_bit | (bci & info_data_mask));
  }
  static CellTypeState make_slot_ref(int slot_num) {
    assert(slot_num >= 0 && slot_num < ref_data_mask, "slot out of range");
    return make_any(ref_bit | not_bottom_info_bit | ref_not_lock_bit | ref_slot_bit |
                    (slot_num & ref_data_mask));
  }
  static CellTypeState make_line_ref(int bci) {
    assert(bci >= 0 && bci < ref_data_mask, "line out of range");
    return make_any(ref_bit | not_bottom_info_bit | ref_not_lock_bit |
                    (bci & ref_data_mask));
  }
  static CellTypeState make_lock_ref(int bci) {
    assert(bci >= 0 && bci < ref_data_mask, "line out of range");
    return make_any(ref_bit | not_bottom_info_bit | (bci & ref_data_mask));
  }
  bool is_bottom() const                { return _state == 0; }
  bool is_live() const                  { return ((_state & live_bits_mask) != 0); }
  bool is_valid_state() const {
    if ((can_be_uninit() || can_be_value()) && !is_info_top()) {
      return false;
    }
    if (is_info_top() && ((_state & info_mask) != info_mask)) {
      return false;
    }
    if (is_info_bottom() && ((_state & info_mask) != 0)) {
      return false;
    }
    return true;
  }
  bool is_address() const               { return ((_state & bits_mask) == addr_bit); }
  bool is_reference() const             { return ((_state & bits_mask) == ref_bit); }
  bool is_value() const                 { return ((_state & bits_mask) == val_bit); }
  bool is_uninit() const                { return ((_state & bits_mask) == (uint)uninit_bit); }
  bool can_be_address() const           { return ((_state & addr_bit) != 0); }
  bool can_be_reference() const         { return ((_state & ref_bit) != 0); }
  bool can_be_value() const             { return ((_state & val_bit) != 0); }
  bool can_be_uninit() const            { return ((_state & uninit_bit) != 0); }
  bool is_info_bottom() const           { return ((_state & not_bottom_info_bit) == 0); }
  bool is_info_top() const              { return ((_state & top_info_bit) != 0); }
  int  get_info() const {
    assert((!is_info_top() && !is_info_bottom()),
           "check to make sure top/bottom info is not used");
    return (_state & info_data_mask);
  }
  bool is_good_address() const          { return is_address() && !is_info_top(); }
  bool is_lock_reference() const {
    return ((_state & (bits_mask | top_info_bit | ref_not_lock_bit)) == ref_bit);
  }
  bool is_nonlock_reference() const {
    return ((_state & (bits_mask | top_info_bit | ref_not_lock_bit)) == (ref_bit | ref_not_lock_bit));
  }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值