New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8261941: Use ClassLoader for unregistered classes during -Xshare:dump #5458
8261941: Use ClassLoader for unregistered classes during -Xshare:dump #5458
Conversation
/label remove hotspot |
|
@calvinccheung The |
@calvinccheung |
Webrevs
|
@@ -466,16 +473,16 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS | |||
_interfaces->length(), k->local_interfaces()->length()); | |||
} | |||
|
|||
// This tells JVM_FindLoadedClass to not find this class. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment can be deleted.
The class k
used to be defined by the boot loader. As a result, when JVM_FindLoadedClass
looked up a class in the boot/platform/app loaders, it may inadvertently find k
.
However, after this PR, k
is no longer defined by the boot loader.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the comment.
return k; | ||
} | ||
|
||
class URLClassLoaderTable : public ResourceHashtable< |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should try to decouple the loading of unregistered classes from ClassLoader/ClassloaderExt. Maybe these new functions can be placed in a new file, shared/cds/unregisteredClasses.cpp, and the API entry point would be UnregisteredClasses::load_class(name, path)
.
Also, ClassLoaderExt::find_classpath_entry_from_cache
shouldn't be needed anymore. If the JAR file doesn't exist, URLClassLoader will throw an exception, so we don't need to create a ClassPathEntry just to check for the JAR file's existence.
I wonder if there's any code in classLoader.cpp that was used only for supporting the loading of unregistered classes. If so, it can be removed, too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should try to decouple the loading of unregistered classes from ClassLoader/ClassloaderExt. Maybe these new functions can be placed in a new file, shared/cds/unregisteredClasses.cpp, and the API entry point would be
UnregisteredClasses::load_class(name, path)
.
I've moved the new code to unregistedClasses.[c|h]pp.
Also,
ClassLoaderExt::find_classpath_entry_from_cache
shouldn't be needed anymore. If the JAR file doesn't exist, URLClassLoader will throw an exception, so we don't need to create a ClassPathEntry just to check for the JAR file's existence.
As we've discussed off-line, after removing the ClassLoaderExt::find_classpath_entry_from_cache
, the calculation of the length and crc of the ClassFileSteam will be performed in jvm_define_class_common()
.
I wonder if there's any code in classLoader.cpp that was used only for supporting the loading of unregistered classes. If so, it can be removed, too.
I don't see any functions in classLoader.cpp could be removed. However, I think the ClassLoader::record_result()
could be simplified since it is no longer called with unregistered classes. I'd prefer handle the simplification in a follow-up bug.
|
||
class URLClassLoaderTable : public ResourceHashtable< | ||
Symbol*, Handle, | ||
7, // prime number |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think 7 is too small. Maybe 137?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. I've increased it to 137.
|
||
Handle ClassLoaderExt::create_and_add_url_classloader(Symbol* path, TRAPS) { | ||
Handle url_classloader = create_url_classloader(path, CHECK_NH); | ||
bool added = _url_classloader_table->put(path, url_classloader); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added is not used. Did you want to assert that added == true
?
I think it's better to move the body of this function to line 342. Then it would be clear that the entry doesn't exist (and there's no need to check for added
).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Modified per your suggestions and I don't need to keep the bool variable.
if (_url_classloader_table == NULL) { | ||
_url_classloader_table = new (ResourceObj::C_HEAP, mtClass)URLClassLoaderTable(); | ||
Handle url_classloader = create_and_add_url_classloader(path, CHECK_NH); | ||
return url_classloader; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the above 2 lines should be removed and the creation should be done in a single place. This means _url_classloader_table->get()
would be unnecessarily called when the table is created, but I think that's OK since this happens only once.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
CHECK_NULL); | ||
assert(result.get_type() == T_OBJECT, "just checking"); | ||
oop obj = result.get_oop(); | ||
InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(obj)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for the temp variable k
since it's immediately returned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed.
…_class_misc_info() is being called in ClassLoader::record_result(); 2. remove UnregisteredClasses::seen_classloader(); 3. remove call to ClassLoaderExt::record_result() in ClassListParser::load_class_from_source() since it is being called in ClassLoader::record_result().
if (k->local_interfaces()->length() != _interfaces->length()) { | ||
print_specified_interfaces(); | ||
print_actual_interfaces(k); | ||
error("The number of interfaces (%d) specified in class list does not match the class file (%d)", | ||
_interfaces->length(), k->local_interfaces()->length()); | ||
} | ||
|
||
k->clear_shared_class_loader_type(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this may not be necessary, as the correct loader type should have been set inside ClassLoaderExt::record_result(). Maybe change this to?
assert(k->is_shared_unregistered_class(), "must be");
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've changed it to assert. Also removed the clear_shared_class_loader_type()
since it is not used anymore.
The class loader type is not set not due to the call to ClassLoaderExt::record_result()
which will default the loader type to boot loader. For unregistered classes, the ClassLoaderExt::record_result()
won't be called in ClassLoader::record_result()
.
} else { | ||
return false; | ||
} | ||
return add_unregistered_class(current, k); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this function is now just a pass-through to add_unregistered_class()
, maybe we should delete this function, and make add_unregistered_class()
public?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've made the change. The add_unregistered_class()
is already declared public.
@calvinccheung This change now passes all automated pre-integration checks. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 114 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details.
|
Going to push as commit 12fa707.
Your commit was automatically rebased without conflicts. |
@calvinccheung Pushed as commit 12fa707. |
Before this change, unregistered classes are loaded by the boot class loader during CDS dump time.
This RFE creates an URLClassLoader based on the source specified in the classlist and uses the URLClassLoader to load the unregistered class during CDS dump time. The URLClassLoader instances will be cached in a hash table with the source as the key so that classes associated with the same source will be loaded by the same instance of class loader.
Passed tiers 1 - 4 testing.
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/5458/head:pull/5458
$ git checkout pull/5458
Update a local copy of the PR:
$ git checkout pull/5458
$ git pull https://git.openjdk.java.net/jdk pull/5458/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 5458
View PR using the GUI difftool:
$ git pr show -t 5458
Using diff file
Download this PR as a diff file:
https://git.openjdk.java.net/jdk/pull/5458.diff