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

📄 compiling.doc.html

📁 A Java virtual machine instruction consists of an opcode specifying the operation to be performed, f
💻 HTML
📖 第 1 页 / 共 5 页
字号:
of 2:<p><blockquote><pre><code>int align2grain(int i, int grain) {</code><code>    return ((i + grain-1) &amp; ~(grain-1));</code><code>}</code></pre></blockquote><a name="15003"></a>Operands for arithmetic operations are popped from the operand stack, and the results of operations are pushed back onto the operand stack. Results of arithmetic subcomputations can thus be made available as operands of their nesting computation. For instance, the calculation of <code>~(grain</code>-<code>1)</code> is handled by these instructions:<p><blockquote><pre>   5 	iload_2			// Push <code>grain</code>    6 	iconst_1		// Push <code>int</code> constant <code>1</code>    7 	isub			// Subtract; push result    8 	iconst_m1		// Push <code>int</code> constant -<code>1</code>    9 	ixor			// Do XOR; push result </pre></blockquote>First <code>grain</code> &#32;- &#32;<code>1</code> is calculated using the contents of local variable 2 and an immediate<code>int</code> value <code>1</code>. These operands are popped from the operand stack and their difference pushed back onto the operand stack. The difference is thus immediatelyavailable for use as one operand of the ixor instruction. (Recall that ~<code>x</code> == -<code>1^x</code>.) Similarly, the result of the ixor instruction becomes an operand for the subsequent iand instruction.<p><a name="9759"></a>The code for the entire method follows:<p><blockquote><pre>Method <code>int</code> <code>align2grain(int,int)</code>   0 	iload_1   1 	iload_2   2 	iadd   3 	iconst_1   4 	isub   5 	iload_2   6 	iconst_1   7 	isub   8 	iconst_m1   9 	ixor  10	iand  11	ireturn</pre></blockquote><a name="5841"></a><hr><h2>7.4    Accessing the Runtime Constant Pool</h2>Many numeric constants, as well as objects, fields, and methods, are accessed via the runtime constant pool of the current class. Object access is considered later <a href="Compiling.doc.html#4089">(&#167;7.8)</a>. Data of types <code>int</code>, <code>long</code>, <code>float</code>, and <code>double</code>, as well as references to instances of class <code>String</code>, are managed using the ldc, ldc_w, and ldc2_w instructions.<p><a name="6072"></a>The ldc and ldc_w instructions are used to access values in the runtime constant pool (including instances of class <code>String</code>) of types other than <code>double</code> and <code>long</code>. The ldc_w instruction is used in place of ldc only when there is a large number of runtime constant pool items and a larger index is needed to access an item. The ldc2_w instruction is used to access all values of types <code>double</code> and <code>long</code>; there is no non-wide variant.<p><a name="6073"></a>Integral constants of types <code>byte</code>, <code>char</code>, or <code>short</code>, as well as small <code>int</code> values, may be compiled using the bipush, sipush, or iconst_&lt;i&gt; instructions, as seen earlier <a href="Compiling.doc.html#4182">(&#167;7.2)</a>. Certain small floating-point constants may be compiled using the fconst_&lt;f&gt; and dconst_&lt;d&gt; instructions. <p><a name="10300"></a>In all of these cases, compilation is straightforward. For instance, the constants for<p><blockquote><pre><code>void useManyNumeric() {</code><code>    int i = 100;</code><code>    int j = 1000000;</code><code>    long l1 = 1;</code><code>    long l2 = 0xffffffff;</code><code>    double d = 2.2;</code><code>    ...do some calculations...</code><code>}</code></pre></blockquote>are set up as follows:<p><blockquote><pre>Method <code>void</code> <code>useManyNumeric()</code>   0	bipush 100		// Push a small <code>int</code> with bipush   2	istore_1   3 	ldc #1 			// Push <code>int</code> constant <code>1000000</code>; a larger <code>int</code>				// value uses ldc   5 	istore_2   6 	lconst_1		// A tiny <code>long</code> value uses short, fast lconst_1   7 	lstore_3   8	ldc2_w #6 		// Push <code>long</code> <code>0xffffffff</code> (that is, an <code>int</code> -<code>1</code>); any				// <code>long</code> constant value can be pushed using ldc2_w  11	lstore 5  13 	ldc2_w #8 		// Push <code>double</code> constant <code>2.200000</code>; uncommon				// <code>double</code> values are also pushed using ldc2_w  16 	dstore 7...do those calculations...</pre></blockquote><a name="8478"></a><hr><h2>7.5    More Control Examples</h2>Compilation of <code>for</code> statements was shown in an earlier section <a href="Compiling.doc.html#4182">(&#167;7.2)</a>. Most of the Java programming language's other control constructs (<code>if-then-else</code>, <code>do</code>, <code>while</code>, <code>break</code>, and <code>continue</code>) are also compiled in the obvious ways. The compilation of <code>switch</code> statements is handled in a separate section (<a href="Compiling.doc.html#14942">Section 7.10, "Compiling Switches"</a>), as are the compilation of exceptions (<a href="Compiling.doc.html#9934">Section 7.12, "Throwing and HandlingExceptions"</a>) and the compilation of <code>finally</code> clauses (<a href="Compiling.doc.html#13789">Section 7.13, "Compiling <sub>finally</sub>"</a>).<p><a name="14987"></a>As a further example, a <code>while</code> loop is compiled in an obvious way, although the specific control transfer instructions made available by the Java virtual machine vary by data type. As usual, there is more support for data of type <code>int</code>, for example:<p><blockquote><pre><code>void whileInt() {</code><code>    int i = 0;</code><code>    while (i &lt; 100) {</code><code>        i++;</code><code>    }</code><code>}</code></pre></blockquote>is compiled to<p><blockquote><pre>Method <code>void</code> <code>whileInt()</code>   0 	iconst_0   1 	istore_1   2 	goto 8   5 	iinc 1 1   8 	iload_1   9 	bipush 100  11 	if_icmplt 5  14 	return</pre></blockquote><a name="8508"></a>Note that the test of the <code>while</code> statement (implemented using the if_icmplt instruction) is at the bottom of the Java virtual machine code for the loop. (This was also the case in the <code>spin</code> examples earlier.) The test being at the bottom of the loop forces the use of a goto instruction to get to the test prior to the first iteration of the loop. If that test fails, and the loop body is never entered, this extra instruction is wasted. However, <code>while</code> loops are typically used when their body is expected to be run, often for many iterations. For subsequent iterations, putting the test at the bottom of the loop saves a Java virtual machine instruction each time around the loop: if the test were at the top of the loop, the loop body would need a trailing goto instruction to get back to the top.<p><a name="8700"></a>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, for example:<p><blockquote><pre><code>void whileDouble() {</code><code>    double i = 0.0;</code><code>    while (i &lt; 100.1) {</code><code>        i++;</code><code>    }</code><code>}</code></pre></blockquote>is compiled to<p><blockquote><pre>Method <code>void</code> <code>whileDouble()</code>   0 	dconst_0   1 	dstore_1   2 	goto 9   5 	dload_1   6 	dconst_1   7 	dadd   8 	dstore_1   9 	dload_1  10 	ldc2_w #4 		// Push <code>double</code> constant <code>100.1</code>  13 	dcmpg			// To do the compare and branch we have to use...  14 	iflt 5			// ...two instructions  17 	return</pre></blockquote><a name="8555"></a>Each floating-point type has two comparison instructions: fcmpl and fcmpg for type <code>float</code>, and dcmpl and dcmpg 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. <p><a name="18373"></a>For instance:<p><blockquote><pre><code>int lessThan100(double d) {</code><code>    if (d &lt; 100.0) {</code><code>        return 1;				</code><code>    } else {</code><code>        return -1;				</code><code>    }</code><code>}</code></pre></blockquote>compiles to<p><blockquote><pre>Method <code>int</code> <code>lessThan100(double)</code>   0 	dload_1   1 	ldc2_w #4 		// Push <code>double</code> constant <code>100.0</code>   4 	dcmpg			// Push 1 if <code>d</code> is NaN or <code>d</code> \> <code>100.0</code>;				// push 0 if <code>d</code> == <code>100.0</code>   5 	ifge 10			// Branch on 0 or 1   8 	iconst_1   9 	ireturn  10 	iconst_m1  11 	ireturn</pre></blockquote>If <code>d</code> is not NaN and is less than <code>100.0</code>, the dcmpg instruction pushes an <code>int</code> -1 onto the operand stack, and the ifge instruction does not branch. Whether <code>d</code> is greater than <code>100.0</code> or is NaN, the dcmpg instruction pushes an <code>int</code> 1 onto the operand stack, and the ifge branches. If <code>d</code> is equal to <code>100.0</code>, the dcmpg instruction pushes an <code>int</code> 0 onto the operand stack, and the ifge branches.<p><a name="10361"></a>The dcmpl instruction achieves the same effect if the comparison is reversed:<p><blockquote><pre><code>int greaterThan100(double d) {</code><code>    if (d &gt; 100.0) {</code><code>        return 1;			</code><code>    } else {</code><code>        return -1;			</code><code>    }</code><code>}</code></pre></blockquote>becomes<p><blockquote><pre>Method <code>int</code> <code>greaterThan100(double)</code>   0 	dload_1   1 	ldc2_w #4 		// Push <code>double</code> constant <code>100.0</code>   4 	dcmpl			// Push -1 if <code>d</code> is Nan or <code>d</code> <<code> 100.0</code>;				// push 0 if <code>d</code> == <code>100.0</code>   5 	ifle 10			// Branch on 0 or -1   8 	iconst_1   9 	ireturn  10 	iconst_m1  11 	ireturn</pre></blockquote>Once again, whether the comparison fails on a non-NaN value or because it is passed a NaN, the dcmpl instruction pushes an <code>int</code> value onto the operand stack that causes the ifle to branch. If both of the dcmp 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>If <em>n</em> arguments are passed to an instance method, they are received, by convention, in the local variables numbered 1 through n of the frame created for the new method invocation. The arguments are received in the order they were passed. For example:<p><blockquote><pre><code>int addTwo(int i, int j) {</code><code>    return i + j;</code><code>}</code></pre></blockquote>compiles to<p><blockquote><pre>Method <code>int</code> <code>addTwo(int,int)</code>   0	iload_1			// Push value of local variable 1 (<code>i</code>)   1	iload_2			// Push value of local variable 2 (<code>j</code>)   2	iadd			// Add; leave <code>int</code> result on operand stack   3 	ireturn			// Return <code>int</code> result</pre></blockquote><a name="9840"></a>By convention, an instance method is passed a <code>reference</code> to its instance in local variable 0. In the Java programming language the instance is accessible via the <code>this</code> keyword. <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 were a class method, its arguments would be passed in a similar way to the first version:<p><blockquote><pre><code>static int addTwoStatic(int i, int j) {

⌨️ 快捷键说明

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