Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 31 additions & 16 deletions core/src/main/java/com/alibaba/fastjson2/JSONReaderUTF16.java
Original file line number Diff line number Diff line change
Expand Up @@ -1115,6 +1115,11 @@ public final long readFieldNameHashCodeUnquote() {

@Override
public final long readFieldNameHashCode() {
// JDK 8 HotSpot C2 on aarch64 can miscompile the UNSAFE.getLong SWAR scan.
if (AARCH64_JDK8) {
return readFieldNameHashCode0();
}

final char[] chars = this.chars;
int ch = this.ch;
if (ch == '/') {
Expand Down Expand Up @@ -1181,6 +1186,11 @@ public final long readFieldNameHashCode() {

@Override
public final long readFieldNameHashCode(int keySize, int min, int max) {
// JDK 8 HotSpot C2 on aarch64 can miscompile the UNSAFE.getLong SWAR scan.
if (AARCH64_JDK8) {
return readFieldNameHashCode0();
}

final char[] chars = this.chars;
int ch = this.ch;
if (ch == '/') {
Expand Down Expand Up @@ -1252,6 +1262,11 @@ public final long readFieldNameHashCode(int keySize, int min, int max) {

@Override
public long readFieldNameHashCodeE(int size0, int size1, int size3) {
// JDK 8 HotSpot C2 on aarch64 can miscompile the UNSAFE.getLong SWAR scan.
if (AARCH64_JDK8) {
return readFieldNameHashCode0();
}

final char[] chars = this.chars;
int ch = this.ch;
if (ch == '/') {
Expand Down Expand Up @@ -1370,15 +1385,15 @@ private final long readFieldNameHashCode0() {
if (c0 == quote) {
nameValue = 0;
} else if (c1 == quote && c0 != 0 && c0 != '\\' && c0 <= 0xFF) {
nameValue = (byte) c0;
nameValue = c0;
this.nameLength = 1;
this.nameEnd = offset + 1;
offset += 2;
} else if (c2 == quote && c0 != 0
&& c0 != '\\' && c1 != '\\'
&& c0 <= 0xFF && c1 <= 0xFF
) {
nameValue = (((byte) c1) << 8)
nameValue = (c1 << 8)
+ c0;
this.nameLength = 2;
this.nameEnd = offset + 2;
Expand All @@ -1387,7 +1402,7 @@ private final long readFieldNameHashCode0() {
&& c0 != '\\' && c1 != '\\' && c2 != '\\'
&& c0 <= 0xFF && c1 <= 0xFF && c2 <= 0xFF) {
nameValue
= (((byte) c2) << 16)
= (c2 << 16)
+ (c1 << 8)
+ c0;
this.nameLength = 3;
Expand All @@ -1398,7 +1413,7 @@ private final long readFieldNameHashCode0() {
&& c0 <= 0xFF && c1 <= 0xFF && c2 <= 0xFF && c3 <= 0xFF
) {
nameValue
= (((byte) c3) << 24)
= (((long) c3) << 24)
+ (c2 << 16)
+ (c1 << 8)
+ c0;
Expand All @@ -1410,7 +1425,7 @@ private final long readFieldNameHashCode0() {
&& c0 <= 0xFF && c1 <= 0xFF && c2 <= 0xFF && c3 <= 0xFF && c4 <= 0xFF
) {
nameValue
= (((long) ((byte) c4)) << 32)
= (((long) c4) << 32)
+ (((long) c3) << 24)
+ (((long) c2) << 16)
+ (((long) c1) << 8)
Expand All @@ -1423,7 +1438,7 @@ private final long readFieldNameHashCode0() {
&& c0 <= 0xFF && c1 <= 0xFF && c2 <= 0xFF && c3 <= 0xFF && c4 <= 0xFF && c5 <= 0xFF
) {
nameValue
= (((long) ((byte) c5)) << 40)
= (((long) c5) << 40)
+ (((long) c4) << 32)
+ (((long) c3) << 24)
+ (((long) c2) << 16)
Expand All @@ -1437,7 +1452,7 @@ private final long readFieldNameHashCode0() {
&& c0 <= 0xFF && c1 <= 0xFF && c2 <= 0xFF && c3 <= 0xFF && c4 <= 0xFF && c5 <= 0xFF && c6 <= 0xFF
) {
nameValue
= (((long) ((byte) c6)) << 48)
= (((long) c6) << 48)
+ (((long) c5) << 40)
+ (((long) c4) << 32)
+ (((long) c3) << 24)
Expand All @@ -1452,7 +1467,7 @@ private final long readFieldNameHashCode0() {
&& c0 <= 0xFF && c1 <= 0xFF && c2 <= 0xFF && c3 <= 0xFF && c4 <= 0xFF && c5 <= 0xFF && c6 <= 0xFF && c7 <= 0xFF
) {
nameValue
= (((long) ((byte) c7)) << 56)
= (((long) c7) << 56)
+ (((long) c6) << 48)
+ (((long) c5) << 40)
+ (((long) c4) << 32)
Expand Down Expand Up @@ -1512,28 +1527,28 @@ private final long readFieldNameHashCode0() {

switch (i) {
case 0:
nameValue = (byte) c;
nameValue = c;
break;
case 1:
nameValue = (((byte) c) << 8) + (nameValue & 0xFFL);
nameValue = ((long) c << 8) + (nameValue & 0xFFL);
break;
case 2:
nameValue = (((byte) c) << 16) + (nameValue & 0xFFFFL);
nameValue = ((long) c << 16) + (nameValue & 0xFFFFL);
break;
case 3:
nameValue = (((byte) c) << 24) + (nameValue & 0xFFFFFFL);
nameValue = ((long) c << 24) + (nameValue & 0xFFFFFFL);
break;
case 4:
nameValue = (((long) (byte) c) << 32) + (nameValue & 0xFFFFFFFFL);
nameValue = ((long) c << 32) + (nameValue & 0xFFFFFFFFL);
break;
case 5:
nameValue = (((long) (byte) c) << 40L) + (nameValue & 0xFFFFFFFFFFL);
nameValue = ((long) c << 40L) + (nameValue & 0xFFFFFFFFFFL);
break;
case 6:
nameValue = (((long) (byte) c) << 48L) + (nameValue & 0xFFFFFFFFFFFFL);
nameValue = ((long) c << 48L) + (nameValue & 0xFFFFFFFFFFFFL);
break;
case 7:
nameValue = (((long) (byte) c) << 56L) + (nameValue & 0xFFFFFFFFFFFFFFL);
nameValue = ((long) c << 56L) + (nameValue & 0xFFFFFFFFFFFFFFL);
break;
default:
break;
Expand Down
62 changes: 62 additions & 0 deletions core/src/main/java/com/alibaba/fastjson2/util/IOUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -1200,6 +1200,9 @@ public static int writeLocalTime(char[] buf, int off, LocalTime time) {
}

private static int writeInt4(byte[] buf, int off, int v) {
if (JDKUtils.AARCH64_JDK8) {
return writeIntNSafe(buf, off, v, 4);
}
int v1 = (int) (v * 1374389535L >> 37); // v / 100;
int v0 = v - v1 * 100;
int v2 = PACKED_DIGITS[v1 & 0x7f] | (PACKED_DIGITS[v0 & 0x7f] << 16);
Expand All @@ -1211,6 +1214,9 @@ private static int writeInt4(byte[] buf, int off, int v) {
}

private static int writeInt4(char[] buf, int off, int v) {
if (JDKUtils.AARCH64_JDK8) {
return writeIntNSafe(buf, off, v, 4);
}
int v1 = (int) (v * 1374389535L >> 37); // v / 100;
putLongUnaligned(buf, off, mergeInt64(v - v1 * 100, v1));
return off + 4;
Expand All @@ -1225,18 +1231,27 @@ private static long mergeInt64(int v1, int v2) {
}

private static int writeInt3(byte[] buf, int off, int val) {
if (JDKUtils.AARCH64_JDK8) {
return writeInt3Safe(buf, off, val);
}
int v = DIGITS_K_32[val & 0x3ff];
UNSAFE.putInt(buf, ARRAY_BYTE_BASE_OFFSET + off, v >> ((((byte) v) + 1) << 3));
return off + 3 - (byte) v;
}

private static int writeInt3(char[] buf, int off, int val) {
if (JDKUtils.AARCH64_JDK8) {
return writeInt3Safe(buf, off, val);
}
long v = DIGITS_K_64[val & 0x3ff];
UNSAFE.putLong(buf, ARRAY_CHAR_BASE_OFFSET + ((long) off << 1), v >> ((((short) v) + 1) << 4));
return off + 3 - (byte) v;
}

private static int writeInt8(byte[] buf, int off, int v1, int v2) {
if (JDKUtils.AARCH64_JDK8) {
return writeInt8Safe(buf, off, v1, v2);
}
int r1 = (int) (v1 * 1374389535L >> 37); // v1 / 100;
int r2 = (int) (v2 * 1374389535L >> 37); // v2 / 100;
long v = (PACKED_DIGITS[r1 & 0x7f])
Expand All @@ -1251,6 +1266,9 @@ private static int writeInt8(byte[] buf, int off, int v1, int v2) {
}

private static int writeInt8(char[] buf, int off, int v1, int v2) {
if (JDKUtils.AARCH64_JDK8) {
return writeInt8Safe(buf, off, v1, v2);
}
int r1 = (int) (v1 * 1374389535L >> 37); // v1 / 100;
long x1 = (PACKED_DIGITS_UTF16[r1 & 0x7f])
| ((long) PACKED_DIGITS_UTF16[(v1 - r1 * 100) & 0x7f] << 32);
Expand All @@ -1266,6 +1284,50 @@ private static int writeInt8(char[] buf, int off, int v1, int v2) {
return off + 8;
}

static int writeInt3Safe(byte[] buf, int off, int value) {
int length = value < 100 ? (value < 10 ? 1 : 2) : 3;
for (int i = length; i > 0; i--) {
buf[off + i - 1] = (byte) ('0' + value % 10);
value /= 10;
}
return off + length;
}

static int writeInt3Safe(char[] buf, int off, int value) {
int length = value < 100 ? (value < 10 ? 1 : 2) : 3;
for (int i = length; i > 0; i--) {
buf[off + i - 1] = (char) ('0' + value % 10);
value /= 10;
}
return off + length;
}

static int writeIntNSafe(byte[] buf, int off, int value, int digits) {
for (int i = digits; i > 0; i--) {
buf[off + i - 1] = (byte) ('0' + value % 10);
value /= 10;
}
return off + digits;
}

static int writeIntNSafe(char[] buf, int off, int value, int digits) {
for (int i = digits; i > 0; i--) {
buf[off + i - 1] = (char) ('0' + value % 10);
value /= 10;
}
return off + digits;
}

static int writeInt8Safe(byte[] buf, int off, int high, int low) {
off = writeIntNSafe(buf, off, high, 4);
return writeIntNSafe(buf, off, low, 4);
}

static int writeInt8Safe(char[] buf, int off, int high, int low) {
off = writeIntNSafe(buf, off, high, 4);
return writeIntNSafe(buf, off, low, 4);
}

/**
* Writes a 64-bit long integer value to a byte array.
* This method converts a long integer to its string representation and writes it
Expand Down
12 changes: 12 additions & 0 deletions core/src/main/java/com/alibaba/fastjson2/util/JDKUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,11 @@ public class JDKUtils {
public static final long ARRAY_CHAR_BASE_OFFSET;

public static final int JVM_VERSION;
public static final String OS_ARCH;
public static final Byte LATIN1 = 0;
public static final boolean AARCH64;
public static final Byte UTF16 = 1;
public static final boolean AARCH64_JDK8;

public static final Field FIELD_STRING_VALUE;
public static final long FIELD_STRING_VALUE_OFFSET;
Expand Down Expand Up @@ -87,8 +90,10 @@ public class JDKUtils {
}

int jvmVersion = -1, android_sdk_int = -1;
String osArch = null;
boolean openj9 = false, android = false, graal = false;
try {
osArch = System.getProperty("os.arch");
String jvmName = System.getProperty("java.vm.name");
if (jvmName != null) {
openj9 = jvmName.contains("OpenJ9");
Expand Down Expand Up @@ -122,6 +127,9 @@ public class JDKUtils {
GRAAL = graal;
ANDROID_SDK_INT = android_sdk_int;

OS_ARCH = osArch;
AARCH64 = "aarch64".equals(osArch) || "arm64".equals(osArch);

boolean hasJavaSql = true;
Class dataSourceClass = null;
Class rowSetClass = null;
Expand All @@ -145,6 +153,10 @@ public class JDKUtils {
CLASS_TRANSIENT = transientClass;

JVM_VERSION = jvmVersion;
// JDK 8 HotSpot C2 on aarch64 can miscompile the UNSAFE.getLong SWAR
// field-name scan. Keep the safe char[] path for #7732/#3763 until
// affected JDK 8 builds are no longer supported.
AARCH64_JDK8 = AARCH64 && JVM_VERSION == 8 && !ANDROID && !GRAAL && !OPENJ9;

if (JVM_VERSION == 8) {
Field field = null;
Expand Down
Loading