8339290: Optimize ClassFile Utf8EntryImpl#writeTo

Reviewed-by: redestad, liach
This commit is contained in:
Shaojin Wen 2024-09-05 11:45:49 +00:00 committed by Claes Redestad
parent 340e131d61
commit cb9f5c5791
7 changed files with 268 additions and 49 deletions

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, Alibaba Group Holding Limited. 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
@ -34,6 +35,45 @@ class StringCoding {
private StringCoding() { }
/**
* Count the number of leading non-zero ascii chars in the range.
*/
public static int countNonZeroAscii(String s) {
byte[] value = s.value();
if (s.isLatin1()) {
return countNonZeroAsciiLatin1(value, 0, value.length);
} else {
return countNonZeroAsciiUTF16(value, 0, s.length());
}
}
/**
* Count the number of non-zero ascii chars in the range.
*/
public static int countNonZeroAsciiLatin1(byte[] ba, int off, int len) {
int limit = off + len;
for (int i = off; i < limit; i++) {
if (ba[i] <= 0) {
return i - off;
}
}
return len;
}
/**
* Count the number of leading non-zero ascii chars in the range.
*/
public static int countNonZeroAsciiUTF16(byte[] ba, int off, int strlen) {
int limit = off + strlen;
for (int i = off; i < limit; i++) {
char c = StringUTF16.charAt(ba, i);
if (c == 0 || c > 0x7F) {
return i - off;
}
}
return strlen;
}
public static boolean hasNegatives(byte[] ba, int off, int len) {
return countPositives(ba, off, len) != len;
}

View file

@ -2569,6 +2569,9 @@ public final class System {
public int countPositives(byte[] bytes, int offset, int length) {
return StringCoding.countPositives(bytes, offset, length);
}
public int countNonZeroAscii(String s) {
return StringCoding.countNonZeroAscii(s);
}
public String newStringNoRepl(byte[] bytes, Charset cs) throws CharacterCodingException {
return String.newStringNoRepl(bytes, cs);
}

View file

@ -318,6 +318,11 @@ public interface JavaLangAccess {
*/
int countPositives(byte[] ba, int off, int len);
/**
* Count the number of leading non-zero ascii chars in the String.
*/
int countNonZeroAscii(String s);
/**
* Constructs a new {@code String} by decoding the specified subarray of
* bytes using the specified {@linkplain java.nio.charset.Charset charset}.

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, Alibaba Group Holding Limited. 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
@ -409,60 +410,14 @@ public abstract sealed class AbstractPoolEntry {
@Override
void writeTo(BufWriterImpl pool) {
pool.writeU1(tag);
if (rawBytes != null) {
pool.writeU1(tag);
pool.writeU2(rawLen);
pool.writeBytes(rawBytes, offset, rawLen);
}
else {
// state == STRING and no raw bytes
if (stringValue.length() > 65535) {
throw new IllegalArgumentException("string too long");
}
pool.writeU1(tag);
pool.writeU2(charLen);
for (int i = 0; i < charLen; ++i) {
char c = stringValue.charAt(i);
if (c >= '\001' && c <= '\177') {
// Optimistic writing -- hope everything is bytes
// If not, we bail out, and alternate path patches the length
pool.writeU1((byte) c);
}
else {
int charLength = stringValue.length();
int byteLength = i;
char c1;
for (int j = i; j < charLength; ++j) {
c1 = (stringValue).charAt(j);
if (c1 >= '\001' && c1 <= '\177') {
byteLength++;
} else if (c1 > '\u07FF') {
byteLength += 3;
} else {
byteLength += 2;
}
}
if (byteLength > 65535) {
throw new IllegalArgumentException();
}
int byteLengthFinal = byteLength;
pool.patchInt(pool.size() - i - 2, 2, byteLengthFinal);
for (int j = i; j < charLength; ++j) {
c1 = (stringValue).charAt(j);
if (c1 >= '\001' && c1 <= '\177') {
pool.writeU1((byte) c1);
} else if (c1 > '\u07FF') {
pool.writeU1((byte) (0xE0 | c1 >> 12 & 0xF));
pool.writeU1((byte) (0x80 | c1 >> 6 & 0x3F));
pool.writeU1((byte) (0x80 | c1 & 0x3F));
} else {
pool.writeU1((byte) (0xC0 | c1 >> 6 & 0x1F));
pool.writeU1((byte) (0x80 | c1 & 0x3F));
}
}
break;
}
}
pool.writeUTF(stringValue);
}
}
}

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2024, Alibaba Group Holding Limited. 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
@ -34,7 +35,11 @@ import java.lang.classfile.constantpool.ConstantPool;
import java.lang.classfile.constantpool.ConstantPoolBuilder;
import java.lang.classfile.constantpool.PoolEntry;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
public final class BufWriterImpl implements BufWriter {
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
private final ConstantPoolBuilder constantPool;
private final ClassFileImpl context;
@ -152,6 +157,52 @@ public final class BufWriterImpl implements BufWriter {
writeBytes(other.elems, 0, other.offset);
}
@SuppressWarnings("deprecation")
void writeUTF(String str) {
int strlen = str.length();
int countNonZeroAscii = JLA.countNonZeroAscii(str);
int utflen = strlen;
if (countNonZeroAscii != strlen) {
for (int i = countNonZeroAscii; i < strlen; i++) {
int c = str.charAt(i);
if (c >= 0x80 || c == 0)
utflen += (c >= 0x800) ? 2 : 1;
}
}
if (utflen > 65535) {
throw new IllegalArgumentException("string too long");
}
reserveSpace(utflen + 2);
int offset = this.offset;
byte[] elems = this.elems;
elems[offset ] = (byte) (utflen >> 8);
elems[offset + 1] = (byte) utflen;
offset += 2;
str.getBytes(0, countNonZeroAscii, elems, offset);
offset += countNonZeroAscii;
for (int i = countNonZeroAscii; i < strlen; ++i) {
char c = str.charAt(i);
if (c >= '\001' && c <= '\177') {
elems[offset++] = (byte) c;
} else if (c > '\u07FF') {
elems[offset ] = (byte) (0xE0 | c >> 12 & 0xF);
elems[offset + 1] = (byte) (0x80 | c >> 6 & 0x3F);
elems[offset + 2] = (byte) (0x80 | c & 0x3F);
offset += 3;
} else {
elems[offset ] = (byte) (0xC0 | c >> 6 & 0x1F);
elems[offset + 1] = (byte) (0x80 | c & 0x3F);
offset += 2;
}
}
this.offset = offset;
}
@Override
public void writeBytes(byte[] arr, int start, int length) {
reserveSpace(length);