⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chap16.html

📁 Inside the java virtualMachine,深入研究java虚拟机
💻 HTML
📖 第 1 页 / 共 3 页
字号:
</TABLE>
<P>The two opcodes for <CODE>float</CODE> comparisons (<EM><FONT FACE="Courier New">fcmpg</FONT></EM> and <EM><FONT FACE="Courier New">fcmpl</FONT></EM>) differ only in how they handle NaN&nbsp;("not a number"). In the Java Virtual Machine, comparisons of floating-point numbers always fail if one of the values being compared is NaN. If neither value being compared is NaN, both <EM><FONT FACE="Courier New">fcmpg</FONT></EM> and <EM><FONT FACE="Courier New">fcmpl</FONT></EM> instructions push a 0 if the values are equal, a 1 if value1 is greater than value2, and a -1 if value1 is less than value2. But if one or both of the values is NaN, the <EM><FONT FACE="Courier New">fcmpg</FONT></EM> instruction pushes a 1, whereas the <EM><FONT FACE="Courier New">fcmpl</FONT></EM> instruction pushes a -1. Because both of these operands are available, any comparison between two <CODE>float</CODE> values can push the same result onto the stack independent of whether the comparison failed because of a NaN. This is also true for the two opcodes that compare <CODE>double</CODE> values: <EM><FONT FACE="Courier New">dcmpg</FONT></EM> and <EM><FONT FACE="Courier New">dcmpl</FONT></EM>. </P>
<P>A fourth family of <CODE>if</CODE> opcodes, shown in Table 16-4, pops one object reference off the top of the stack and compares it with <FONT FACE="Courier New">null</FONT>. If the comparison succeeds, the Java Virtual Machine branches. </P>
<P>Table 16-4. <STRONG>Conditional branch: object reference comparison with <FONT FACE="Courier New">null</FONT></P>
</STRONG><TABLE WIDTH="500">
<TR><TD VALIGN="TOP"><STRONG>Opcode</STRONG></TD><TD VALIGN="TOP"><STRONG>Operand(s)</STRONG></TD><TD VALIGN="TOP"><STRONG>Description</STRONG></TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">ifnull</FONT></TD><TD VALIGN="TOP">branchbyte1, branchbyte2</TD><TD VALIGN="TOP">pop reference value, if value == null, branches to offset</TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">ifnonnull</FONT></TD><TD VALIGN="TOP">branchbyte1, branchbyte2</TD><TD VALIGN="TOP">pop reference value, if value != null, branches to offset</TD></TR>
</TABLE>
<P>The last family of <CODE>if</CODE> opcodes, which is shown in Table 16-5, pops two object references off the stack and compares them with each other. In this case, there are only two comparisons that make sense: "equals" and "not equals." If the references are equal, then they refer to the exact same object on the heap. If not, they refer to two different objects. As with all the other <CODE>if</CODE> opcodes, if the comparison succeeds, the Java Virtual Machine branches.</P>
<P>Table 16-5. <STRONG>Conditional branch: comparison of two object references</P>
</STRONG><TABLE WIDTH="500">
<TR><TD VALIGN="TOP"><STRONG>Opcode</STRONG></TD><TD VALIGN="TOP"><STRONG>Operand(s)</STRONG></TD><TD VALIGN="TOP"><STRONG>Description</STRONG></TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">if_acmpeq</FONT></TD><TD VALIGN="TOP">branchbyte1, branchbyte2</TD><TD VALIGN="TOP">pop reference value2 and value1, if value1 == value2, branch to offset</TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">if_acmpne</FONT></TD><TD VALIGN="TOP">branchbyte1, branchbyte2</TD><TD VALIGN="TOP">pop reference value2 and value1, if value1 != value2, branch to offset</TD></TR>
</TABLE>
<I><STRONG><P>Unconditional Branching</P>
</I></STRONG><P>That韘 all of the opcodes that cause the Java Virtual Machine to branch conditionally. One other family of opcodes, however, causes the virtual machine to branch unconditionally. Not surprisingly, these opcodes, shown in Table 16-6, are called "<EM><FONT FACE="Courier New">goto</FONT></EM>." To execute a <FONT FACE="Courier New">goto</FONT> instruction, the virtual machine forms a signed 16-bit offset from two operand bytes that follow the <FONT FACE="Courier New">goto</FONT> opcode.  (To execute a <FONT FACE="Courier New">goto_w</FONT> instruction, the virtual machine forms a signed 32-bit offset from four operand bytes that follow the <FONT FACE="Courier New">goto_w</FONT> opcode.) The virtual machine adds this offset to the current contents of the pc register. The resulting address must contain an opcode of an instruction in the current method. The virtual machine continues execution at this instruction.</P>
<P>Table 16-6. <STRONG>Unconditional branch</P>
</STRONG><TABLE WIDTH="500">
<TR><TD VALIGN="TOP"><STRONG>Opcode</STRONG></TD><TD VALIGN="TOP"><STRONG>Operand(s)</STRONG></TD><TD VALIGN="TOP"><STRONG>Description</STRONG></TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">goto</FONT></TD><TD VALIGN="TOP">branchbyte1, branchbyte2</TD><TD VALIGN="TOP">branch to offset</TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">goto</FONT>_w</TD><TD VALIGN="TOP">branchbyte1, branchbyte2, branchbyte3, branchbyte4</TD><TD VALIGN="TOP">branch to offset</TD></TR>
</TABLE>
<P>The opcodes shown in Tables 16-1 through 16-6 are sufficient to express in bytecodes the any control flow specified in Java source code with an <CODE>if</CODE>, <CODE>if-else</CODE>, <CODE>while</CODE>, <CODE>do-while</CODE>, or <CODE>for</CODE> statement. The above opcodes also could be used to express a <CODE>switch</CODE> statement, but the Java Virtual Machine's instruction set includes two opcodes specially designed for the <CODE>switch</CODE> statement: <EM><FONT FACE="Courier New">tableswitch</FONT></EM> and <EM><FONT FACE="Courier New">lookupswitch</FONT></EM>. </P>
<I><STRONG><P>Conditional Branching with Tables</P>
</I></STRONG><H3><P></H3>The <CODE>tableswitch</CODE> and <CODE>lookupswitch</CODE> instructions, shown in Table 16-7, both include one default branch offset and a variable-length set of <CODE>case</CODE> value/branch offset pairs. Both instructions pop the key (the value of the expression in the parentheses immediately following the <CODE>switch</CODE> keyword) from the stack. The key is compared with all the case values. If a match is found, the branch offset associated with the case value is taken. If no match is found, the default branch offset is taken. </P>
<P>The difference between <CODE>tableswitch</CODE> and <CODE>lookupswitch</CODE> is in how they indicate the case values. The <CODE>lookupswitch</CODE> instruction is more general-purpose than <CODE>tableswitch</CODE>, but <CODE>tableswitch</CODE> is usually more efficient. Both instructions are followed by zero to three bytes of padding--enough so that the byte immediately following the padding starts at an address that is a multiple of four bytes from the beginning of the method. (These two instructions, by the way, are the only ones in the entire Java Virtual Machine instruction set that involve alignment on a greater than one-byte boundary.) For both instructions, the next four bytes after the padding is the default branch offset. </P>
<P>After the zero- to three-byte padding and the four-byte default branch offset, the <CODE>lookupswitch</CODE> opcode is followed by a four-byte value, <EM>npairs</EM>, which indicates the number of case value/branch offset pairs that will follow. The case value is an <CODE>int</CODE>, which highlights the fact that switch statements in Java require a key expression that is an <CODE>int</CODE>, <CODE>short</CODE>, <CODE>char</CODE>, or <CODE>byte</CODE>. If you attempt to use a <CODE>long</CODE>, <CODE>float</CODE>, or <CODE>double</CODE> as a switch key, your program won't compile. The branch offset associated with each case value is another four-byte offset. The value/branch offset pairs must appear in increasing numerical order of case value.</P>
<P>In the <CODE>tableswitch</CODE> instruction, the zero- to three-byte padding and the four-byte default branch offset are followed by low and high <CODE>int</CODE> values. The low and high values indicate the endpoints of a range of case values included in this <CODE>tableswitch</CODE> instruction. Following the low and high values are high - low + 1 branch offsets--one branch offset for high, one for low, and one for each integer case value in between high and low. The branch offset for low immediately follows the high value. </P>
<P>Thus, when the Java Virtual Machine encounters a <CODE>lookupswitch</CODE> instruction, it must check the key against each case value until it finds a match, encounters a case value greater than the key (the values/branch offset pairs are sorted in increasing numerical order of case value), or runs out of case values. If it doesn韙 find a match, it uses the default branch offset. On the other hand, when the Java Virtual Machine encounters a <CODE>tableswitch</CODE> instruction, it can simply check to see if the key is within the range defined by low and high. If not, it takes the default branch offset. If so, it just subtracts low from key to get an offset into the list of branch offsets. This way, it can determine the appropriate branch offset without having to check each case value. </P>
<P>Table 16-7. <STRONG>Table jumping</P>
</STRONG><TABLE WIDTH="500">
<TR><TD VALIGN="TOP"><STRONG>Opcode</STRONG></TD><TD VALIGN="TOP"><STRONG>Operand(s)</STRONG></TD><TD VALIGN="TOP"><STRONG>Description</STRONG></TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">lookupswitch</FONT></TD><TD VALIGN="TOP">&lt;0-3 byte pad</FONT>defaultbyte1, defaultbyte2, defaultbyte3, defaultbyte4, npairs1, npairs2, <FONT FACE="Courier New"></FONT>pairs3, npairs4, case value/branch offset pairs...</TD><TD VALIGN="TOP">pop key, match key with case values, if match found jump to associated branch offset, else jump to default branch offset</TD></TR>
<TR><TD VALIGN="TOP"><FONT FACE="Courier New">tableswitch</FONT></TD><TD VALIGN="TOP">&lt;0-3 byte pad</FONT>defaultbyte1, defaultbyte2, defaultbyte3, defaultbyte4, lowbyte1, lowbyte2, lowbyte3, lowbyte4, highbyte1, highbyte2, highbyte3, highbyte4, branch offsets...</TD><TD VALIGN="TOP">pop key, if not in low/high range jump to default branch offset, else get the (key - low) branch offset and jump</TD></TR>
</TABLE>
<P>Other than the opcodes described above, the only Java Virtual Machine instructions that affect control flow are those that deal with throwing and catching exceptions, finally clauses, and invoking and returning from methods. These opcodes are discussed in later chapters.</P>
<I><STRONG><P>Saying Tomato: A Simulation</P>
</I></STRONG><H3><P></H3>The <STRONG><I>Saying Tomato</I></STRONG> applet, shown in Figure 16-1, demonstrates a Java Virtual Machine executing a sequence of bytecodes. The applet is part of a web page on the CD-ROM in file <FONT FACE="Courier New">applets/SayingTomato.html</FONT>. The bytecode sequence in the simulation was generated by the <CODE>javac</CODE> compiler for the <CODE>argue()</CODE> method of the class shown below:</P>
<PRE><P><FONT FACE="Courier New">begin</FONT></P>
<FONT SIZE="2"><P></FONT><FONT FACE="Courier New">// On CD-ROM in file opcodes/ex1/Struggle.java
<P>class Struggle {</P>
<P>&nbsp;</P>
<P>    public final static int TOMAYTO = 0;</P>
<P>    public final static int TOMAHTO = 1;</P>
<P>&nbsp;</P>
<P>    static void argue() {</P>
<P>&nbsp;</P>
<P>        int say = TOMAYTO;</P>
<P>&nbsp;</P>
<P>        for (;;) {</P>
<P>&nbsp;</P>
<P>            switch (say) {</P>
<P>&nbsp;</P>
<P>            case TOMAYTO:</P>
<P>&nbsp;</P>
<P>                say = TOMAHTO;</P>
<P>                break;</P>
<P>&nbsp;</P>
<P>            case TOMAHTO:</P>
<P>&nbsp;</P>
<P>                say = TOMAYTO;</P>
<P>                break;</P>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -