Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/231.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 如何在Dalvik中生成调用多态操作码_Android_Dalvik_Dex - Fatal编程技术网

Android 如何在Dalvik中生成调用多态操作码

Android 如何在Dalvik中生成调用多态操作码,android,dalvik,dex,Android,Dalvik,Dex,我正在为16位板开发Dalvik字节码解释器。我已经实现并测试了大多数操作码的翻译操作,但无法测试其他一些操作码,因为我无法理解如何编写生成它们的Java代码。特别是,我无法生成调用多态性和调用自定义操作码。与Dalvik 35中的等价物一样,我正在开发Dalvik 38,我已经尝试在一个类中运行一个方法,该方法覆盖一个超类方法,如下所示: SuperClass x = new SubClass(); x.mymethod(); 这是一个教科书上简单的多态性示例,但它似乎只是生成常规的调用直接

我正在为16位板开发Dalvik字节码解释器。我已经实现并测试了大多数操作码的翻译操作,但无法测试其他一些操作码,因为我无法理解如何编写生成它们的Java代码。特别是,我无法生成调用多态性和调用自定义操作码。与Dalvik 35中的等价物一样,我正在开发Dalvik 38,我已经尝试在一个类中运行一个方法,该方法覆盖一个超类方法,如下所示:

SuperClass x = new SubClass();
x.mymethod();
这是一个教科书上简单的多态性示例,但它似乎只是生成常规的调用直接操作码

此外,我还不完全清楚方法句柄或调用站点是什么意思,以及多态调用为什么需要它们。Dalvik文档似乎没有对此进行详细阐述。

invoke polymorphic 多态性是一个相当模糊的术语。例如,方法重写或重载通常被称为多态性。在调用多态指令的情况下,该术语指的是所谓的签名多态方法

签名多态方法可以接受任何类型和数量的参数。 从java源代码的角度来看,它们的外观和行为类似于任何带有一个vararg对象的方法。。。参数,但它们在字节码级别上有所不同。虽然varargs方法是通过传递一个包含所有附加参数的数组来调用的,但这对于调用多态方法不是必需的。多态方法可以用任何描述符调用。不需要创建参数数组或基本类型的装箱参数

现有的唯一签名多态方法是和,请参阅

下面是生成调用多态指令的代码:

void foo(MethodHandle handle) throws Throwable {
    handle.invoke(10, 20);
    handle.invokeExact("foo", "bar");
}
invoke-custom {}, call_site_0("get", ()Ljava/util/function/Supplier;, ()Ljava/lang/Object;, invoke-static@LTest;->lambda$foo$0()Ljava/lang/String;, ()Ljava/lang/String;)@Ljava/lang/invoke/LambdaMetafactory;->metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;

.method private static synthetic lambda$foo$0()Ljava/lang/String;
    const-string v0, "foo"
    return-object v0
.end method
让我们编译它,运行dx并使用baksmali查看它:

调用自定义 调用自定义指令是dalvik的指令,相当于JVM的指令

动态调用不会调用静态已知的方法。它们提供用于解析调用站点的引导方法。CallSite基本上是一个包装器,它围绕着一个可能是可变的,也可能不是可变的。一旦InvokedDynamic指令的调用站点被解析,它将被JVM存储,并且从现在起,在执行该指令时被调用。整个过程在本手册中有更详细的描述

引导方法只是返回调用站点的常规java方法,必须至少有三个参数

第一个参数是一个实例,它可以访问可以从包含invokedynamic指令的方法访问的所有类/字段/方法。 第二个参数通常称为name。它是由invokedynamic指令定义的任意字符串。 第三个参数是MethodType。返回的调用站点必须与此类型完全匹配。这可以通过该方法实现。 可以传递进一步的参数。它们必须是存储在invokedynamic指令中的常量值。 注意:不要期望引导方法与上述签名完全匹配。例如,参数可以是Object类型。也可以针对一个vararg参数替换一些参数

InvokedDynamic指令是在JVM7中引入的,以支持动态语言,但java语言本身没有使用它。该指令首先在Java8中用于编译lambdas。因为java 9字符串连接是通过InvokedDynamic调用实现的

下面是生成调用动态指令的示例代码:

Supplier<String> someLambda = () -> "foo";
invoke-custom {p1, p2}, call_site_0("makeConcatWithConstants", (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/String;, "a = \u0001, b = \u0001")@Ljava/lang/invoke/StringConcatFactory;->makeConcatWithConstants(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
让我们仔细看看Java9是如何编译字符串连接的。 下面是我们的示例代码:

String foo(Object a, Object b) {
    return "a = " + a + ", b = " + b;
}
以及由此产生的指令:

Supplier<String> someLambda = () -> "foo";
invoke-custom {p1, p2}, call_site_0("makeConcatWithConstants", (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/String;, "a = \u0001, b = \u0001")@Ljava/lang/invoke/StringConcatFactory;->makeConcatWithConstants(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
首先我们有{p1,p2}。这两个寄存器是调用CallSite后作为参数传递给它的值

然后我们得到了呼叫站点0。。。块call_site_0是此callsite的名称,可用于区分其他相同的callsite。块存储一些作为参数传递给引导方法的信息

第一个值makeConcatWithConstants是作为第二个参数传递给引导方法的任意字符串。 第二个值是MethodType常量。它作为第三个参数传递给bootstrap方法,并与返回的调用站点的类型完全匹配。在本例中,我们得到了一个方法,该方法接受两个对象p1和p2,并返回一个字符串,即连接的字符串。 以下所有值都是传递给引导方法的附加常量参数。在本例中,只有一个字符串是最终连接字符串的模式。 从“@”符号开始的最后一件事是对引导方法的引用。

invoke polymorphic 多态性是一个相当模糊的术语。例如,方法重写或重载通常被称为多态性。就 调用多态性指令,这个术语指的是所谓的签名多态性方法

签名多态方法可以接受任何类型和数量的参数。 从java源代码的角度来看,它们的外观和行为类似于任何带有一个vararg对象的方法。。。参数,但它们在字节码级别上有所不同。虽然varargs方法是通过传递一个包含所有附加参数的数组来调用的,但这对于调用多态方法不是必需的。多态方法可以用任何描述符调用。不需要创建参数数组或基本类型的装箱参数

现有的唯一签名多态方法是和,请参阅

下面是生成调用多态指令的代码:

void foo(MethodHandle handle) throws Throwable {
    handle.invoke(10, 20);
    handle.invokeExact("foo", "bar");
}
invoke-custom {}, call_site_0("get", ()Ljava/util/function/Supplier;, ()Ljava/lang/Object;, invoke-static@LTest;->lambda$foo$0()Ljava/lang/String;, ()Ljava/lang/String;)@Ljava/lang/invoke/LambdaMetafactory;->metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;

.method private static synthetic lambda$foo$0()Ljava/lang/String;
    const-string v0, "foo"
    return-object v0
.end method
让我们编译它,运行dx并使用baksmali查看它:

调用自定义 调用自定义指令是dalvik的指令,相当于JVM的指令

动态调用不会调用静态已知的方法。它们提供用于解析调用站点的引导方法。CallSite基本上是一个包装器,它围绕着一个可能是可变的,也可能不是可变的。一旦InvokedDynamic指令的调用站点被解析,它将被JVM存储,并且从现在起,在执行该指令时被调用。整个过程在本手册中有更详细的描述

引导方法只是返回调用站点的常规java方法,必须至少有三个参数

第一个参数是一个实例,它可以访问可以从包含invokedynamic指令的方法访问的所有类/字段/方法。 第二个参数通常称为name。它是由invokedynamic指令定义的任意字符串。 第三个参数是MethodType。返回的调用站点必须与此类型完全匹配。这可以通过该方法实现。 可以传递进一步的参数。它们必须是存储在invokedynamic指令中的常量值。 注意:不要期望引导方法与上述签名完全匹配。例如,参数可以是Object类型。也可以针对一个vararg参数替换一些参数

InvokedDynamic指令是在JVM7中引入的,以支持动态语言,但java语言本身没有使用它。该指令首先在Java8中用于编译lambdas。因为java 9字符串连接是通过InvokedDynamic调用实现的

下面是生成调用动态指令的示例代码:

Supplier<String> someLambda = () -> "foo";
invoke-custom {p1, p2}, call_site_0("makeConcatWithConstants", (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/String;, "a = \u0001, b = \u0001")@Ljava/lang/invoke/StringConcatFactory;->makeConcatWithConstants(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
让我们仔细看看Java9是如何编译字符串连接的。 下面是我们的示例代码:

String foo(Object a, Object b) {
    return "a = " + a + ", b = " + b;
}
以及由此产生的指令:

Supplier<String> someLambda = () -> "foo";
invoke-custom {p1, p2}, call_site_0("makeConcatWithConstants", (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/String;, "a = \u0001, b = \u0001")@Ljava/lang/invoke/StringConcatFactory;->makeConcatWithConstants(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
首先我们有{p1,p2}。这两个寄存器是调用CallSite后作为参数传递给它的值

然后我们得到了呼叫站点0。。。块call_site_0是此callsite的名称,可用于区分其他相同的callsite。块存储一些作为参数传递给引导方法的信息

第一个值makeConcatWithConstants是作为第二个参数传递给引导方法的任意字符串。 第二个值是MethodType常量。它作为第三个参数传递给bootstrap方法,并与返回的调用站点的类型完全匹配。在本例中,我们得到了一个方法,该方法接受两个对象p1和p2,并返回一个字符串,即连接的字符串。 以下所有值都是传递给引导方法的附加常量参数。在本例中,只有一个字符串是最终连接字符串的模式。 从“@”符号开始的最后一件事是对引导方法的引用