8259947: (fs) Optimize UnixPath.encode implementation

Reviewed-by: chegar, shade, alanb
This commit is contained in:
Claes Redestad 2021-01-20 15:14:48 +00:00
parent 69f90b5fd4
commit 5891509d13
6 changed files with 64 additions and 67 deletions

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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,9 +25,6 @@
package sun.nio.fs; package sun.nio.fs;
import java.security.AccessController;
import java.security.PrivilegedAction;
/** /**
* Bsd specific system calls. * Bsd specific system calls.
*/ */

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2008, 2012, 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,9 +25,6 @@
package sun.nio.fs; package sun.nio.fs;
import java.nio.file.*;
import java.io.IOException;
import java.util.*;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static sun.nio.fs.MacOSXNativeDispatcher.*; import static sun.nio.fs.MacOSXNativeDispatcher.*;
@ -47,14 +44,18 @@ class MacOSXFileSystem extends BsdFileSystem {
return Pattern.compile(expr, Pattern.CANON_EQ) ; return Pattern.compile(expr, Pattern.CANON_EQ) ;
} }
char[] normalizeNativePath(char[] path) { @Override
for (char c : path) { String normalizeNativePath(String path) {
for (int i = 0; i < path.length(); i++) {
char c = path.charAt(i);
if (c > 0x80) if (c > 0x80)
return normalizepath(path, kCFStringNormalizationFormD); return new String(normalizepath(path.toCharArray(),
kCFStringNormalizationFormD));
} }
return path; return path;
} }
@Override
String normalizeJavaPath(String path) { String normalizeJavaPath(String path) {
for (int i = 0; i < path.length(); i++) { for (int i = 0; i < path.length(); i++) {
if (path.charAt(i) > 0x80) if (path.charAt(i) > 0x80)

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2008, 2012, 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,9 +25,6 @@
package sun.nio.fs; package sun.nio.fs;
import java.security.AccessController;
import java.security.PrivilegedAction;
/** /**
* MacOSX specific system calls. * MacOSX specific system calls.
*/ */

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2008, 2020, 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -343,7 +343,7 @@ abstract class UnixFileSystem
// Override if the platform uses different Unicode normalization form // Override if the platform uses different Unicode normalization form
// for native file path. For example on MacOSX, the native path is stored // for native file path. For example on MacOSX, the native path is stored
// in Unicode NFD form. // in Unicode NFD form.
char[] normalizeNativePath(char[] path) { String normalizeNativePath(String path) {
return path; return path;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2008, 2020, 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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -25,26 +25,25 @@
package sun.nio.fs; package sun.nio.fs;
import java.nio.*;
import java.nio.file.*; import java.nio.file.*;
import java.nio.charset.*; import java.nio.charset.*;
import java.io.*; import java.io.*;
import java.net.URI; import java.net.URI;
import java.util.*; import java.util.*;
import java.lang.ref.SoftReference;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;
import static sun.nio.fs.UnixNativeDispatcher.*; import static sun.nio.fs.UnixNativeDispatcher.*;
import static sun.nio.fs.UnixConstants.*; import static sun.nio.fs.UnixConstants.*;
/** /**
* Solaris/Linux implementation of java.nio.file.Path * Linux/Mac implementation of java.nio.file.Path
*/ */
class UnixPath implements Path { class UnixPath implements Path {
private static ThreadLocal<SoftReference<CharsetEncoder>> encoder =
new ThreadLocal<SoftReference<CharsetEncoder>>();
// FIXME - eliminate this reference to reduce space private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
private final UnixFileSystem fs; private final UnixFileSystem fs;
// internal representation // internal representation
@ -115,43 +114,13 @@ class UnixPath implements Path {
// encodes the given path-string into a sequence of bytes // encodes the given path-string into a sequence of bytes
private static byte[] encode(UnixFileSystem fs, String input) { private static byte[] encode(UnixFileSystem fs, String input) {
SoftReference<CharsetEncoder> ref = encoder.get(); input = fs.normalizeNativePath(input);
CharsetEncoder ce = (ref != null) ? ref.get() : null; try {
if (ce == null) { return JLA.getBytesNoRepl(input, Util.jnuEncoding());
ce = Util.jnuEncoding().newEncoder() } catch (CharacterCodingException cce) {
.onMalformedInput(CodingErrorAction.REPORT)
.onUnmappableCharacter(CodingErrorAction.REPORT);
encoder.set(new SoftReference<>(ce));
}
char[] ca = fs.normalizeNativePath(input.toCharArray());
// size output buffer for worse-case size
byte[] ba = new byte[(int)(ca.length * (double)ce.maxBytesPerChar())];
// encode
ByteBuffer bb = ByteBuffer.wrap(ba);
CharBuffer cb = CharBuffer.wrap(ca);
ce.reset();
CoderResult cr = ce.encode(cb, bb, true);
boolean error;
if (!cr.isUnderflow()) {
error = true;
} else {
cr = ce.flush(bb);
error = !cr.isUnderflow();
}
if (error) {
throw new InvalidPathException(input, throw new InvalidPathException(input,
"Malformed input or input contains unmappable characters"); "Malformed input or input contains unmappable characters");
} }
// trim result to actual length if required
int len = bb.position();
if (len != ba.length)
ba = Arrays.copyOf(ba, len);
return ba;
} }
// package-private // package-private

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -27,24 +27,24 @@ import org.openjdk.jmh.infra.Blackhole;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Path;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
/** /**
* Tests the overheads of I/O API. * Tests the overheads of creating File objects, and converting such objects to Paths.
*/ */
@BenchmarkMode(Mode.AverageTime) @BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS) @OutputTimeUnit(TimeUnit.NANOSECONDS)
@State(Scope.Thread) @State(Scope.Thread)
@Warmup(time=2, iterations=5) @Warmup(time=2, iterations=5)
@Measurement(time=3, iterations=5) @Measurement(time=3, iterations=5)
@Fork(value=2, jvmArgs="-Xmx1g") @Fork(value=2, jvmArgs="-Xmx1g")
public class FileOpen { public class FileOpen {
public String normalFile = "/test/dir/file/name.txt"; private String normalFile = "/test/dir/file/name.txt";
public String root = "/"; private String root = "/";
public String trailingSlash = "/test/dir/file/name.txt/"; private String trailingSlash = "/test/dir/file/name.txt/";
public String notNormalizedFile = "/test/dir/file//name.txt"; private String notNormalizedFile = "/test/dir/file//name.txt";
public File tmp; public File tmp;
@ -68,6 +68,11 @@ public class FileOpen {
return new File(normalFile); return new File(normalFile);
} }
@Benchmark
public File root() {
return new File(root);
}
@Benchmark @Benchmark
public File trailingSlash() { public File trailingSlash() {
return new File(trailingSlash); return new File(trailingSlash);
@ -85,4 +90,32 @@ public class FileOpen {
&& tmp.isDirectory() && tmp.isDirectory()
&& tmp.isFile(); && tmp.isFile();
} }
@Benchmark
public void mixToPath(Blackhole bh) {
bh.consume(new File(normalFile).toPath());
bh.consume(new File(root).toPath());
bh.consume(new File(trailingSlash).toPath());
bh.consume(new File(notNormalizedFile).toPath());
}
@Benchmark
public Path normalizedToPath() {
return new File(normalFile).toPath();
}
@Benchmark
public Path rootToPath() {
return new File(root).toPath();
}
@Benchmark
public Path trailingSlashToPath() {
return new File(trailingSlash).toPath();
}
@Benchmark
public Path notNormalizedToPath() {
return new File(notNormalizedFile).toPath();
}
} }