# HG changeset patch # User redestad # Date 1405976860 -7200 # Node ID a5d9c415d1fd3decdcaa114b47192be4ab889204 # Parent 7428dc33b2bd81b5a35d5b0078f2a011673878bc 8006627: UUID to/from String performance should be improved by reducing object allocations Reviewed-by: mduigou, plevart Contributed-by: Steven Schlansker , Claes Redestad diff -r 7428dc33b2bd -r a5d9c415d1fd jdk/src/share/classes/java/util/UUID.java --- a/jdk/src/share/classes/java/util/UUID.java Tue Jul 22 13:13:27 2014 -0700 +++ b/jdk/src/share/classes/java/util/UUID.java Mon Jul 21 23:07:40 2014 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, 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 @@ -27,6 +27,9 @@ import java.security.*; +import sun.misc.JavaLangAccess; +import sun.misc.SharedSecrets; + /** * A class that represents an immutable universally unique identifier (UUID). * A UUID represents a 128-bit value. @@ -88,6 +91,8 @@ */ private final long leastSigBits; + private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess(); + /* * The random number generator used by this class to create random * based UUIDs. In a holder class to defer initialization until needed. @@ -189,21 +194,35 @@ * */ public static UUID fromString(String name) { - String[] components = name.split("-"); - if (components.length != 5) - throw new IllegalArgumentException("Invalid UUID string: "+name); - for (int i=0; i<5; i++) - components[i] = "0x"+components[i]; + if (name.length() > 36) { + throw new IllegalArgumentException("UUID string too large"); + } + + int dash1 = name.indexOf('-', 0); + int dash2 = name.indexOf('-', dash1 + 1); + int dash3 = name.indexOf('-', dash2 + 1); + int dash4 = name.indexOf('-', dash3 + 1); + int dash5 = name.indexOf('-', dash4 + 1); - long mostSigBits = Long.decode(components[0]).longValue(); + // For any valid input, dash1 through dash4 will be positive and dash5 + // negative, but it's enough to check dash4 and dash5: + // - if dash1 is -1, dash4 will be -1 + // - if dash1 is positive but dash2 is -1, dash4 will be -1 + // - if dash1 and dash2 is positive, dash3 will be -1, dash4 will be + // positive, but so will dash5 + if (dash4 < 0 || dash5 >= 0) { + throw new IllegalArgumentException("Invalid UUID string: " + name); + } + + long mostSigBits = Long.parseLong(name, 16, 0, dash1) & 0xffffffffL; mostSigBits <<= 16; - mostSigBits |= Long.decode(components[1]).longValue(); + mostSigBits |= Long.parseLong(name, 16, dash1 + 1, dash2) & 0xffffL; mostSigBits <<= 16; - mostSigBits |= Long.decode(components[2]).longValue(); + mostSigBits |= Long.parseLong(name, 16, dash2 + 1, dash3) & 0xffffL; - long leastSigBits = Long.decode(components[3]).longValue(); + long leastSigBits = Long.parseLong(name, 16, dash3 + 1, dash4) & 0xffffL; leastSigBits <<= 48; - leastSigBits |= Long.decode(components[4]).longValue(); + leastSigBits |= Long.parseLong(name, 16, dash4 + 1) & 0xffffffffffffL; return new UUID(mostSigBits, leastSigBits); } @@ -373,17 +392,17 @@ * @return A string representation of this {@code UUID} */ public String toString() { - return (digits(mostSigBits >> 32, 8) + "-" + - digits(mostSigBits >> 16, 4) + "-" + - digits(mostSigBits, 4) + "-" + - digits(leastSigBits >> 48, 4) + "-" + - digits(leastSigBits, 12)); - } - - /** Returns val represented by the specified number of hex digits. */ - private static String digits(long val, int digits) { - long hi = 1L << (digits * 4); - return Long.toHexString(hi | (val & (hi - 1))).substring(1); + char[] chars = new char[36]; + jla.formatUnsignedLong(mostSigBits >> 32, 4, chars, 0, 8); + chars[8] = '-'; + jla.formatUnsignedLong(mostSigBits >> 16, 4, chars, 9, 4); + chars[13] = '-'; + jla.formatUnsignedLong(mostSigBits, 4, chars, 14, 4); + chars[18] = '-'; + jla.formatUnsignedLong(leastSigBits >> 48, 4, chars, 19, 4); + chars[23] = '-'; + jla.formatUnsignedLong(leastSigBits, 4, chars, 24, 12); + return jla.newStringUnsafe(chars); } /** diff -r 7428dc33b2bd -r a5d9c415d1fd jdk/test/java/util/UUID/UUIDTest.java --- a/jdk/test/java/util/UUID/UUIDTest.java Tue Jul 22 13:13:27 2014 -0700 +++ b/jdk/test/java/util/UUID/UUIDTest.java Mon Jul 21 23:07:40 2014 +0200 @@ -96,6 +96,23 @@ if (!u1.equals(u2)) throw new Exception("UUID -> string -> UUID failed"); } + + testFromStringError("-0"); + testFromStringError("x"); + testFromStringError("----"); + testFromStringError("-0-0-0-0"); + testFromStringError("0-0-0-0-"); + testFromStringError("0-0-0-0-0-"); + testFromStringError("0-0-0-0-x"); + } + + private static void testFromStringError(String str) { + try { + UUID test = UUID.fromString(str); + throw new RuntimeException("Should have thrown IAE"); + } catch (IllegalArgumentException iae) { + // pass + } } private static void versionTest() throws Exception {