mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 06:45:07 +02:00
8339290: Optimize ClassFile Utf8EntryImpl#writeTo
Reviewed-by: redestad, liach
This commit is contained in:
parent
340e131d61
commit
cb9f5c5791
7 changed files with 268 additions and 49 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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}.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue