diff --git a/make/autoconf/version-numbers b/make/autoconf/version-numbers index 9ddd07452ff..c0a30cb58fb 100644 --- a/make/autoconf/version-numbers +++ b/make/autoconf/version-numbers @@ -37,7 +37,7 @@ DEFAULT_VERSION_DATE=2024-04-16 DEFAULT_VERSION_CLASSFILE_MAJOR=55 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_ACCEPTABLE_BOOT_VERSIONS="10 11" -DEFAULT_PROMOTED_VERSION_PRE=ea +DEFAULT_PROMOTED_VERSION_PRE= LAUNCHER_NAME=openjdk PRODUCT_NAME=OpenJDK diff --git a/src/java.base/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java b/src/java.base/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java index 212a612c1f7..57bcf1e0309 100644 --- a/src/java.base/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java +++ b/src/java.base/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java @@ -32,6 +32,8 @@ import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; +import java.util.LinkedList; +import java.util.List; import java.util.jar.JarOutputStream; import java.util.jar.Pack200; import java.util.zip.CRC32; @@ -78,8 +80,13 @@ class NativeUnpack { private int _estFileLimit; // ditto private int _prevPercent = -1; // for monotonicity - private final CRC32 _crc32 = new CRC32(); - private byte[] _buf = new byte[1<<14]; + private final CRC32 _crc32 = new CRC32(); + private static final int MAX_BUFFER_SIZE = 1 << 20; // 1 MB byte[] + private byte[] _buf = new byte[1 << 14]; // 16 KB byte[] initially + private List _extra_buf = new LinkedList<>(); // extra buffers + // for large files + private byte[] _current_buf; // buffer being filled + private int _current_buf_pos; // position to fill in more data private UnpackerImpl _p200; private PropMap _props; @@ -196,41 +203,44 @@ void run(InputStream inRaw, JarOutputStream jstream, updateProgress(); // reset progress bar for (;;) { // Read the packed bits. - long counts = start(presetInput, 0); - _byteCount = _estByteLimit = 0; // reset partial scan counts - ++_segCount; // just finished scanning a whole segment... - int nextSeg = (int)( counts >>> 32 ); - int nextFile = (int)( counts >>> 0 ); - - // Estimate eventual total number of segments and files. - _estSegLimit = _segCount + nextSeg; - double filesAfterThisSeg = _fileCount + nextFile; - _estFileLimit = (int)( (filesAfterThisSeg * - _estSegLimit) / _segCount ); - - // Write the files. - int[] intParts = { 0,0, 0, 0 }; - // intParts = {size.hi/lo, mod, defl} - Object[] parts = { intParts, null, null, null }; - // parts = { {intParts}, name, data0/1 } - while (getNextFile(parts)) { - //BandStructure.printArrayTo(System.out, intParts, 0, parts.length); - String name = (String) parts[1]; - long size = ( (long)intParts[0] << 32) - + (((long)intParts[1] << 32) >>> 32); - - long mtime = (modtime != Constants.NO_MODTIME ) ? - modtime : intParts[2] ; - boolean deflateHint = (intParts[3] != 0); - ByteBuffer data0 = (ByteBuffer) parts[2]; - ByteBuffer data1 = (ByteBuffer) parts[3]; - writeEntry(jstream, name, mtime, size, deflateHint, - data0, data1); - ++_fileCount; - updateProgress(); + long counts = start(presetInput, 0), consumed; + try { + _byteCount = _estByteLimit = 0; // reset partial scan counts + ++_segCount; // just finished scanning a whole segment... + int nextSeg = (int) (counts >>> 32); + int nextFile = (int) (counts >>> 0); + + // Estimate eventual total number of segments and files. + _estSegLimit = _segCount + nextSeg; + double filesAfterThisSeg = _fileCount + nextFile; + _estFileLimit = (int) ((filesAfterThisSeg * + _estSegLimit) / _segCount); + + // Write the files. + int[] intParts = {0, 0, 0, 0}; + // intParts = {size.hi/lo, mod, defl} + Object[] parts = {intParts, null, null, null}; + // parts = { {intParts}, name, data0/1 } + while (getNextFile(parts)) { + //BandStructure.printArrayTo(System.out, intParts, 0, parts.length); + String name = (String) parts[1]; + long size = ((long) intParts[0] << 32) + + (((long) intParts[1] << 32) >>> 32); + + long mtime = (modtime != Constants.NO_MODTIME) ? + modtime : intParts[2]; + boolean deflateHint = (intParts[3] != 0); + ByteBuffer data0 = (ByteBuffer) parts[2]; + ByteBuffer data1 = (ByteBuffer) parts[3]; + writeEntry(jstream, name, mtime, size, deflateHint, + data0, data1); + ++_fileCount; + updateProgress(); + } + presetInput = getUnusedInput(); + } finally { + consumed = finish(); } - presetInput = getUnusedInput(); - long consumed = finish(); if (_verbose > 0) Utils.log.info("bytes consumed = "+consumed); if (presetInput == null && @@ -257,76 +267,145 @@ void run(File inFile, JarOutputStream jstream) throws IOException { // Note: caller is responsible to finish with jstream. } - private void writeEntry(JarOutputStream j, String name, - long mtime, long lsize, boolean deflateHint, - ByteBuffer data0, ByteBuffer data1) throws IOException { - int size = (int)lsize; - if (size != lsize) - throw new IOException("file too large: "+lsize); - - CRC32 crc32 = _crc32; - - if (_verbose > 1) - Utils.log.fine("Writing entry: "+name+" size="+size - +(deflateHint?" deflated":"")); - - if (_buf.length < size) { - int newSize = size; - while (newSize < _buf.length) { - newSize <<= 1; - if (newSize <= 0) { - newSize = size; - break; - } - } - _buf = new byte[newSize]; + private void writeEntry(JarOutputStream j, String name, long mtime, + long lsize, boolean deflateHint, ByteBuffer data0, + ByteBuffer data1) throws IOException { + if (lsize < 0 || lsize > Integer.MAX_VALUE) { + throw new IOException("file too large: " + lsize); } - assert(_buf.length >= size); + int size = (int) lsize; - int fillp = 0; - if (data0 != null) { - int size0 = data0.capacity(); - data0.get(_buf, fillp, size0); - fillp += size0; - } - if (data1 != null) { - int size1 = data1.capacity(); - data1.get(_buf, fillp, size1); - fillp += size1; - } - while (fillp < size) { - // Fill in rest of data from the stream itself. - int nr = in.read(_buf, fillp, size - fillp); - if (nr <= 0) throw new IOException("EOF at end of archive"); - fillp += nr; + if (_verbose > 1) { + Utils.log.fine("Writing entry: " + name + " size=" + size + + (deflateHint ? " deflated" : "")); } ZipEntry z = new ZipEntry(name); z.setTime(mtime * 1000); - + z.setSize(size); if (size == 0) { z.setMethod(ZipOutputStream.STORED); - z.setSize(0); + z.setCompressedSize(size); z.setCrc(0); - z.setCompressedSize(0); + j.putNextEntry(z); } else if (!deflateHint) { z.setMethod(ZipOutputStream.STORED); - z.setSize(size); z.setCompressedSize(size); - crc32.reset(); - crc32.update(_buf, 0, size); - z.setCrc(crc32.getValue()); + writeEntryData(j, z, data0, data1, size, true); } else { z.setMethod(Deflater.DEFLATED); - z.setSize(size); + writeEntryData(j, z, data0, data1, size, false); } + j.closeEntry(); - j.putNextEntry(z); + if (_verbose > 0) Utils.log.info("Writing " + Utils.zeString(z)); + } - if (size > 0) - j.write(_buf, 0, size); + private void writeEntryData(JarOutputStream j, ZipEntry z, ByteBuffer data0, + ByteBuffer data1, int size, boolean computeCrc32) + throws IOException { + prepareReadBuffers(size); + try { + int inBytes = size; + inBytes -= readDataByteBuffer(data0); + inBytes -= readDataByteBuffer(data1); + inBytes -= readDataInputStream(inBytes); + if (inBytes != 0L) { + throw new IOException("invalid size: " + size); + } + if (computeCrc32) { + _crc32.reset(); + processReadData((byte[] buff, int offset, int len) -> { + _crc32.update(buff, offset, len); + }); + z.setCrc(_crc32.getValue()); + } + j.putNextEntry(z); + processReadData((byte[] buff, int offset, int len) -> { + j.write(buff, offset, len); + }); + } finally { + resetReadBuffers(); + } + } - j.closeEntry(); - if (_verbose > 0) Utils.log.info("Writing " + Utils.zeString(z)); + private void prepareReadBuffers(int size) { + if (_buf.length < size && _buf.length < MAX_BUFFER_SIZE) { + // Grow the regular buffer to accomodate lsize up to a limit. + long newIdealSize = _buf.length; + while (newIdealSize < size && newIdealSize < MAX_BUFFER_SIZE) { + // Never overflows: size is [0, 0x7FFFFFFF]. + newIdealSize <<= 1; + } + int newSize = (int) Long.min(newIdealSize, MAX_BUFFER_SIZE); + _buf = new byte[newSize]; + } + resetReadBuffers(); + } + + private void resetReadBuffers() { + _extra_buf.clear(); + _current_buf = _buf; + _current_buf_pos = 0; + } + + private int readDataByteBuffer(ByteBuffer data) throws IOException { + if (data == null) { + return 0; + } + return readData(data.remaining(), + (byte[] buff, int offset, int len) -> { + data.get(buff, offset, len); + return len; + }); + } + + private int readDataInputStream(int inBytes) throws IOException { + return readData(inBytes, (byte[] buff, int offset, int len) -> { + return in.read(buff, offset, len); + }); + } + + private static interface ReadDataCB { + public int read(byte[] buff, int offset, int len) throws IOException; + } + + private int readData(int bytesToRead, ReadDataCB readDataCb) + throws IOException { + int bytesRemaining = bytesToRead; + while (bytesRemaining > 0) { + if (_current_buf_pos == _current_buf.length) { + byte[] newBuff = new byte[Integer.min(bytesRemaining, + MAX_BUFFER_SIZE)]; + _extra_buf.add(newBuff); + _current_buf = newBuff; + _current_buf_pos = 0; + } + int current_buffer_space = _current_buf.length - _current_buf_pos; + int nextRead = Integer.min(current_buffer_space, bytesRemaining); + int bytesRead = readDataCb.read(_current_buf, _current_buf_pos, + nextRead); + if (bytesRead <= 0) { + throw new IOException("EOF at end of archive"); + } + _current_buf_pos += bytesRead; + bytesRemaining -= bytesRead; + } + return bytesToRead - bytesRemaining; + } + + private static interface ProcessDataCB { + public void apply(byte[] buff, int offset, int len) throws IOException; + } + + private void processReadData(ProcessDataCB processDataCB) + throws IOException { + processDataCB.apply(_buf, 0, _buf == _current_buf ? _current_buf_pos : + _buf.length); + for (byte[] buff : _extra_buf) { + // Extra buffers are allocated of a size such that they are always + // full, including the last one. + processDataCB.apply(buff, 0, buff.length); + }; } } diff --git a/src/java.base/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java b/src/java.base/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java index b1631e42fde..f3f263bbab2 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java @@ -343,14 +343,6 @@ public AlgorithmParameterSpec getParams() { return keyParams; } - // return a string representation of this key for debugging - @Override - public String toString() { - return "SunRsaSign " + type.keyAlgo + " private CRT key, " - + n.bitLength() + " bits" + "\n params: " + keyParams - + "\n modulus: " + n + "\n private exponent: " + d; - } - // utility method for parsing DER encoding of RSA private keys in PKCS#1 // format as defined in RFC 8017 Appendix A.1.2, i.e. SEQ of version, n, // e, d, p, q, pe, qe, and coeff, and return the parsed components. diff --git a/src/java.base/share/classes/sun/security/rsa/RSAPrivateKeyImpl.java b/src/java.base/share/classes/sun/security/rsa/RSAPrivateKeyImpl.java index defa58b9fd0..e732a0a84e8 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAPrivateKeyImpl.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAPrivateKeyImpl.java @@ -135,14 +135,6 @@ public AlgorithmParameterSpec getParams() { return keyParams; } - // return a string representation of this key for debugging - @Override - public String toString() { - return "Sun " + type.keyAlgo + " private key, " + n.bitLength() - + " bits" + "\n params: " + keyParams + "\n modulus: " + n - + "\n private exponent: " + d; - } - /** * Restores the state of this object from the stream. *

diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java index 186d397698f..02dc8d30679 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java @@ -103,14 +103,10 @@ public boolean equals(Object obj) { return false; } if (secure && destination != null) { - if (destination.getHostName() != null) { - if (!destination.getHostName().equalsIgnoreCase( - other.destination.getHostName())) { - return false; - } - } else { - if (other.destination.getHostName() != null) - return false; + String hostString = destination.getHostString(); + if (hostString == null || !hostString.equalsIgnoreCase( + other.destination.getHostString())) { + return false; } } return true; diff --git a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKey.java b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKey.java index fe0fac5f10a..801d2ad0b59 100644 --- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKey.java +++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKey.java @@ -75,10 +75,14 @@ protected void finalize() throws Throwable { protected final String algorithm; - protected CKey(String algorithm, NativeHandles handles, int keyLength) { + private final boolean isPublic; + + protected CKey(String algorithm, NativeHandles handles, int keyLength, + boolean isPublic) { this.algorithm = algorithm; this.handles = handles; this.keyLength = keyLength; + this.isPublic = isPublic; } // Native method to cleanup the key handle. @@ -101,6 +105,18 @@ public String getAlgorithm() { return algorithm; } + public String toString() { + String typeStr; + if (handles.hCryptKey != 0) { + typeStr = getKeyType(handles.hCryptKey) + ", container=" + + getContainerName(handles.hCryptProv); + } else { + typeStr = "CNG"; + } + return algorithm + " " + (isPublic ? "PublicKey" : "PrivateKey") + + " [size=" + keyLength + " bits, type=" + typeStr + "]"; + } + protected native static String getContainerName(long hCryptProv); protected native static String getKeyType(long hCryptKey); diff --git a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPrivateKey.java b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPrivateKey.java index cea2f93ed5f..8effc135155 100644 --- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPrivateKey.java +++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPrivateKey.java @@ -41,7 +41,7 @@ class CPrivateKey extends CKey implements PrivateKey { private static final long serialVersionUID = 8113152807912338063L; private CPrivateKey(String alg, NativeHandles handles, int keyLength) { - super(alg, handles, keyLength); + super(alg, handles, keyLength, false); } // Called by native code inside security.cpp @@ -64,16 +64,6 @@ public byte[] getEncoded() { return null; } - public String toString() { - if (handles.hCryptKey != 0) { - return algorithm + "PrivateKey [size=" + keyLength + " bits, type=" + - getKeyType(handles.hCryptKey) + ", container=" + - getContainerName(handles.hCryptProv) + "]"; - } else { - return algorithm + "PrivateKey [size=" + keyLength + " bits, type=CNG]"; - } - } - // This class is not serializable private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException { diff --git a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPublicKey.java b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPublicKey.java index 93c11c8d561..9ca0955bc53 100644 --- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPublicKey.java +++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPublicKey.java @@ -110,9 +110,8 @@ public ECParameterSpec getParams() { } public String toString() { - StringBuffer sb = new StringBuffer(); - sb.append(algorithm).append("PublicKey [size=").append(keyLength) - .append("]\n ECPoint: ").append(getW()) + StringBuffer sb = new StringBuffer(super.toString()); + sb.append("\n ECPoint: ").append(getW()) .append("\n params: ").append(getParams()); return sb.toString(); } @@ -129,16 +128,8 @@ public static class CRSAPublicKey extends CPublicKey implements RSAPublicKey { } public String toString() { - StringBuffer sb = new StringBuffer(); - sb.append(algorithm).append("PublicKey [size=").append(keyLength) - .append(" bits, type="); - if (handles.hCryptKey != 0) { - sb.append(getKeyType(handles.hCryptKey)) - .append(", container=").append(getContainerName(handles.hCryptProv)); - } else { - sb.append("CNG"); - } - sb.append("]\n modulus: ").append(getModulus()) + StringBuffer sb = new StringBuffer(super.toString()); + sb.append("\n modulus: ").append(getModulus()) .append("\n public exponent: ").append(getPublicExponent()); return sb.toString(); } @@ -209,7 +200,7 @@ public static CPublicKey of( protected CPublicKey( String alg, NativeHandles handles, int keyLength) { - super(alg, handles, keyLength); + super(alg, handles, keyLength, true); } @Override diff --git a/test/hotspot/jtreg/compiler/regalloc/TestNodeRegArrayOverflow.java b/test/hotspot/jtreg/compiler/regalloc/TestNodeRegArrayOverflow.java new file mode 100644 index 00000000000..281524cc13f --- /dev/null +++ b/test/hotspot/jtreg/compiler/regalloc/TestNodeRegArrayOverflow.java @@ -0,0 +1,599 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.regalloc; + +/** + * @test + * @bug 8317507 + * @summary Test that C2's PhaseRegAlloc::_node_regs (a post-register-allocation + * mapping from machine nodes to assigned registers) does not overflow + * in the face of a program with a high-density of CISC spilling + * candidate nodes. + * @run main/othervm -Xcomp -XX:CompileOnly=compiler.regalloc.TestNodeRegArrayOverflow::testWithCompilerUnrolling + -XX:CompileCommand=dontinline,compiler.regalloc.TestNodeRegArrayOverflow::dontInline + compiler.regalloc.TestNodeRegArrayOverflow compiler + * @run main/othervm -Xcomp -XX:CompileOnly=compiler.regalloc.TestNodeRegArrayOverflow::testWithManualUnrolling + -XX:CompileCommand=dontinline,compiler.regalloc.TestNodeRegArrayOverflow::dontInline + compiler.regalloc.TestNodeRegArrayOverflow manual + */ + +public class TestNodeRegArrayOverflow { + + static int dontInline() { + return 0; + } + + static float testWithCompilerUnrolling(float inc) { + int i = 0, j = 0; + // This non-inlined method call causes 'inc' to be spilled. + float f = dontInline(); + // This two-level reduction loop is unrolled 512 times, which is + // requested by the SLP-specific unrolling analysis, but not vectorized. + // Because 'inc' is spilled, each of the unrolled AddF nodes is + // CISC-spill converted (PhaseChaitin::fixup_spills()). Before the fix, + // this causes the unique node index counter (Compile::_unique) to grow + // beyond the size of the node register array + // (PhaseRegAlloc::_node_regs), and leads to overflow when accessed for + // nodes that are created later (e.g. during the peephole phase). + while (i++ < 128) { + for (j = 0; j < 16; j++) { + f += inc; + } + } + return f; + } + + // This test reproduces the same failure as 'testWithCompilerUnrolling' + // without relying on loop transformations. + static float testWithManualUnrolling(float inc) { + int i = 0, j = 0; + float f = dontInline(); + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + f += inc; + return f; + } + + public static void main(String[] args) { + switch (args[0]) { + case "compiler": + testWithCompilerUnrolling(0); + break; + case "manual": + testWithManualUnrolling(0); + break; + default: + throw new IllegalArgumentException("Invalid mode: " + args[0]); + } + } +}