This is currently the 'slow' implementation and actually slows down invokeinterface too - need to get the fast version done...
53 lines
2.8 KiB
Markdown
53 lines
2.8 KiB
Markdown
|
|
Implementation details:
|
|
|
|
catchers
|
|
========
|
|
- A catcher is added to a reloadable type as it is being loaded for the first time. A reloadable type gets
|
|
a catcher for each method it inherits from a parent but does not override, or for an abstract class each
|
|
method it receives from an interface. They basically stand in for methods that could be added in later
|
|
reloads. The catchers 'catch' virtual method dispatches. Their job is either to (a) make a simple super
|
|
call if the reloadable type does not implement the specified method (yet), or (b) if the method
|
|
has been implemented by a reload, forward to the new implementation. Catchers are not created for
|
|
private, final or static methods since those cannot be overridden. If you modify a final method in a reloadable
|
|
type to make it non final and then override it, it will be handled in a different way than catchers.
|
|
|
|
superdispatchers
|
|
================
|
|
- Where a method is protected in a non-reloadable type it is necessary to add a superdispatcher method to the
|
|
subtype so that when the executor for a new version is running it can access that protected method. The
|
|
superdispatcher is simply a public method on a type that calls super.
|
|
|
|
Generic dispatcher method __execute
|
|
===================================
|
|
|
|
The way in which we handle new methods appearing on types is that all reloadable types get a generic handler method added to
|
|
them when first loaded - this can forward it on to the new method that has appeared. The method is like this:
|
|
|
|
__execute(Object[] params, Object target, String nameAndDescriptor)
|
|
|
|
All interfaces also get this method.
|
|
|
|
(#001) Lambdas introduce a problem here. The Lambda meta factory creates anonymous classes that forward to the lambda handling
|
|
method. It does this outside of our control using a more direct form of class defining which we don't see (can't instrument). This means
|
|
these generated classes don't get an __execute. This means if a new method is added to the SAM type, although we notice it
|
|
we can't generate an __execute in the meta factory created class. This means the standard redirection of INVOKEINTERFACE which says:
|
|
does this method exist on the original form of the type? yes, then call it. no, then call the __execute telling it what we'd like to run.
|
|
Well that will fail because of the missing __execute. There are two solutions:
|
|
- modify the InnerClassLambdaMetaFactory to ensure an __execute (and relevant marker interface) are added
|
|
- change how we handle the INVOKEINTERFACE rewrite.
|
|
|
|
The second option is cheap to implement but performance will likely suck. The simplest way to do it is call the type registry to do the
|
|
suitable invoke via reflection - and it will recognize the lambda case and know what to do.
|
|
|
|
|
|
|
|
----------
|
|
Helpful snippets when debugging tests:
|
|
ClassPrinter.print(z.getLatestExecutorBytes());
|
|
Utils.dump("foo/SubControllerB", rtype.bytesLoaded);
|
|
|
|
|
|
|
|
|
|
|