8261744: Implement CharsetDecoder ASCII and latin-1 fast-paths

Reviewed-by: naoto, alanb
This commit is contained in:
Claes Redestad 2021-02-19 15:05:25 +00:00
parent efbaedeb81
commit 433096a45e
13 changed files with 453 additions and 263 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2021, 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
@ -25,6 +25,9 @@
package sun.nio.cs;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
@ -75,6 +78,9 @@ class CESU_8 extends Unicode
private static class Decoder extends CharsetDecoder
implements ArrayDecoder {
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
private Decoder(Charset cs) {
super(cs, 1.0f, 1.0f);
}
@ -96,27 +102,6 @@ class CESU_8 extends Unicode
(b2 & 0xc0) != 0x80;
}
// [F0] [90..BF] [80..BF] [80..BF]
// [F1..F3] [80..BF] [80..BF] [80..BF]
// [F4] [80..8F] [80..BF] [80..BF]
// only check 80-be range here, the [0xf0,0x80...] and [0xf4,0x90-...]
// will be checked by Character.isSupplementaryCodePoint(uc)
private static boolean isMalformed4(int b2, int b3, int b4) {
return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 ||
(b4 & 0xc0) != 0x80;
}
// only used when there is less than 4 bytes left in src buffer
private static boolean isMalformed4_2(int b1, int b2) {
return (b1 == 0xf0 && b2 == 0x90) ||
(b2 & 0xc0) != 0x80;
}
private static boolean isMalformed4_3(int b3) {
return (b3 & 0xc0) != 0x80;
}
private static CoderResult malformedN(ByteBuffer src, int nb) {
switch (nb) {
case 1:
@ -202,17 +187,19 @@ class CESU_8 extends Unicode
{
// This method is optimized for ASCII input.
byte[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
int soff = src.arrayOffset();
int sp = soff + src.position();
int sl = soff + src.limit();
char[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
int dlASCII = dp + Math.min(sl - sp, dl - dp);
int doff = dst.arrayOffset();
int dp = doff + dst.position();
int dl = doff + dst.limit();
int n = JLA.decodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp));
sp += n;
dp += n;
// ASCII only loop
while (dp < dlASCII && sa[sp] >= 0)
da[dp++] = (char) sa[sp++];
while (sp < sl) {
int b1 = sa[sp];
if (b1 >= 0) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2021, 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
@ -32,6 +32,9 @@ import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.util.Arrays;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import sun.nio.cs.Surrogate;
import sun.nio.cs.ArrayDecoder;
import sun.nio.cs.ArrayEncoder;
@ -111,6 +114,8 @@ public class DoubleByte {
public static class Decoder extends CharsetDecoder
implements DelegatableDecoder, ArrayDecoder
{
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
final char[][] b2c;
final char[] b2cSB;
final int b2Min;
@ -154,14 +159,21 @@ public class DoubleByte {
protected CoderResult decodeArrayLoop(ByteBuffer src, CharBuffer dst) {
byte[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
int soff = src.arrayOffset();
int sp = soff + src.position();
int sl = soff + src.limit();
char[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
int doff = dst.arrayOffset();
int dp = doff + dst.position();
int dl = doff + dst.limit();
try {
if (isASCIICompatible) {
int n = JLA.decodeASCII(sa, sp, da, dp, Math.min(dl - dp, sl - sp));
dp += n;
sp += n;
}
while (sp < sl && dp < dl) {
// inline the decodeSingle/Double() for better performance
int inSize = 1;
@ -183,8 +195,8 @@ public class DoubleByte {
return (sp >= sl) ? CoderResult.UNDERFLOW
: CoderResult.OVERFLOW;
} finally {
src.position(sp - src.arrayOffset());
dst.position(dp - dst.arrayOffset());
src.position(sp - soff);
dst.position(dp - doff);
}
}
@ -342,7 +354,7 @@ public class DoubleByte {
else
currentState = SBCS;
} else {
char c = UNMAPPABLE_DECODING;
char c;
if (currentState == SBCS) {
c = b2cSB[b1];
if (c == UNMAPPABLE_DECODING)

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2021, 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
@ -33,6 +33,8 @@ import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.util.Objects;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.vm.annotation.IntrinsicCandidate;
public class ISO_8859_1
@ -64,6 +66,8 @@ public class ISO_8859_1
private static class Decoder extends CharsetDecoder {
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
private Decoder(Charset cs) {
super(cs, 1.0f, 1.0f);
}
@ -72,29 +76,25 @@ public class ISO_8859_1
CharBuffer dst)
{
byte[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
assert (sp <= sl);
sp = (sp <= sl ? sp : sl);
char[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
assert (dp <= dl);
dp = (dp <= dl ? dp : dl);
int soff = src.arrayOffset();
int sp = soff + src.position();
int sl = soff + src.limit();
try {
while (sp < sl) {
byte b = sa[sp];
if (dp >= dl)
return CoderResult.OVERFLOW;
da[dp++] = (char)(b & 0xff);
sp++;
}
return CoderResult.UNDERFLOW;
} finally {
src.position(sp - src.arrayOffset());
dst.position(dp - dst.arrayOffset());
char[] da = dst.array();
int doff = dst.arrayOffset();
int dp = doff + dst.position();
int dl = doff + dst.limit();
int decodeLen = Math.min(sl - sp, dl - dp);
JLA.inflateBytesToChars(sa, sp, da, dp, decodeLen);
sp += decodeLen;
dp += decodeLen;
src.position(sp - soff);
dst.position(dp - doff);
if (sl - sp > dl - dp) {
return CoderResult.OVERFLOW;
}
return CoderResult.UNDERFLOW;
}
private CoderResult decodeBufferLoop(ByteBuffer src,

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2008, 2021, 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
@ -25,6 +25,9 @@
package sun.nio.cs;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
@ -48,6 +51,9 @@ public class SingleByte
public static final class Decoder extends CharsetDecoder
implements ArrayDecoder {
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
private final char[] b2c;
private final boolean isASCIICompatible;
private final boolean isLatin1Decodable;
@ -88,6 +94,11 @@ public class SingleByte
cr = CoderResult.OVERFLOW;
}
if (isASCIICompatible) {
int n = JLA.decodeASCII(sa, sp, da, dp, Math.min(dl - dp, sl - sp));
sp += n;
dp += n;
}
while (sp < sl) {
char c = decode(sa[sp]);
if (c == UNMAPPABLE_DECODING) {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2021, 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
@ -28,7 +28,6 @@
package sun.nio.cs;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
@ -42,9 +41,9 @@ import java.nio.charset.CharsetDecoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
public class StreamDecoder extends Reader
{
public class StreamDecoder extends Reader {
private static final int MIN_BYTE_BUFFER_SIZE = 32;
private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
@ -72,13 +71,14 @@ public class StreamDecoder extends Reader
throws UnsupportedEncodingException
{
String csn = charsetName;
if (csn == null)
if (csn == null) {
csn = Charset.defaultCharset().name();
}
try {
if (Charset.isSupported(csn))
return new StreamDecoder(in, lock, Charset.forName(csn));
} catch (IllegalCharsetNameException x) { }
throw new UnsupportedEncodingException (csn);
return new StreamDecoder(in, lock, Charset.forName(csn));
} catch (IllegalCharsetNameException | UnsupportedCharsetException x) {
throw new UnsupportedEncodingException (csn);
}
}
public static StreamDecoder forInputStreamReader(InputStream in,
@ -133,7 +133,7 @@ public class StreamDecoder extends Reader
}
// Convert more bytes
char cb[] = new char[2];
char[] cb = new char[2];
int n = read(cb, 0, 2);
switch (n) {
case -1:
@ -151,7 +151,7 @@ public class StreamDecoder extends Reader
}
}
public int read(char cbuf[], int offset, int length) throws IOException {
public int read(char[] cbuf, int offset, int length) throws IOException {
int off = offset;
int len = length;
synchronized (lock) {
@ -215,54 +215,28 @@ public class StreamDecoder extends Reader
// -- Charset-based stream decoder impl --
// In the early stages of the build we haven't yet built the NIO native
// code, so guard against that by catching the first UnsatisfiedLinkError
// and setting this flag so that later attempts fail quickly.
//
private static volatile boolean channelsAvailable = true;
private static FileChannel getChannel(FileInputStream in) {
if (!channelsAvailable)
return null;
try {
return in.getChannel();
} catch (UnsatisfiedLinkError x) {
channelsAvailable = false;
return null;
}
}
private Charset cs;
private CharsetDecoder decoder;
private ByteBuffer bb;
private final Charset cs;
private final CharsetDecoder decoder;
private final ByteBuffer bb;
// Exactly one of these is non-null
private InputStream in;
private ReadableByteChannel ch;
private final InputStream in;
private final ReadableByteChannel ch;
StreamDecoder(InputStream in, Object lock, Charset cs) {
this(in, lock,
cs.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE));
cs.newDecoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE));
}
StreamDecoder(InputStream in, Object lock, CharsetDecoder dec) {
super(lock);
this.cs = dec.charset();
this.decoder = dec;
// This path disabled until direct buffers are faster
if (false && in instanceof FileInputStream) {
ch = getChannel((FileInputStream)in);
if (ch != null)
bb = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE);
}
if (ch == null) {
this.in = in;
this.ch = null;
bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
}
bb.flip(); // So that bb is initially empty
}
@ -282,35 +256,34 @@ public class StreamDecoder extends Reader
private int readBytes() throws IOException {
bb.compact();
try {
if (ch != null) {
// Read from the channel
int n = ch.read(bb);
if (n < 0)
return n;
} else {
// Read from the input stream, and then update the buffer
int lim = bb.limit();
int pos = bb.position();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
assert rem > 0;
int n = in.read(bb.array(), bb.arrayOffset() + pos, rem);
if (n < 0)
return n;
if (n == 0)
throw new IOException("Underlying input stream returned zero bytes");
assert (n <= rem) : "n = " + n + ", rem = " + rem;
bb.position(pos + n);
}
if (ch != null) {
// Read from the channel
int n = ch.read(bb);
if (n < 0)
return n;
} else {
// Read from the input stream, and then update the buffer
int lim = bb.limit();
int pos = bb.position();
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
int n = in.read(bb.array(), bb.arrayOffset() + pos, rem);
if (n < 0)
return n;
if (n == 0)
throw new IOException("Underlying input stream returned zero bytes");
assert (n <= rem) : "n = " + n + ", rem = " + rem;
bb.position(pos + n);
}
} finally {
// Flip even when an IOException is thrown,
// otherwise the stream will stutter
bb.flip();
// Flip even when an IOException is thrown,
// otherwise the stream will stutter
bb.flip();
}
int rem = bb.remaining();
assert (rem != 0) : rem;
return rem;
assert (rem != 0) : rem;
return rem;
}
int implRead(char[] cbuf, int off, int end) throws IOException {
@ -322,44 +295,46 @@ public class StreamDecoder extends Reader
assert (end - off > 1);
CharBuffer cb = CharBuffer.wrap(cbuf, off, end - off);
if (cb.position() != 0)
// Ensure that cb[0] == cbuf[off]
cb = cb.slice();
if (cb.position() != 0) {
// Ensure that cb[0] == cbuf[off]
cb = cb.slice();
}
boolean eof = false;
for (;;) {
CoderResult cr = decoder.decode(bb, cb, eof);
if (cr.isUnderflow()) {
if (eof)
break;
if (!cb.hasRemaining())
break;
if ((cb.position() > 0) && !inReady())
break; // Block at most once
int n = readBytes();
if (n < 0) {
eof = true;
if ((cb.position() == 0) && (!bb.hasRemaining()))
CoderResult cr = decoder.decode(bb, cb, eof);
if (cr.isUnderflow()) {
if (eof)
break;
decoder.reset();
if (!cb.hasRemaining())
break;
if ((cb.position() > 0) && !inReady())
break; // Block at most once
int n = readBytes();
if (n < 0) {
eof = true;
if ((cb.position() == 0) && (!bb.hasRemaining()))
break;
decoder.reset();
}
continue;
}
continue;
}
if (cr.isOverflow()) {
assert cb.position() > 0;
break;
}
cr.throwException();
if (cr.isOverflow()) {
assert cb.position() > 0;
break;
}
cr.throwException();
}
if (eof) {
// ## Need to flush decoder
decoder.reset();
// ## Need to flush decoder
decoder.reset();
}
if (cb.position() == 0) {
if (eof)
if (eof) {
return -1;
}
assert false;
}
return cb.position();
@ -373,22 +348,22 @@ public class StreamDecoder extends Reader
private boolean inReady() {
try {
return (((in != null) && (in.available() > 0))
|| (ch instanceof FileChannel)); // ## RBC.available()?
return (((in != null) && (in.available() > 0))
|| (ch instanceof FileChannel)); // ## RBC.available()?
} catch (IOException x) {
return false;
return false;
}
}
boolean implReady() {
return bb.hasRemaining() || inReady();
return bb.hasRemaining() || inReady();
}
void implClose() throws IOException {
if (ch != null)
ch.close();
else
in.close();
if (ch != null) {
ch.close();
} else {
in.close();
}
}
}

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2021, 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
@ -25,7 +25,6 @@
package sun.nio.cs;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
@ -38,6 +37,7 @@ import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.CodingErrorAction;
import java.nio.charset.IllegalCharsetNameException;
import java.nio.charset.UnsupportedCharsetException;
public class StreamEncoder extends Writer
{
@ -58,13 +58,14 @@ public class StreamEncoder extends Writer
throws UnsupportedEncodingException
{
String csn = charsetName;
if (csn == null)
if (csn == null) {
csn = Charset.defaultCharset().name();
}
try {
if (Charset.isSupported(csn))
return new StreamEncoder(out, lock, Charset.forName(csn));
} catch (IllegalCharsetNameException x) { }
throw new UnsupportedEncodingException (csn);
return new StreamEncoder(out, lock, Charset.forName(csn));
} catch (IllegalCharsetNameException | UnsupportedCharsetException x) {
throw new UnsupportedEncodingException (csn);
}
}
public static StreamEncoder forOutputStreamWriter(OutputStream out,
@ -114,12 +115,12 @@ public class StreamEncoder extends Writer
}
public void write(int c) throws IOException {
char cbuf[] = new char[1];
char[] cbuf = new char[1];
cbuf[0] = (char) c;
write(cbuf, 0, 1);
}
public void write(char cbuf[], int off, int len) throws IOException {
public void write(char[] cbuf, int off, int len) throws IOException {
synchronized (lock) {
ensureOpen();
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
@ -136,7 +137,7 @@ public class StreamEncoder extends Writer
/* Check the len before creating a char buffer */
if (len < 0)
throw new IndexOutOfBoundsException();
char cbuf[] = new char[len];
char[] cbuf = new char[len];
str.getChars(off, off + len, cbuf, 0);
write(cbuf, 0, len);
}
@ -179,13 +180,13 @@ public class StreamEncoder extends Writer
// -- Charset-based stream encoder impl --
private Charset cs;
private CharsetEncoder encoder;
private ByteBuffer bb;
private final Charset cs;
private final CharsetEncoder encoder;
private final ByteBuffer bb;
// Exactly one of these is non-null
private final OutputStream out;
private WritableByteChannel ch;
private final WritableByteChannel ch;
// Leftover first char in a surrogate pair
private boolean haveLeftoverChar = false;
@ -194,9 +195,9 @@ public class StreamEncoder extends Writer
private StreamEncoder(OutputStream out, Object lock, Charset cs) {
this(out, lock,
cs.newEncoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE));
cs.newEncoder()
.onMalformedInput(CodingErrorAction.REPLACE)
.onUnmappableCharacter(CodingErrorAction.REPLACE));
}
private StreamEncoder(OutputStream out, Object lock, CharsetEncoder enc) {
@ -205,16 +206,7 @@ public class StreamEncoder extends Writer
this.ch = null;
this.cs = enc.charset();
this.encoder = enc;
// This path disabled until direct buffers are faster
if (false && out instanceof FileOutputStream) {
ch = ((FileOutputStream)out).getChannel();
if (ch != null)
bb = ByteBuffer.allocateDirect(DEFAULT_BYTE_BUFFER_SIZE);
}
if (ch == null) {
bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
}
this.bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
}
private StreamEncoder(WritableByteChannel ch, CharsetEncoder enc, int mbc) {
@ -234,16 +226,16 @@ public class StreamEncoder extends Writer
assert (pos <= lim);
int rem = (pos <= lim ? lim - pos : 0);
if (rem > 0) {
if (ch != null) {
if (ch.write(bb) != rem)
assert false : rem;
} else {
out.write(bb.array(), bb.arrayOffset() + pos, rem);
}
if (rem > 0) {
if (ch != null) {
int wc = ch.write(bb);
assert wc == rem : rem;
} else {
out.write(bb.array(), bb.arrayOffset() + pos, rem);
}
}
bb.clear();
}
}
private void flushLeftoverChar(CharBuffer cb, boolean endOfInput)
throws IOException
@ -283,7 +275,7 @@ public class StreamEncoder extends Writer
haveLeftoverChar = false;
}
void implWrite(char cbuf[], int off, int len)
void implWrite(char[] cbuf, int off, int len)
throws IOException
{
CharBuffer cb = CharBuffer.wrap(cbuf, off, len);
@ -317,14 +309,16 @@ public class StreamEncoder extends Writer
}
void implFlushBuffer() throws IOException {
if (bb.position() > 0)
writeBytes();
if (bb.position() > 0) {
writeBytes();
}
}
void implFlush() throws IOException {
implFlushBuffer();
if (out != null)
out.flush();
if (out != null) {
out.flush();
}
}
void implClose() throws IOException {

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2021, 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
@ -25,6 +25,9 @@
package sun.nio.cs;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
@ -60,6 +63,8 @@ public class US_ASCII
private static class Decoder extends CharsetDecoder {
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
private Decoder(Charset cs) {
super(cs, 1.0f, 1.0f);
}
@ -68,33 +73,28 @@ public class US_ASCII
CharBuffer dst)
{
byte[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
assert (sp <= sl);
sp = (sp <= sl ? sp : sl);
char[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
assert (dp <= dl);
dp = (dp <= dl ? dp : dl);
int soff = src.arrayOffset();
int sp = soff + src.position();
int sl = soff + src.limit();
try {
while (sp < sl) {
byte b = sa[sp];
if (b >= 0) {
if (dp >= dl)
return CoderResult.OVERFLOW;
da[dp++] = (char)b;
sp++;
continue;
}
return CoderResult.malformedForLength(1);
char[] da = dst.array();
int doff = dst.arrayOffset();
int dp = doff + dst.position();
int dl = doff + dst.limit();
// ASCII only loop
int n = JLA.decodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp));
sp += n;
dp += n;
src.position(sp - soff);
dst.position(dp - doff);
if (sp < sl) {
if (dp >= dl) {
return CoderResult.OVERFLOW;
}
return CoderResult.UNDERFLOW;
} finally {
src.position(sp - src.arrayOffset());
dst.position(dp - dst.arrayOffset());
return CoderResult.malformedForLength(1);
}
return CoderResult.UNDERFLOW;
}
private CoderResult decodeBufferLoop(ByteBuffer src,

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2021, 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
@ -25,6 +25,9 @@
package sun.nio.cs;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
@ -82,6 +85,8 @@ public final class UTF_8 extends Unicode {
private static class Decoder extends CharsetDecoder {
private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
private Decoder(Charset cs) {
super(cs, 1.0f, 1.0f);
}
@ -129,15 +134,6 @@ public final class UTF_8 extends Unicode {
return (b3 & 0xc0) != 0x80;
}
private static CoderResult lookupN(ByteBuffer src, int n)
{
for (int i = 1; i < n; i++) {
if (isNotContinuation(src.get()))
return CoderResult.malformedForLength(i);
}
return CoderResult.malformedForLength(n);
}
private static CoderResult malformedN(ByteBuffer src, int nb) {
switch (nb) {
case 1:
@ -223,17 +219,19 @@ public final class UTF_8 extends Unicode {
{
// This method is optimized for ASCII input.
byte[] sa = src.array();
int sp = src.arrayOffset() + src.position();
int sl = src.arrayOffset() + src.limit();
int soff = src.arrayOffset();
int sp = soff + src.position();
int sl = soff + src.limit();
char[] da = dst.array();
int dp = dst.arrayOffset() + dst.position();
int dl = dst.arrayOffset() + dst.limit();
int dlASCII = dp + Math.min(sl - sp, dl - dp);
int doff = dst.arrayOffset();
int dp = doff + dst.position();
int dl = doff + dst.limit();
int n = JLA.decodeASCII(sa, sp, da, dp, Math.min(sl - sp, dl - dp));
sp += n;
dp += n;
// ASCII only loop
while (dp < dlASCII && sa[sp] >= 0)
da[dp++] = (char) sa[sp++];
while (sp < sl) {
int b1 = sa[sp];
if (b1 >= 0) {
@ -415,14 +413,6 @@ public final class UTF_8 extends Unicode {
else
return decodeBufferLoop(src, dst);
}
private static ByteBuffer getByteBuffer(ByteBuffer bb, byte[] ba, int sp)
{
if (bb == null)
bb = ByteBuffer.wrap(ba);
bb.position(sp);
return bb;
}
}
private static final class Encoder extends CharsetEncoder {