src/hotspot/share/classfile/classLoaderExt.cpp
changeset 48138 78b2ecdd3c4b
parent 47216 71c04702a3d5
child 49340 4e82736053ae
equal deleted inserted replaced
48137:0afc5f9eafef 48138:78b2ecdd3c4b
     1 /*
     1 /*
     2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     7  * published by the Free Software Foundation.
    21  * questions.
    21  * questions.
    22  *
    22  *
    23  */
    23  */
    24 
    24 
    25 #include "precompiled.hpp"
    25 #include "precompiled.hpp"
       
    26 #include "classfile/classFileParser.hpp"
       
    27 #include "classfile/classFileStream.hpp"
    26 #include "classfile/classListParser.hpp"
    28 #include "classfile/classListParser.hpp"
       
    29 #include "classfile/classLoader.hpp"
    27 #include "classfile/classLoaderExt.hpp"
    30 #include "classfile/classLoaderExt.hpp"
    28 #include "classfile/symbolTable.hpp"
    31 #include "classfile/classLoaderData.inline.hpp"
    29 #include "classfile/systemDictionary.hpp"
    32 #include "classfile/klassFactory.hpp"
    30 
    33 #include "classfile/sharedClassUtil.hpp"
       
    34 #include "classfile/sharedPathsMiscInfo.hpp"
       
    35 #include "classfile/systemDictionaryShared.hpp"
       
    36 #include "classfile/vmSymbols.hpp"
       
    37 #include "memory/allocation.inline.hpp"
       
    38 #include "memory/filemap.hpp"
       
    39 #include "memory/resourceArea.hpp"
       
    40 #include "oops/instanceKlass.hpp"
       
    41 #include "oops/oop.inline.hpp"
       
    42 #include "oops/symbol.hpp"
       
    43 #include "runtime/arguments.hpp"
       
    44 #include "runtime/java.hpp"
       
    45 #include "runtime/javaCalls.hpp"
       
    46 #include "runtime/os.hpp"
       
    47 #include "services/threadService.hpp"
       
    48 #include "utilities/stringUtils.hpp"
       
    49 
       
    50 jshort ClassLoaderExt::_app_paths_start_index = ClassLoaderExt::max_classpath_index;
       
    51 bool ClassLoaderExt::_has_app_classes = false;
       
    52 bool ClassLoaderExt::_has_platform_classes = false;
       
    53 
       
    54 void ClassLoaderExt::setup_app_search_path() {
       
    55   assert(DumpSharedSpaces, "this function is only used with -Xshare:dump and -XX:+UseAppCDS");
       
    56   _app_paths_start_index = ClassLoader::num_boot_classpath_entries();
       
    57   char* app_class_path = os::strdup(Arguments::get_appclasspath());
       
    58 
       
    59   if (strcmp(app_class_path, ".") == 0) {
       
    60     // This doesn't make any sense, even for AppCDS, so let's skip it. We
       
    61     // don't want to throw an error here because -cp "." is usually assigned
       
    62     // by the launcher when classpath is not specified.
       
    63     trace_class_path("app loader class path (skipped)=", app_class_path);
       
    64   } else {
       
    65     trace_class_path("app loader class path=", app_class_path);
       
    66     shared_paths_misc_info()->add_app_classpath(app_class_path);
       
    67     ClassLoader::setup_app_search_path(app_class_path);
       
    68   }
       
    69 }
       
    70 
       
    71 char* ClassLoaderExt::read_manifest(ClassPathEntry* entry, jint *manifest_size, bool clean_text, TRAPS) {
       
    72   const char* name = "META-INF/MANIFEST.MF";
       
    73   char* manifest;
       
    74   jint size;
       
    75 
       
    76   assert(entry->is_jar_file(), "must be");
       
    77   manifest = (char*) ((ClassPathZipEntry*)entry )->open_entry(name, &size, true, CHECK_NULL);
       
    78 
       
    79   if (manifest == NULL) { // No Manifest
       
    80     *manifest_size = 0;
       
    81     return NULL;
       
    82   }
       
    83 
       
    84 
       
    85   if (clean_text) {
       
    86     // See http://docs.oracle.com/javase/6/docs/technotes/guides/jar/jar.html#JAR%20Manifest
       
    87     // (1): replace all CR/LF and CR with LF
       
    88     StringUtils::replace_no_expand(manifest, "\r\n", "\n");
       
    89 
       
    90     // (2) remove all new-line continuation (remove all "\n " substrings)
       
    91     StringUtils::replace_no_expand(manifest, "\n ", "");
       
    92   }
       
    93 
       
    94   *manifest_size = (jint)strlen(manifest);
       
    95   return manifest;
       
    96 }
       
    97 
       
    98 char* ClassLoaderExt::get_class_path_attr(const char* jar_path, char* manifest, jint manifest_size) {
       
    99   const char* tag = "Class-Path: ";
       
   100   const int tag_len = (int)strlen(tag);
       
   101   char* found = NULL;
       
   102   char* line_start = manifest;
       
   103   char* end = manifest + manifest_size;
       
   104 
       
   105   assert(*end == 0, "must be nul-terminated");
       
   106 
       
   107   while (line_start < end) {
       
   108     char* line_end = strchr(line_start, '\n');
       
   109     if (line_end == NULL) {
       
   110       // JAR spec require the manifest file to be terminated by a new line.
       
   111       break;
       
   112     }
       
   113     if (strncmp(tag, line_start, tag_len) == 0) {
       
   114       if (found != NULL) {
       
   115         // Same behavior as jdk/src/share/classes/java/util/jar/Attributes.java
       
   116         // If duplicated entries are found, the last one is used.
       
   117         tty->print_cr("Warning: Duplicate name in Manifest: %s.\n"
       
   118                       "Ensure that the manifest does not have duplicate entries, and\n"
       
   119                       "that blank lines separate individual sections in both your\n"
       
   120                       "manifest and in the META-INF/MANIFEST.MF entry in the jar file:\n%s\n", tag, jar_path);
       
   121       }
       
   122       found = line_start + tag_len;
       
   123       assert(found <= line_end, "sanity");
       
   124       *line_end = '\0';
       
   125     }
       
   126     line_start = line_end + 1;
       
   127   }
       
   128   return found;
       
   129 }
       
   130 
       
   131 void ClassLoaderExt::process_jar_manifest(ClassPathEntry* entry,
       
   132                                           bool check_for_duplicates) {
       
   133   Thread* THREAD = Thread::current();
       
   134   ResourceMark rm(THREAD);
       
   135   jint manifest_size;
       
   136   char* manifest = read_manifest(entry, &manifest_size, CHECK);
       
   137 
       
   138   if (manifest == NULL) {
       
   139     return;
       
   140   }
       
   141 
       
   142   if (strstr(manifest, "Extension-List:") != NULL) {
       
   143     tty->print_cr("-Xshare:dump does not support Extension-List in JAR manifest: %s", entry->name());
       
   144     vm_exit(1);
       
   145   }
       
   146 
       
   147   char* cp_attr = get_class_path_attr(entry->name(), manifest, manifest_size);
       
   148 
       
   149   if (cp_attr != NULL && strlen(cp_attr) > 0) {
       
   150     trace_class_path("found Class-Path: ", cp_attr);
       
   151 
       
   152     char sep = os::file_separator()[0];
       
   153     const char* dir_name = entry->name();
       
   154     const char* dir_tail = strrchr(dir_name, sep);
       
   155     int dir_len;
       
   156     if (dir_tail == NULL) {
       
   157       dir_len = 0;
       
   158     } else {
       
   159       dir_len = dir_tail - dir_name + 1;
       
   160     }
       
   161 
       
   162     // Split the cp_attr by spaces, and add each file
       
   163     char* file_start = cp_attr;
       
   164     char* end = file_start + strlen(file_start);
       
   165 
       
   166     while (file_start < end) {
       
   167       char* file_end = strchr(file_start, ' ');
       
   168       if (file_end != NULL) {
       
   169         *file_end = 0;
       
   170         file_end += 1;
       
   171       } else {
       
   172         file_end = end;
       
   173       }
       
   174 
       
   175       int name_len = (int)strlen(file_start);
       
   176       if (name_len > 0) {
       
   177         ResourceMark rm(THREAD);
       
   178         char* libname = NEW_RESOURCE_ARRAY(char, dir_len + name_len + 1);
       
   179         *libname = 0;
       
   180         strncat(libname, dir_name, dir_len);
       
   181         strncat(libname, file_start, name_len);
       
   182         trace_class_path("library = ", libname);
       
   183         ClassLoader::update_class_path_entry_list(libname, true, false);
       
   184       }
       
   185 
       
   186       file_start = file_end;
       
   187     }
       
   188   }
       
   189 }
       
   190 
       
   191 void ClassLoaderExt::setup_search_paths() {
       
   192   if (UseAppCDS) {
       
   193     shared_paths_misc_info()->record_app_offset();
       
   194     ClassLoaderExt::setup_app_search_path();
       
   195   }
       
   196 }
       
   197 
       
   198 Thread* ClassLoaderExt::Context::_dump_thread = NULL;
       
   199 
       
   200 bool ClassLoaderExt::check(ClassLoaderExt::Context *context,
       
   201                            const ClassFileStream* stream,
       
   202                            const int classpath_index) {
       
   203   if (stream != NULL) {
       
   204     // Ignore any App classes from signed JAR file during CDS archiving
       
   205     // dumping
       
   206     if (DumpSharedSpaces &&
       
   207         SharedClassUtil::is_classpath_entry_signed(classpath_index) &&
       
   208         classpath_index >= _app_paths_start_index) {
       
   209       tty->print_cr("Preload Warning: Skipping %s from signed JAR",
       
   210                     context->class_name());
       
   211       return false;
       
   212     }
       
   213     if (classpath_index >= _app_paths_start_index) {
       
   214       _has_app_classes = true;
       
   215       _has_platform_classes = true;
       
   216     }
       
   217   }
       
   218 
       
   219   return true;
       
   220 }
       
   221 
       
   222 void ClassLoaderExt::record_result(ClassLoaderExt::Context *context,
       
   223                                    Symbol* class_name,
       
   224                                    const s2 classpath_index,
       
   225                                    InstanceKlass* result,
       
   226                                    TRAPS) {
       
   227   assert(DumpSharedSpaces, "Sanity");
       
   228 
       
   229   // We need to remember where the class comes from during dumping.
       
   230   oop loader = result->class_loader();
       
   231   s2 classloader_type = ClassLoader::BOOT_LOADER;
       
   232   if (SystemDictionary::is_system_class_loader(loader)) {
       
   233     classloader_type = ClassLoader::APP_LOADER;
       
   234     ClassLoaderExt::set_has_app_classes();
       
   235   } else if (SystemDictionary::is_platform_class_loader(loader)) {
       
   236     classloader_type = ClassLoader::PLATFORM_LOADER;
       
   237     ClassLoaderExt::set_has_platform_classes();
       
   238   }
       
   239   result->set_shared_classpath_index(classpath_index);
       
   240   result->set_class_loader_type(classloader_type);
       
   241 }
       
   242 
       
   243 void ClassLoaderExt::finalize_shared_paths_misc_info() {
       
   244   if (UseAppCDS) {
       
   245     if (!_has_app_classes) {
       
   246       shared_paths_misc_info()->pop_app();
       
   247     }
       
   248   }
       
   249 }
       
   250 
       
   251 // Load the class of the given name from the location given by path. The path is specified by
       
   252 // the "source:" in the class list file (see classListParser.cpp), and can be a directory or
       
   253 // a JAR file.
       
   254 InstanceKlass* ClassLoaderExt::load_class(Symbol* name, const char* path, TRAPS) {
       
   255 
       
   256   assert(name != NULL, "invariant");
       
   257   assert(DumpSharedSpaces && UseAppCDS, "this function is only used with -Xshare:dump and -XX:+UseAppCDS");
       
   258   ResourceMark rm(THREAD);
       
   259   const char* class_name = name->as_C_string();
       
   260 
       
   261   const char* file_name = file_name_for_class_name(class_name,
       
   262                                                    name->utf8_length());
       
   263   assert(file_name != NULL, "invariant");
       
   264 
       
   265   // Lookup stream for parsing .class file
       
   266   ClassFileStream* stream = NULL;
       
   267   ClassPathEntry* e = find_classpath_entry_from_cache(path, CHECK_NULL);
       
   268   if (e == NULL) {
       
   269     return NULL;
       
   270   }
       
   271   {
       
   272     PerfClassTraceTime vmtimer(perf_sys_class_lookup_time(),
       
   273                                ((JavaThread*) THREAD)->get_thread_stat()->perf_timers_addr(),
       
   274                                PerfClassTraceTime::CLASS_LOAD);
       
   275     stream = e->open_stream(file_name, CHECK_NULL);
       
   276   }
       
   277 
       
   278   if (NULL == stream) {
       
   279     tty->print_cr("Preload Warning: Cannot find %s", class_name);
       
   280     return NULL;
       
   281   }
       
   282 
       
   283   assert(stream != NULL, "invariant");
       
   284   stream->set_verify(true);
       
   285 
       
   286   ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
       
   287   Handle protection_domain;
       
   288 
       
   289   InstanceKlass* result = KlassFactory::create_from_stream(stream,
       
   290                                                            name,
       
   291                                                            loader_data,
       
   292                                                            protection_domain,
       
   293                                                            NULL, // host_klass
       
   294                                                            NULL, // cp_patches
       
   295                                                            THREAD);
       
   296 
       
   297   if (HAS_PENDING_EXCEPTION) {
       
   298     tty->print_cr("Preload Error: Failed to load %s", class_name);
       
   299     return NULL;
       
   300   }
       
   301   result->set_shared_classpath_index(UNREGISTERED_INDEX);
       
   302   SystemDictionaryShared::set_shared_class_misc_info(result, stream);
       
   303   return result;
       
   304 }
       
   305 
       
   306 struct CachedClassPathEntry {
       
   307   const char* _path;
       
   308   ClassPathEntry* _entry;
       
   309 };
       
   310 
       
   311 static GrowableArray<CachedClassPathEntry>* cached_path_entries = NULL;
       
   312 
       
   313 ClassPathEntry* ClassLoaderExt::find_classpath_entry_from_cache(const char* path, TRAPS) {
       
   314   // This is called from dump time so it's single threaded and there's no need for a lock.
       
   315   assert(DumpSharedSpaces && UseAppCDS, "this function is only used with -Xshare:dump and -XX:+UseAppCDS");
       
   316   if (cached_path_entries == NULL) {
       
   317     cached_path_entries = new (ResourceObj::C_HEAP, mtClass) GrowableArray<CachedClassPathEntry>(20, /*c heap*/ true);
       
   318   }
       
   319   CachedClassPathEntry ccpe;
       
   320   for (int i=0; i<cached_path_entries->length(); i++) {
       
   321     ccpe = cached_path_entries->at(i);
       
   322     if (strcmp(ccpe._path, path) == 0) {
       
   323       if (i != 0) {
       
   324         // Put recent entries at the beginning to speed up searches.
       
   325         cached_path_entries->remove_at(i);
       
   326         cached_path_entries->insert_before(0, ccpe);
       
   327       }
       
   328       return ccpe._entry;
       
   329     }
       
   330   }
       
   331 
       
   332   struct stat st;
       
   333   if (os::stat(path, &st) != 0) {
       
   334     // File or directory not found
       
   335     return NULL;
       
   336   }
       
   337   ClassPathEntry* new_entry = NULL;
       
   338 
       
   339   new_entry = create_class_path_entry(path, &st, false, false, CHECK_NULL);
       
   340   if (new_entry == NULL) {
       
   341     return NULL;
       
   342   }
       
   343   ccpe._path = strdup(path);
       
   344   ccpe._entry = new_entry;
       
   345   cached_path_entries->insert_before(0, ccpe);
       
   346   return new_entry;
       
   347 }
    31 
   348 
    32 Klass* ClassLoaderExt::load_one_class(ClassListParser* parser, TRAPS) {
   349 Klass* ClassLoaderExt::load_one_class(ClassListParser* parser, TRAPS) {
    33   TempNewSymbol class_name_symbol = SymbolTable::new_symbol(parser->current_class_name(), THREAD);
   350   return parser->load_current_class(THREAD);
    34   guarantee(!HAS_PENDING_EXCEPTION, "Exception creating a symbol.");
   351 }
    35   return SystemDictionary::resolve_or_null(class_name_symbol, THREAD);
       
    36 }