-
Notifications
You must be signed in to change notification settings - Fork 5
invoke‐polymorphic
The invoke-polymorphic
instruction was introduced alongside invoke-custom
in DEX version 038, specifically designed to call "signature polymorphic" methods like MethodHandle.invoke
and MethodHandle.invokeExact
. This functionality enables more flexible method invocation in bytecode, allowing methods to be called with a variable number and type of arguments, without the need for wrapping them in arrays or converting primitive types.
In the case of invoke-polymorphic
, "polymorphism" refers to methods capable of handling different types and numbers of arguments, known as "signature polymorphic" methods. Unlike standard methods, which require fixed parameter types and counts, signature polymorphic methods can accept any combination of argument types directly in bytecode. This contrasts with Java's usual Object...
(varargs) parameter style, where arguments are typically passed as an array of Object
s, making invoke-polymorphic
highly efficient for diverse method signatures.
Currently, the only signature polymorphic methods in Java are:
MethodHandle.invoke(Object...)
MethodHandle.invokeExact(Object...)
These methods are designed to accept different signatures, a capability defined in the JVM Specification, §2.9.3.
invoke-polymorphic {vC, vD, ...}, Ljava/lang/invoke/MethodHandle;->methodName([Ljava/lang/Object;)Ljava/lang/Object;, (Signature)ReturnType
In this structure:
-
Registers (
{vC, vD, ...}
): These contain the actual arguments for theMethodHandle
invocation. -
Method Reference (
Ljava/lang/invoke/MethodHandle;->methodName(...)
): Refers toinvoke
orinvokeExact
method, specifying the signature and return type dynamically. - Signature and Return Type: Directly specified in the instruction, allowing it to match the expected argument and return types of each invocation.
Consider this Java method that uses MethodHandle.invoke
and MethodHandle.invokeExact
:
void foo(MethodHandle handle) throws Throwable {
handle.invoke(10, 20);
handle.invokeExact("foo", "bar");
}
This code translates into Dalvik bytecode as follows:
const/16 v0, 0xa
const/16 v1, 0x14
invoke-polymorphic {p1, v0, v1}, Ljava/lang/invoke/MethodHandle;->invoke([Ljava/lang/Object;)Ljava/lang/Object;, (II)V
const-string v0, "foo"
const-string v1, "bar"
invoke-polymorphic {p1, v0, v1}, Ljava/lang/invoke/MethodHandle;->invokeExact([Ljava/lang/Object;)Ljava/lang/Object;, (Ljava/lang/String;Ljava/lang/String;)V
In this bytecode:
- The
invoke-polymorphic
instruction is used to callMethodHandle.invoke
andMethodHandle.invokeExact
directly, with arguments passed in registers ({v0, v1}
) instead of a single array. - The
(II)V
and(Ljava/lang/String;Ljava/lang/String;)V
type signatures are explicitly included, allowing theMethodHandle
to handle primitive and object types interchangeably.
-
Efficiency: Unlike varargs methods,
invoke-polymorphic
calls can handle primitive types directly without boxing, and arguments don’t need to be bundled into arrays. - Dynamic Invocation: Provides a flexible, low-overhead way to call methods dynamically in DEX, particularly beneficial for applications requiring runtime method dispatch.
-
Purpose:
invoke-custom
provides a general mechanism for dynamic method calls, whileinvoke-polymorphic
is specifically designed for signature polymorphic methods in theMethodHandle
class. -
Signature Flexibility:
invoke-polymorphic
allows different signatures for each call without needing wrappers, unlikeinvoke-custom
, which relies on thecall_site_item
structure to define a method signature statically.