📄 compiling.doc.html
字号:
Control constructs involving other data types are compiled in similar ways, but must use the instructions available for those data types. This leads to somewhat less efficient code because more Java Virtual Machine instructions are needed:<p>
<pre><br><a name="8509"></a> <code>void whileDouble() {
</code></pre><pre> <code> double i = 0.0;
</code> <code> while (i < 100.1) {
</code> <code> i++;
</code> <code> }
</code><a name="8514"></a> <code>}
</code><br></pre><a name="8516"></a>
is compiled to
<p><a name="15354"></a>
<i>Method </i><code>void</code> <code>whileDouble()<p><Table Border="0">
<tr><td> <i> 0
</i><br><td> <i>dconst_0
</i><br><td>
<tr><td> <i> 1
</i><br><td> <i>dstore_1
</i><br><td>
<tr><td> <i> 2
</i><br><td> <i>goto 9
</i><br><td>
<tr><td> <i> 5
</i><br><td> <i>dload_1
</i><br><td>
<tr><td> <i> 6
</i><br><td> <i>dconst_1
</i><br><td>
<tr><td> <i> 7
</i><br><td> <i>dadd
</i><br><td>
<tr><td> <i> 8
</i><br><td> <i>dstore_1
</i><br><td>
<tr><td> <i> 9
</i><br><td> <i>dload_1
</i><br><td>
<tr><td> <i> 10
</i><br><td> <i>ldc2_w #4
</i><br><td><i>// Double </i><code>100.100000
</code>
<tr><td> <i> 13
</i><br><td> <i>dcmpg
</i><br><td><i>// To test we have to use
</i>
<tr><td> <i> 14
</i><br><td> <i>iflt 5
</i><br><td><i>// two instructions...
</i>
<tr><td> <i> 17
</i><br><td> <i>return
</i><br><td>
</Table><br><br></code><p>
<a name="8555"></a>
Each floating-point type has two comparison instructions: <i>fcmpl</i> and <i>fcmpg</i> for type <code>float</code>, and <i>dcmpl</i> and <i>dcmpg</i> for type <code>double</code>. The variants differ only in their treatment of NaN. NaN is unordered, so all floating-point comparisons fail if either of their operands is NaN. The compiler chooses the variant of the comparison instruction for the appropriate type that produces the same result whether the comparison fails on non-NaN values or encounters a NaN. For instance:<p>
<pre><br><a name="8563"></a> <code>int lessThan100(double d) {
</code></pre><pre> <code> if (d < 100.0) {
</code> <code> return 1;
</code> <code> } else {
</code> <code> return -1;
</code> <code> }
</code><a name="8569"></a> <code>}
</code><br></pre><a name="8594"></a>
compiles to
<p><a name="8571"></a>
<i>Method </i><code>int</code> <code>lessThan100(double)<p><Table Border="0">
<tr><td> <i> 0
</i><br><td> <i>dload_1
</i><br><td>
<tr><td> <i> 1
</i><br><td> <i>ldc2_w #4
</i><br><td><i>// Double </i><code>100.000000
</code>
<tr><td> <i> 4
</i><br><td> <i>dcmpg
</i><br><td><i>// Push 1 if </i><code>d</code><i> is NaN or </i><code>d</code><i> </i>> <code>100.000000</code><i>;
</i>
<tr><td> <i>
</i><br><td> <i>
</i><br><td><i>// push 0 if </i><code>d</code><i> == </i><code>100.000000
</code>
<tr><td> <i> 5
</i><br><td> <i>ifge 10
</i><br><td><i>// Branch on 0 or 1
</i>
<tr><td> <i> 8
</i><br><td> <i>iconst_1
</i><br><td>
<tr><td> <i> 9
</i><br><td> <i>ireturn
</i><br><td>
<tr><td> <i> 10
</i><br><td> <i>iconst_m1
</i><br><td>
<tr><td> <i> 11
</i><br><td> <i>ireturn
</i><br><td>
</Table><br><br></code><p>
<a name="8595"></a>
If <code>d</code> is not NaN and is less than <code>100.0</code>, the <i>dcmpg</i> instruction pushes an <code>int</code> -<i>1</i> onto the
operand stack, and the <i>ifge</i> instruction does not branch. Whether <code>d</code> is greater than
<code>100.0</code> or is NaN, the <i>dcmpg</i> instruction pushes an <code>int</code> <i>1</i> onto the operand stack, and
the <i>ifge</i> branches. If <code>d</code> is equal to <code>100.0</code>, the <i>dcmpg</i> instruction pushes an <code>int</code> <i>0</i> onto the
operand stack, and the <i>ifge</i> branches.
<p><a name="10361"></a>
The <i>dcmpl</i> instruction achieves the same effect if the comparison is reversed:<p>
<pre><br><a name="8634"></a> <code>int greaterThan100(double d) {
</code></pre><pre> <code> if (d > 100.0) {
</code> <code> return 1;
</code> <code> } else {
</code> <code> return -1;
</code> <code> }
</code><a name="8633"></a> <code>}
</code><br></pre><a name="8657"></a>
becomes
<p><a name="8625"></a>
<i>Method </i><code>int</code> <code>greaterThan100(double)<p><Table Border="0">
<tr><td> <i> 0
</i><br><td> <i>dload_1
</i><br><td>
<tr><td> <i> 1
</i><br><td> <i>ldc2_w #4
</i><br><td><i>// Double </i><code>100.000000
</code>
<tr><td> <i> 4
</i><br><td> <i>dcmpl
</i><br><td><i>// Push </i>-<i>1 if </i><code>d</code><i> is Nan or </i><code>d</code><i> </i><<code> 100.000000</code><i>;
</i>
<tr><td> <i>
</i><br><td> <i>
</i><br><td><i>// push 0 if </i><code>d</code><i> == </i><code>100.000000
</code>
<tr><td> <i> 5
</i><br><td> <i>ifle 10
</i><br><td><i>// Branch on 0 or </i>-<i>1
</i>
<tr><td> <i> 8
</i><br><td> <i>iconst_1
</i><br><td>
<tr><td> <i> 9
</i><br><td> <i>ireturn
</i><br><td>
<tr><td> <i> 10
</i><br><td> <i>iconst_m1
</i><br><td>
<tr><td> <i> 11
</i><br><td> <i>ireturn
</i><br><td>
</Table><br><br></code><p>
<a name="8658"></a>
Once again, whether the comparison fails on a non-NaN value or because it is
passed a NaN, the <i>dcmpl</i> instruction pushes an <code>int</code> value onto the operand stack that
causes the <i>ifle</i> to branch. If both of the <i>dcmp</i> instructions did not exist, one of the
example methods would have had to do more work to detect NaN.
<p><a name="8556"></a>
<hr><h2>7.6 Receiving Arguments</h2>
<a name="4344"></a>
If <em>n</em> arguments are passed to a Java instance method, they are received, by convention,
in the local variables numbered <i>1</i> through <i>n</i> of the frame created for the new method
invocation. The arguments are received in the order they were passed. For example:
<p><pre><br><a name="5021"></a> <code>int addTwo(int i, int j) {
</code></pre><pre> <code> return i + j;
</code><a name="4353"></a> <code>}
</code><br></pre><a name="4349"></a>
compiles to
<p><a name="4360"></a>
<i>Method </i><code>int</code> <code>addTwo(int,int)<p><Table Border="0">
<tr><td> <i> 0
</i><br><td> <i>iload_1
</i><br><td><i>// Push value of local 1 (</i><code>i</code><i>)
</i>
<tr><td> <i> 1
</i><br><td> <i>iload_2
</i><br><td><i>// Push value of local 2 (</i><code>j</code><i>)
</i>
<tr><td> <i> 2
</i><br><td> <i>iadd
</i><br><td><i>// Add; leave </i><code>int</code><i> result on val stack
</i>
<tr><td> <i> 3
</i><br><td> <i>ireturn
</i><br><td><i>// Return </i><code>int</code><i> result
</i>
</Table><br><br></code><p>
<a name="9840"></a>
By convention, an instance method is passed a <code>reference</code> to its instance in local variable zero. The instance is accessible in Java via the <code>this</code> keyword. Code to push <code>this</code> into local variable zero must be present in the invoker of an instance method (see <a href="Compiling.doc.html#4425">Section 7.7, "Invoking Methods"</a>).<p>
<a name="9846"></a>
Class (<code>static</code>) methods do not have an instance, so for them this use of local variable zero is unnecessary. A class method starts using local variables at index zero. If the <code>addTwo</code> method was a class method, its arguments would be passed in a similar way to the first version:<p>
<pre><br><a name="5917"></a> <code>static int addTwoStatic(int i, int j) {
</code></pre><pre> <code> return i + j;
</code><a name="5919"></a> <code>}
</code><br></pre><a name="5915"></a>
compiles to
<p><a name="5910"></a>
<i>Method </i><code>int</code> <code>addTwoStatic(int,int)<p><Table Border="0">
<tr><td> <i> 0
</i><br><td><i>iload_0
</i>
<tr><td> <i> 1
</i><br><td><i>iload_1
</i>
<tr><td> <i> 2
</i><br><td><i>iadd
</i>
<tr><td> <i> 3
</i><br><td><i>ireturn
</i>
</Table><br><br></code><p>
<a name="10390"></a>
The only difference is that the method arguments appear starting in local variable <i>0</i>
rather than <i>1</i>.
<p><a name="4425"></a>
<hr><h2>7.7 Invoking Methods</h2>
<a name="5974"></a>
The normal method invocation for a Java instance method dispatches on the runtime
type of the object (they are virtual, in C++ terms). Such an invocation is implemented using the <i>invokevirtual</i> instruction, which takes as its argument an index to
a constant pool entry giving the fully qualified name of the class type of the object,
the name of the method to invoke, and that method's descriptor <a href="ClassFile.doc.html#7035">(§4.3.3)</a>. To invoke
the <code>addTwo</code> method, defined earlier as an instance method, we might write
<p><pre><br><a name="5975"></a> <code>int add12and13() {
</code></pre><pre> <code> return addTwo(12, 13);
</code><a name="4398"></a> <code>}
</code><br></pre><a name="25875"></a>
This compiles to
<p><a name="25880"></a>
<i>Method </i><code>int</code> <code>add12and13()</code><p><Table Border="0">
<tr><td> <i> 0
</i><br><td> <i>aload_0
</i><br><td><i>// Push this local 0 (</i><code>this</code><i>) onto stack
</i>
<tr><td> <i> 1
</i><br><td> <i>bipush 12
</i><br><td><i>// Push </i><code>int</code><i> constant </i><code>12</code><i> onto stack
</i>
<tr><td> <i> 3
</i><br><td> <i>bipush 13
</i><br><td><i>// Push </i><code>int</code><i> constant </i><code>13</code><i> onto stack
</i>
<tr><td> <i> 5
</i><br><td> <i>invokevirtual
#4
</i><br><td><i>// Method </i><code>Example.addtwo(II)I
</code>
<tr><td> <i> 8
</i><br><td> <i>ireturn
</i><br><td><i>// Return </i><code>int</code><i> on top of stack; it is
</i>
<tr><td>
<br><td>
<br><td><i>// the </i><code>int</code><i> result of </i><code>addTwo()
</code>
</Table><br><br><p>
<a name="25876"></a>
<p>
<a name="25877"></a>
The invocation is set up by first pushing a <code>reference</code> to the current instance, <code>this</code>, onto the operand stack. The method invocation's arguments, <code>int</code> values <code>12</code> and <code>13</code>, are then pushed. When the frame for the <code>addTwo</code> method is created, the arguments passed to the method become the initial values of the new frame's local variables. That is, the <code>reference</code> for <code>this</code> and the two arguments, pushed onto the operand stack by the invoker, will become the initial values of local variables <i>0</i>, <i>1</i>, and <i>2</i> of the invoked method. <p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -