From 236216530f74500d7b8d8c7a2e63256b2aa183dd Mon Sep 17 00:00:00 2001 From: Chris Hegarty <62058229+ChrisHegarty@users.noreply.github.com> Date: Thu, 25 May 2023 07:59:50 +0100 Subject: [PATCH 1/6] Integrate the Incubating Panama Vector API (#12311) Leverage accelerated vector hardware instructions in Vector Search. Lucene already has a mechanism that enables the use of non-final JDK APIs, currently used for the Previewing Pamana Foreign API. This change expands this mechanism to include the Incubating Pamana Vector API. When the jdk.incubator.vector module is present at run time the Panamaized version of the low-level primitives used by Vector Search is enabled. If not present, the default scalar version of these low-level primitives is used (as it was previously). Currently, we're only targeting support for JDK 20. A subsequent PR should evaluate JDK 21. --------- Co-authored-by: Uwe Schindler Co-authored-by: Robert Muir --- build.gradle | 4 +- ...foreign.gradle => extract-jdk-apis.gradle} | 23 +- .../ExtractJdkApis.java} | 102 +++- ...segment-mrjar.gradle => core-mrjar.gradle} | 10 +- gradle/testing/defaults-tests.gradle | 9 +- lucene/CHANGES.txt | 9 + lucene/core/src/generated/jdk/README.md | 2 +- ...nama-foreign-jdk19.apijar => jdk19.apijar} | Bin lucene/core/src/generated/jdk/jdk20.apijar | Bin 0 -> 52851 bytes .../index/VectorSimilarityFunction.java | 4 +- .../org/apache/lucene/util/VectorUtil.java | 158 +----- .../util/VectorUtilDefaultProvider.java | 178 +++++++ .../lucene/util/VectorUtilProvider.java | 145 ++++++ .../lucene/util/VectorUtilPanamaProvider.java | 477 ++++++++++++++++++ .../lucene/util/TestVectorUtilProviders.java | 83 +++ 15 files changed, 1025 insertions(+), 179 deletions(-) rename gradle/generation/{panama-foreign.gradle => extract-jdk-apis.gradle} (76%) rename gradle/generation/{panama-foreign/ExtractForeignAPI.java => extract-jdk-apis/ExtractJdkApis.java} (53%) rename gradle/java/{memorysegment-mrjar.gradle => core-mrjar.gradle} (82%) rename lucene/core/src/generated/jdk/{panama-foreign-jdk19.apijar => jdk19.apijar} (100%) create mode 100644 lucene/core/src/generated/jdk/jdk20.apijar create mode 100644 lucene/core/src/java/org/apache/lucene/util/VectorUtilDefaultProvider.java create mode 100644 lucene/core/src/java/org/apache/lucene/util/VectorUtilProvider.java create mode 100644 lucene/core/src/java20/org/apache/lucene/util/VectorUtilPanamaProvider.java create mode 100644 lucene/core/src/test/org/apache/lucene/util/TestVectorUtilProviders.java diff --git a/build.gradle b/build.gradle index f1441cefb17b..0eae57bd10f3 100644 --- a/build.gradle +++ b/build.gradle @@ -119,7 +119,7 @@ apply from: file('gradle/ide/eclipse.gradle') // (java, tests) apply from: file('gradle/java/folder-layout.gradle') apply from: file('gradle/java/javac.gradle') -apply from: file('gradle/java/memorysegment-mrjar.gradle') +apply from: file('gradle/java/core-mrjar.gradle') apply from: file('gradle/testing/defaults-tests.gradle') apply from: file('gradle/testing/randomization.gradle') apply from: file('gradle/testing/fail-on-no-tests.gradle') @@ -158,7 +158,7 @@ apply from: file('gradle/generation/javacc.gradle') apply from: file('gradle/generation/forUtil.gradle') apply from: file('gradle/generation/antlr.gradle') apply from: file('gradle/generation/unicode-test-classes.gradle') -apply from: file('gradle/generation/panama-foreign.gradle') +apply from: file('gradle/generation/extract-jdk-apis.gradle') apply from: file('gradle/datasets/external-datasets.gradle') diff --git a/gradle/generation/panama-foreign.gradle b/gradle/generation/extract-jdk-apis.gradle similarity index 76% rename from gradle/generation/panama-foreign.gradle rename to gradle/generation/extract-jdk-apis.gradle index 119dc8fad008..834a490cc0d9 100644 --- a/gradle/generation/panama-foreign.gradle +++ b/gradle/generation/extract-jdk-apis.gradle @@ -17,10 +17,17 @@ def resources = scriptResources(buildscript) +configure(rootProject) { + ext { + // also change this in extractor tool: ExtractForeignAPI + vectorIncubatorJavaVersions = [ JavaVersion.VERSION_20 ] as Set + } +} + configure(project(":lucene:core")) { ext { apijars = file('src/generated/jdk'); - panamaJavaVersions = [ 19, 20 ] + mrjarJavaVersions = [ 19, 20 ] } configurations { @@ -31,9 +38,9 @@ configure(project(":lucene:core")) { apiextractor "org.ow2.asm:asm:${scriptDepVersions['asm']}" } - for (jdkVersion : panamaJavaVersions) { - def task = tasks.create(name: "generatePanamaForeignApiJar${jdkVersion}", type: JavaExec) { - description "Regenerate the API-only JAR file with public Panama Foreign API from JDK ${jdkVersion}" + for (jdkVersion : mrjarJavaVersions) { + def task = tasks.create(name: "generateJdkApiJar${jdkVersion}", type: JavaExec) { + description "Regenerate the API-only JAR file with public Panama Foreign & Vector API from JDK ${jdkVersion}" group "generation" javaLauncher = javaToolchains.launcherFor { @@ -45,21 +52,21 @@ configure(project(":lucene:core")) { javaLauncher.get() return true } catch (Exception e) { - logger.warn('Launcher for Java {} is not available; skipping regeneration of Panama Foreign API JAR.', jdkVersion) + logger.warn('Launcher for Java {} is not available; skipping regeneration of Panama Foreign & Vector API JAR.', jdkVersion) logger.warn('Error: {}', e.cause?.message) logger.warn("Please make sure to point env 'JAVA{}_HOME' to exactly JDK version {} or enable Gradle toolchain auto-download.", jdkVersion, jdkVersion) return false } } - + classpath = configurations.apiextractor - mainClass = file("${resources}/ExtractForeignAPI.java") as String + mainClass = file("${resources}/ExtractJdkApis.java") as String systemProperties = [ 'user.timezone': 'UTC' ] args = [ jdkVersion, - new File(apijars, "panama-foreign-jdk${jdkVersion}.apijar"), + new File(apijars, "jdk${jdkVersion}.apijar"), ] } diff --git a/gradle/generation/panama-foreign/ExtractForeignAPI.java b/gradle/generation/extract-jdk-apis/ExtractJdkApis.java similarity index 53% rename from gradle/generation/panama-foreign/ExtractForeignAPI.java rename to gradle/generation/extract-jdk-apis/ExtractJdkApis.java index 44253ea0122b..973a12bd03c7 100644 --- a/gradle/generation/panama-foreign/ExtractForeignAPI.java +++ b/gradle/generation/extract-jdk-apis/ExtractJdkApis.java @@ -18,11 +18,21 @@ import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.PathMatcher; import java.nio.file.Paths; import java.nio.file.attribute.FileTime; import java.time.Instant; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.Set; +import java.util.TreeMap; +import java.util.function.Predicate; import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -35,54 +45,100 @@ import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; -public final class ExtractForeignAPI { +public final class ExtractJdkApis { private static final FileTime FIXED_FILEDATE = FileTime.from(Instant.parse("2022-01-01T00:00:00Z")); + static final Map CLASSFILE_MATCHERS = Map.of( + "java.base", "glob:java/{lang/foreign/*,nio/channels/FileChannel}.class", + "jdk.incubator.vector", "glob:jdk/incubator/vector/*.class" + ); + + static final Map> MODULES_TO_PROCESS = Map.of( + 19, List.of("java.base"), + 20, List.of("java.base", "jdk.incubator.vector") + ); + public static void main(String... args) throws IOException { if (args.length != 2) { throw new IllegalArgumentException("Need two parameters: java version, output file"); } - if (Integer.parseInt(args[0]) != Runtime.version().feature()) { + Integer jdk = Integer.valueOf(args[0]); + if (jdk.intValue() != Runtime.version().feature()) { throw new IllegalStateException("Incorrect java version: " + Runtime.version().feature()); } + if (!MODULES_TO_PROCESS.containsKey(jdk)) { + throw new IllegalArgumentException("No support to extract stubs from java version: " + jdk); + } var outputPath = Paths.get(args[1]); - var javaBaseModule = Paths.get(URI.create("jrt:/")).resolve("java.base").toRealPath(); - var fileMatcher = javaBaseModule.getFileSystem().getPathMatcher("glob:java/{lang/foreign/*,nio/channels/FileChannel,util/Objects}.class"); - try (var out = new ZipOutputStream(Files.newOutputStream(outputPath)); var stream = Files.walk(javaBaseModule)) { - var filesToExtract = stream.map(javaBaseModule::relativize).filter(fileMatcher::matches).sorted().collect(Collectors.toList()); + + try (var out = new ZipOutputStream(Files.newOutputStream(outputPath))) { + for (String mod : MODULES_TO_PROCESS.get(jdk)) { + var modulePath = Paths.get(URI.create("jrt:/")).resolve(mod).toRealPath(); + var moduleMatcher = modulePath.getFileSystem().getPathMatcher(CLASSFILE_MATCHERS.get(mod)); + process(modulePath, moduleMatcher, out); + } + } + } + + static void process(Path modulePath, PathMatcher fileMatcher, ZipOutputStream out) throws IOException { + var classesToInclude = new HashSet(); + var references = new HashMap(); + var processed = new TreeMap(); + try (var stream = Files.walk(modulePath)) { + var filesToExtract = stream.map(modulePath::relativize).filter(fileMatcher::matches).toArray(Path[]::new); + System.out.println("Transforming " + filesToExtract.length + " class files in [" + modulePath + "]..."); for (Path relative : filesToExtract) { - System.out.println("Processing class file: " + relative); - try (var in = Files.newInputStream(javaBaseModule.resolve(relative))) { - final var reader = new ClassReader(in); - final var cw = new ClassWriter(0); - reader.accept(new Cleaner(cw), ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); - out.putNextEntry(new ZipEntry(relative.toString()).setLastModifiedTime(FIXED_FILEDATE)); - out.write(cw.toByteArray()); - out.closeEntry(); + try (var in = Files.newInputStream(modulePath.resolve(relative))) { + var reader = new ClassReader(in); + var cw = new ClassWriter(0); + var cleaner = new Cleaner(cw, classesToInclude, references); + reader.accept(cleaner, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + processed.put(reader.getClassName(), cw.toByteArray()); } } } + // recursively add all superclasses / interfaces of visible classes to classesToInclude: + for (Set a = classesToInclude; !a.isEmpty(); + a = a.stream().map(references::get).filter(Objects::nonNull).flatMap(Arrays::stream).collect(Collectors.toSet())) { + classesToInclude.addAll(a); + } + // remove all non-visible or not referenced classes: + processed.keySet().removeIf(Predicate.not(classesToInclude::contains)); + System.out.println("Writing " + processed.size() + " visible classes for [" + modulePath + "]..."); + for (var cls : processed.entrySet()) { + String cn = cls.getKey(); + System.out.println("Writing stub for class: " + cn); + out.putNextEntry(new ZipEntry(cn.concat(".class")).setLastModifiedTime(FIXED_FILEDATE)); + out.write(cls.getValue()); + out.closeEntry(); + } + } + + static boolean isVisible(int access) { + return (access & (Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC)) != 0; } static class Cleaner extends ClassVisitor { private static final String PREVIEW_ANN = "jdk/internal/javac/PreviewFeature"; private static final String PREVIEW_ANN_DESCR = Type.getObjectType(PREVIEW_ANN).getDescriptor(); - private boolean completelyHidden = false; + private final Set classesToInclude; + private final Map references; - Cleaner(ClassWriter out) { + Cleaner(ClassWriter out, Set classesToInclude, Map references) { super(Opcodes.ASM9, out); - } - - private boolean isHidden(int access) { - return completelyHidden || (access & (Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC)) == 0; + this.classesToInclude = classesToInclude; + this.references = references; } @Override public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { super.visit(Opcodes.V11, access, name, signature, superName, interfaces); - completelyHidden = isHidden(access); + if (isVisible(access)) { + classesToInclude.add(name); + } + references.put(name, Stream.concat(Stream.of(superName), Arrays.stream(interfaces)).toArray(String[]::new)); } @Override @@ -92,7 +148,7 @@ public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { @Override public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { - if (isHidden(access)) { + if (!isVisible(access)) { return null; } return new FieldVisitor(Opcodes.ASM9, super.visitField(access, name, descriptor, signature, value)) { @@ -105,7 +161,7 @@ public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) { @Override public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { - if (isHidden(access)) { + if (!isVisible(access)) { return null; } return new MethodVisitor(Opcodes.ASM9, super.visitMethod(access, name, descriptor, signature, exceptions)) { diff --git a/gradle/java/memorysegment-mrjar.gradle b/gradle/java/core-mrjar.gradle similarity index 82% rename from gradle/java/memorysegment-mrjar.gradle rename to gradle/java/core-mrjar.gradle index 137f8a3c567d..5715e782f000 100644 --- a/gradle/java/memorysegment-mrjar.gradle +++ b/gradle/java/core-mrjar.gradle @@ -15,11 +15,11 @@ * limitations under the License. */ -// Produce an MR-JAR with Java 19+ MemorySegment implementation for MMapDirectory +// Produce an MR-JAR with Java 19+ foreign and vector implementations configure(project(":lucene:core")) { plugins.withType(JavaPlugin) { - for (jdkVersion : panamaJavaVersions) { + for (jdkVersion : mrjarJavaVersions) { sourceSets.create("main${jdkVersion}") { java { srcDirs = ["src/java${jdkVersion}"] @@ -29,7 +29,7 @@ configure(project(":lucene:core")) { dependencies.add("main${jdkVersion}Implementation", sourceSets.main.output) tasks.named("compileMain${jdkVersion}Java").configure { - def apijar = new File(apijars, "panama-foreign-jdk${jdkVersion}.apijar") + def apijar = new File(apijars, "jdk${jdkVersion}.apijar") inputs.file(apijar) @@ -40,12 +40,14 @@ configure(project(":lucene:core")) { "-Xlint:-options", "--patch-module", "java.base=${apijar}", "--add-exports", "java.base/java.lang.foreign=ALL-UNNAMED", + // for compilation we patch the incubator packages into java.base, this has no effect on resulting class files: + "--add-exports", "java.base/jdk.incubator.vector=ALL-UNNAMED", ] } } tasks.named('jar').configure { - for (jdkVersion : panamaJavaVersions) { + for (jdkVersion : mrjarJavaVersions) { into("META-INF/versions/${jdkVersion}") { from sourceSets["main${jdkVersion}"].output } diff --git a/gradle/testing/defaults-tests.gradle b/gradle/testing/defaults-tests.gradle index 9f50cda8ca79..f7a348f0b66c 100644 --- a/gradle/testing/defaults-tests.gradle +++ b/gradle/testing/defaults-tests.gradle @@ -47,7 +47,7 @@ allprojects { description: "Number of forked test JVMs"], [propName: 'tests.haltonfailure', value: true, description: "Halt processing on test failure."], [propName: 'tests.jvmargs', - value: { -> propertyOrEnvOrDefault("tests.jvmargs", "TEST_JVM_ARGS", "-XX:TieredStopAtLevel=1 -XX:+UseParallelGC -XX:ActiveProcessorCount=1") }, + value: { -> propertyOrEnvOrDefault("tests.jvmargs", "TEST_JVM_ARGS", isCIBuild ? "" : "-XX:TieredStopAtLevel=1 -XX:+UseParallelGC -XX:ActiveProcessorCount=1") }, description: "Arguments passed to each forked JVM."], // Other settings. [propName: 'tests.neverUpToDate', value: true, @@ -119,11 +119,16 @@ allprojects { if (rootProject.runtimeJavaVersion < JavaVersion.VERSION_16) { jvmArgs '--illegal-access=deny' } - + // Lucene needs to optional modules at runtime, which we want to enforce for testing // (if the runner JVM does not support them, it will fail tests): jvmArgs '--add-modules', 'jdk.unsupported,jdk.management' + // Enable the vector incubator module on supported Java versions: + if (rootProject.vectorIncubatorJavaVersions.contains(rootProject.runtimeJavaVersion)) { + jvmArgs '--add-modules', 'jdk.incubator.vector' + } + def loggingConfigFile = layout.projectDirectory.file("${resources}/logging.properties") def tempDir = layout.projectDirectory.dir(testsTmpDir.toString()) jvmArgumentProviders.add( diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt index ebd8486df156..89d645fa9bf9 100644 --- a/lucene/CHANGES.txt +++ b/lucene/CHANGES.txt @@ -20,6 +20,15 @@ New Features * GITHUB#12257: Create OnHeapHnswGraphSearcher to let OnHeapHnswGraph to be searched in a thread-safety manner. (Patrick Zhai) +* GITHUB#12302, GITHUB#12311: Add vectorized implementations of VectorUtil.dotProduct(), + squareDistance(), cosine() with Java 20 jdk.incubator.vector APIs. Applications started + with command line parameter "java --add-modules jdk.incubator.vector" on exactly Java 20 + will automatically use the new vectorized implementations if running on a supported platform + (x86 AVX2 or later, ARM SVE or later). This is an opt-in feature and requires explicit Java + command line flag! When enabled, Lucene logs a notice using java.util.logging. Please test + thoroughly and report bugs/slowness to Lucene's mailing list. + (Chris Hegarty, Robert Muir, Uwe Schindler) + Improvements --------------------- diff --git a/lucene/core/src/generated/jdk/README.md b/lucene/core/src/generated/jdk/README.md index 371bbebf8518..48a014b992b8 100644 --- a/lucene/core/src/generated/jdk/README.md +++ b/lucene/core/src/generated/jdk/README.md @@ -40,4 +40,4 @@ to point the Lucene build system to missing JDK versions. The regeneration task a warning if a specific JDK is missing, leaving the already existing `.apijar` file untouched. -The extraction is done with the ASM library, see `ExtractForeignAPI.java` source code. +The extraction is done with the ASM library, see `ExtractJdkApis.java` source code. diff --git a/lucene/core/src/generated/jdk/panama-foreign-jdk19.apijar b/lucene/core/src/generated/jdk/jdk19.apijar similarity index 100% rename from lucene/core/src/generated/jdk/panama-foreign-jdk19.apijar rename to lucene/core/src/generated/jdk/jdk19.apijar diff --git a/lucene/core/src/generated/jdk/jdk20.apijar b/lucene/core/src/generated/jdk/jdk20.apijar new file mode 100644 index 0000000000000000000000000000000000000000..de737b7eb751200d47d528463d95e70111a17085 GIT binary patch literal 52851 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 T3= 21) { + LOG.warning( + "You are running with Java 21 or later. To make full use of the Vector API, please update Apache Lucene."); + } + return new VectorUtilDefaultProvider(); + } + + private static boolean vectorModulePresentAndReadable() { + var opt = + ModuleLayer.boot().modules().stream() + .filter(m -> m.getName().equals("jdk.incubator.vector")) + .findFirst(); + if (opt.isPresent()) { + VectorUtilProvider.class.getModule().addReads(opt.get()); + return true; + } + return false; + } + + /** + * Check if runtime is affected by JDK-8301190 (avoids assertion when default language is say + * "tr"). + */ + private static boolean isAffectedByJDK8301190() { + return VERSION_JDK8301190_FIXED.compareToIgnoreOptional(Runtime.version()) > 0 + && !Objects.equals("I", "i".toUpperCase(Locale.getDefault())); + } + + @SuppressWarnings("removal") + @SuppressForbidden(reason = "security manager") + private static boolean isClientVM() { + try { + final PrivilegedAction action = + () -> System.getProperty("java.vm.info", "").contains("emulated-client"); + return AccessController.doPrivileged(action); + } catch ( + @SuppressWarnings("unused") + SecurityException e) { + LOG.warning( + "SecurityManager denies permission to 'java.vm.info' system property, so state of C2 compiler can't be detected. " + + "In case of performance issues allow access to this property."); + return false; + } + } +} diff --git a/lucene/core/src/java20/org/apache/lucene/util/VectorUtilPanamaProvider.java b/lucene/core/src/java20/org/apache/lucene/util/VectorUtilPanamaProvider.java new file mode 100644 index 000000000000..2d8a22380088 --- /dev/null +++ b/lucene/core/src/java20/org/apache/lucene/util/VectorUtilPanamaProvider.java @@ -0,0 +1,477 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.lucene.util; + +import java.util.logging.Logger; +import jdk.incubator.vector.ByteVector; +import jdk.incubator.vector.FloatVector; +import jdk.incubator.vector.IntVector; +import jdk.incubator.vector.ShortVector; +import jdk.incubator.vector.Vector; +import jdk.incubator.vector.VectorOperators; +import jdk.incubator.vector.VectorShape; +import jdk.incubator.vector.VectorSpecies; + +/** A VectorUtil provider implementation that leverages the Panama Vector API. */ +final class VectorUtilPanamaProvider implements VectorUtilProvider { + + /** + * The bit size of the preferred species (this field is package private to allow the lookup to + * load it). + */ + static final int INT_SPECIES_PREF_BIT_SIZE = IntVector.SPECIES_PREFERRED.vectorBitSize(); + + private static final VectorSpecies PREF_FLOAT_SPECIES = FloatVector.SPECIES_PREFERRED; + private static final VectorSpecies PREF_BYTE_SPECIES; + private static final VectorSpecies PREF_SHORT_SPECIES; + + /** + * x86 and less than 256-bit vectors. + * + *

it could be that it has only AVX1 and integer vectors are fast. it could also be that it has + * no AVX and integer vectors are extremely slow. don't use integer vectors to avoid landmines. + */ + private static final boolean IS_AMD64_WITHOUT_AVX2 = + Constants.OS_ARCH.equals("amd64") && INT_SPECIES_PREF_BIT_SIZE < 256; + + static { + if (INT_SPECIES_PREF_BIT_SIZE >= 256) { + PREF_BYTE_SPECIES = + ByteVector.SPECIES_MAX.withShape( + VectorShape.forBitSize(IntVector.SPECIES_PREFERRED.vectorBitSize() >> 2)); + PREF_SHORT_SPECIES = + ShortVector.SPECIES_MAX.withShape( + VectorShape.forBitSize(IntVector.SPECIES_PREFERRED.vectorBitSize() >> 1)); + } else { + PREF_BYTE_SPECIES = null; + PREF_SHORT_SPECIES = null; + } + } + + VectorUtilPanamaProvider() { + if (INT_SPECIES_PREF_BIT_SIZE < 128) { + throw new UnsupportedOperationException( + "Vector bit size is less than 128: " + INT_SPECIES_PREF_BIT_SIZE); + } + var log = Logger.getLogger(getClass().getName()); + log.info( + "Java vector incubator API enabled; uses preferredBitSize=" + INT_SPECIES_PREF_BIT_SIZE); + } + + @Override + public float dotProduct(float[] a, float[] b) { + int i = 0; + float res = 0; + // if the array size is large (> 2x platform vector size), its worth the overhead to vectorize + if (a.length > 2 * PREF_FLOAT_SPECIES.length()) { + // vector loop is unrolled 4x (4 accumulators in parallel) + FloatVector acc1 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector acc2 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector acc3 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector acc4 = FloatVector.zero(PREF_FLOAT_SPECIES); + int upperBound = PREF_FLOAT_SPECIES.loopBound(a.length - 3 * PREF_FLOAT_SPECIES.length()); + for (; i < upperBound; i += 4 * PREF_FLOAT_SPECIES.length()) { + FloatVector va = FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i); + FloatVector vb = FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i); + acc1 = acc1.add(va.mul(vb)); + FloatVector vc = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + PREF_FLOAT_SPECIES.length()); + FloatVector vd = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + PREF_FLOAT_SPECIES.length()); + acc2 = acc2.add(vc.mul(vd)); + FloatVector ve = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + 2 * PREF_FLOAT_SPECIES.length()); + FloatVector vf = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + 2 * PREF_FLOAT_SPECIES.length()); + acc3 = acc3.add(ve.mul(vf)); + FloatVector vg = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + 3 * PREF_FLOAT_SPECIES.length()); + FloatVector vh = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + 3 * PREF_FLOAT_SPECIES.length()); + acc4 = acc4.add(vg.mul(vh)); + } + // vector tail: less scalar computations for unaligned sizes, esp with big vector sizes + upperBound = PREF_FLOAT_SPECIES.loopBound(a.length); + for (; i < upperBound; i += PREF_FLOAT_SPECIES.length()) { + FloatVector va = FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i); + FloatVector vb = FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i); + acc1 = acc1.add(va.mul(vb)); + } + // reduce + FloatVector res1 = acc1.add(acc2); + FloatVector res2 = acc3.add(acc4); + res += res1.add(res2).reduceLanes(VectorOperators.ADD); + } + + for (; i < a.length; i++) { + res += b[i] * a[i]; + } + return res; + } + + @Override + public float cosine(float[] a, float[] b) { + int i = 0; + float sum = 0; + float norm1 = 0; + float norm2 = 0; + // if the array size is large (> 2x platform vector size), its worth the overhead to vectorize + if (a.length > 2 * PREF_FLOAT_SPECIES.length()) { + // vector loop is unrolled 4x (4 accumulators in parallel) + FloatVector sum1 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector sum2 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector sum3 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector sum4 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector norm1_1 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector norm1_2 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector norm1_3 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector norm1_4 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector norm2_1 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector norm2_2 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector norm2_3 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector norm2_4 = FloatVector.zero(PREF_FLOAT_SPECIES); + int upperBound = PREF_FLOAT_SPECIES.loopBound(a.length - 3 * PREF_FLOAT_SPECIES.length()); + for (; i < upperBound; i += 4 * PREF_FLOAT_SPECIES.length()) { + FloatVector va = FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i); + FloatVector vb = FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i); + sum1 = sum1.add(va.mul(vb)); + norm1_1 = norm1_1.add(va.mul(va)); + norm2_1 = norm2_1.add(vb.mul(vb)); + FloatVector vc = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + PREF_FLOAT_SPECIES.length()); + FloatVector vd = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + PREF_FLOAT_SPECIES.length()); + sum2 = sum2.add(vc.mul(vd)); + norm1_2 = norm1_2.add(vc.mul(vc)); + norm2_2 = norm2_2.add(vd.mul(vd)); + FloatVector ve = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + 2 * PREF_FLOAT_SPECIES.length()); + FloatVector vf = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + 2 * PREF_FLOAT_SPECIES.length()); + sum3 = sum3.add(ve.mul(vf)); + norm1_3 = norm1_3.add(ve.mul(ve)); + norm2_3 = norm2_3.add(vf.mul(vf)); + FloatVector vg = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + 3 * PREF_FLOAT_SPECIES.length()); + FloatVector vh = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + 3 * PREF_FLOAT_SPECIES.length()); + sum4 = sum4.add(vg.mul(vh)); + norm1_4 = norm1_4.add(vg.mul(vg)); + norm2_4 = norm2_4.add(vh.mul(vh)); + } + // vector tail: less scalar computations for unaligned sizes, esp with big vector sizes + upperBound = PREF_FLOAT_SPECIES.loopBound(a.length); + for (; i < upperBound; i += PREF_FLOAT_SPECIES.length()) { + FloatVector va = FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i); + FloatVector vb = FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i); + sum1 = sum1.add(va.mul(vb)); + norm1_1 = norm1_1.add(va.mul(va)); + norm2_1 = norm2_1.add(vb.mul(vb)); + } + // reduce + FloatVector sumres1 = sum1.add(sum2); + FloatVector sumres2 = sum3.add(sum4); + FloatVector norm1res1 = norm1_1.add(norm1_2); + FloatVector norm1res2 = norm1_3.add(norm1_4); + FloatVector norm2res1 = norm2_1.add(norm2_2); + FloatVector norm2res2 = norm2_3.add(norm2_4); + sum += sumres1.add(sumres2).reduceLanes(VectorOperators.ADD); + norm1 += norm1res1.add(norm1res2).reduceLanes(VectorOperators.ADD); + norm2 += norm2res1.add(norm2res2).reduceLanes(VectorOperators.ADD); + } + + for (; i < a.length; i++) { + float elem1 = a[i]; + float elem2 = b[i]; + sum += elem1 * elem2; + norm1 += elem1 * elem1; + norm2 += elem2 * elem2; + } + return (float) (sum / Math.sqrt(norm1 * norm2)); + } + + @Override + public float squareDistance(float[] a, float[] b) { + int i = 0; + float res = 0; + // if the array size is large (> 2x platform vector size), its worth the overhead to vectorize + if (a.length > 2 * PREF_FLOAT_SPECIES.length()) { + // vector loop is unrolled 4x (4 accumulators in parallel) + FloatVector acc1 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector acc2 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector acc3 = FloatVector.zero(PREF_FLOAT_SPECIES); + FloatVector acc4 = FloatVector.zero(PREF_FLOAT_SPECIES); + int upperBound = PREF_FLOAT_SPECIES.loopBound(a.length - 3 * PREF_FLOAT_SPECIES.length()); + for (; i < upperBound; i += 4 * PREF_FLOAT_SPECIES.length()) { + FloatVector va = FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i); + FloatVector vb = FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i); + FloatVector diff1 = va.sub(vb); + acc1 = acc1.add(diff1.mul(diff1)); + FloatVector vc = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + PREF_FLOAT_SPECIES.length()); + FloatVector vd = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + PREF_FLOAT_SPECIES.length()); + FloatVector diff2 = vc.sub(vd); + acc2 = acc2.add(diff2.mul(diff2)); + FloatVector ve = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + 2 * PREF_FLOAT_SPECIES.length()); + FloatVector vf = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + 2 * PREF_FLOAT_SPECIES.length()); + FloatVector diff3 = ve.sub(vf); + acc3 = acc3.add(diff3.mul(diff3)); + FloatVector vg = + FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i + 3 * PREF_FLOAT_SPECIES.length()); + FloatVector vh = + FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i + 3 * PREF_FLOAT_SPECIES.length()); + FloatVector diff4 = vg.sub(vh); + acc4 = acc4.add(diff4.mul(diff4)); + } + // vector tail: less scalar computations for unaligned sizes, esp with big vector sizes + upperBound = PREF_FLOAT_SPECIES.loopBound(a.length); + for (; i < upperBound; i += PREF_FLOAT_SPECIES.length()) { + FloatVector va = FloatVector.fromArray(PREF_FLOAT_SPECIES, a, i); + FloatVector vb = FloatVector.fromArray(PREF_FLOAT_SPECIES, b, i); + FloatVector diff = va.sub(vb); + acc1 = acc1.add(diff.mul(diff)); + } + // reduce + FloatVector res1 = acc1.add(acc2); + FloatVector res2 = acc3.add(acc4); + res += res1.add(res2).reduceLanes(VectorOperators.ADD); + } + + for (; i < a.length; i++) { + float diff = a[i] - b[i]; + res += diff * diff; + } + return res; + } + + // Binary functions, these all follow a general pattern like this: + // + // short intermediate = a * b; + // int accumulator = accumulator + intermediate; + // + // 256 or 512 bit vectors can process 64 or 128 bits at a time, respectively + // intermediate results use 128 or 256 bit vectors, respectively + // final accumulator uses 256 or 512 bit vectors, respectively + // + // We also support 128 bit vectors, using two 128 bit accumulators. + // This is slower but still faster than not vectorizing at all. + + @Override + public int dotProduct(byte[] a, byte[] b) { + int i = 0; + int res = 0; + // only vectorize if we'll at least enter the loop a single time, and we have at least 128-bit + // vectors (256-bit on intel to dodge performance landmines) + if (a.length >= 16 && IS_AMD64_WITHOUT_AVX2 == false) { + // compute vectorized dot product consistent with VPDPBUSD instruction + if (INT_SPECIES_PREF_BIT_SIZE >= 256) { + // optimized 256/512 bit implementation, processes 8/16 bytes at a time + int upperBound = PREF_BYTE_SPECIES.loopBound(a.length); + IntVector acc = IntVector.zero(IntVector.SPECIES_PREFERRED); + for (; i < upperBound; i += PREF_BYTE_SPECIES.length()) { + ByteVector va8 = ByteVector.fromArray(PREF_BYTE_SPECIES, a, i); + ByteVector vb8 = ByteVector.fromArray(PREF_BYTE_SPECIES, b, i); + Vector va16 = va8.convertShape(VectorOperators.B2S, PREF_SHORT_SPECIES, 0); + Vector vb16 = vb8.convertShape(VectorOperators.B2S, PREF_SHORT_SPECIES, 0); + Vector prod16 = va16.mul(vb16); + Vector prod32 = + prod16.convertShape(VectorOperators.S2I, IntVector.SPECIES_PREFERRED, 0); + acc = acc.add(prod32); + } + // reduce + res += acc.reduceLanes(VectorOperators.ADD); + } else { + // 128-bit implementation, which must "split up" vectors due to widening conversions + int upperBound = ByteVector.SPECIES_64.loopBound(a.length); + IntVector acc1 = IntVector.zero(IntVector.SPECIES_128); + IntVector acc2 = IntVector.zero(IntVector.SPECIES_128); + for (; i < upperBound; i += ByteVector.SPECIES_64.length()) { + ByteVector va8 = ByteVector.fromArray(ByteVector.SPECIES_64, a, i); + ByteVector vb8 = ByteVector.fromArray(ByteVector.SPECIES_64, b, i); + // expand each byte vector into short vector and multiply + Vector va16 = va8.convertShape(VectorOperators.B2S, ShortVector.SPECIES_128, 0); + Vector vb16 = vb8.convertShape(VectorOperators.B2S, ShortVector.SPECIES_128, 0); + Vector prod16 = va16.mul(vb16); + // split each short vector into two int vectors and add + Vector prod32_1 = + prod16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 0); + Vector prod32_2 = + prod16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 1); + acc1 = acc1.add(prod32_1); + acc2 = acc2.add(prod32_2); + } + // reduce + res += acc1.add(acc2).reduceLanes(VectorOperators.ADD); + } + } + + for (; i < a.length; i++) { + res += b[i] * a[i]; + } + return res; + } + + @Override + public float cosine(byte[] a, byte[] b) { + int i = 0; + int sum = 0; + int norm1 = 0; + int norm2 = 0; + // only vectorize if we'll at least enter the loop a single time, and we have at least 128-bit + // vectors (256-bit on intel to dodge performance landmines) + if (a.length >= 16 && IS_AMD64_WITHOUT_AVX2 == false) { + if (INT_SPECIES_PREF_BIT_SIZE >= 256) { + // optimized 256/512 bit implementation, processes 8/16 bytes at a time + int upperBound = PREF_BYTE_SPECIES.loopBound(a.length); + IntVector accSum = IntVector.zero(IntVector.SPECIES_PREFERRED); + IntVector accNorm1 = IntVector.zero(IntVector.SPECIES_PREFERRED); + IntVector accNorm2 = IntVector.zero(IntVector.SPECIES_PREFERRED); + for (; i < upperBound; i += PREF_BYTE_SPECIES.length()) { + ByteVector va8 = ByteVector.fromArray(PREF_BYTE_SPECIES, a, i); + ByteVector vb8 = ByteVector.fromArray(PREF_BYTE_SPECIES, b, i); + Vector va16 = va8.convertShape(VectorOperators.B2S, PREF_SHORT_SPECIES, 0); + Vector vb16 = vb8.convertShape(VectorOperators.B2S, PREF_SHORT_SPECIES, 0); + Vector prod16 = va16.mul(vb16); + Vector norm1_16 = va16.mul(va16); + Vector norm2_16 = vb16.mul(vb16); + Vector prod32 = + prod16.convertShape(VectorOperators.S2I, IntVector.SPECIES_PREFERRED, 0); + Vector norm1_32 = + norm1_16.convertShape(VectorOperators.S2I, IntVector.SPECIES_PREFERRED, 0); + Vector norm2_32 = + norm2_16.convertShape(VectorOperators.S2I, IntVector.SPECIES_PREFERRED, 0); + accSum = accSum.add(prod32); + accNorm1 = accNorm1.add(norm1_32); + accNorm2 = accNorm2.add(norm2_32); + } + // reduce + sum += accSum.reduceLanes(VectorOperators.ADD); + norm1 += accNorm1.reduceLanes(VectorOperators.ADD); + norm2 += accNorm2.reduceLanes(VectorOperators.ADD); + } else { + // 128-bit implementation, which must "split up" vectors due to widening conversions + int upperBound = ByteVector.SPECIES_64.loopBound(a.length); + IntVector accSum1 = IntVector.zero(IntVector.SPECIES_128); + IntVector accSum2 = IntVector.zero(IntVector.SPECIES_128); + IntVector accNorm1_1 = IntVector.zero(IntVector.SPECIES_128); + IntVector accNorm1_2 = IntVector.zero(IntVector.SPECIES_128); + IntVector accNorm2_1 = IntVector.zero(IntVector.SPECIES_128); + IntVector accNorm2_2 = IntVector.zero(IntVector.SPECIES_128); + for (; i < upperBound; i += ByteVector.SPECIES_64.length()) { + ByteVector va8 = ByteVector.fromArray(ByteVector.SPECIES_64, a, i); + ByteVector vb8 = ByteVector.fromArray(ByteVector.SPECIES_64, b, i); + // expand each byte vector into short vector and perform multiplications + Vector va16 = va8.convertShape(VectorOperators.B2S, ShortVector.SPECIES_128, 0); + Vector vb16 = vb8.convertShape(VectorOperators.B2S, ShortVector.SPECIES_128, 0); + Vector prod16 = va16.mul(vb16); + Vector norm1_16 = va16.mul(va16); + Vector norm2_16 = vb16.mul(vb16); + // split each short vector into two int vectors and add + Vector prod32_1 = + prod16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 0); + Vector prod32_2 = + prod16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 1); + Vector norm1_32_1 = + norm1_16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 0); + Vector norm1_32_2 = + norm1_16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 1); + Vector norm2_32_1 = + norm2_16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 0); + Vector norm2_32_2 = + norm2_16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 1); + accSum1 = accSum1.add(prod32_1); + accSum2 = accSum2.add(prod32_2); + accNorm1_1 = accNorm1_1.add(norm1_32_1); + accNorm1_2 = accNorm1_2.add(norm1_32_2); + accNorm2_1 = accNorm2_1.add(norm2_32_1); + accNorm2_2 = accNorm2_2.add(norm2_32_2); + } + // reduce + sum += accSum1.add(accSum2).reduceLanes(VectorOperators.ADD); + norm1 += accNorm1_1.add(accNorm1_2).reduceLanes(VectorOperators.ADD); + norm2 += accNorm2_1.add(accNorm2_2).reduceLanes(VectorOperators.ADD); + } + } + + for (; i < a.length; i++) { + byte elem1 = a[i]; + byte elem2 = b[i]; + sum += elem1 * elem2; + norm1 += elem1 * elem1; + norm2 += elem2 * elem2; + } + return (float) (sum / Math.sqrt((double) norm1 * (double) norm2)); + } + + @Override + public int squareDistance(byte[] a, byte[] b) { + int i = 0; + int res = 0; + // only vectorize if we'll at least enter the loop a single time, and we have at least 128-bit + // vectors (256-bit on intel to dodge performance landmines) + if (a.length >= 16 && IS_AMD64_WITHOUT_AVX2 == false) { + if (INT_SPECIES_PREF_BIT_SIZE >= 256) { + // optimized 256/512 bit implementation, processes 8/16 bytes at a time + int upperBound = PREF_BYTE_SPECIES.loopBound(a.length); + IntVector acc = IntVector.zero(IntVector.SPECIES_PREFERRED); + for (; i < upperBound; i += PREF_BYTE_SPECIES.length()) { + ByteVector va8 = ByteVector.fromArray(PREF_BYTE_SPECIES, a, i); + ByteVector vb8 = ByteVector.fromArray(PREF_BYTE_SPECIES, b, i); + Vector va16 = va8.convertShape(VectorOperators.B2S, PREF_SHORT_SPECIES, 0); + Vector vb16 = vb8.convertShape(VectorOperators.B2S, PREF_SHORT_SPECIES, 0); + Vector diff16 = va16.sub(vb16); + Vector diff32 = + diff16.convertShape(VectorOperators.S2I, IntVector.SPECIES_PREFERRED, 0); + acc = acc.add(diff32.mul(diff32)); + } + // reduce + res += acc.reduceLanes(VectorOperators.ADD); + } else { + // 128-bit implementation, which must "split up" vectors due to widening conversions + int upperBound = ByteVector.SPECIES_64.loopBound(a.length); + IntVector acc1 = IntVector.zero(IntVector.SPECIES_128); + IntVector acc2 = IntVector.zero(IntVector.SPECIES_128); + for (; i < upperBound; i += ByteVector.SPECIES_64.length()) { + ByteVector va8 = ByteVector.fromArray(ByteVector.SPECIES_64, a, i); + ByteVector vb8 = ByteVector.fromArray(ByteVector.SPECIES_64, b, i); + // expand each byte vector into short vector and subtract + Vector va16 = va8.convertShape(VectorOperators.B2S, ShortVector.SPECIES_128, 0); + Vector vb16 = vb8.convertShape(VectorOperators.B2S, ShortVector.SPECIES_128, 0); + Vector diff16 = va16.sub(vb16); + // split each short vector into two int vectors, square, and add + Vector diff32_1 = + diff16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 0); + Vector diff32_2 = + diff16.convertShape(VectorOperators.S2I, IntVector.SPECIES_128, 1); + acc1 = acc1.add(diff32_1.mul(diff32_1)); + acc2 = acc2.add(diff32_2.mul(diff32_2)); + } + // reduce + res += acc1.add(acc2).reduceLanes(VectorOperators.ADD); + } + } + + for (; i < a.length; i++) { + int diff = a[i] - b[i]; + res += diff * diff; + } + return res; + } +} diff --git a/lucene/core/src/test/org/apache/lucene/util/TestVectorUtilProviders.java b/lucene/core/src/test/org/apache/lucene/util/TestVectorUtilProviders.java new file mode 100644 index 000000000000..c8443b964e39 --- /dev/null +++ b/lucene/core/src/test/org/apache/lucene/util/TestVectorUtilProviders.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.lucene.util; + +import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; +import java.util.function.ToDoubleFunction; +import java.util.function.ToIntFunction; +import java.util.stream.IntStream; +import org.apache.lucene.tests.util.LuceneTestCase; +import org.junit.BeforeClass; + +public class TestVectorUtilProviders extends LuceneTestCase { + + private static final double DELTA = 1e-4; + private static final VectorUtilProvider LUCENE_PROVIDER = new VectorUtilDefaultProvider(); + private static final VectorUtilProvider JDK_PROVIDER = VectorUtil.PROVIDER; + + private static final int[] VECTOR_SIZES = { + 1, 4, 6, 8, 13, 16, 25, 32, 64, 100, 128, 207, 256, 300, 512, 702, 1024 + }; + + private final int size; + + public TestVectorUtilProviders(int size) { + this.size = size; + } + + @ParametersFactory + public static Iterable parametersFactory() { + return () -> IntStream.of(VECTOR_SIZES).boxed().map(i -> new Object[] {i}).iterator(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + assumeFalse( + "Test only works when JDK's vector incubator module is enabled.", + JDK_PROVIDER instanceof VectorUtilDefaultProvider); + } + + public void testFloatVectors() { + var a = new float[size]; + var b = new float[size]; + for (int i = 0; i < size; ++i) { + a[i] = random().nextFloat(); + b[i] = random().nextFloat(); + } + assertFloatReturningProviders(p -> p.dotProduct(a, b)); + assertFloatReturningProviders(p -> p.squareDistance(a, b)); + assertFloatReturningProviders(p -> p.cosine(a, b)); + } + + public void testBinaryVectors() { + var a = new byte[size]; + var b = new byte[size]; + random().nextBytes(a); + random().nextBytes(b); + assertIntReturningProviders(p -> p.dotProduct(a, b)); + assertIntReturningProviders(p -> p.squareDistance(a, b)); + assertFloatReturningProviders(p -> p.cosine(a, b)); + } + + private void assertFloatReturningProviders(ToDoubleFunction func) { + assertEquals(func.applyAsDouble(LUCENE_PROVIDER), func.applyAsDouble(JDK_PROVIDER), DELTA); + } + + private void assertIntReturningProviders(ToIntFunction func) { + assertEquals(func.applyAsInt(LUCENE_PROVIDER), func.applyAsInt(JDK_PROVIDER)); + } +} From 35bd37d6943d4163d8a1725a1cdc581dddc8ffa0 Mon Sep 17 00:00:00 2001 From: Uwe Schindler Date: Thu, 25 May 2023 09:06:45 +0200 Subject: [PATCH 2/6] Refactor loop to not addAll set to itsself on initial round (followup of #12311) --- gradle/generation/extract-jdk-apis/ExtractJdkApis.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gradle/generation/extract-jdk-apis/ExtractJdkApis.java b/gradle/generation/extract-jdk-apis/ExtractJdkApis.java index 973a12bd03c7..be8741db3667 100644 --- a/gradle/generation/extract-jdk-apis/ExtractJdkApis.java +++ b/gradle/generation/extract-jdk-apis/ExtractJdkApis.java @@ -99,8 +99,8 @@ static void process(Path modulePath, PathMatcher fileMatcher, ZipOutputStream ou } } // recursively add all superclasses / interfaces of visible classes to classesToInclude: - for (Set a = classesToInclude; !a.isEmpty(); - a = a.stream().map(references::get).filter(Objects::nonNull).flatMap(Arrays::stream).collect(Collectors.toSet())) { + for (Set a = classesToInclude; !a.isEmpty();) { + a = a.stream().map(references::get).filter(Objects::nonNull).flatMap(Arrays::stream).collect(Collectors.toSet()); classesToInclude.addAll(a); } // remove all non-visible or not referenced classes: From c610686189690cb52d9fb4c3da4985dfe6de8696 Mon Sep 17 00:00:00 2001 From: ChrisHegarty Date: Thu, 25 May 2023 09:08:21 +0100 Subject: [PATCH 3/6] restore j.u.Objects to the glob --- .../extract-jdk-apis/ExtractJdkApis.java | 2 +- lucene/core/src/generated/jdk/jdk19.apijar | Bin 20781 -> 19164 bytes lucene/core/src/generated/jdk/jdk20.apijar | Bin 52851 -> 53553 bytes 3 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/generation/extract-jdk-apis/ExtractJdkApis.java b/gradle/generation/extract-jdk-apis/ExtractJdkApis.java index be8741db3667..886cc34fd988 100644 --- a/gradle/generation/extract-jdk-apis/ExtractJdkApis.java +++ b/gradle/generation/extract-jdk-apis/ExtractJdkApis.java @@ -50,7 +50,7 @@ public final class ExtractJdkApis { private static final FileTime FIXED_FILEDATE = FileTime.from(Instant.parse("2022-01-01T00:00:00Z")); static final Map CLASSFILE_MATCHERS = Map.of( - "java.base", "glob:java/{lang/foreign/*,nio/channels/FileChannel}.class", + "java.base", "glob:java/{lang/foreign/*,nio/channels/FileChannel,util/Objects}.class", "jdk.incubator.vector", "glob:jdk/incubator/vector/*.class" ); diff --git a/lucene/core/src/generated/jdk/jdk19.apijar b/lucene/core/src/generated/jdk/jdk19.apijar index f1672b81fcb0c7d6bbf459063a8a6c006c7d69ac..4a04f1440e4a413b27a65d8a9af993bb90af6f56 100644 GIT binary patch delta 1066 zcmZ3xi1E%;#tFXly}_~hmkmU0@15G@lqj3i{K=5(wt}NmrQ?SSnL#sKGDIb!mfC)J zW)k=M>PGiRB2(udW43RQZ{1OxcsE03nTMVE_2)73s~`XQ^Yt%#gZT%^S?V=soR5B0 zurZrCfmwFj<2z}4@|EojTfZKVcx8Oeu}10Fl-QITbFSA3tURe!Kehh4L|K~5%HwG& z9ZBtKmFG(rx$KjbG}iL7t(bmlYM^b1dvEo`g_^po1V6_J#91ITK@YKp4l#6sU;Ej`|}coU-vge@rb_tB3&2otm~ocOShG( zvwqK9xc$;L(YaH(ax)jyefP4%7Yb2uKsn(%~#@$7CA;wy!i8>1@F#l z$37X`KeV3w)zw{lCF|5rE3SluO#P`oPbKAi=pP@^b{qM3vt4$$wA=Ok2r8Irye59m zgD=;%%sDhGvz;fq&fvcJ;jqeX@%LgI<6=K@|5aZ7P2*(l#EFlOB`#d+b9CaF)HN=@ z>uVTN_FuagmGZmm`OXvCzB&t-UiJN(J-fwp`@0Lbneqa+G+7;8{pF6``TGkqcwg)7 zZ`|F&^PNL-Uf>>=8wERm*MF0Hu<)?^jglV{z6%b0VDWFPnw^zv8FO&k?Rvl0rH4|Z z@)vxR4)A8@xMe!$$RkDuhHK0W3<2KEEFugX92^Xj&nXE^_GJ^Btk1Y=^I0Yzrp>-= zG3=W|_#ZKEUdg+fadH%w%w!KwvCSF6KiMZsvH}uwcf#lLxmtQ+g*5EWgf$y+(Z zCinS>Zoa26jcM{dB@l;g^ISDCCa}QYCt!`3`|A8WIlU?1Vn7mmhC%Q*4ZDyam&`o6Wd3SrJ z2u?7w0O&rD^6ef{Ov`z|LJb}~li9uGCkFt9It8FY=97gyrI<{Fpqki#o^oIck$`iT zc&bhA^^#(WmjVkxd}+yaUKY%i@z$NZ%v*}-mOPl7r6LWsG|oqgiCt;3V}RJ?2|mh` z8GWP}PfR}OEeZ;O$#d1j!HQG^q?mrG0TtOz-V9W~QVYnGpZw0pnW;|)%&gLt1S_oe zm0~K=0}I9Ji-Cpi0EPSwz(UrB5FuMXDJDH5u#l9o#N-KnT1)~aVD29ih=ol4QcNFA z!9uqF_DrYE!OXe-4os^o!OVaD>XYk%uIjd)JUbwQxyFuR@=qs4u>fyYHU=P&2EtpM K3=D4^Ks*4$GP0fk delta 2160 zcmZWpd0bOh7Jhjl2}=Y9!y|;0u!LP>0=QI`AegWOfhtg-s02bWAP@s(5OI=WQK^(A zSJ^6vC|0c~7%SLP1sdzpFj5;vWpHE@`zut?DyY98^YUcG<-LE-`R=**p7WjWp235- zmL^=q2AS8h%-g<1A~B1&g-BqWQ$AqB?cwIqhU*qe4-trIf2W4;<1Y znjh9`CvU+y#2m_Kt4ngqkVuqJcp^nK^jOXLMX+4@ui#~@u;rhBl8}&?AcR6Z zB*lr1ZLas)7(fvMl73!#$E79+f*wPljYJ2ra2L)CgqxXz6?iilGg>GW3q|52{udcZ z+2YI$R?>E1R#sFb0m8{^ZweP{H0Be3`>@9LTb*MHwbr{@GcwksE>LLg4z{YA)T#q& zQ4PflZ*N~{$cejaSz~Fb*Z0iBeL8piK{N94LndPJ4dUT0;XH3fs&mIIs@YUFo72kn zgO=j0D#j8M^!B&82eDfVd9hdxHKivi3eXyQUe{2{LX<1;t6;E`hJalJBNv3yXSbRj>M4fwL2rR z*&;FaxX!)5y7tdU6INY5FN-G3Gjrp2#HyxFA<4F*;+9Fr(Ze_DuBW+V5$y((1E*sL z%J)vnII^9g`oC^1?{+E;`<{&Jp7-(V_*l`rT@$Cu>{%A&JL-P6s6iCc^5-5~W@-3Q z@@9X@kim}@F1)$O9WBLEKf5Q;?Nj1(Xzn1d2{$>tXybaYOxI&eVUnf;b%38B2Q;42QilIsra zD0L}WT5~FYQ`TSmU4^MJmSk!THHJ#HyhH8MB}3Bx=OC*s9!;*~b*qk=BA}dRDr0hj zGPjG8rSCT>%q#3CKhxbnFB1yzjr7z%BA5T%6jEtu%d~fhkQ7|8Ry%%Of9;1c356~X zu#J`umz8=lemp$>a2D+l#i{5&&Hw#Fo%(6=)JEmW_?a91b(=fdqYXbg)-d=WQE&W&cC|aD`;%a^$e{_^Lermt*wXCegcYHn4NEi_J6R`*Zc@Qf6!|7?LvM zyltoU3lEL%%O3IFS3g3&xF$Q4M_lura2_^^ViE(6dR$#Tyl+?6c!N zr0F9nKS2w3Uk&e3@37Zk)?Y7YwD1s2A{Q2LA4fxxE8hMPX^RqhhIuQk^D|g=VFnGKh6MPwTai=7vXCJ04vh)BX>YqQlh!_Xj!fa=B6Kl|Ep% zaxhX*(p}GFocZB=qnamZ&hGifC2BlhKD{yi?11wN-| zuSB~#NzMxR`)|E{^G|kIQ(btDRfBQotUET=YNAi%hd%lwe63|%yXf9m7mV?mzOE;l zwuz~Lt!Zw}h1NN=^ziJy*)MLUE%E&I=Sx$m+b-dC3iIYLVM|o{Rxn28Q^s;wN97QY zsC>mlV9-m_Ip)exyDAu*SjGe|`G|7PwapY{5S9QxPa{yzH&L#4lHrxjUY`;S-x`p_ zb?NXt1a|N!AQPs6MxH5sar8it7i568@c-Xs92SU<(Z78#MnNTy0hH@#uo7Mfvc*n& z`{_ErbK1Nf7KlzW0yfRC6Da;P*n_yRfaL=+Q0QxY3~KP_!hVLB86H3cWd?}u4v-f> zgUgpJz+`YCzzr}^XsyWtGX27t@A2es&p!5=N))>!t>QRt$L4pLatG0qnI z4MC3Y9I3KH<7{9i2O}$rhZf015iTI`X>f`ou;s4mZ_A4;6m9-QLd=N;3Ar1;{#oY(OphURa6I&1Sq+sht!8G{DDhy(+ zGQ*%W6v|(NK_`QK;Lp}#reO#ZB%-%^d!sG`)gJ?}LTK;=7leew;0OI7Q0r@pLcts28L|?~67@?o4pmV%vN{U(|b}M%{u2C+%5R)qB^fEMeTt+jzvx?!@H{vbP)G=G>jD`pW);{?7;e zAKWF=)0cN&$j!d-=GnQu&+i$RpS$z-@AK#S4C_D6NqE>YFHn2RovrnJ{r)qQn{_xG z1KVS@cB#!dYTCr}TPVm};l`Rb@qR0M-B!)#;F3MYwtJb*^~H|sAC^iuTDC6C5KeAafyxk-f3TUz7Wb;68J~B>vI-MzFK+qry%d{OPj5IJoNVSZa-@kSMN|;+E)I5 z>7jo+5Anu&E`9!b^OaX`w=e#AyMAif?q&C`?E1ysn)CWqW&B;X?>8IO`JArLUDwVj zxTfd+_EmOFu2(F#?wD{!{L0pIzr;ijO%5sYkEova-XMBM%m(eu*;_sq)ktgd?Apk~ z|7i2FzJ96gYa~_$?$S8FPI|-2yM98srH@jNzMbm+z2>}%WAdAAzpCup4_&;p?a;vk zPwUV4zfVY?756gb>)MKxlJ@rSClY%nC?+3#Y54q#nC!Qy3G0$>U(69JEja)ESMGTS zN!H9YQxc>yKfc$|$}wAgR%5lK{wLjgq9JV;>$m+;45?3;U;Bj7zU-!-Q8!~;BHQMU zc}AaRIJ>R=bV6!&u>1#R)|l)6c<-2$#odlRrk}(Z!E*je6`Sf){YTrPj@C&=pGp(i zx1?CSQ2pS$xI@zl{crz1W_RFlOS$XM{tp%(!%eU6+`sHksZHQN*K^BnTqwJIqckL_ zXqB4!rXSn^-s~Jg21`wpm>3uyuufjsF0=WCO>L(>LX3d{l-dyBoDBnJ+MCRHKz?%S zF)1cH`^k;R;+SqbO@4SRim5OV$P=F&a@>{aVmz2RC01&(zyX2DcaBRjy~+g(@t<&F z5~%?*vrafO33q{+$4}lNX-R zob0+@1gxj^j1*JVCZJFXQ{85;BE7SAOs!jhOxekPn;?qTpOs?Twhb&)zeNnJkMEom elhH1)(C_VHlVi_u@EJ20GyD-^V36Mj3OfMtJh|`y delta 416 zcmdnEi23sz<_#}wHb>akc1~74DaCZoX0qUE@yTH)-I=l-z)U`8$;l0e1Sa1H$};+c zg_Zero?VzQkE7J4v4 z6fDGcMv7_9T&NJ+WcxF=O!F7Qx$jnSPF`}xlF4-il90+|g|k{rQ7e&zxF++iftWYr ztQ1qyDio>PXPub}R-*{HpL1p^T#F*4vOyf|pj+ppm>AZhNXedeVB*? Date: Thu, 25 May 2023 12:06:05 +0100 Subject: [PATCH 4/6] update glob to include VectorSupport --- .../extract-jdk-apis/ExtractJdkApis.java | 2 +- lucene/core/src/generated/jdk/jdk20.apijar | Bin 53553 -> 70895 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/generation/extract-jdk-apis/ExtractJdkApis.java b/gradle/generation/extract-jdk-apis/ExtractJdkApis.java index 886cc34fd988..af3f706901e0 100644 --- a/gradle/generation/extract-jdk-apis/ExtractJdkApis.java +++ b/gradle/generation/extract-jdk-apis/ExtractJdkApis.java @@ -50,7 +50,7 @@ public final class ExtractJdkApis { private static final FileTime FIXED_FILEDATE = FileTime.from(Instant.parse("2022-01-01T00:00:00Z")); static final Map CLASSFILE_MATCHERS = Map.of( - "java.base", "glob:java/{lang/foreign/*,nio/channels/FileChannel,util/Objects}.class", + "java.base", "glob:{java/lang/foreign/*,java/nio/channels/FileChannel,java/util/Objects,jdk/internal/vm/vector/VectorSupport*}.class", "jdk.incubator.vector", "glob:jdk/incubator/vector/*.class" ); diff --git a/lucene/core/src/generated/jdk/jdk20.apijar b/lucene/core/src/generated/jdk/jdk20.apijar index 9aadb26bd850658a2c54457fd119b2ea29a607c4..5371b5c5b6eafbad12353e12d4273870d094ed30 100644 GIT binary patch delta 16295 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 Date: Thu, 25 May 2023 17:21:03 +0200 Subject: [PATCH 5/6] Handle jdk.internal classes mentioned in vector superclass or interfaces during extraction (#12329) --- .../extract-jdk-apis/ExtractJdkApis.java | 60 ++++++++++-------- lucene/core/src/generated/jdk/jdk20.apijar | Bin 70895 -> 58047 bytes 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/gradle/generation/extract-jdk-apis/ExtractJdkApis.java b/gradle/generation/extract-jdk-apis/ExtractJdkApis.java index af3f706901e0..8d185f9b4298 100644 --- a/gradle/generation/extract-jdk-apis/ExtractJdkApis.java +++ b/gradle/generation/extract-jdk-apis/ExtractJdkApis.java @@ -49,14 +49,13 @@ public final class ExtractJdkApis { private static final FileTime FIXED_FILEDATE = FileTime.from(Instant.parse("2022-01-01T00:00:00Z")); - static final Map CLASSFILE_MATCHERS = Map.of( - "java.base", "glob:{java/lang/foreign/*,java/nio/channels/FileChannel,java/util/Objects,jdk/internal/vm/vector/VectorSupport*}.class", - "jdk.incubator.vector", "glob:jdk/incubator/vector/*.class" - ); + private static final String PATTERN_PANAMA_FOREIGN = "java.base/{java/lang/foreign/*,java/nio/channels/FileChannel}"; + private static final String PATTERN_VECTOR_INCUBATOR = "jdk.incubator.vector/jdk/incubator/vector/*"; + private static final String PATTERN_VECTOR_VM_INTERNALS = "java.base/jdk/internal/vm/vector/VectorSupport{,$Vector,$VectorMask,$VectorPayload,$VectorShuffle}"; - static final Map> MODULES_TO_PROCESS = Map.of( - 19, List.of("java.base"), - 20, List.of("java.base", "jdk.incubator.vector") + static final Map> CLASSFILE_PATTERNS = Map.of( + 19, List.of(PATTERN_PANAMA_FOREIGN), + 20, List.of(PATTERN_PANAMA_FOREIGN, PATTERN_VECTOR_VM_INTERNALS, PATTERN_VECTOR_INCUBATOR) ); public static void main(String... args) throws IOException { @@ -67,35 +66,42 @@ public static void main(String... args) throws IOException { if (jdk.intValue() != Runtime.version().feature()) { throw new IllegalStateException("Incorrect java version: " + Runtime.version().feature()); } - if (!MODULES_TO_PROCESS.containsKey(jdk)) { + if (!CLASSFILE_PATTERNS.containsKey(jdk)) { throw new IllegalArgumentException("No support to extract stubs from java version: " + jdk); } var outputPath = Paths.get(args[1]); + // create JRT filesystem and build a combined FileMatcher: + var jrtPath = Paths.get(URI.create("jrt:/")).toRealPath(); + var patterns = CLASSFILE_PATTERNS.get(jdk).stream() + .map(pattern -> jrtPath.getFileSystem().getPathMatcher("glob:" + pattern + ".class")) + .toArray(PathMatcher[]::new); + PathMatcher pattern = p -> Arrays.stream(patterns).anyMatch(matcher -> matcher.matches(p)); + + // Collect all files to process: + final List filesToExtract; + try (var stream = Files.walk(jrtPath)) { + filesToExtract = stream.filter(p -> pattern.matches(jrtPath.relativize(p))).collect(Collectors.toList()); + } + + // Process all class files: try (var out = new ZipOutputStream(Files.newOutputStream(outputPath))) { - for (String mod : MODULES_TO_PROCESS.get(jdk)) { - var modulePath = Paths.get(URI.create("jrt:/")).resolve(mod).toRealPath(); - var moduleMatcher = modulePath.getFileSystem().getPathMatcher(CLASSFILE_MATCHERS.get(mod)); - process(modulePath, moduleMatcher, out); - } + process(filesToExtract, out); } } - static void process(Path modulePath, PathMatcher fileMatcher, ZipOutputStream out) throws IOException { + private static void process(List filesToExtract, ZipOutputStream out) throws IOException { var classesToInclude = new HashSet(); var references = new HashMap(); var processed = new TreeMap(); - try (var stream = Files.walk(modulePath)) { - var filesToExtract = stream.map(modulePath::relativize).filter(fileMatcher::matches).toArray(Path[]::new); - System.out.println("Transforming " + filesToExtract.length + " class files in [" + modulePath + "]..."); - for (Path relative : filesToExtract) { - try (var in = Files.newInputStream(modulePath.resolve(relative))) { - var reader = new ClassReader(in); - var cw = new ClassWriter(0); - var cleaner = new Cleaner(cw, classesToInclude, references); - reader.accept(cleaner, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); - processed.put(reader.getClassName(), cw.toByteArray()); - } + System.out.println("Transforming " + filesToExtract.size() + " class files..."); + for (Path p : filesToExtract) { + try (var in = Files.newInputStream(p)) { + var reader = new ClassReader(in); + var cw = new ClassWriter(0); + var cleaner = new Cleaner(cw, classesToInclude, references); + reader.accept(cleaner, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); + processed.put(reader.getClassName(), cw.toByteArray()); } } // recursively add all superclasses / interfaces of visible classes to classesToInclude: @@ -105,7 +111,7 @@ static void process(Path modulePath, PathMatcher fileMatcher, ZipOutputStream ou } // remove all non-visible or not referenced classes: processed.keySet().removeIf(Predicate.not(classesToInclude::contains)); - System.out.println("Writing " + processed.size() + " visible classes for [" + modulePath + "]..."); + System.out.println("Writing " + processed.size() + " visible classes..."); for (var cls : processed.entrySet()) { String cn = cls.getKey(); System.out.println("Writing stub for class: " + cn); @@ -113,6 +119,8 @@ static void process(Path modulePath, PathMatcher fileMatcher, ZipOutputStream ou out.write(cls.getValue()); out.closeEntry(); } + classesToInclude.removeIf(processed.keySet()::contains); + System.out.println("Referenced classes not included: " + classesToInclude); } static boolean isVisible(int access) { diff --git a/lucene/core/src/generated/jdk/jdk20.apijar b/lucene/core/src/generated/jdk/jdk20.apijar index 5371b5c5b6eafbad12353e12d4273870d094ed30..d6340fd093879e0d85daa27a78b77d4e38b46804 100644 GIT binary patch delta 572 zcmX}pODIHP6bJD8%|#6Jz!+nYkcnh=l7^7MMkx!VELf07GAYHvV?}J#DW8Q$V&Rbt zS4kEk%KNcU%EB`Znn5h=INx{5y{q&4pVPhHcitC*w)a)9FHcM9I_!n3YMWM5;5KN1 zMip{)WN3Gk&plK@=`IS`~?D z!=g;#_L2U0S765yq5p}{8HMOsCJa2s%JFf5%8CN@FX_AuTV-j4mgR8hq-P8#Q?%8Gu4pH#Q!FR`^D85rs{Q<_O B+iL&- delta 10369 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 Date: Thu, 25 May 2023 16:33:30 +0100 Subject: [PATCH 6/6] add Objects --- .../extract-jdk-apis/ExtractJdkApis.java | 2 +- lucene/core/src/generated/jdk/jdk20.apijar | Bin 58047 -> 58749 bytes 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/generation/extract-jdk-apis/ExtractJdkApis.java b/gradle/generation/extract-jdk-apis/ExtractJdkApis.java index 8d185f9b4298..b7e99cb83cc8 100644 --- a/gradle/generation/extract-jdk-apis/ExtractJdkApis.java +++ b/gradle/generation/extract-jdk-apis/ExtractJdkApis.java @@ -49,7 +49,7 @@ public final class ExtractJdkApis { private static final FileTime FIXED_FILEDATE = FileTime.from(Instant.parse("2022-01-01T00:00:00Z")); - private static final String PATTERN_PANAMA_FOREIGN = "java.base/{java/lang/foreign/*,java/nio/channels/FileChannel}"; + private static final String PATTERN_PANAMA_FOREIGN = "java.base/java/{lang/foreign/*,nio/channels/FileChannel,util/Objects}"; private static final String PATTERN_VECTOR_INCUBATOR = "jdk.incubator.vector/jdk/incubator/vector/*"; private static final String PATTERN_VECTOR_VM_INTERNALS = "java.base/jdk/internal/vm/vector/VectorSupport{,$Vector,$VectorMask,$VectorPayload,$VectorShuffle}"; diff --git a/lucene/core/src/generated/jdk/jdk20.apijar b/lucene/core/src/generated/jdk/jdk20.apijar index d6340fd093879e0d85daa27a78b77d4e38b46804..942ddef057b7dcc70997d162e44ddc49a908fabd 100644 GIT binary patch delta 1048 zcmdmgl=<%|<_#}w>cts28L|?~67@?o4pmV%vN{U(|b}M%{u2C+%5R)qB^fEMeTt+jzvx?!@H{vbP)G=G>jD`pW);{?7;e zAKWF=)0cN&$j!d-=GnQu&+i$RpS$z-@AK#S4C_D6NqE>YFHn2RovrnJ{r)qQn{_xG z1KVS@cB#!dYTCr}TPVm};l`Rb@qR0M-B!)#;F3MYwtJb*^~H|sAC^iuTDC6C5KeAafyxk-f3TUz7Wb;68J~B>vI-MzFK+qry%d{OPj5IJoNVSZa-@kSMN|;+E)I5 z>7jo+5Anu&E`9!b^OaX`w=e#AyMAif?q&C`?E1ysn)CWqW&B;X?>8IO`JArLUDwVj zxTfd+_EmOFu2(F#?wD{!{L0pIzr;ijO%5sYkEova-XMBM%m(eu*;_sq)ktgd?Apk~ z|7i2FzJ96gYa~_$?$S8FPI|-2yM98srH@jNzMbm+z2>}%WAdAAzpCup4_&;p?a;vk zPwUV4zfVY?756gb>)MKxlJ@rSClY%nC?+3#Y54q#nC!Qy3G0$>U(69JEja)ESMGTS zN!H9YQxc>yKfc$|$}wAgR%5lK{wLjgq9JV;>$m+;45?3;U;Bj7zU-!-Q8!~;BHQMU zc}AaRIJ>R=bV6!&u>1#R)|l)6c<-2$#odlRrk}(Z!E*je6`Sf){YTrPj@C&=pGp(i zx1?CSQ2pS$xI@zl{crz1W_RFlOS$XM{tp%(!%eU6+`sHksZHQN*K^BnTqwJIqckL_ zXqB4!rXSn^-s~Jg21`wpm>3uyuufjsF0=WC&9>S42r&i*P-;Vfb2bc^X>W4k1^LPI zZb&iN*-tjSB|iD$4R@y7PGIId2g%6=7X&6p-IQV~3fK0W? z@^>tmwypv))hBnXkOEt|`i>OSsnuYicX#ZWF0BDG!|pmWJy;87Ze9(s>-AkJ#)p#& z?rBWcyXVMMun{Pk&Q!GtNNG;?-yjG!Oy#~5Q{85;w)FdUOs!jhOxekPn?%5}FMzV! zwtUAVsmv2LSrg=ZRn>{(^wiMGjo5_lg#V7aQc4x|V05jj;c4lJq2Q$6zxH2Wi zf|)DtxG+^^gPF2<5|bZX5}2%aSBhy#C0NM4MiMO41r%D`4i?&b*M-S;8jvYFS>c`~ z)10|rX2m^QruhrO%y+9eC*K9ixUPV5Rlr7M-j`yES_u{6n#{XK6fArZD4etkE-bnh zVxjE=DW-zeaN&jr&P;`C;oLV59GMu_!?|G(9hkT_z`6S$+A{HNgmYCN*)fT30&?Xh z@82Q}wshGeDJHiqV4(+(?3oU22Qp)s*6*JD@UhzDWsfbHKA!+G)0p&50V&fyYHU=Ot2f~9Q3=A*Mf_MN