Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  javaClasses.cpp   Sprache: C

 
/*
 * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 *
 */


#include "precompiled.hpp"
#include "cds/archiveBuilder.hpp"
#include "cds/archiveHeapLoader.hpp"
#include "cds/heapShared.hpp"
#include "cds/metaspaceShared.hpp"
#include "classfile/altHashing.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/javaClassesImpl.hpp"
#include "classfile/javaThreadStatus.hpp"
#include "classfile/moduleEntry.hpp"
#include "classfile/stringTable.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmClasses.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/debugInfo.hpp"
#include "code/dependencyContext.hpp"
#include "code/pcDesc.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/linkResolver.hpp"
#include "jvm.h"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/fieldStreams.inline.hpp"
#include "oops/instanceKlass.inline.hpp"
#include "oops/instanceMirrorKlass.hpp"
#include "oops/klass.hpp"
#include "oops/klass.inline.hpp"
#include "oops/method.inline.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/objArrayOop.inline.hpp"
#include "oops/oopCast.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "oops/recordComponent.hpp"
#include "oops/typeArrayOop.inline.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/methodHandles.hpp"
#include "prims/resolvedMethodTable.hpp"
#include "runtime/continuationEntry.inline.hpp"
#include "runtime/continuationJavaClasses.inline.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/handshake.hpp"
#include "runtime/init.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/jniHandles.inline.hpp"
#include "runtime/reflectionUtils.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/safepointVerifiers.hpp"
#include "runtime/threadSMR.hpp"
#include "runtime/vframe.inline.hpp"
#include "runtime/vm_version.hpp"
#include "utilities/align.hpp"
#include "utilities/growableArray.hpp"
#include "utilities/preserveException.hpp"
#include "utilities/utf8.hpp"
#if INCLUDE_JVMCI
#include "jvmci/jvmciJavaClasses.hpp"
#endif

#define DECLARE_INJECTED_FIELD(klass, name, signature, may_be_java)           \
  { VM_CLASS_ID(klass), VM_SYMBOL_ENUM_NAME(name##_name), VM_SYMBOL_ENUM_NAME(signature), may_be_java },

InjectedField JavaClasses::_injected_fields[] = {
  ALL_INJECTED_FIELDS(DECLARE_INJECTED_FIELD)
};

// Register native methods of Object
void java_lang_Object::register_natives(TRAPS) {
  InstanceKlass* obj = vmClasses::Object_klass();
  Method::register_native(obj, vmSymbols::hashCode_name(),
                          vmSymbols::void_int_signature(), (address) &JVM_IHashCode, CHECK);
  Method::register_native(obj, vmSymbols::wait_name(),
                          vmSymbols::long_void_signature(), (address) &JVM_MonitorWait, CHECK);
  Method::register_native(obj, vmSymbols::notify_name(),
                          vmSymbols::void_method_signature(), (address) &JVM_MonitorNotify, CHECK);
  Method::register_native(obj, vmSymbols::notifyAll_name(),
                          vmSymbols::void_method_signature(), (address) &JVM_MonitorNotifyAll, CHECK);
  Method::register_native(obj, vmSymbols::clone_name(),
                          vmSymbols::void_object_signature(), (address) &JVM_Clone, THREAD);
}

int JavaClasses::compute_injected_offset(InjectedFieldID id) {
  return _injected_fields[(int)id].compute_offset();
}

InjectedField* JavaClasses::get_injected(Symbol* class_name, int* field_count) {
  *field_count = 0;

  vmSymbolID sid = vmSymbols::find_sid(class_name);
  if (sid == vmSymbolID::NO_SID) {
    // Only well known classes can inject fields
    return NULL;
  }

  int count = 0;
  int start = -1;

#define LOOKUP_INJECTED_FIELD(klass, name, signature, may_be_java) \
  if (sid == VM_SYMBOL_ENUM_NAME(klass)) {                         \
    count++;                                                       \
    if (start == -1) {                                             \
      start = (int)InjectedFieldID::klass##_##name##_enum;         \
    }                                                              \
  }
  ALL_INJECTED_FIELDS(LOOKUP_INJECTED_FIELD);
#undef LOOKUP_INJECTED_FIELD

  if (start != -1) {
    *field_count = count;
    return _injected_fields + start;
  }
  return NULL;
}


// Helpful routine for computing field offsets at run time rather than hardcoding them
// Finds local fields only, including static fields.  Static field offsets are from the
// beginning of the mirror.
void JavaClasses::compute_offset(int &dest_offset,
                                 InstanceKlass* ik, Symbol* name_symbol, Symbol* signature_symbol,
                                 bool is_static) {
  fieldDescriptor fd;
  if (ik == NULL) {
    ResourceMark rm;
    log_error(class)("Mismatch JDK version for field: %s type: %s", name_symbol->as_C_string(), signature_symbol->as_C_string());
    vm_exit_during_initialization("Invalid layout of well-known class");
  }

  if (!ik->find_local_field(name_symbol, signature_symbol, &fd) || fd.is_static() != is_static) {
    ResourceMark rm;
    log_error(class)("Invalid layout of %s field: %s type: %s", ik->external_name(),
                     name_symbol->as_C_string(), signature_symbol->as_C_string());
#ifndef PRODUCT
    // Prints all fields and offsets
    Log(class) lt;
    LogStream ls(lt.error());
    ik->print_on(&ls);
#endif //PRODUCT
    vm_exit_during_initialization("Invalid layout of well-known class: use -Xlog:class+load=info to see the origin of the problem class");
  }
  dest_offset = fd.offset();
}

// Overloading to pass name as a string.
void JavaClasses::compute_offset(int& dest_offset, InstanceKlass* ik,
                                 const char* name_string, Symbol* signature_symbol,
                                 bool is_static) {
  TempNewSymbol name = SymbolTable::probe(name_string, (int)strlen(name_string));
  if (name == NULL) {
    ResourceMark rm;
    log_error(class)("Name %s should be in the SymbolTable since its class is loaded", name_string);
    vm_exit_during_initialization("Invalid layout of well-known class", ik->external_name());
  }
  compute_offset(dest_offset, ik, name, signature_symbol, is_static);
}

// java_lang_String

int java_lang_String::_value_offset;
int java_lang_String::_hash_offset;
int java_lang_String::_hashIsZero_offset;
int java_lang_String::_coder_offset;
int java_lang_String::_flags_offset;

bool java_lang_String::_initialized;


bool java_lang_String::test_and_set_flag(oop java_string, uint8_t flag_mask) {
  uint8_t* addr = flags_addr(java_string);
  uint8_t value = Atomic::load(addr);
  while ((value & flag_mask) == 0) {
    uint8_t old_value = value;
    value |= flag_mask;
    value = Atomic::cmpxchg(addr, old_value, value);
    if (value == old_value) return false// Flag bit changed from 0 to 1.
  }
  return true;                  // Flag bit is already 1.
}

#define STRING_FIELDS_DO(macro) \
  macro(_value_offset, k, vmSymbols::value_name(), byte_array_signature, false); \
  macro(_hash_offset,  k, "hash",                  int_signature,        false); \
  macro(_hashIsZero_offset, k, "hashIsZero",       bool_signature,       false); \
  macro(_coder_offset, k, "coder",                 byte_signature,       false);

void java_lang_String::compute_offsets() {
  if (_initialized) {
    return;
  }

  InstanceKlass* k = vmClasses::String_klass();
  STRING_FIELDS_DO(FIELD_COMPUTE_OFFSET);
  STRING_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);

  _initialized = true;
}

#if INCLUDE_CDS
void java_lang_String::serialize_offsets(SerializeClosure* f) {
  STRING_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
  STRING_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);
  f->do_bool(&_initialized);
}
#endif

class CompactStringsFixup : public FieldClosure {
private:
  bool _value;

public:
  CompactStringsFixup(bool value) : _value(value) {}

  void do_field(fieldDescriptor* fd) {
    if (fd->name() == vmSymbols::compact_strings_name()) {
      oop mirror = fd->field_holder()->java_mirror();
      assert(fd->field_holder() == vmClasses::String_klass(), "Should be String");
      assert(mirror != NULL, "String must have mirror already");
      mirror->bool_field_put(fd->offset(), _value);
    }
  }
};

void java_lang_String::set_compact_strings(bool value) {
  CompactStringsFixup fix(value);
  vmClasses::String_klass()->do_local_static_fields(&fix);
}

Handle java_lang_String::basic_create(int length, bool is_latin1, TRAPS) {
  assert(_initialized, "Must be initialized");
  assert(CompactStrings || !is_latin1, "Must be UTF16 without CompactStrings");

  // Create the String object first, so there's a chance that the String
  // and the char array it points to end up in the same cache line.
  oop obj;
  obj = vmClasses::String_klass()->allocate_instance(CHECK_NH);

  // Create the char array.  The String object must be handlized here
  // because GC can happen as a result of the allocation attempt.
  Handle h_obj(THREAD, obj);
  int arr_length = is_latin1 ? length : length << 1; // 2 bytes per UTF16.
  typeArrayOop buffer = oopFactory::new_byteArray(arr_length, CHECK_NH);;

  // Point the String at the char array
  obj = h_obj();
  set_value(obj, buffer);
  // No need to zero the offset, allocation zero'ed the entire String object
  set_coder(obj, is_latin1 ? CODER_LATIN1 : CODER_UTF16);
  return h_obj;
}

Handle java_lang_String::create_from_unicode(const jchar* unicode, int length, TRAPS) {
  bool is_latin1 = CompactStrings && UNICODE::is_latin1(unicode, length);
  Handle h_obj = basic_create(length, is_latin1, CHECK_NH);
  typeArrayOop buffer = value(h_obj());
  assert(TypeArrayKlass::cast(buffer->klass())->element_type() == T_BYTE, "only byte[]");
  if (is_latin1) {
    for (int index = 0; index < length; index++) {
      buffer->byte_at_put(index, (jbyte)unicode[index]);
    }
  } else {
    for (int index = 0; index < length; index++) {
      buffer->char_at_put(index, unicode[index]);
    }
  }

#ifdef ASSERT
  {
    ResourceMark rm;
    char* expected = UNICODE::as_utf8(unicode, length);
    char* actual = as_utf8_string(h_obj());
    if (strcmp(expected, actual) != 0) {
      fatal("Unicode conversion failure: %s --> %s", expected, actual);
    }
  }
#endif

  return h_obj;
}

oop java_lang_String::create_oop_from_unicode(const jchar* unicode, int length, TRAPS) {
  Handle h_obj = create_from_unicode(unicode, length, CHECK_NULL);
  return h_obj();
}

Handle java_lang_String::create_from_str(const char* utf8_str, TRAPS) {
  if (utf8_str == NULL) {
    return Handle();
  }
  bool has_multibyte, is_latin1;
  int length = UTF8::unicode_length(utf8_str, is_latin1, has_multibyte);
  if (!CompactStrings) {
    has_multibyte = true;
    is_latin1 = false;
  }

  Handle h_obj = basic_create(length, is_latin1, CHECK_NH);
  if (length > 0) {
    if (!has_multibyte) {
      const jbyte* src = reinterpret_cast<const jbyte*>(utf8_str);
      ArrayAccess<>::arraycopy_from_native(src, value(h_obj()), typeArrayOopDesc::element_offset<jbyte>(0), length);
    } else if (is_latin1) {
      UTF8::convert_to_unicode(utf8_str, value(h_obj())->byte_at_addr(0), length);
    } else {
      UTF8::convert_to_unicode(utf8_str, value(h_obj())->char_at_addr(0), length);
    }
  }

#ifdef ASSERT
  // This check is too strict when the input string is not a valid UTF8.
  // For example, it may be created with arbitrary content via jni_NewStringUTF.
  if (UTF8::is_legal_utf8((const unsigned char*)utf8_str, (int)strlen(utf8_str), false)) {
    ResourceMark rm;
    const char* expected = utf8_str;
    char* actual = as_utf8_string(h_obj());
    if (strcmp(expected, actual) != 0) {
      fatal("String conversion failure: %s --> %s", expected, actual);
    }
  }
#endif

  return h_obj;
}

oop java_lang_String::create_oop_from_str(const char* utf8_str, TRAPS) {
  Handle h_obj = create_from_str(utf8_str, CHECK_NULL);
  return h_obj();
}

Handle java_lang_String::create_from_symbol(Symbol* symbol, TRAPS) {
  const char* utf8_str = (char*)symbol->bytes();
  int utf8_len = symbol->utf8_length();

  bool has_multibyte, is_latin1;
  int length = UTF8::unicode_length(utf8_str, utf8_len, is_latin1, has_multibyte);
  if (!CompactStrings) {
    has_multibyte = true;
    is_latin1 = false;
  }

  Handle h_obj = basic_create(length, is_latin1, CHECK_NH);
  if (length > 0) {
    if (!has_multibyte) {
      const jbyte* src = reinterpret_cast<const jbyte*>(utf8_str);
      ArrayAccess<>::arraycopy_from_native(src, value(h_obj()), typeArrayOopDesc::element_offset<jbyte>(0), length);
    } else if (is_latin1) {
      UTF8::convert_to_unicode(utf8_str, value(h_obj())->byte_at_addr(0), length);
    } else {
      UTF8::convert_to_unicode(utf8_str, value(h_obj())->char_at_addr(0), length);
    }
  }

#ifdef ASSERT
  {
    ResourceMark rm;
    const char* expected = symbol->as_utf8();
    char* actual = as_utf8_string(h_obj());
    if (strncmp(expected, actual, utf8_len) != 0) {
      fatal("Symbol conversion failure: %s --> %s", expected, actual);
    }
  }
#endif

  return h_obj;
}

// Converts a C string to a Java String based on current encoding
Handle java_lang_String::create_from_platform_dependent_str(const char* str, TRAPS) {
  assert(str != NULL, "bad arguments");

  typedef jstring (JNICALL *to_java_string_fn_t)(JNIEnv*, const char *);
  static to_java_string_fn_t _to_java_string_fn = NULL;

  if (_to_java_string_fn == NULL) {
    void *lib_handle = os::native_java_library();
    _to_java_string_fn = CAST_TO_FN_PTR(to_java_string_fn_t, os::dll_lookup(lib_handle, "JNU_NewStringPlatform"));
#if defined(_WIN32) && !defined(_WIN64)
    if (_to_java_string_fn == NULL) {
      // On 32 bit Windows, also try __stdcall decorated name
      _to_java_string_fn = CAST_TO_FN_PTR(to_java_string_fn_t, os::dll_lookup(lib_handle, "_JNU_NewStringPlatform@8"));
    }
#endif
    if (_to_java_string_fn == NULL) {
      fatal("JNU_NewStringPlatform missing");
    }
  }

  jstring js = NULL;
  {
    JavaThread* thread = THREAD;
    HandleMark hm(thread);
    ThreadToNativeFromVM ttn(thread);
    js = (_to_java_string_fn)(thread->jni_environment(), str);
  }

  Handle native_platform_string(THREAD, JNIHandles::resolve(js));
  JNIHandles::destroy_local(js);  // destroy local JNIHandle.
  return native_platform_string;
}

// Converts a Java String to a native C string that can be used for
// native OS calls.
char* java_lang_String::as_platform_dependent_str(Handle java_string, TRAPS) {
  typedef char* (*to_platform_string_fn_t)(JNIEnv*, jstring, bool*);
  static to_platform_string_fn_t _to_platform_string_fn = NULL;

  if (_to_platform_string_fn == NULL) {
    void *lib_handle = os::native_java_library();
    _to_platform_string_fn = CAST_TO_FN_PTR(to_platform_string_fn_t, os::dll_lookup(lib_handle, "GetStringPlatformChars"));
    if (_to_platform_string_fn == NULL) {
      fatal("GetStringPlatformChars missing");
    }
  }

  char *native_platform_string;
  jstring js;
  { JavaThread* thread = THREAD;
    js = (jstring) JNIHandles::make_local(thread, java_string());
    HandleMark hm(thread);
    ThreadToNativeFromVM ttn(thread);
    JNIEnv *env = thread->jni_environment();
    bool is_copy;
    native_platform_string = (_to_platform_string_fn)(env, js, &is_copy);
    assert(is_copy == JNI_TRUE, "is_copy value changed");
  }

  // Uses a store barrier and therefore needs to be in vm state
  JNIHandles::destroy_local(js);

  return native_platform_string;
}

Handle java_lang_String::externalize_classname(Symbol* java_name, TRAPS) {
  ResourceMark rm(THREAD);
  return create_from_str(java_name->as_klass_external_name(), THREAD);
}

jchar* java_lang_String::as_unicode_string(oop java_string, int& length, TRAPS) {
  jchar* result = as_unicode_string_or_null(java_string, length);
  if (result == NULL) {
    THROW_MSG_0(vmSymbols::java_lang_OutOfMemoryError(), "could not allocate Unicode string");
  }
  return result;
}

jchar* java_lang_String::as_unicode_string_or_null(oop java_string, int& length) {
  typeArrayOop value  = java_lang_String::value(java_string);
               length = java_lang_String::length(java_string, value);
  bool      is_latin1 = java_lang_String::is_latin1(java_string);

  jchar* result = NEW_RESOURCE_ARRAY_RETURN_NULL(jchar, length);
  if (result != NULL) {
    if (!is_latin1) {
      for (int index = 0; index < length; index++) {
        result[index] = value->char_at(index);
      }
    } else {
      for (int index = 0; index < length; index++) {
        result[index] = ((jchar) value->byte_at(index)) & 0xff;
      }
    }
  }
  return result;
}

inline unsigned int java_lang_String::hash_code_impl(oop java_string, bool update) {
  // The hash and hashIsZero fields are subject to a benign data race,
  // making it crucial to ensure that any observable result of the
  // calculation in this method stays correct under any possible read of
  // these fields. Necessary restrictions to allow this to be correct
  // without explicit memory fences or similar concurrency primitives is
  // that we can ever only write to one of these two fields for a given
  // String instance, and that the computation is idempotent and derived
  // from immutable state
  assert(_initialized && (_hash_offset > 0) && (_hashIsZero_offset > 0), "Must be initialized");
  if (java_lang_String::hash_is_set(java_string)) {
    return java_string->int_field(_hash_offset);
  }

  typeArrayOop value = java_lang_String::value(java_string);
  int         length = java_lang_String::length(java_string, value);
  bool     is_latin1 = java_lang_String::is_latin1(java_string);

  unsigned int hash = 0;
  if (length > 0) {
    if (is_latin1) {
      hash = java_lang_String::hash_code(value->byte_at_addr(0), length);
    } else {
      hash = java_lang_String::hash_code(value->char_at_addr(0), length);
    }
  }

  if (update) {
    if (hash != 0) {
      java_string->int_field_put(_hash_offset, hash);
    } else {
      java_string->bool_field_put(_hashIsZero_offset, true);
    }
  }
  return hash;
}

unsigned int java_lang_String::hash_code(oop java_string) {
  return hash_code_impl(java_string, /*update=*/true);
}

unsigned int java_lang_String::hash_code_noupdate(oop java_string) {
  return hash_code_impl(java_string, /*update=*/false);
}


char* java_lang_String::as_quoted_ascii(oop java_string) {
  typeArrayOop value  = java_lang_String::value(java_string);
  int          length = java_lang_String::length(java_string, value);
  bool      is_latin1 = java_lang_String::is_latin1(java_string);

  if (length == 0) return NULL;

  char* result;
  int result_length;
  if (!is_latin1) {
    jchar* base = value->char_at_addr(0);
    result_length = UNICODE::quoted_ascii_length(base, length) + 1;
    result = NEW_RESOURCE_ARRAY(char, result_length);
    UNICODE::as_quoted_ascii(base, length, result, result_length);
  } else {
    jbyte* base = value->byte_at_addr(0);
    result_length = UNICODE::quoted_ascii_length(base, length) + 1;
    result = NEW_RESOURCE_ARRAY(char, result_length);
    UNICODE::as_quoted_ascii(base, length, result, result_length);
  }
  assert(result_length >= length + 1, "must not be shorter");
  assert(result_length == (int)strlen(result) + 1, "must match");
  return result;
}

Symbol* java_lang_String::as_symbol(oop java_string) {
  typeArrayOop value  = java_lang_String::value(java_string);
  int          length = java_lang_String::length(java_string, value);
  bool      is_latin1 = java_lang_String::is_latin1(java_string);
  if (!is_latin1) {
    jchar* base = (length == 0) ? NULL : value->char_at_addr(0);
    Symbol* sym = SymbolTable::new_symbol(base, length);
    return sym;
  } else {
    ResourceMark rm;
    jbyte* position = (length == 0) ? NULL : value->byte_at_addr(0);
    const char* base = UNICODE::as_utf8(position, length);
    Symbol* sym = SymbolTable::new_symbol(base, length);
    return sym;
  }
}

Symbol* java_lang_String::as_symbol_or_null(oop java_string) {
  typeArrayOop value  = java_lang_String::value(java_string);
  int          length = java_lang_String::length(java_string, value);
  bool      is_latin1 = java_lang_String::is_latin1(java_string);
  if (!is_latin1) {
    jchar* base = (length == 0) ? NULL : value->char_at_addr(0);
    return SymbolTable::probe_unicode(base, length);
  } else {
    ResourceMark rm;
    jbyte* position = (length == 0) ? NULL : value->byte_at_addr(0);
    const char* base = UNICODE::as_utf8(position, length);
    return SymbolTable::probe(base, length);
  }
}

int java_lang_String::utf8_length(oop java_string, typeArrayOop value) {
  assert(value_equals(value, java_lang_String::value(java_string)),
         "value must be same as java_lang_String::value(java_string)");
  int length = java_lang_String::length(java_string, value);
  if (length == 0) {
    return 0;
  }
  if (!java_lang_String::is_latin1(java_string)) {
    return UNICODE::utf8_length(value->char_at_addr(0), length);
  } else {
    return UNICODE::utf8_length(value->byte_at_addr(0), length);
  }
}

int java_lang_String::utf8_length(oop java_string) {
  typeArrayOop value = java_lang_String::value(java_string);
  return utf8_length(java_string, value);
}

char* java_lang_String::as_utf8_string(oop java_string) {
  int length;
  return as_utf8_string(java_string, length);
}

char* java_lang_String::as_utf8_string(oop java_string, int& length) {
  typeArrayOop value = java_lang_String::value(java_string);
  length             = java_lang_String::length(java_string, value);
  bool     is_latin1 = java_lang_String::is_latin1(java_string);
  if (!is_latin1) {
    jchar* position = (length == 0) ? NULL : value->char_at_addr(0);
    return UNICODE::as_utf8(position, length);
  } else {
    jbyte* position = (length == 0) ? NULL : value->byte_at_addr(0);
    return UNICODE::as_utf8(position, length);
  }
}

// Uses a provided buffer if it's sufficiently large, otherwise allocates
// a resource array to fit
char* java_lang_String::as_utf8_string_full(oop java_string, char* buf, int buflen, int&&nbsp;utf8_len) {
  typeArrayOop value = java_lang_String::value(java_string);
  int            len = java_lang_String::length(java_string, value);
  bool     is_latin1 = java_lang_String::is_latin1(java_string);
  if (!is_latin1) {
    jchar *position = (len == 0) ? NULL : value->char_at_addr(0);
    utf8_len = UNICODE::utf8_length(position, len);
    if (utf8_len >= buflen) {
      buf = NEW_RESOURCE_ARRAY(char, utf8_len + 1);
    }
    return UNICODE::as_utf8(position, len, buf, utf8_len + 1);
  } else {
    jbyte *position = (len == 0) ? NULL : value->byte_at_addr(0);
    utf8_len = UNICODE::utf8_length(position, len);
    if (utf8_len >= buflen) {
      buf = NEW_RESOURCE_ARRAY(char, utf8_len + 1);
    }
    return UNICODE::as_utf8(position, len, buf, utf8_len + 1);
  }
}

char* java_lang_String::as_utf8_string(oop java_string, typeArrayOop value, char* buf, int buflen) {
  assert(value_equals(value, java_lang_String::value(java_string)),
         "value must be same as java_lang_String::value(java_string)");
  int     length = java_lang_String::length(java_string, value);
  bool is_latin1 = java_lang_String::is_latin1(java_string);
  if (!is_latin1) {
    jchar* position = (length == 0) ? NULL : value->char_at_addr(0);
    return UNICODE::as_utf8(position, length, buf, buflen);
  } else {
    jbyte* position = (length == 0) ? NULL : value->byte_at_addr(0);
    return UNICODE::as_utf8(position, length, buf, buflen);
  }
}

char* java_lang_String::as_utf8_string(oop java_string, char* buf, int buflen) {
  typeArrayOop value = java_lang_String::value(java_string);
  return as_utf8_string(java_string, value, buf, buflen);
}

char* java_lang_String::as_utf8_string(oop java_string, int start, int len) {
  typeArrayOop value  = java_lang_String::value(java_string);
  bool      is_latin1 = java_lang_String::is_latin1(java_string);
  assert(start + len <= java_lang_String::length(java_string), "just checking");
  if (!is_latin1) {
    jchar* position = value->char_at_addr(start);
    return UNICODE::as_utf8(position, len);
  } else {
    jbyte* position = value->byte_at_addr(start);
    return UNICODE::as_utf8(position, len);
  }
}

char* java_lang_String::as_utf8_string(oop java_string, typeArrayOop value, int start, int len, char* buf, int buflen) {
  assert(value_equals(value, java_lang_String::value(java_string)),
         "value must be same as java_lang_String::value(java_string)");
  assert(start + len <= java_lang_String::length(java_string), "just checking");
  bool is_latin1 = java_lang_String::is_latin1(java_string);
  if (!is_latin1) {
    jchar* position = value->char_at_addr(start);
    return UNICODE::as_utf8(position, len, buf, buflen);
  } else {
    jbyte* position = value->byte_at_addr(start);
    return UNICODE::as_utf8(position, len, buf, buflen);
  }
}

bool java_lang_String::equals(oop java_string, const jchar* chars, int len) {
  assert(java_string->klass() == vmClasses::String_klass(),
         "must be java_string");
  typeArrayOop value = java_lang_String::value_no_keepalive(java_string);
  int length = java_lang_String::length(java_string, value);
  if (length != len) {
    return false;
  }
  bool is_latin1 = java_lang_String::is_latin1(java_string);
  if (!is_latin1) {
    for (int i = 0; i < len; i++) {
      if (value->char_at(i) != chars[i]) {
        return false;
      }
    }
  } else {
    for (int i = 0; i < len; i++) {
      if ((((jchar) value->byte_at(i)) & 0xff) != chars[i]) {
        return false;
      }
    }
  }
  return true;
}

bool java_lang_String::equals(oop str1, oop str2) {
  assert(str1->klass() == vmClasses::String_klass(),
         "must be java String");
  assert(str2->klass() == vmClasses::String_klass(),
         "must be java String");
  typeArrayOop value1    = java_lang_String::value_no_keepalive(str1);
  bool         is_latin1 = java_lang_String::is_latin1(str1);
  typeArrayOop value2    = java_lang_String::value_no_keepalive(str2);
  bool         is_latin2 = java_lang_String::is_latin1(str2);

  if (is_latin1 != is_latin2) {
    // Strings with different coders are never equal.
    return false;
  }
  return value_equals(value1, value2);
}

void java_lang_String::print(oop java_string, outputStream* st) {
  assert(java_string->klass() == vmClasses::String_klass(), "must be java_string");
  typeArrayOop value  = java_lang_String::value_no_keepalive(java_string);

  if (value == NULL) {
    // This can happen if, e.g., printing a String
    // object before its initializer has been called
    st->print("NULL");
    return;
  }

  int length = java_lang_String::length(java_string, value);
  bool is_latin1 = java_lang_String::is_latin1(java_string);

  st->print("\"");
  for (int index = 0; index < length; index++) {
    st->print("%c", (!is_latin1) ?  value->char_at(index) :
                           ((jchar) value->byte_at(index)) & 0xff );
  }
  st->print("\"");
}

// java_lang_Class

int java_lang_Class::_klass_offset;
int java_lang_Class::_array_klass_offset;
int java_lang_Class::_oop_size_offset;
int java_lang_Class::_static_oop_field_count_offset;
int java_lang_Class::_class_loader_offset;
int java_lang_Class::_module_offset;
int java_lang_Class::_protection_domain_offset;
int java_lang_Class::_component_mirror_offset;
int java_lang_Class::_signers_offset;
int java_lang_Class::_name_offset;
int java_lang_Class::_source_file_offset;
int java_lang_Class::_classData_offset;
int java_lang_Class::_classRedefinedCount_offset;

bool java_lang_Class::_offsets_computed = false;
GrowableArray<Klass*>* java_lang_Class::_fixup_mirror_list = NULL;
GrowableArray<Klass*>* java_lang_Class::_fixup_module_field_list = NULL;

#ifdef ASSERT
inline static void assert_valid_static_string_field(fieldDescriptor* fd) {
  assert(fd->has_initial_value(), "caller should have checked this");
  assert(fd->field_type() == T_OBJECT, "caller should have checked this");
  // Can't use vmSymbols::string_signature() as fd->signature() may have been relocated
  // during DumpSharedSpaces
  assert(fd->signature()->equals("Ljava/lang/String;"), "just checking");
}
#endif

static void initialize_static_string_field(fieldDescriptor* fd, Handle mirror, TRAPS) {
  DEBUG_ONLY(assert_valid_static_string_field(fd);)
  oop string = fd->string_initial_value(CHECK);
  mirror()->obj_field_put(fd->offset(), string);
}

#if INCLUDE_CDS_JAVA_HEAP
static void initialize_static_string_field_for_dump(fieldDescriptor* fd, Handle mirror) {
  DEBUG_ONLY(assert_valid_static_string_field(fd);)
  assert(DumpSharedSpaces, "must be");
  assert(HeapShared::is_archived_object_during_dumptime(mirror()), "must be");
  // Archive the String field and update the pointer.
  oop s = mirror()->obj_field(fd->offset());
  oop archived_s = StringTable::create_archived_string(s);
  mirror()->obj_field_put(fd->offset(), archived_s);
}
#endif

static void initialize_static_primitive_field(fieldDescriptor* fd, Handle mirror) {
  assert(fd->has_initial_value(), "caller should have checked this");
  BasicType t = fd->field_type();
  switch (t) {
  case T_BYTE:
    mirror()->byte_field_put(fd->offset(), fd->int_initial_value());
    break;
  case T_BOOLEAN:
    mirror()->bool_field_put(fd->offset(), fd->int_initial_value());
    break;
  case T_CHAR:
    mirror()->char_field_put(fd->offset(), fd->int_initial_value());
    break;
  case T_SHORT:
    mirror()->short_field_put(fd->offset(), fd->int_initial_value());
    break;
  case T_INT:
    mirror()->int_field_put(fd->offset(), fd->int_initial_value());
    break;
  case T_FLOAT:
    mirror()->float_field_put(fd->offset(), fd->float_initial_value());
    break;
  case T_DOUBLE:
    mirror()->double_field_put(fd->offset(), fd->double_initial_value());
    break;
  case T_LONG:
    mirror()->long_field_put(fd->offset(), fd->long_initial_value());
    break;
  default:
    // Illegal ConstantValue attribute in class file should have been
    // caught during classfile parsing.
    ShouldNotReachHere();
  }
}

static void initialize_static_field(fieldDescriptor* fd, Handle mirror, TRAPS) {
  assert(mirror.not_null() && fd->is_static(), "just checking");
  if (fd->has_initial_value()) {
    if (fd->field_type() != T_OBJECT) {
      initialize_static_primitive_field(fd, mirror);
    } else {
      initialize_static_string_field(fd, mirror, CHECK);
    }
  }
}

#if INCLUDE_CDS_JAVA_HEAP
static void initialize_static_field_for_dump(fieldDescriptor* fd, Handle mirror) {
  assert(mirror.not_null() && fd->is_static(), "just checking");
  if (fd->has_initial_value()) {
    if (fd->field_type() != T_OBJECT) {
      initialize_static_primitive_field(fd, mirror);
    } else {
      initialize_static_string_field_for_dump(fd, mirror);
    }
  }
}
#endif

void java_lang_Class::fixup_mirror(Klass* k, TRAPS) {
  assert(InstanceMirrorKlass::offset_of_static_fields() != 0, "must have been computed already");

  // If the offset was read from the shared archive, it was fixed up already
  if (!k->is_shared()) {
    if (k->is_instance_klass()) {
      // During bootstrap, java.lang.Class wasn't loaded so static field
      // offsets were computed without the size added it.  Go back and
      // update all the static field offsets to included the size.
      for (JavaFieldStream fs(InstanceKlass::cast(k)); !fs.done(); fs.next()) {
        if (fs.access_flags().is_static()) {
          int real_offset = fs.offset() + InstanceMirrorKlass::offset_of_static_fields();
          fs.set_offset(real_offset);
        }
      }
    }
  }

  if (k->is_shared() && k->has_archived_mirror_index()) {
    if (ArchiveHeapLoader::are_archived_mirrors_available()) {
      bool present = restore_archived_mirror(k, Handle(), Handle(), Handle(), CHECK);
      assert(present, "Missing archived mirror for %s", k->external_name());
      return;
    } else {
      k->clear_java_mirror_handle();
      k->clear_archived_mirror_index();
    }
  }
  create_mirror(k, Handle(), Handle(), Handle(), Handle(), CHECK);
}

void java_lang_Class::initialize_mirror_fields(Klass* k,
                                               Handle mirror,
                                               Handle protection_domain,
                                               Handle classData,
                                               TRAPS) {
  // Set protection domain also
  set_protection_domain(mirror(), protection_domain());

  // Initialize static fields
  InstanceKlass::cast(k)->do_local_static_fields(&initialize_static_field, mirror, CHECK);

 // Set classData
  set_class_data(mirror(), classData());
}

// Set the java.lang.Module module field in the java_lang_Class mirror
void java_lang_Class::set_mirror_module_field(JavaThread* current, Klass* k, Handle mirror, Handle module) {
  if (module.is_null()) {
    // During startup, the module may be NULL only if java.base has not been defined yet.
    // Put the class on the fixup_module_list to patch later when the java.lang.Module
    // for java.base is known. But note that since we captured the NULL module another
    // thread may have completed that initialization.

    bool javabase_was_defined = false;
    {
      MutexLocker m1(current, Module_lock);
      // Keep list of classes needing java.base module fixup
      if (!ModuleEntryTable::javabase_defined()) {
        assert(k->java_mirror() != NULL, "Class's mirror is null");
        k->class_loader_data()->inc_keep_alive();
        assert(fixup_module_field_list() != NULL, "fixup_module_field_list not initialized");
        fixup_module_field_list()->push(k);
      } else {
        javabase_was_defined = true;
      }
    }

    // If java.base was already defined then patch this particular class with java.base.
    if (javabase_was_defined) {
      ModuleEntry *javabase_entry = ModuleEntryTable::javabase_moduleEntry();
      assert(javabase_entry != NULL && javabase_entry->module() != NULL,
             "Setting class module field, " JAVA_BASE_NAME " should be defined");
      Handle javabase_handle(current, javabase_entry->module());
      set_module(mirror(), javabase_handle());
    }
  } else {
    assert(Universe::is_module_initialized() ||
           (ModuleEntryTable::javabase_defined() &&
            (module() == ModuleEntryTable::javabase_moduleEntry()->module())),
           "Incorrect java.lang.Module specification while creating mirror");
    set_module(mirror(), module());
  }
}

// Statically allocate fixup lists because they always get created.
void java_lang_Class::allocate_fixup_lists() {
  GrowableArray<Klass*>* mirror_list =
    new (mtClass) GrowableArray<Klass*>(40, mtClass);
  set_fixup_mirror_list(mirror_list);

  GrowableArray<Klass*>* module_list =
    new (mtModule) GrowableArray<Klass*>(500, mtModule);
  set_fixup_module_field_list(module_list);
}

void java_lang_Class::create_mirror(Klass* k, Handle class_loader,
                                    Handle module, Handle protection_domain,
                                    Handle classData, TRAPS) {
  assert(k != NULL, "Use create_basic_type_mirror for primitive types");
  assert(k->java_mirror() == NULL, "should only assign mirror once");

  // Use this moment of initialization to cache modifier_flags also,
  // to support Class.getModifiers().  Instance classes recalculate
  // the cached flags after the class file is parsed, but before the
  // class is put into the system dictionary.
  int computed_modifiers = k->compute_modifier_flags();
  k->set_modifier_flags(computed_modifiers);
  // Class_klass has to be loaded because it is used to allocate
  // the mirror.
  if (vmClasses::Class_klass_loaded()) {
    // Allocate mirror (java.lang.Class instance)
    oop mirror_oop = InstanceMirrorKlass::cast(vmClasses::Class_klass())->allocate_instance(k, CHECK);
    Handle mirror(THREAD, mirror_oop);
    Handle comp_mirror;

    // Setup indirection from mirror->klass
    set_klass(mirror(), k);

    InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(mirror->klass());
    assert(oop_size(mirror()) == mk->instance_size(k), "should have been set");

    set_static_oop_field_count(mirror(), mk->compute_static_oop_field_count(mirror()));

    // It might also have a component mirror.  This mirror must already exist.
    if (k->is_array_klass()) {
      if (k->is_typeArray_klass()) {
        BasicType type = TypeArrayKlass::cast(k)->element_type();
        comp_mirror = Handle(THREAD, Universe::java_mirror(type));
      } else {
        assert(k->is_objArray_klass(), "Must be");
        Klass* element_klass = ObjArrayKlass::cast(k)->element_klass();
        assert(element_klass != NULL, "Must have an element klass");
        comp_mirror = Handle(THREAD, element_klass->java_mirror());
      }
      assert(comp_mirror() != NULL, "must have a mirror");

      // Two-way link between the array klass and its component mirror:
      // (array_klass) k -> mirror -> component_mirror -> array_klass -> k
      set_component_mirror(mirror(), comp_mirror());
      // See below for ordering dependencies between field array_klass in component mirror
      // and java_mirror in this klass.
    } else {
      assert(k->is_instance_klass(), "Must be");

      initialize_mirror_fields(k, mirror, protection_domain, classData, THREAD);
      if (HAS_PENDING_EXCEPTION) {
        // If any of the fields throws an exception like OOM remove the klass field
        // from the mirror so GC doesn't follow it after the klass has been deallocated.
        // This mirror looks like a primitive type, which logically it is because it
        // it represents no class.
        set_klass(mirror(), NULL);
        return;
      }
    }

    // set the classLoader field in the java_lang_Class instance
    assert(class_loader() == k->class_loader(), "should be same");
    set_class_loader(mirror(), class_loader());

    // Setup indirection from klass->mirror
    // after any exceptions can happen during allocations.
    k->set_java_mirror(mirror);

    // Set the module field in the java_lang_Class instance.  This must be done
    // after the mirror is set.
    set_mirror_module_field(THREAD, k, mirror, module);

    if (comp_mirror() != NULL) {
      // Set after k->java_mirror() is published, because compiled code running
      // concurrently doesn't expect a k to have a null java_mirror.
      release_set_array_klass(comp_mirror(), k);
    }
  } else {
    assert(fixup_mirror_list() != NULL, "fixup_mirror_list not initialized");
    fixup_mirror_list()->push(k);
  }
}

#if INCLUDE_CDS_JAVA_HEAP
// Clears mirror fields. Static final fields with initial values are reloaded
// from constant pool. The object identity hash is in the object header and is
// not affected.
class ResetMirrorField: public FieldClosure {
 private:
  Handle _m;

 public:
  ResetMirrorField(Handle mirror) : _m(mirror) {}

  void do_field(fieldDescriptor* fd) {
    assert(DumpSharedSpaces, "dump time only");
    assert(_m.not_null(), "Mirror cannot be NULL");

    if (fd->is_static() && fd->has_initial_value()) {
      initialize_static_field_for_dump(fd, _m);
      return;
    }

    BasicType ft = fd->field_type();
    switch (ft) {
      case T_BYTE:
        _m()->byte_field_put(fd->offset(), 0);
        break;
      case T_CHAR:
        _m()->char_field_put(fd->offset(), 0);
        break;
      case T_DOUBLE:
        _m()->double_field_put(fd->offset(), 0);
        break;
      case T_FLOAT:
        _m()->float_field_put(fd->offset(), 0);
        break;
      case T_INT:
        _m()->int_field_put(fd->offset(), 0);
        break;
      case T_LONG:
        _m()->long_field_put(fd->offset(), 0);
        break;
      case T_SHORT:
        _m()->short_field_put(fd->offset(), 0);
        break;
      case T_BOOLEAN:
        _m()->bool_field_put(fd->offset(), false);
        break;
      case T_ARRAY:
      case T_OBJECT: {
        // It might be useful to cache the String field, but
        // for now just clear out any reference field
        oop o = _m()->obj_field(fd->offset());
        _m()->obj_field_put(fd->offset(), NULL);
        break;
      }
      default:
        ShouldNotReachHere();
        break;
     }
  }
};

void java_lang_Class::archive_basic_type_mirrors() {
  assert(HeapShared::can_write(), "must be");

  for (int t = T_BOOLEAN; t < T_VOID+1; t++) {
    BasicType bt = (BasicType)t;
    if (!is_reference_type(bt)) {
      oop m = Universe::java_mirror(bt);
      assert(m != NULL, "sanity");
      // Update the field at _array_klass_offset to point to the relocated array klass.
      oop archived_m = HeapShared::archive_object(m);
      assert(archived_m != NULL, "sanity");

      // Clear the fields. Just to be safe
      Klass *k = m->klass();
      Handle archived_mirror_h(Thread::current(), archived_m);
      ResetMirrorField reset(archived_mirror_h);
      InstanceKlass::cast(k)->do_nonstatic_fields(&reset);

      log_trace(cds, heap, mirror)(
        "Archived %s mirror object from " PTR_FORMAT " ==> " PTR_FORMAT,
        type2name(bt), p2i(m), p2i(archived_m));

      Universe::set_archived_basic_type_mirror_index(bt, HeapShared::append_root(archived_m));
    }
  }
}
//
// After the mirror object is successfully archived, the archived
// klass is set with _has_archived_raw_mirror flag.
//
// The _has_archived_raw_mirror flag is cleared at runtime when the
// archived mirror is restored. If archived java heap data cannot
// be used at runtime, new mirror object is created for the shared
// class. The _has_archived_raw_mirror is cleared also during the process.
oop java_lang_Class::archive_mirror(Klass* k) {
  assert(HeapShared::can_write(), "must be");

  // Mirror is already archived
  if (k->has_archived_mirror_index()) {
    assert(k->archived_java_mirror() != NULL, "no archived mirror");
    return k->archived_java_mirror();
  }

  // No mirror
  oop mirror = k->java_mirror();
  if (mirror == NULL) {
    return NULL;
  }

  if (k->is_instance_klass()) {
    InstanceKlass *ik = InstanceKlass::cast(k);
    assert(ik->signers() == NULL, "class with signer should have been excluded");

    if (!(ik->is_shared_boot_class() || ik->is_shared_platform_class() ||
          ik->is_shared_app_class())) {
      // Archiving mirror for classes from non-builtin loaders is not
      // supported.
      return NULL;
    }
  }

  // Now start archiving the mirror object
  oop archived_mirror = HeapShared::archive_object(mirror);
  if (archived_mirror == NULL) {
    return NULL;
  }

  archived_mirror = process_archived_mirror(k, mirror, archived_mirror);
  if (archived_mirror == NULL) {
    return NULL;
  }

  k->set_archived_java_mirror(archived_mirror);

  ResourceMark rm;
  log_trace(cds, heap, mirror)(
    "Archived %s mirror object from " PTR_FORMAT " ==> " PTR_FORMAT,
    k->external_name(), p2i(mirror), p2i(archived_mirror));

  return archived_mirror;
}

// The process is based on create_mirror().
oop java_lang_Class::process_archived_mirror(Klass* k, oop mirror,
                                             oop archived_mirror) {
  // Clear nonstatic fields in archived mirror. Some of the fields will be set
  // to archived metadata and objects below.
  Klass *c = archived_mirror->klass();
  Handle archived_mirror_h(Thread::current(), archived_mirror);
  ResetMirrorField reset(archived_mirror_h);
  InstanceKlass::cast(c)->do_nonstatic_fields(&reset);

  if (k->is_array_klass()) {
    oop archived_comp_mirror;
    if (k->is_typeArray_klass()) {
      // The primitive type mirrors are already archived. Get the archived mirror.
      oop comp_mirror = component_mirror(mirror);
      archived_comp_mirror = HeapShared::find_archived_heap_object(comp_mirror);
      assert(archived_comp_mirror != NULL, "Must be");
    } else {
      assert(k->is_objArray_klass(), "Must be");
      Klass* element_klass = ObjArrayKlass::cast(k)->element_klass();
      assert(element_klass != NULL, "Must have an element klass");
      archived_comp_mirror = archive_mirror(element_klass);
      if (archived_comp_mirror == NULL) {
        return NULL;
      }
    }
    set_component_mirror(archived_mirror, archived_comp_mirror);
  } else {
    assert(k->is_instance_klass(), "Must be");

    // Reset local static fields in the mirror
    InstanceKlass::cast(k)->do_local_static_fields(&reset);

    set_protection_domain(archived_mirror, NULL);
    set_signers(archived_mirror, NULL);
    set_source_file(archived_mirror, NULL);
  }

  // clear class loader and mirror_module_field
  set_class_loader(archived_mirror, NULL);
  set_module(archived_mirror, NULL);

  return archived_mirror;
}

// Returns true if the mirror is updated, false if no archived mirror
// data is present. After the archived mirror object is restored, the
// shared klass' _has_raw_archived_mirror flag is cleared.
bool java_lang_Class::restore_archived_mirror(Klass *k,
                                              Handle class_loader, Handle module,
                                              Handle protection_domain, TRAPS) {
  // Postpone restoring archived mirror until java.lang.Class is loaded. Please
  // see more details in vmClasses::resolve_all().
  if (!vmClasses::Class_klass_loaded()) {
    assert(fixup_mirror_list() != NULL, "fixup_mirror_list not initialized");
    fixup_mirror_list()->push(k);
    return true;
  }

  oop m = k->archived_java_mirror();
  assert(m != NULL, "must have stored non-null archived mirror");

  // Sanity: clear it now to prevent re-initialization if any of the following fails
  k->clear_archived_mirror_index();

  // mirror is archived, restore
  log_debug(cds, mirror)("Archived mirror is: " PTR_FORMAT, p2i(m));
  if (ArchiveHeapLoader::is_mapped()) {
    assert(Universe::heap()->is_archived_object(m), "must be archived mirror object");
  }
  assert(as_Klass(m) == k, "must be");
  Handle mirror(THREAD, m);

  if (!k->is_array_klass()) {
    // - local static final fields with initial values were initialized at dump time

    if (protection_domain.not_null()) {
      set_protection_domain(mirror(), protection_domain());
    }
  }

  assert(class_loader() == k->class_loader(), "should be same");
  if (class_loader.not_null()) {
    set_class_loader(mirror(), class_loader());
  }

  k->set_java_mirror(mirror);

  set_mirror_module_field(THREAD, k, mirror, module);

  if (log_is_enabled(Trace, cds, heap, mirror)) {
    ResourceMark rm(THREAD);
    log_trace(cds, heap, mirror)(
        "Restored %s archived mirror " PTR_FORMAT, k->external_name(), p2i(mirror()));
  }

  return true;
}
#endif // INCLUDE_CDS_JAVA_HEAP

void java_lang_Class::fixup_module_field(Klass* k, Handle module) {
  assert(_module_offset != 0, "must have been computed already");
  set_module(k->java_mirror(), module());
}

void java_lang_Class::set_oop_size(HeapWord* java_class, size_t size) {
  assert(_oop_size_offset != 0, "must be set");
  assert(size > 0, "Oop size must be greater than zero, not " SIZE_FORMAT, size);
  assert(size <= INT_MAX, "Lossy conversion: " SIZE_FORMAT, size);
  *(int*)(((char*)java_class) + _oop_size_offset) = (int)size;
}

int  java_lang_Class::static_oop_field_count(oop java_class) {
  assert(_static_oop_field_count_offset != 0, "must be set");
  return java_class->int_field(_static_oop_field_count_offset);
}

void java_lang_Class::set_static_oop_field_count(oop java_class, int size) {
  assert(_static_oop_field_count_offset != 0, "must be set");
  java_class->int_field_put(_static_oop_field_count_offset, size);
}

oop java_lang_Class::protection_domain(oop java_class) {
  assert(_protection_domain_offset != 0, "must be set");
  return java_class->obj_field(_protection_domain_offset);
}
void java_lang_Class::set_protection_domain(oop java_class, oop pd) {
  assert(_protection_domain_offset != 0, "must be set");
  java_class->obj_field_put(_protection_domain_offset, pd);
}

void java_lang_Class::set_component_mirror(oop java_class, oop comp_mirror) {
  assert(_component_mirror_offset != 0, "must be set");
    java_class->obj_field_put(_component_mirror_offset, comp_mirror);
  }
oop java_lang_Class::component_mirror(oop java_class) {
  assert(_component_mirror_offset != 0, "must be set");
  return java_class->obj_field(_component_mirror_offset);
}

objArrayOop java_lang_Class::signers(oop java_class) {
  assert(_signers_offset != 0, "must be set");
  return (objArrayOop)java_class->obj_field(_signers_offset);
}
void java_lang_Class::set_signers(oop java_class, objArrayOop signers) {
  assert(_signers_offset != 0, "must be set");
  java_class->obj_field_put(_signers_offset, signers);
}

oop java_lang_Class::class_data(oop java_class) {
  assert(_classData_offset != 0, "must be set");
  return java_class->obj_field(_classData_offset);
}
void java_lang_Class::set_class_data(oop java_class, oop class_data) {
  assert(_classData_offset != 0, "must be set");
  java_class->obj_field_put(_classData_offset, class_data);
}

void java_lang_Class::set_class_loader(oop java_class, oop loader) {
  assert(_class_loader_offset != 0, "offsets should have been initialized");
  java_class->obj_field_put(_class_loader_offset, loader);
}

oop java_lang_Class::class_loader(oop java_class) {
  assert(_class_loader_offset != 0, "must be set");
  return java_class->obj_field(_class_loader_offset);
}

oop java_lang_Class::module(oop java_class) {
  assert(_module_offset != 0, "must be set");
  return java_class->obj_field(_module_offset);
}

void java_lang_Class::set_module(oop java_class, oop module) {
  assert(_module_offset != 0, "must be set");
  java_class->obj_field_put(_module_offset, module);
}

oop java_lang_Class::name(Handle java_class, TRAPS) {
  assert(_name_offset != 0, "must be set");
  oop o = java_class->obj_field(_name_offset);
  if (o == NULL) {
    o = StringTable::intern(as_external_name(java_class()), THREAD);
    java_class->obj_field_put(_name_offset, o);
  }
  return o;
}

oop java_lang_Class::source_file(oop java_class) {
  assert(_source_file_offset != 0, "must be set");
  return java_class->obj_field(_source_file_offset);
}

void java_lang_Class::set_source_file(oop java_class, oop source_file) {
  assert(_source_file_offset != 0, "must be set");
  java_class->obj_field_put(_source_file_offset, source_file);
}

oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) {
  // This should be improved by adding a field at the Java level or by
  // introducing a new VM klass (see comment in ClassFileParser)
  oop java_class = InstanceMirrorKlass::cast(vmClasses::Class_klass())->allocate_instance(NULL, CHECK_NULL);
  if (type != T_VOID) {
    Klass* aklass = Universe::typeArrayKlassObj(type);
    assert(aklass != NULL, "correct bootstrap");
    release_set_array_klass(java_class, aklass);
  }
#ifdef ASSERT
  InstanceMirrorKlass* mk = InstanceMirrorKlass::cast(vmClasses::Class_klass());
  assert(static_oop_field_count(java_class) == 0, "should have been zeroed by allocation");
#endif
  return java_class;
}

void java_lang_Class::set_klass(oop java_class, Klass* klass) {
  assert(is_instance(java_class), "must be a Class object");
  java_class->metadata_field_put(_klass_offset, klass);
}


void java_lang_Class::print_signature(oop java_class, outputStream* st) {
  assert(is_instance(java_class), "must be a Class object");
  Symbol* name = NULL;
  bool is_instance = false;
  if (is_primitive(java_class)) {
    name = vmSymbols::type_signature(primitive_type(java_class));
  } else {
    Klass* k = as_Klass(java_class);
    is_instance = k->is_instance_klass();
    name = k->name();
  }
  if (name == NULL) {
    st->print("");
    return;
  }
  if (is_instance)  st->print("L");
  st->write((char*) name->base(), (int) name->utf8_length());
  if (is_instance)  st->print(";");
}

Symbol* java_lang_Class::as_signature(oop java_class, bool intern_if_not_found) {
  assert(is_instance(java_class), "must be a Class object");
  Symbol* name;
  if (is_primitive(java_class)) {
    name = vmSymbols::type_signature(primitive_type(java_class));
    // Because this can create a new symbol, the caller has to decrement
    // the refcount, so make adjustment here and below for symbols returned
    // that are not created or incremented due to a successful lookup.
    name->increment_refcount();
  } else {
    Klass* k = as_Klass(java_class);
    if (!k->is_instance_klass()) {
      name = k->name();
      name->increment_refcount();
    } else {
      ResourceMark rm;
      const char* sigstr = k->signature_name();
      int         siglen = (int) strlen(sigstr);
      if (!intern_if_not_found) {
        name = SymbolTable::probe(sigstr, siglen);
      } else {
        name = SymbolTable::new_symbol(sigstr, siglen);
      }
    }
  }
  return name;
}

// Returns the Java name for this Java mirror (Resource allocated)
// See Klass::external_name().
// For primitive type Java mirrors, its type name is returned.
const char* java_lang_Class::as_external_name(oop java_class) {
  assert(is_instance(java_class), "must be a Class object");
  const char* name = NULL;
  if (is_primitive(java_class)) {
    name = type2name(primitive_type(java_class));
  } else {
    name = as_Klass(java_class)->external_name();
  }
  if (name == NULL) {
    name = "";
  }
  return name;
}

Klass* java_lang_Class::array_klass_acquire(oop java_class) {
  Klass* k = ((Klass*)java_class->metadata_field_acquire(_array_klass_offset));
  assert(k == NULL || k->is_klass() && k->is_array_klass(), "should be array klass");
  return k;
}


void java_lang_Class::release_set_array_klass(oop java_class, Klass* klass) {
  assert(klass->is_klass() && klass->is_array_klass(), "should be array klass");
  java_class->release_metadata_field_put(_array_klass_offset, klass);
}


BasicType java_lang_Class::primitive_type(oop java_class) {
  assert(is_primitive(java_class), "just checking");
  Klass* ak = ((Klass*)java_class->metadata_field(_array_klass_offset));
  BasicType type = T_VOID;
  if (ak != NULL) {
    // Note: create_basic_type_mirror above initializes ak to a non-null value.
    type = ArrayKlass::cast(ak)->element_type();
  } else {
    assert(java_class == Universe::void_mirror(), "only valid non-array primitive");
  }
  assert(Universe::java_mirror(type) == java_class, "must be consistent");
  return type;
}

BasicType java_lang_Class::as_BasicType(oop java_class, Klass** reference_klass) {
  assert(is_instance(java_class), "must be a Class object");
  if (is_primitive(java_class)) {
    if (reference_klass != NULL)
      (*reference_klass) = NULL;
    return primitive_type(java_class);
  } else {
    if (reference_klass != NULL)
      (*reference_klass) = as_Klass(java_class);
    return T_OBJECT;
  }
}


oop java_lang_Class::primitive_mirror(BasicType t) {
  oop mirror = Universe::java_mirror(t);
  assert(mirror != NULL && mirror->is_a(vmClasses::Class_klass()), "must be a Class");
  assert(is_primitive(mirror), "must be primitive");
  return mirror;
}

#define CLASS_FIELDS_DO(macro) \
  macro(_classRedefinedCount_offset, k, "classRedefinedCount", int_signature,         false); \
  macro(_class_loader_offset,        k, "classLoader",         classloader_signature, false); \
  macro(_component_mirror_offset,    k, "componentType",       class_signature,       false); \
  macro(_module_offset,              k, "module",              module_signature,      false); \
  macro(_name_offset,                k, "name",                string_signature,      false); \
  macro(_classData_offset,           k, "classData",           object_signature,      false);

void java_lang_Class::compute_offsets() {
  if (_offsets_computed) {
    return;
  }

  _offsets_computed = true;

  InstanceKlass* k = vmClasses::Class_klass();
  CLASS_FIELDS_DO(FIELD_COMPUTE_OFFSET);

  CLASS_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
}

#if INCLUDE_CDS
void java_lang_Class::serialize_offsets(SerializeClosure* f) {
  f->do_bool(&_offsets_computed);

  CLASS_FIELDS_DO(FIELD_SERIALIZE_OFFSET);

  CLASS_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);
}
#endif

int java_lang_Class::classRedefinedCount(oop the_class_mirror) {
  assert(_classRedefinedCount_offset != 0, "offsets should have been initialized");
  return the_class_mirror->int_field(_classRedefinedCount_offset);
}

void java_lang_Class::set_classRedefinedCount(oop the_class_mirror, int value) {
  assert(_classRedefinedCount_offset != 0, "offsets should have been initialized");
  the_class_mirror->int_field_put(_classRedefinedCount_offset, value);
}


// Note: JDK1.1 and before had a privateInfo_offset field which was used for the
//       platform thread structure, and a eetop offset which was used for thread
//       local storage (and unused by the HotSpot VM). In JDK1.2 the two structures
//       merged, so in the HotSpot VM we just use the eetop field for the thread
//       instead of the privateInfo_offset.
//
// Note: The stackSize field is only present starting in 1.4.

int java_lang_Thread_FieldHolder::_group_offset;
int java_lang_Thread_FieldHolder::_priority_offset;
int java_lang_Thread_FieldHolder::_stackSize_offset;
int java_lang_Thread_FieldHolder::_daemon_offset;
int java_lang_Thread_FieldHolder::_thread_status_offset;

#define THREAD_FIELD_HOLDER_FIELDS_DO(macro) \
  macro(_group_offset,         k, vmSymbols::group_name(),    threadgroup_signature, false); \
  macro(_priority_offset,      k, vmSymbols::priority_name(), int_signature,         false); \
  macro(_stackSize_offset,     k, "stackSize",                long_signature,        false); \
  macro(_daemon_offset,        k, vmSymbols::daemon_name(),   bool_signature,        false); \
  macro(_thread_status_offset, k, "threadStatus",             int_signature,         false)

void java_lang_Thread_FieldHolder::compute_offsets() {
  assert(_group_offset == 0, "offsets should be initialized only once");

  InstanceKlass* k = vmClasses::Thread_FieldHolder_klass();
  THREAD_FIELD_HOLDER_FIELDS_DO(FIELD_COMPUTE_OFFSET);
}

#if INCLUDE_CDS
void java_lang_Thread_FieldHolder::serialize_offsets(SerializeClosure* f) {
  THREAD_FIELD_HOLDER_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
}
#endif

oop java_lang_Thread_FieldHolder::threadGroup(oop holder) {
  return holder->obj_field(_group_offset);
}

ThreadPriority java_lang_Thread_FieldHolder::priority(oop holder) {
  return (ThreadPriority)holder->int_field(_priority_offset);
}

void java_lang_Thread_FieldHolder::set_priority(oop holder, ThreadPriority priority) {
  holder->int_field_put(_priority_offset, priority);
}

jlong java_lang_Thread_FieldHolder::stackSize(oop holder) {
  return holder->long_field(_stackSize_offset);
}

bool java_lang_Thread_FieldHolder::is_daemon(oop holder) {
  return holder->bool_field(_daemon_offset) != 0;
}

void java_lang_Thread_FieldHolder::set_daemon(oop holder) {
  holder->bool_field_put(_daemon_offset, true);
}

void java_lang_Thread_FieldHolder::set_thread_status(oop holder, JavaThreadStatus status) {
  holder->int_field_put(_thread_status_offset, static_cast<int>(status));
}

JavaThreadStatus java_lang_Thread_FieldHolder::get_thread_status(oop holder) {
  return static_cast<JavaThreadStatus>(holder->int_field(_thread_status_offset));
}


int java_lang_Thread_Constants::_static_VTHREAD_GROUP_offset = 0;
int java_lang_Thread_Constants::_static_NOT_SUPPORTED_CLASSLOADER_offset = 0;

#define THREAD_CONSTANTS_STATIC_FIELDS_DO(macro) \
  macro(_static_VTHREAD_GROUP_offset,             k, "VTHREAD_GROUP",             threadgroup_signature, true); \
  macro(_static_NOT_SUPPORTED_CLASSLOADER_offset, k, "NOT_SUPPORTED_CLASSLOADER", classloader_signature, true);

void java_lang_Thread_Constants::compute_offsets() {
  assert(_static_VTHREAD_GROUP_offset == 0, "offsets should be initialized only once");

  InstanceKlass* k = vmClasses::Thread_Constants_klass();
  THREAD_CONSTANTS_STATIC_FIELDS_DO(FIELD_COMPUTE_OFFSET);
}

#if INCLUDE_CDS
void java_lang_Thread_Constants::serialize_offsets(SerializeClosure* f) {
  THREAD_CONSTANTS_STATIC_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
}
#endif

oop java_lang_Thread_Constants::get_VTHREAD_GROUP() {
  InstanceKlass* k = vmClasses::Thread_Constants_klass();
  oop base = k->static_field_base_raw();
  return base->obj_field(_static_VTHREAD_GROUP_offset);
}

oop java_lang_Thread_Constants::get_NOT_SUPPORTED_CLASSLOADER() {
  InstanceKlass* k = vmClasses::Thread_Constants_klass();
  oop base = k->static_field_base_raw();
  return base->obj_field(_static_NOT_SUPPORTED_CLASSLOADER_offset);
}

int java_lang_Thread::_holder_offset;
int java_lang_Thread::_name_offset;
int java_lang_Thread::_contextClassLoader_offset;
int java_lang_Thread::_inheritedAccessControlContext_offset;
int java_lang_Thread::_eetop_offset;
int java_lang_Thread::_jvmti_thread_state_offset;
int java_lang_Thread::_interrupted_offset;
int java_lang_Thread::_tid_offset;
int java_lang_Thread::_continuation_offset;
int java_lang_Thread::_park_blocker_offset;
int java_lang_Thread::_scopedValueBindings_offset;
JFR_ONLY(int java_lang_Thread::_jfr_epoch_offset;)

#define THREAD_FIELDS_DO(macro) \
  macro(_holder_offset,        k, "holder", thread_fieldholder_signature, false); \
  macro(_name_offset,          k, vmSymbols::name_name(), string_signature, false); \
  macro(_contextClassLoader_offset, k, vmSymbols::contextClassLoader_name(), classloader_signature, false); \
  macro(_inheritedAccessControlContext_offset, k, vmSymbols::inheritedAccessControlContext_name(), accesscontrolcontext_signature, false); \
  macro(_eetop_offset,         k, "eetop", long_signature, false); \
  macro(_interrupted_offset,   k, "interrupted", bool_signature, false); \
  macro(_tid_offset,           k, "tid", long_signature, false); \
  macro(_park_blocker_offset,  k, "parkBlocker", object_signature, false); \
  macro(_continuation_offset,  k, "cont", continuation_signature, false); \
  macro(_scopedValueBindings_offset, k, "scopedValueBindings", object_signature, false);

void java_lang_Thread::compute_offsets() {
  assert(_holder_offset == 0, "offsets should be initialized only once");

  InstanceKlass* k = vmClasses::Thread_klass();
  THREAD_FIELDS_DO(FIELD_COMPUTE_OFFSET);
  THREAD_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
}

#if INCLUDE_CDS
void java_lang_Thread::serialize_offsets(SerializeClosure* f) {
  THREAD_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
  THREAD_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);
}
#endif

JavaThread* java_lang_Thread::thread(oop java_thread) {
  return (JavaThread*)java_thread->address_field(_eetop_offset);
}

void java_lang_Thread::set_thread(oop java_thread, JavaThread* thread) {
  java_thread->address_field_put(_eetop_offset, (address)thread);
}

JvmtiThreadState* java_lang_Thread::jvmti_thread_state(oop java_thread) {
  return (JvmtiThreadState*)java_thread->address_field(_jvmti_thread_state_offset);
}

void java_lang_Thread::set_jvmti_thread_state(oop java_thread, JvmtiThreadState* state) {
  java_thread->address_field_put(_jvmti_thread_state_offset, (address)state);
}

void java_lang_Thread::clear_scopedValueBindings(oop java_thread) {
  assert(java_thread != NULL, "need a java_lang_Thread pointer here");
  java_thread->obj_field_put(_scopedValueBindings_offset, NULL);
}

oop java_lang_Thread::holder(oop java_thread) {
    return java_thread->obj_field(_holder_offset);
}

bool java_lang_Thread::interrupted(oop java_thread) {
  // Make sure the caller can safely access oops.
  assert(Thread::current()->is_VM_thread() ||
         (JavaThread::current()->thread_state() != _thread_blocked &&
          JavaThread::current()->thread_state() != _thread_in_native),
         "Unsafe access to oop");
  return java_thread->bool_field_volatile(_interrupted_offset);
}

void java_lang_Thread::set_interrupted(oop java_thread, bool val) {
  // Make sure the caller can safely access oops.
  assert(Thread::current()->is_VM_thread() ||
         (JavaThread::current()->thread_state() != _thread_blocked &&
          JavaThread::current()->thread_state() != _thread_in_native),
         "Unsafe access to oop");
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=94 H=90 G=91

¤ Dauer der Verarbeitung: 0.22 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge