gpt4 book ai didi

java - JVM 的 LookupSwitch 和 TableSwitch 的区别?

转载 作者:IT老高 更新时间:2023-10-28 20:23:30 26 4
gpt4 key购买 nike

我在理解 Java 字节码中的 LookUpSwitch 和 TableSwitch 时有些困难。

如果我理解得很好,LookUpSwitch 和 TableSwitch 都对应于 switch Java源代码的声明?为什么一个 JAVA 语句会生成 2 个不同的字节码?

每个 Jasmin 文档:

  • LookupSwitch
  • tableswitch
  • both
  • 最佳答案

    不同之处在于

  • 查找开关使用 带 key 和标签的 table
  • tableswitch 使用 一个只有标签的表格 .

  • 执行 时桌面开关 ,栈顶的int值直接作为表中的索引来抓取跳转目标并立即执行跳转。整个查找+跳转过程是一个 O(1) 操作 ,这意味着它的速度非常快。
    执行 时查找开关 ,堆栈顶部的 int 值与表中的键进行比较,直到找到匹配项,然后使用此键旁边的跳转目标执行跳转。由于查找开关表总是 必须排序 这样keyX < keyY for 每一个X < Y,整个lookup+jump的过程就是一个 O(log n) 操作 因为将使用二进制搜索算法搜索键(没有必要将 int 值与所有可能的键进行比较以找到匹配项或确定没有任何键匹配)。 O(log n) 比 O(1) 慢一些,但它仍然可以,因为许多众所周知的算法都是 O(log n) 并且这些通常被认为是快速的;甚至 O(n) 或 O(n * log n) 仍然被认为是一个很好的算法(慢/坏算法有 O(n^2)、O(n^3),甚至更糟)。
    编译器根据 switch 语句的紧凑程度来决定使用哪条指令,例如
    switch (inputValue) {
    case 1: // ...
    case 2: // ...
    case 3: // ...
    default: // ...
    }
    上面的开关非常紧凑,没有数字“孔”。编译器会像这样创建一个 tableswitch:
     tableswitch 1 3
    OneLabel
    TwoLabel
    ThreeLabel
    default: DefaultLabel
    Jasmin 页面中的伪代码很好地解释了这一点:
    int val = pop();                // pop an int from the stack
    if (val < low || val > high) { // if its less than <low> or greater than <high>,
    pc += default; // branch to default
    } else { // otherwise
    pc += table[val - low]; // branch to entry in table
    }
    这段代码非常清楚地说明了这种 tableswitch 是如何工作的。 valinputValue , low将是 1(开关中的最低值)和 high将是 3(开关中的最高值)。
    即使有一些孔,开关也可以很紧凑,例如
    switch (inputValue) {
    case 1: // ...
    case 3: // ...
    case 4: // ...
    case 5: // ...
    default: // ...
    }
    上面的开关“几乎紧凑”,它只有一个孔。编译器可以生成以下指令:
     tableswitch 1 6
    OneLabel
    FakeTwoLabel
    ThreeLabel
    FourLabel
    FiveLabel
    default: DefaultLabel

    ; <...code left out...>

    FakeTwoLabel:
    DefaultLabel:
    ; default code
    如您所见,编译器必须为 2 添加一个假 case, FakeTwoLabel .由于 2 不是开关的实际值, FakeTwoLabel实际上是一个标签,可以准确地更改默认情况所在的代码流,因为值 2 实际上应该执行默认情况。
    因此,编译器创建 tableswitch 时,开关不必非常紧凑,但它至少应该非常接近紧凑。现在考虑以下开关:
    switch (inputValue) {
    case 1: // ...
    case 10: // ...
    case 100: // ...
    case 1000: // ...
    default: // ...
    }
    这个开关远非紧凑,它的孔比值多一百倍。人们将其称为稀疏开关。编译器必须生成 近千件假货将此开关表示为 tableswitch。结果将是一个巨大的表,极大地增加了类文件的大小。这是不实用的。相反,它会生成一个查找开关:
    lookupswitch
    1 : Label1
    10 : Label10
    100 : Label100
    1000 : Label1000
    default : DefaultLabel
    这个表只有5个条目,而不是一千多个。该表有 4 个实数值,O(log 4) 是 2(这里的 log 是以 2 BTW 为底的,而不是以 10 为底的,因为计算机对二进制数进行运算)。这意味着 VM 最多需要两次比较才能找到 inputValue 的标签或得出结论,该值不在表中,因此必须执行默认值。即使该表有 100 个条目,VM 最多也需要 7 次比较才能找到正确的标签或决定跳转到默认标签(并且 7 次比较比 100 次比较少很多,你不觉得吗?)。
    所以说这两条指令可以互换或者说两条指令的原因有历史原因都是无稽之谈。对于两种不同的情况有两种指令,一种用于具有紧凑值的开关(用于最大速度),另一种用于具有稀疏值的开关(不是最大速度,但仍然具有良好的速度和非常紧凑的表格表示,无论数字孔如何)。

    关于java - JVM 的 LookupSwitch 和 TableSwitch 的区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10287700/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com