--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/classfile/klassFactory.cpp Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,257 @@
+/*
+* Copyright (c) 2015, 2017, 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 "classfile/classFileParser.hpp"
+#include "classfile/classFileStream.hpp"
+#include "classfile/classLoader.hpp"
+#include "classfile/classLoaderData.hpp"
+#include "classfile/classLoaderData.inline.hpp"
+#include "classfile/klassFactory.hpp"
+#include "classfile/sharedClassUtil.hpp"
+#include "memory/metaspaceShared.hpp"
+#include "memory/resourceArea.hpp"
+#include "prims/jvmtiEnvBase.hpp"
+#include "prims/jvmtiRedefineClasses.hpp"
+#include "trace/traceMacros.hpp"
+
+// called during initial loading of a shared class
+InstanceKlass* KlassFactory::check_shared_class_file_load_hook(
+ InstanceKlass* ik,
+ Symbol* class_name,
+ Handle class_loader,
+ Handle protection_domain, TRAPS) {
+#if INCLUDE_CDS && INCLUDE_JVMTI
+ assert(ik != NULL, "sanity");
+ assert(ik->is_shared(), "expecting a shared class");
+
+ if (JvmtiExport::should_post_class_file_load_hook()) {
+ assert(THREAD->is_Java_thread(), "must be JavaThread");
+
+ // Post the CFLH
+ JvmtiCachedClassFileData* cached_class_file = NULL;
+ JvmtiCachedClassFileData* archived_class_data = ik->get_archived_class_data();
+ assert(archived_class_data != NULL, "shared class has no archived class data");
+ unsigned char* ptr =
+ VM_RedefineClasses::get_cached_class_file_bytes(archived_class_data);
+ unsigned char* end_ptr =
+ ptr + VM_RedefineClasses::get_cached_class_file_len(archived_class_data);
+ unsigned char* old_ptr = ptr;
+ JvmtiExport::post_class_file_load_hook(class_name,
+ class_loader,
+ protection_domain,
+ &ptr,
+ &end_ptr,
+ &cached_class_file);
+ if (old_ptr != ptr) {
+ // JVMTI agent has modified class file data.
+ // Set new class file stream using JVMTI agent modified class file data.
+ ClassLoaderData* loader_data =
+ ClassLoaderData::class_loader_data(class_loader());
+ int path_index = ik->shared_classpath_index();
+ const char* pathname;
+ if (path_index < 0) {
+ // shared classes loaded by user defined class loader
+ // do not have shared_classpath_index
+ ModuleEntry* mod_entry = ik->module();
+ if (mod_entry != NULL && (mod_entry->location() != NULL)) {
+ ResourceMark rm;
+ pathname = (const char*)(mod_entry->location()->as_C_string());
+ } else {
+ pathname = "";
+ }
+ } else {
+ SharedClassPathEntry* ent =
+ (SharedClassPathEntry*)FileMapInfo::shared_classpath(path_index);
+ pathname = ent == NULL ? NULL : ent->name();
+ }
+ ClassFileStream* stream = new ClassFileStream(ptr,
+ end_ptr - ptr,
+ pathname,
+ ClassFileStream::verify);
+ ClassFileParser parser(stream,
+ class_name,
+ loader_data,
+ protection_domain,
+ NULL,
+ NULL,
+ ClassFileParser::BROADCAST, // publicity level
+ CHECK_NULL);
+ InstanceKlass* new_ik = parser.create_instance_klass(true /* changed_by_loadhook */,
+ CHECK_NULL);
+ if (cached_class_file != NULL) {
+ new_ik->set_cached_class_file(cached_class_file);
+ }
+
+ if (class_loader.is_null()) {
+ ResourceMark rm;
+ ClassLoader::add_package(class_name->as_C_string(), path_index, THREAD);
+ }
+
+ return new_ik;
+ }
+ }
+#endif
+
+ return NULL;
+}
+
+
+static ClassFileStream* check_class_file_load_hook(ClassFileStream* stream,
+ Symbol* name,
+ ClassLoaderData* loader_data,
+ Handle protection_domain,
+ JvmtiCachedClassFileData** cached_class_file,
+ TRAPS) {
+
+ assert(stream != NULL, "invariant");
+
+ if (JvmtiExport::should_post_class_file_load_hook()) {
+ assert(THREAD->is_Java_thread(), "must be a JavaThread");
+ const JavaThread* jt = (JavaThread*)THREAD;
+
+ Handle class_loader(THREAD, loader_data->class_loader());
+
+ // Get the cached class file bytes (if any) from the class that
+ // is being redefined or retransformed. We use jvmti_thread_state()
+ // instead of JvmtiThreadState::state_for(jt) so we don't allocate
+ // a JvmtiThreadState any earlier than necessary. This will help
+ // avoid the bug described by 7126851.
+
+ JvmtiThreadState* state = jt->jvmti_thread_state();
+
+ if (state != NULL) {
+ Klass* k = state->get_class_being_redefined();
+
+ if (k != NULL) {
+ InstanceKlass* class_being_redefined = InstanceKlass::cast(k);
+ *cached_class_file = class_being_redefined->get_cached_class_file();
+ }
+ }
+
+ unsigned char* ptr = const_cast<unsigned char*>(stream->buffer());
+ unsigned char* end_ptr = ptr + stream->length();
+
+ JvmtiExport::post_class_file_load_hook(name,
+ class_loader,
+ protection_domain,
+ &ptr,
+ &end_ptr,
+ cached_class_file);
+
+ if (ptr != stream->buffer()) {
+ // JVMTI agent has modified class file data.
+ // Set new class file stream using JVMTI agent modified class file data.
+ stream = new ClassFileStream(ptr,
+ end_ptr - ptr,
+ stream->source(),
+ stream->need_verify());
+ }
+ }
+
+ return stream;
+}
+
+
+InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
+ Symbol* name,
+ ClassLoaderData* loader_data,
+ Handle protection_domain,
+ const InstanceKlass* host_klass,
+ GrowableArray<Handle>* cp_patches,
+ TRAPS) {
+ assert(stream != NULL, "invariant");
+ assert(loader_data != NULL, "invariant");
+ assert(THREAD->is_Java_thread(), "must be a JavaThread");
+
+ ResourceMark rm;
+ HandleMark hm;
+
+ JvmtiCachedClassFileData* cached_class_file = NULL;
+
+ ClassFileStream* old_stream = stream;
+
+ // Skip this processing for VM anonymous classes
+ if (host_klass == NULL) {
+ stream = check_class_file_load_hook(stream,
+ name,
+ loader_data,
+ protection_domain,
+ &cached_class_file,
+ CHECK_NULL);
+ }
+
+ ClassFileParser parser(stream,
+ name,
+ loader_data,
+ protection_domain,
+ host_klass,
+ cp_patches,
+ ClassFileParser::BROADCAST, // publicity level
+ CHECK_NULL);
+
+ InstanceKlass* result = parser.create_instance_klass(old_stream != stream, CHECK_NULL);
+ assert(result == parser.create_instance_klass(old_stream != stream, THREAD), "invariant");
+
+ if (result == NULL) {
+ return NULL;
+ }
+
+ if (cached_class_file != NULL) {
+ // JVMTI: we have an InstanceKlass now, tell it about the cached bytes
+ result->set_cached_class_file(cached_class_file);
+ }
+
+ if (InstanceKlass::should_store_fingerprint()) {
+ result->store_fingerprint(!result->is_anonymous() ? stream->compute_fingerprint() : 0);
+ }
+
+ TRACE_KLASS_CREATION(result, parser, THREAD);
+
+#if INCLUDE_CDS
+ if (DumpSharedSpaces) {
+ ClassLoader::record_shared_class_loader_type(result, stream);
+#if INCLUDE_JVMTI
+ assert(cached_class_file == NULL, "Sanity");
+ // Archive the class stream data into the optional data section
+ JvmtiCachedClassFileData *p;
+ int len;
+ const unsigned char *bytes;
+ // event based tracing might set cached_class_file
+ if ((bytes = result->get_cached_class_file_bytes()) != NULL) {
+ len = result->get_cached_class_file_len();
+ } else {
+ len = stream->length();
+ bytes = stream->buffer();
+ }
+ p = (JvmtiCachedClassFileData*)os::malloc(offset_of(JvmtiCachedClassFileData, data) + len, mtInternal);
+ p->length = len;
+ memcpy(p->data, bytes, len);
+ result->set_archived_class_data(p);
+#endif // INCLUDE_JVMTI
+ }
+#endif // INCLUDE_CDS
+
+ return result;
+}