1 // Copyright 2016 The Bazel Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package com.google.devtools.build.android.desugar; 15 16 import static com.google.common.base.Preconditions.checkArgument; 17 import static com.google.common.collect.Iterables.getOnlyElement; 18 19 import com.google.common.collect.ImmutableList; 20 import com.google.common.collect.ImmutableMap; 21 import java.io.IOException; 22 import java.lang.invoke.MethodHandle; 23 import java.nio.file.Files; 24 import java.nio.file.Path; 25 import java.util.ArrayList; 26 import java.util.HashSet; 27 import java.util.LinkedHashMap; 28 import java.util.Map; 29 import java.util.Set; 30 import java.util.stream.Stream; 31 32 class LambdaClassMaker { 33 34 static final String LAMBDA_METAFACTORY_DUMPER_PROPERTY = "jdk.internal.lambda.dumpProxyClasses"; 35 36 private final Path rootDirectory; 37 private final Map<Path, LambdaInfo> generatedClasses = new LinkedHashMap<>(); 38 private final Set<Path> existingPaths = new HashSet<>(); 39 LambdaClassMaker(Path rootDirectory)40 public LambdaClassMaker(Path rootDirectory) { 41 checkArgument( 42 Files.isDirectory(rootDirectory), "The argument '%s' is not a directory.", rootDirectory); 43 this.rootDirectory = rootDirectory; 44 } 45 generateLambdaClass(String invokerInternalName, LambdaInfo lambdaInfo, MethodHandle bootstrapMethod, ArrayList<Object> bsmArgs)46 public void generateLambdaClass(String invokerInternalName, LambdaInfo lambdaInfo, 47 MethodHandle bootstrapMethod, ArrayList<Object> bsmArgs) throws IOException { 48 // Invoking the bootstrap method will dump the generated class. Ignore any pre-existing 49 // matching files, which can come from desugar's implementation using classes being desugared. 50 existingPaths.addAll(findUnprocessed(invokerInternalName + "$$Lambda$")); 51 try { 52 bootstrapMethod.invokeWithArguments(bsmArgs); 53 } catch (Throwable e) { 54 throw new IllegalStateException("Failed to generate lambda class for class " 55 + invokerInternalName + " using " + bootstrapMethod + " with arguments " + bsmArgs, e); 56 } 57 58 Path generatedClassFile = getOnlyElement(findUnprocessed(invokerInternalName + "$$Lambda$")); 59 generatedClasses.put(generatedClassFile, lambdaInfo); 60 existingPaths.add(generatedClassFile); 61 } 62 63 /** 64 * Returns absolute paths to .class files generated since the last call to this method together 65 * with a string descriptor of the factory method. 66 */ drain()67 public ImmutableMap<Path, LambdaInfo> drain() { 68 ImmutableMap<Path, LambdaInfo> result = ImmutableMap.copyOf(generatedClasses); 69 generatedClasses.clear(); 70 return result; 71 } 72 findUnprocessed(String pathPrefix)73 private ImmutableList<Path> findUnprocessed(String pathPrefix) throws IOException { 74 // pathPrefix is an internal class name prefix containing '/', but paths obtained on Windows 75 // will not contain '/' and searches will fail. So, construct an absolute path from the given 76 // string and use its string representation to find the file we need regardless of host 77 // system's file system 78 Path rootPathPrefix = rootDirectory.resolve(pathPrefix); 79 final String rootPathPrefixStr = rootPathPrefix.toString(); 80 81 if (!Files.exists(rootPathPrefix.getParent())) { 82 return ImmutableList.of(); 83 } 84 try (Stream<Path> paths = Files.list(rootPathPrefix.getParent())) { 85 return paths 86 .filter( 87 path -> 88 path.toString().startsWith(rootPathPrefixStr) && !existingPaths.contains(path)) 89 .collect(ImmutableList.toImmutableList()); 90 } 91 } 92 } 93