返回首页

Java字节码浅析(二)(2)

时间:2019-09-01 来源:原创/投稿/转载作者:管理员点击: 162

  这个指令用来比较栈顶的两个长整型,然后将结果值压入栈中: 如果value1value2,压入1,如果value1==value2,压入0,如果value1value2压入-1.

  fcmpcond l g dcompcond

  这组指令用来比较两个float或者double类型的值,然后然后将结果值压入栈中:如果value1value2,压入1,如果value1==value2,压入0,如果value1value2压入-1. 指令可以以l或者g结尾,不同之处在于它们是如何处理NaN的。fcmpg和dcmpg指令把整数1压入操作数栈,而fcmpl和dcmpl把-1压入操作数栈。这确保了比较两个值的时候,如果其中一个不是数字(Not A Number, NaN),比较的结果不会相等。比如判断if x y(x和y都是浮点数),就会用的fcmpl,如果其中一个值是NaN的线会被压入栈顶,下一条指令则是ifle,如果分支小于0则跳转。因此如果有一个是NaN的话,ifle会跳过if块,不让它执行。

  如果栈顶对象的类型是指定的类的线压入栈中。这个指令的操作数指定的是某个类型在常量池的序号。如果对象为空或者不是对应的类型,则将0压入操作数栈中。

  将栈顶值和0进行比较,如果条件为真,则跳转到指定的分支继续执行。这些指令通常用于较复杂的条件判断中,在一些单条指令无法完成的情况。比如验证方法调用的返回值。

  tableswitch指令里0,1,4的值和代码里的case语句一一对应,它们指向的是对应代码块的字节码。tableswitch指令同样有2,3的值,但代码中并没有对应的case语句,它们指向的是default代码块。当这条指令执行的时候,会判断操作数栈顶的值是否在最大值和最小值之间。如果不在的话,直接跳去default分支,也就是上面的42行处的字节码。为了确保能找到default分支,它都是出现在tableswitch指令的第一个字节(如果需要内存对齐的话,则在补齐了之后的第一个字节)。如果栈顶的值在最大最小值的范围内,则用它作为tableswtich内部的索引,定位到应该跳转的分支。比如1的线行处继续执行。下图会演示这条指令是如何执行的:

  如果case语句里面的值取值范围太广了(也就是太分散了)这个方法就不太好了,因为它占用的内存太多了。因此当switch的case条件里面的值比较分散的时候,就会使用lookupswitch指令。这个指令会列出case语句里的所有跳转的分支,但它没有列出所有可能的值。当执行这条指令的时候,栈顶的值会和lookupswitch里的每个值进行比较,来确定要跳转的分支。执行lookupswitch指令的时候,JVM会在列表中查找匹配的元素,这和tableswitch比起来要慢一些,因为tableswitch直接用索引就定位到正确的位置了。当switch语句编译的时候,编译器必须去权衡内存的使用和性能的影响,来决定到底该使用哪条指令。下面的代码,编译器会生成lookupswitch语句:

【责任编辑:管理员】
随机推荐 更多>>