1 /* 2 * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.lang; 27 28 import jdk.internal.misc.Unsafe; 29 import jdk.internal.vm.annotation.ForceInline; 30 31 import java.lang.invoke.MethodHandle; 32 import java.lang.invoke.MethodHandles; 33 import java.lang.invoke.MethodType; 34 35 /** 36 * Helper for string concatenation. These methods are mostly looked up with private lookups 37 * from {@link java.lang.invoke.StringConcatFactory}, and used in {@link java.lang.invoke.MethodHandle} 38 * combinators there. 39 */ 40 final class StringConcatHelper { 41 StringConcatHelper()42 private StringConcatHelper() { 43 // no instantiation 44 } 45 46 /** 47 * Check for overflow, throw exception on overflow. 48 * 49 * @param lengthCoder String length with coder packed into higher bits 50 * the upper word. 51 * @return the given parameter value, if valid 52 */ checkOverflow(long lengthCoder)53 private static long checkOverflow(long lengthCoder) { 54 if ((int)lengthCoder >= 0) { 55 return lengthCoder; 56 } 57 throw new OutOfMemoryError("Overflow: String length out of range"); 58 } 59 60 /** 61 * Mix value length and coder into current length and coder. 62 * @param lengthCoder String length with coder packed into higher bits 63 * the upper word. 64 * @param value value to mix in 65 * @return new length and coder 66 */ mix(long lengthCoder, boolean value)67 static long mix(long lengthCoder, boolean value) { 68 return checkOverflow(lengthCoder + (value ? 4 : 5)); 69 } 70 71 /** 72 * Mix value length and coder into current length and coder. 73 * @param lengthCoder String length with coder packed into higher bits 74 * the upper word. 75 * @param value value to mix in 76 * @return new length and coder 77 */ mix(long lengthCoder, byte value)78 static long mix(long lengthCoder, byte value) { 79 return mix(lengthCoder, (int)value); 80 } 81 82 /** 83 * Mix value length and coder into current length and coder. 84 * @param lengthCoder String length with coder packed into higher bits 85 * the upper word. 86 * @param value value to mix in 87 * @return new length and coder 88 */ mix(long lengthCoder, char value)89 static long mix(long lengthCoder, char value) { 90 return checkOverflow(lengthCoder + 1) | (StringLatin1.canEncode(value) ? 0 : UTF16); 91 } 92 93 /** 94 * Mix value length and coder into current length and coder. 95 * @param lengthCoder String length with coder packed into higher bits 96 * the upper word. 97 * @param value value to mix in 98 * @return new length and coder 99 */ mix(long lengthCoder, short value)100 static long mix(long lengthCoder, short value) { 101 return mix(lengthCoder, (int)value); 102 } 103 104 /** 105 * Mix value length and coder into current length and coder. 106 * @param lengthCoder String length with coder packed into higher bits 107 * the upper word. 108 * @param value value to mix in 109 * @return new length and coder 110 */ mix(long lengthCoder, int value)111 static long mix(long lengthCoder, int value) { 112 return checkOverflow(lengthCoder + Integer.stringSize(value)); 113 } 114 115 /** 116 * Mix value length and coder into current length and coder. 117 * @param lengthCoder String length with coder packed into higher bits 118 * the upper word. 119 * @param value value to mix in 120 * @return new length and coder 121 */ mix(long lengthCoder, long value)122 static long mix(long lengthCoder, long value) { 123 return checkOverflow(lengthCoder + Long.stringSize(value)); 124 } 125 126 /** 127 * Mix value length and coder into current length and coder. 128 * @param lengthCoder String length with coder packed into higher bits 129 * the upper word. 130 * @param value value to mix in 131 * @return new length and coder 132 */ mix(long lengthCoder, String value)133 static long mix(long lengthCoder, String value) { 134 lengthCoder += value.length(); 135 if (value.coder() == String.UTF16) { 136 lengthCoder |= UTF16; 137 } 138 return checkOverflow(lengthCoder); 139 } 140 141 /** 142 * Prepends the stringly representation of boolean value into buffer, 143 * given the coder and final index. Index is measured in chars, not in bytes! 144 * 145 * @param indexCoder final char index in the buffer, along with coder packed 146 * into higher bits. 147 * @param buf buffer to append to 148 * @param value boolean value to encode 149 * @return updated index (coder value retained) 150 */ prepend(long indexCoder, byte[] buf, boolean value)151 private static long prepend(long indexCoder, byte[] buf, boolean value) { 152 int index = (int)indexCoder; 153 if (indexCoder < UTF16) { 154 if (value) { 155 buf[--index] = 'e'; 156 buf[--index] = 'u'; 157 buf[--index] = 'r'; 158 buf[--index] = 't'; 159 } else { 160 buf[--index] = 'e'; 161 buf[--index] = 's'; 162 buf[--index] = 'l'; 163 buf[--index] = 'a'; 164 buf[--index] = 'f'; 165 } 166 return index; 167 } else { 168 if (value) { 169 StringUTF16.putChar(buf, --index, 'e'); 170 StringUTF16.putChar(buf, --index, 'u'); 171 StringUTF16.putChar(buf, --index, 'r'); 172 StringUTF16.putChar(buf, --index, 't'); 173 } else { 174 StringUTF16.putChar(buf, --index, 'e'); 175 StringUTF16.putChar(buf, --index, 's'); 176 StringUTF16.putChar(buf, --index, 'l'); 177 StringUTF16.putChar(buf, --index, 'a'); 178 StringUTF16.putChar(buf, --index, 'f'); 179 } 180 return index | UTF16; 181 } 182 } 183 184 /** 185 * Prepends constant and the stringly representation of value into buffer, 186 * given the coder and final index. Index is measured in chars, not in bytes! 187 * 188 * @param indexCoder final char index in the buffer, along with coder packed 189 * into higher bits. 190 * @param buf buffer to append to 191 * @param value boolean value to encode 192 * @param prefix a constant to prepend before value 193 * @return updated index (coder value retained) 194 */ prepend(long indexCoder, byte[] buf, boolean value, String prefix)195 static long prepend(long indexCoder, byte[] buf, boolean value, String prefix) { 196 indexCoder = prepend(indexCoder, buf, value); 197 if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); 198 return indexCoder; 199 } 200 201 /** 202 * Prepends constant and the stringly representation of value into buffer, 203 * given the coder and final index. Index is measured in chars, not in bytes! 204 * 205 * @param indexCoder final char index in the buffer, along with coder packed 206 * into higher bits. 207 * @param buf buffer to append to 208 * @param value boolean value to encode 209 * @param prefix a constant to prepend before value 210 * @return updated index (coder value retained) 211 */ prepend(long indexCoder, byte[] buf, byte value, String prefix)212 static long prepend(long indexCoder, byte[] buf, byte value, String prefix) { 213 indexCoder = prepend(indexCoder, buf, (int)value); 214 if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); 215 return indexCoder; 216 } 217 218 /** 219 * Prepends the stringly representation of char value into buffer, 220 * given the coder and final index. Index is measured in chars, not in bytes! 221 * 222 * @param indexCoder final char index in the buffer, along with coder packed 223 * into higher bits. 224 * @param buf buffer to append to 225 * @param value char value to encode 226 * @return updated index (coder value retained) 227 */ prepend(long indexCoder, byte[] buf, char value)228 private static long prepend(long indexCoder, byte[] buf, char value) { 229 if (indexCoder < UTF16) { 230 buf[(int)(--indexCoder)] = (byte) (value & 0xFF); 231 } else { 232 StringUTF16.putChar(buf, (int)(--indexCoder), value); 233 } 234 return indexCoder; 235 } 236 237 /** 238 * Prepends constant and the stringly representation of value into buffer, 239 * given the coder and final index. Index is measured in chars, not in bytes! 240 * 241 * @param indexCoder final char index in the buffer, along with coder packed 242 * into higher bits. 243 * @param buf buffer to append to 244 * @param value boolean value to encode 245 * @param prefix a constant to prepend before value 246 * @return updated index (coder value retained) 247 */ prepend(long indexCoder, byte[] buf, char value, String prefix)248 static long prepend(long indexCoder, byte[] buf, char value, String prefix) { 249 indexCoder = prepend(indexCoder, buf, value); 250 if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); 251 return indexCoder; 252 } 253 254 /** 255 * Prepends constant and the stringly representation of value into buffer, 256 * given the coder and final index. Index is measured in chars, not in bytes! 257 * 258 * @param indexCoder final char index in the buffer, along with coder packed 259 * into higher bits. 260 * @param buf buffer to append to 261 * @param value boolean value to encode 262 * @param prefix a constant to prepend before value 263 * @return updated index (coder value retained) 264 */ prepend(long indexCoder, byte[] buf, short value, String prefix)265 static long prepend(long indexCoder, byte[] buf, short value, String prefix) { 266 indexCoder = prepend(indexCoder, buf, (int)value); 267 if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); 268 return indexCoder; 269 } 270 271 /** 272 * Prepends the stringly representation of integer value into buffer, 273 * given the coder and final index. Index is measured in chars, not in bytes! 274 * 275 * @param indexCoder final char index in the buffer, along with coder packed 276 * into higher bits. 277 * @param buf buffer to append to 278 * @param value integer value to encode 279 * @return updated index (coder value retained) 280 */ prepend(long indexCoder, byte[] buf, int value)281 private static long prepend(long indexCoder, byte[] buf, int value) { 282 if (indexCoder < UTF16) { 283 return Integer.getChars(value, (int)indexCoder, buf); 284 } else { 285 return StringUTF16.getChars(value, (int)indexCoder, buf) | UTF16; 286 } 287 } 288 289 /** 290 * Prepends constant and the stringly representation of value into buffer, 291 * given the coder and final index. Index is measured in chars, not in bytes! 292 * 293 * @param indexCoder final char index in the buffer, along with coder packed 294 * into higher bits. 295 * @param buf buffer to append to 296 * @param value boolean value to encode 297 * @param prefix a constant to prepend before value 298 * @return updated index (coder value retained) 299 */ prepend(long indexCoder, byte[] buf, int value, String prefix)300 static long prepend(long indexCoder, byte[] buf, int value, String prefix) { 301 indexCoder = prepend(indexCoder, buf, value); 302 if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); 303 return indexCoder; 304 } 305 306 /** 307 * Prepends the stringly representation of long value into buffer, 308 * given the coder and final index. Index is measured in chars, not in bytes! 309 * 310 * @param indexCoder final char index in the buffer, along with coder packed 311 * into higher bits. 312 * @param buf buffer to append to 313 * @param value long value to encode 314 * @return updated index (coder value retained) 315 */ prepend(long indexCoder, byte[] buf, long value)316 private static long prepend(long indexCoder, byte[] buf, long value) { 317 if (indexCoder < UTF16) { 318 return Long.getChars(value, (int)indexCoder, buf); 319 } else { 320 return StringUTF16.getChars(value, (int)indexCoder, buf) | UTF16; 321 } 322 } 323 324 /** 325 * Prepends constant and the stringly representation of value into buffer, 326 * given the coder and final index. Index is measured in chars, not in bytes! 327 * 328 * @param indexCoder final char index in the buffer, along with coder packed 329 * into higher bits. 330 * @param buf buffer to append to 331 * @param value boolean value to encode 332 * @param prefix a constant to prepend before value 333 * @return updated index (coder value retained) 334 */ prepend(long indexCoder, byte[] buf, long value, String prefix)335 static long prepend(long indexCoder, byte[] buf, long value, String prefix) { 336 indexCoder = prepend(indexCoder, buf, value); 337 if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); 338 return indexCoder; 339 } 340 341 /** 342 * Prepends the stringly representation of String value into buffer, 343 * given the coder and final index. Index is measured in chars, not in bytes! 344 * 345 * @param indexCoder final char index in the buffer, along with coder packed 346 * into higher bits. 347 * @param buf buffer to append to 348 * @param value String value to encode 349 * @return updated index (coder value retained) 350 */ prepend(long indexCoder, byte[] buf, String value)351 private static long prepend(long indexCoder, byte[] buf, String value) { 352 indexCoder -= value.length(); 353 if (indexCoder < UTF16) { 354 value.getBytes(buf, (int)indexCoder, String.LATIN1); 355 } else { 356 value.getBytes(buf, (int)indexCoder, String.UTF16); 357 } 358 return indexCoder; 359 } 360 361 /** 362 * Prepends constant and the stringly representation of value into buffer, 363 * given the coder and final index. Index is measured in chars, not in bytes! 364 * 365 * @param indexCoder final char index in the buffer, along with coder packed 366 * into higher bits. 367 * @param buf buffer to append to 368 * @param value boolean value to encode 369 * @param prefix a constant to prepend before value 370 * @return updated index (coder value retained) 371 */ prepend(long indexCoder, byte[] buf, String value, String prefix)372 static long prepend(long indexCoder, byte[] buf, String value, String prefix) { 373 indexCoder = prepend(indexCoder, buf, value); 374 if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); 375 return indexCoder; 376 } 377 378 /** 379 * Instantiates the String with given buffer and coder 380 * @param buf buffer to use 381 * @param indexCoder remaining index (should be zero) and coder 382 * @return String resulting string 383 */ newString(byte[] buf, long indexCoder)384 static String newString(byte[] buf, long indexCoder) { 385 // Use the private, non-copying constructor (unsafe!) 386 if (indexCoder == LATIN1) { 387 return new String(buf, String.LATIN1); 388 } else if (indexCoder == UTF16) { 389 return new String(buf, String.UTF16); 390 } else { 391 throw new InternalError("Storage is not completely initialized, " + (int)indexCoder + " bytes left"); 392 } 393 } 394 395 /** 396 * Perform a simple concatenation between two objects. Added for startup 397 * performance, but also demonstrates the code that would be emitted by 398 * {@code java.lang.invoke.StringConcatFactory$MethodHandleInlineCopyStrategy} 399 * for two Object arguments. 400 * 401 * @param first first argument 402 * @param second second argument 403 * @return String resulting string 404 */ 405 @ForceInline simpleConcat(Object first, Object second)406 static String simpleConcat(Object first, Object second) { 407 String s1 = stringOf(first); 408 String s2 = stringOf(second); 409 if (s1.isEmpty()) { 410 // newly created string required, see JLS 15.18.1 411 return new String(s2); 412 } 413 if (s2.isEmpty()) { 414 // newly created string required, see JLS 15.18.1 415 return new String(s1); 416 } 417 // start "mixing" in length and coder or arguments, order is not 418 // important 419 long indexCoder = mix(initialCoder(), s1); 420 indexCoder = mix(indexCoder, s2); 421 byte[] buf = newArray(indexCoder); 422 // prepend each argument in reverse order, since we prepending 423 // from the end of the byte array 424 indexCoder = prepend(indexCoder, buf, s2); 425 indexCoder = prepend(indexCoder, buf, s1); 426 return newString(buf, indexCoder); 427 } 428 429 /** 430 * Produce a String from a concatenation of single argument, which we 431 * end up using for trivial concatenations like {@code "" + arg}. 432 * 433 * This will always create a new Object to comply with JLS 15.18.1: 434 * "The String object is newly created unless the expression is a 435 * compile-time constant expression". 436 * 437 * @param arg the only argument 438 * @return String resulting string 439 */ 440 @ForceInline newStringOf(Object arg)441 static String newStringOf(Object arg) { 442 return new String(stringOf(arg)); 443 } 444 445 /** 446 * We need some additional conversion for Objects in general, because 447 * {@code String.valueOf(Object)} may return null. String conversion rules 448 * in Java state we need to produce "null" String in this case, so we 449 * provide a customized version that deals with this problematic corner case. 450 */ stringOf(Object value)451 static String stringOf(Object value) { 452 String s; 453 return (value == null || (s = value.toString()) == null) ? "null" : s; 454 } 455 456 private static final long LATIN1 = (long)String.LATIN1 << 32; 457 458 private static final long UTF16 = (long)String.UTF16 << 32; 459 460 private static final Unsafe UNSAFE = Unsafe.getUnsafe(); 461 462 /** 463 * Allocates an uninitialized byte array based on the length and coder 464 * information, then prepends the given suffix string at the end of the 465 * byte array before returning it. The calling code must adjust the 466 * indexCoder so that it's taken the coder of the suffix into account, but 467 * subtracted the length of the suffix. 468 * 469 * @param suffix 470 * @param indexCoder 471 * @return the newly allocated byte array 472 */ 473 @ForceInline newArrayWithSuffix(String suffix, long indexCoder)474 static byte[] newArrayWithSuffix(String suffix, long indexCoder) { 475 byte[] buf = newArray(indexCoder + suffix.length()); 476 if (indexCoder < UTF16) { 477 suffix.getBytes(buf, (int)indexCoder, String.LATIN1); 478 } else { 479 suffix.getBytes(buf, (int)indexCoder, String.UTF16); 480 } 481 return buf; 482 } 483 484 /** 485 * Allocates an uninitialized byte array based on the length and coder information 486 * in indexCoder 487 * @param indexCoder 488 * @return the newly allocated byte array 489 */ 490 @ForceInline newArray(long indexCoder)491 static byte[] newArray(long indexCoder) { 492 byte coder = (byte)(indexCoder >> 32); 493 int index = (int)indexCoder; 494 return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, index << coder); 495 } 496 497 /** 498 * Provides the initial coder for the String. 499 * @return initial coder, adjusted into the upper half 500 */ initialCoder()501 static long initialCoder() { 502 return String.COMPACT_STRINGS ? LATIN1 : UTF16; 503 } 504 lookupStatic(String name, MethodType methodType)505 static MethodHandle lookupStatic(String name, MethodType methodType) { 506 try { 507 return MethodHandles.lookup().findStatic(StringConcatHelper.class, name, methodType); 508 } catch (NoSuchMethodException|IllegalAccessException e) { 509 throw new AssertionError(e); 510 } 511 } 512 513 } 514