From 2e8c6c4c9d1f42d0a6805104e4c5553d12c0347f Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Wed, 11 Oct 2023 13:55:05 +0200 Subject: [PATCH] Avoid streams --- src/main/.checkstyle_checks.xml | 55 ++----------------- .../java/org/truffleruby/aot/ParserCache.java | 13 +++-- .../truffleruby/core/VMPrimitiveNodes.java | 17 +++--- .../truffleruby/core/array/ArrayUtils.java | 34 ++++++++++++ .../core/regexp/TruffleRegexpNodes.java | 24 +++----- .../truffleruby/core/string/StringUtils.java | 18 ++++++ .../truffleruby/debug/TruffleASTPrinter.java | 47 ++++++++-------- .../truffleruby/debug/TruffleDebugNodes.java | 8 +-- .../language/TruffleBootNodes.java | 7 +-- .../arguments/CheckKeywordArityNode.java | 11 +--- .../arguments/KeywordArgumentsDescriptor.java | 5 +- .../arguments/MissingKeywordArgumentNode.java | 11 +--- .../language/loader/RequireNode.java | 15 ++--- .../parser/RubyDeferredWarnings.java | 3 +- 14 files changed, 120 insertions(+), 148 deletions(-) diff --git a/src/main/.checkstyle_checks.xml b/src/main/.checkstyle_checks.xml index 477264eff73a..7094a130dc97 100644 --- a/src/main/.checkstyle_checks.xml +++ b/src/main/.checkstyle_checks.xml @@ -277,6 +277,10 @@ + + + + @@ -287,62 +291,11 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/java/org/truffleruby/aot/ParserCache.java b/src/main/java/org/truffleruby/aot/ParserCache.java index 7358410cde3d..8efaa7e0062c 100644 --- a/src/main/java/org/truffleruby/aot/ParserCache.java +++ b/src/main/java/org/truffleruby/aot/ParserCache.java @@ -12,13 +12,15 @@ import java.io.IOException; import java.util.HashMap; import java.util.Map; -import java.util.stream.Collectors; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.source.Source; import org.truffleruby.core.CoreLibrary; +import org.truffleruby.core.array.ArrayUtils; +import org.truffleruby.core.string.StringUtils; import org.truffleruby.language.loader.ResourceLoader; import org.truffleruby.parser.RubyDeferredWarnings; +import org.truffleruby.parser.RubyDeferredWarnings.WarningMessage; import org.truffleruby.parser.RubySource; import org.truffleruby.parser.TranslatorDriver; import org.truffleruby.parser.ast.RootParseNode; @@ -64,12 +66,11 @@ private static RootParseNode parse(RubySource source) { final StaticScope staticScope = new StaticScope(StaticScope.Type.LOCAL, null); final ParserConfiguration parserConfiguration = new ParserConfiguration(null, false, true, false); RubyDeferredWarnings rubyWarnings = new RubyDeferredWarnings(); - RootParseNode rootParseNode = TranslatorDriver - .parseToJRubyAST(null, source, staticScope, parserConfiguration, rubyWarnings); + var rootParseNode = TranslatorDriver.parseToJRubyAST(null, source, staticScope, parserConfiguration, + rubyWarnings); if (!rubyWarnings.warnings.isEmpty()) { - throw new RuntimeException("Core files should not emit warnings: " + String.join( - "\n", - rubyWarnings.warnings.stream().map(w -> w.getWarningMessage()).collect(Collectors.toList()))); + throw new RuntimeException("Core files should not emit warnings: " + + StringUtils.join(ArrayUtils.map(rubyWarnings.warnings, WarningMessage::getWarningMessage), "\n")); } return rootParseNode; } diff --git a/src/main/java/org/truffleruby/core/VMPrimitiveNodes.java b/src/main/java/org/truffleruby/core/VMPrimitiveNodes.java index 2e8cf56dcefc..2eb65486aeb8 100644 --- a/src/main/java/org/truffleruby/core/VMPrimitiveNodes.java +++ b/src/main/java/org/truffleruby/core/VMPrimitiveNodes.java @@ -37,9 +37,7 @@ */ package org.truffleruby.core; -import java.util.Arrays; import java.util.Map.Entry; -import java.util.stream.Stream; import com.oracle.truffle.api.TruffleStackTrace; import com.oracle.truffle.api.dsl.Bind; @@ -621,15 +619,16 @@ RubyArray argumentsDescriptor(VirtualFrame frame) { private RubyArray descriptorToArray(ArgumentsDescriptor descriptor) { if (descriptor == EmptyArgumentsDescriptor.INSTANCE) { return createEmptyArray(); - } else if (descriptor instanceof KeywordArgumentsDescriptor) { - final KeywordArgumentsDescriptor keywordArgumentsDescriptor = (KeywordArgumentsDescriptor) descriptor; + } else if (descriptor instanceof KeywordArgumentsDescriptor keywordArgumentsDescriptor) { + var keywords = keywordArgumentsDescriptor.getKeywords(); - final Stream keywords = Stream.concat( - Stream.of("keywords"), - Arrays.stream(keywordArgumentsDescriptor.getKeywords())) - .map(getLanguage()::getSymbol); + Object[] array = new Object[1 + keywords.length]; + array[0] = getSymbol("keywords"); + for (int i = 0; i < keywords.length; i++) { + array[i + 1] = getSymbol(keywords[i]); + } - return createArray(keywords.toArray()); + return createArray(array); } else { throw CompilerDirectives.shouldNotReachHere(); } diff --git a/src/main/java/org/truffleruby/core/array/ArrayUtils.java b/src/main/java/org/truffleruby/core/array/ArrayUtils.java index e5a105880df1..37999e6ea6aa 100644 --- a/src/main/java/org/truffleruby/core/array/ArrayUtils.java +++ b/src/main/java/org/truffleruby/core/array/ArrayUtils.java @@ -10,8 +10,11 @@ package org.truffleruby.core.array; import java.lang.reflect.Array; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; +import java.util.function.Function; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.api.TruffleSafepoint; @@ -278,4 +281,35 @@ public static List asList(Object[] array) { return Arrays.asList(array); } + /** Compares by identity using Java {@code ==} */ + @TruffleBoundary + public static Object[] subtract(Object[] a, Object[] b) { + var result = new ArrayList<>(); + for (Object element : a) { + if (!contains(b, element)) { + result.add(element); + } + } + return result.toArray(); + } + + @TruffleBoundary + public static Object[] map(T[] array, Function mapper) { + var result = new Object[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = mapper.apply(array[i]); + } + return result; + } + + @TruffleBoundary + public static Object[] map(Collection list, Function mapper) { + var result = new Object[list.size()]; + var iterator = list.iterator(); + for (int i = 0; i < list.size(); i++) { + result[i] = mapper.apply(iterator.next()); + } + return result; + } + } diff --git a/src/main/java/org/truffleruby/core/regexp/TruffleRegexpNodes.java b/src/main/java/org/truffleruby/core/regexp/TruffleRegexpNodes.java index a2f8b0ead467..b08dce8452d6 100644 --- a/src/main/java/org/truffleruby/core/regexp/TruffleRegexpNodes.java +++ b/src/main/java/org/truffleruby/core/regexp/TruffleRegexpNodes.java @@ -20,7 +20,6 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.function.Function; -import java.util.stream.Collectors; import com.oracle.truffle.api.CompilerDirectives; import com.oracle.truffle.api.TruffleSafepoint; @@ -458,32 +457,23 @@ protected RubyArray fillinInstrumentData(Set map, ArrayBuilderNode arrayB @TruffleBoundary protected static Set allCompiledRegexps() { final Set ret = new HashSet<>(); - ret.addAll(DYNAMIC_REGEXPS); ret.addAll(LITERAL_REGEXPS); - return ret; } @TruffleBoundary protected static Set allMatchedRegexps() { final Set ret = new HashSet<>(); - - ret.addAll( - MATCHED_REGEXPS_JONI - .keySet() - .stream() - .map(matchInfo -> matchInfo.regex) - .collect(Collectors.toSet())); - ret.addAll( - MATCHED_REGEXPS_TREGEX - .keySet() - .stream() - .map(matchInfo -> matchInfo.regex) - .collect(Collectors.toSet())); - + for (var matchInfo : MATCHED_REGEXPS_JONI.keySet()) { + ret.add(matchInfo.regex); + } + for (var matchInfo : MATCHED_REGEXPS_TREGEX.keySet()) { + ret.add(matchInfo.regex); + } return ret; } + } @CoreMethod(names = "regexp_compilation_stats_array", onSingleton = true, required = 1) diff --git a/src/main/java/org/truffleruby/core/string/StringUtils.java b/src/main/java/org/truffleruby/core/string/StringUtils.java index e119d7b35c4e..977097f46edb 100644 --- a/src/main/java/org/truffleruby/core/string/StringUtils.java +++ b/src/main/java/org/truffleruby/core/string/StringUtils.java @@ -56,4 +56,22 @@ public static String toUpperCase(String string) { return string.toUpperCase(Locale.ENGLISH); } + @TruffleBoundary + public static String join(Object[] elements, String separator) { + return join(elements, separator, "", ""); + } + + @TruffleBoundary + public static String join(Object[] elements, String separator, String prefix, String suffix) { + var builder = new StringBuilder(prefix); + for (int i = 0; i < elements.length; i++) { + builder.append(elements[i]); + if (i != elements.length - 1) { + builder.append(separator); + } + } + builder.append(suffix); + return builder.toString(); + } + } diff --git a/src/main/java/org/truffleruby/debug/TruffleASTPrinter.java b/src/main/java/org/truffleruby/debug/TruffleASTPrinter.java index b7cd3675d996..134d7c99da9f 100644 --- a/src/main/java/org/truffleruby/debug/TruffleASTPrinter.java +++ b/src/main/java/org/truffleruby/debug/TruffleASTPrinter.java @@ -16,12 +16,11 @@ import java.util.Set; import java.util.TreeSet; import java.util.regex.Matcher; -import java.util.stream.Collectors; -import java.util.stream.Stream; import com.oracle.truffle.api.profiles.Profile; import org.graalvm.collections.Pair; import org.truffleruby.core.proc.ProcCallTargets; +import org.truffleruby.core.string.StringUtils; import org.truffleruby.core.support.DetailedInspectingSupport; import org.truffleruby.language.RubyRootNode; import org.truffleruby.language.methods.CachedLazyCallTargetSupplier; @@ -121,23 +120,21 @@ private static List> getNodeAttributes(Node node) { } var attributesMap = NodeUtil.collectNodeProperties(node); - var attributes = new ArrayList<>(attributesMap.entrySet()) - .stream() - .map(entry -> Pair.create(entry.getKey(), entry.getValue())) - .map(pair -> { - if (pair.getLeft().startsWith("field.")) { - String name = pair.getLeft().substring("field.".length()); - return Pair.create(name, pair.getRight()); - } else { - return pair; - } - }) - .filter(pair -> pair.getRight() != null) // hide numerous attributes that aren't initialized yet - .filter(pair -> !attributesToIgnore.contains(pair.getLeft())) // ignore some noisy attributes - .filter(pair -> !generatedFieldNames.contains(pair.getLeft())) // ignore attributes of generated -Gen classes - .filter(pair -> !(pair.getRight() instanceof Profile)) // ignore ...Profile as far as they might be disabled/enabled that affects string representation - .collect(Collectors.toList()); + var attributes = new ArrayList>(); + for (var entry : attributesMap.entrySet()) { + String name = entry.getKey(); + Object value = entry.getValue(); + if (name.startsWith("field.")) { + name = name.substring("field.".length()); + } + if (value != null && // hide numerous attributes that aren't initialized yet + !attributesToIgnore.contains(name) && // ignore some noisy attributes + !generatedFieldNames.contains(name) && // ignore attributes of generated -Gen classes + !(value instanceof Profile)) { // ignore ...Profile as far as they might be disabled/enabled that affects string representation + attributes.add(Pair.create(name, value)); + } + } return attributes; } @@ -163,12 +160,12 @@ private static List> getNodeChildren(Node node) { } } - var children = new ArrayList<>(childrenMap.entrySet()) - .stream() - .map(entry -> Pair.create(entry.getKey(), entry.getValue())) - .filter(pair -> pair.getRight() != null) // hide child nodes that aren't initialized yet - .collect(Collectors.toList()); - + var children = new ArrayList>(); + for (var entry : childrenMap.entrySet()) { + if (entry.getValue() != null) { // hide child nodes that aren't initialized yet + children.add(Pair.create(entry.getKey(), entry.getValue())); + } + } return children; } @@ -316,7 +313,7 @@ private static String valueOrArrayToString(Object value) { strings[i] = valueToString(element); } - valueString = Stream.of(strings).collect(Collectors.joining(", ", "[", "]")); + valueString = StringUtils.join(strings, ", ", "[", "]"); } else { valueString = valueToString(value); } diff --git a/src/main/java/org/truffleruby/debug/TruffleDebugNodes.java b/src/main/java/org/truffleruby/debug/TruffleDebugNodes.java index cbadde04d6ee..2232273a1c28 100644 --- a/src/main/java/org/truffleruby/debug/TruffleDebugNodes.java +++ b/src/main/java/org/truffleruby/debug/TruffleDebugNodes.java @@ -46,6 +46,7 @@ import org.truffleruby.core.RubyHandle; import org.truffleruby.core.array.ArrayGuards; import org.truffleruby.core.array.ArrayHelpers; +import org.truffleruby.core.array.ArrayUtils; import org.truffleruby.core.array.RubyArray; import org.truffleruby.core.array.library.ArrayStoreLibrary; import org.truffleruby.core.binding.BindingNodes; @@ -1403,10 +1404,9 @@ public abstract static class PrimitiveNamesNode extends CoreMethodArrayArguments @TruffleBoundary @Specialization RubyArray primitiveNames() { - var primitiveNames = getLanguage().primitiveManager.getPrimitiveNames().stream() - .map(FromJavaStringNode::executeUncached); - - return createArray(primitiveNames.toArray()); + var primitives = getLanguage().primitiveManager.getPrimitiveNames(); + var primitiveNames = ArrayUtils.map(primitives, FromJavaStringNode::executeUncached); + return createArray(primitiveNames); } } diff --git a/src/main/java/org/truffleruby/language/TruffleBootNodes.java b/src/main/java/org/truffleruby/language/TruffleBootNodes.java index ec6533733b69..12ef1add2764 100644 --- a/src/main/java/org/truffleruby/language/TruffleBootNodes.java +++ b/src/main/java/org/truffleruby/language/TruffleBootNodes.java @@ -13,7 +13,6 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.List; -import java.util.stream.Collectors; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.nodes.NodeUtil; @@ -29,6 +28,7 @@ import org.truffleruby.core.array.RubyArray; import org.truffleruby.core.encoding.Encodings; import org.truffleruby.core.string.RubyString; +import org.truffleruby.core.string.StringUtils; import org.truffleruby.core.symbol.RubySymbol; import org.truffleruby.language.control.RaiseException; import org.truffleruby.language.dispatch.DispatchNode; @@ -409,10 +409,7 @@ Object toolchainPaths(RubySymbol pathName, final Toolchain toolchain = getToolchain(getContext(), this); final List paths = toolchain.getPaths(name); if (paths != null) { - String path = paths - .stream() - .map(file -> file.getPath()) - .collect(Collectors.joining(File.pathSeparator)); + String path = StringUtils.join(paths.toArray(), File.pathSeparator); return createString(fromJavaStringNode, path, Encodings.UTF_8); } else { throw new RaiseException( diff --git a/src/main/java/org/truffleruby/language/arguments/CheckKeywordArityNode.java b/src/main/java/org/truffleruby/language/arguments/CheckKeywordArityNode.java index 277b062e4652..754e5f4a6cb6 100644 --- a/src/main/java/org/truffleruby/language/arguments/CheckKeywordArityNode.java +++ b/src/main/java/org/truffleruby/language/arguments/CheckKeywordArityNode.java @@ -11,6 +11,7 @@ import com.oracle.truffle.api.CompilerDirectives; import org.truffleruby.RubyLanguage; +import org.truffleruby.core.array.ArrayUtils; import org.truffleruby.core.exception.RubyException; import org.truffleruby.core.hash.RubyHash; import org.truffleruby.core.hash.library.HashStoreLibrary; @@ -27,9 +28,6 @@ import com.oracle.truffle.api.profiles.BranchProfile; import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; /** Check that no extra keyword arguments are given, when there is no **kwrest */ public final class CheckKeywordArityNode extends RubyBaseNode { @@ -113,12 +111,7 @@ private Object[] findExtraKeywordArguments(RubyHash keywordArguments) { (index, key, value, state) -> ((ArrayList) state).add(key), actualKeywordsAsList); - final List allowedKeywordsAsList = Arrays.asList(allowedKeywords); - final List extraKeywords = actualKeywordsAsList.stream() - .filter(k -> !allowedKeywordsAsList.contains(k)) - .collect(Collectors.toList()); - - return extraKeywords.toArray(); + return ArrayUtils.subtract(actualKeywordsAsList.toArray(), allowedKeywords); } } diff --git a/src/main/java/org/truffleruby/language/arguments/KeywordArgumentsDescriptor.java b/src/main/java/org/truffleruby/language/arguments/KeywordArgumentsDescriptor.java index 5d0241b75228..8692d348148c 100644 --- a/src/main/java/org/truffleruby/language/arguments/KeywordArgumentsDescriptor.java +++ b/src/main/java/org/truffleruby/language/arguments/KeywordArgumentsDescriptor.java @@ -12,8 +12,6 @@ import com.oracle.truffle.api.CompilerDirectives.CompilationFinal; import org.truffleruby.core.string.StringUtils; -import java.util.stream.Collectors; -import java.util.stream.Stream; /** An arguments descriptor that says that keyword arguments were passed (either foo(a: 1) or foo(**kw)). Note that * currently, if kw is empty, then this descriptor is used even though it is semantically the same as if no keyword @@ -33,7 +31,6 @@ public String[] getKeywords() { @Override public String toString() { - final String keywordsAsString = Stream.of(keywords).collect(Collectors.joining(", ", "[", "]")); - return StringUtils.format("KeywordArgumentsDescriptor(keywords = %s)", keywordsAsString); + return StringUtils.format("KeywordArgumentsDescriptor(keywords = [%s])", StringUtils.join(keywords, ", ")); } } diff --git a/src/main/java/org/truffleruby/language/arguments/MissingKeywordArgumentNode.java b/src/main/java/org/truffleruby/language/arguments/MissingKeywordArgumentNode.java index 6049f2be368b..c860c7732150 100644 --- a/src/main/java/org/truffleruby/language/arguments/MissingKeywordArgumentNode.java +++ b/src/main/java/org/truffleruby/language/arguments/MissingKeywordArgumentNode.java @@ -10,6 +10,7 @@ package org.truffleruby.language.arguments; import org.truffleruby.RubyLanguage; +import org.truffleruby.core.array.ArrayUtils; import org.truffleruby.core.exception.RubyException; import org.truffleruby.core.hash.RubyHash; import org.truffleruby.core.hash.library.HashStoreLibrary; @@ -24,9 +25,6 @@ import org.truffleruby.language.methods.Arity; import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; public final class MissingKeywordArgumentNode extends RubyContextSourceNode { @@ -81,12 +79,7 @@ private Object[] findMissingKeywordArguments(RubyHash actualKeywords) { (index, key, value, state) -> ((ArrayList) state).add(key), actualKeywordsAsList); - final List requiredKeywordsAsList = Arrays.asList(requiredKeywords); - final List missingKeywords = requiredKeywordsAsList.stream() - .filter(k -> !actualKeywordsAsList.contains(k)) - .collect(Collectors.toList()); - - return missingKeywords.toArray(); + return ArrayUtils.subtract(requiredKeywords, actualKeywordsAsList.toArray()); } @Override diff --git a/src/main/java/org/truffleruby/language/loader/RequireNode.java b/src/main/java/org/truffleruby/language/loader/RequireNode.java index fc38f91efcbf..892494999e6f 100644 --- a/src/main/java/org/truffleruby/language/loader/RequireNode.java +++ b/src/main/java/org/truffleruby/language/loader/RequireNode.java @@ -16,7 +16,6 @@ import java.util.Locale; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collectors; import com.oracle.truffle.api.RootCallTarget; import com.oracle.truffle.api.dsl.Cached; @@ -26,6 +25,7 @@ import org.truffleruby.cext.ValueWrapperManager; import org.truffleruby.core.array.ArrayUtils; import org.truffleruby.core.cast.BooleanCastNode; +import org.truffleruby.core.string.StringUtils; import org.truffleruby.core.string.TStringWithEncoding; import org.truffleruby.interop.InteropNodes; import org.truffleruby.interop.TranslateInteropExceptionNodeGen; @@ -93,7 +93,7 @@ private boolean requireConsideringAutoload(String feature, String expandedPath, final List constantsUnfiltered = featureLoader.getAutoloadConstants(expandedPath); final List alreadyAutoloading = new ArrayList<>(); if (!constantsUnfiltered.isEmpty()) { - final List toAutoload = new ArrayList<>(); + var toAutoload = new ArrayList(); for (RubyConstant constant : constantsUnfiltered) { // Do not autoload recursively from the #require call in GetConstantNode if (constant.getAutoloadConstant().isAutoloading()) { @@ -105,11 +105,12 @@ private boolean requireConsideringAutoload(String feature, String expandedPath, if (getContext().getOptions().LOG_AUTOLOAD && !toAutoload.isEmpty()) { - String info = toAutoload - .stream() - .filter(c -> !c.getAutoloadConstant().isAutoloading()) - .map(c -> c + " with " + c.getAutoloadConstant().getAutoloadPath()) - .collect(Collectors.joining(" and ")); + var toAutoloadWithPath = new String[toAutoload.size()]; + for (int i = 0; i < toAutoload.size(); i++) { + var constant = toAutoload.get(i); + toAutoloadWithPath[i] = constant + " with " + constant.getAutoloadConstant().getAutoloadPath(); + } + String info = StringUtils.join(toAutoloadWithPath, " and "); RubyLanguage.LOGGER .info(() -> String.format( "%s: requiring %s which is registered as an autoload for %s", diff --git a/src/main/java/org/truffleruby/parser/RubyDeferredWarnings.java b/src/main/java/org/truffleruby/parser/RubyDeferredWarnings.java index e1fb11ce96e8..2a4bcec575cf 100644 --- a/src/main/java/org/truffleruby/parser/RubyDeferredWarnings.java +++ b/src/main/java/org/truffleruby/parser/RubyDeferredWarnings.java @@ -32,13 +32,12 @@ package org.truffleruby.parser; import java.util.ArrayList; -import java.util.List; import org.joni.WarnCallback; public final class RubyDeferredWarnings implements WarnCallback { - public List warnings = new ArrayList<>(); + public ArrayList warnings = new ArrayList<>(); public enum Verbosity { VERBOSE, // -W2