diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib')
5 files changed, 153 insertions, 35 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java index 1f3ef8770a..e90f856709 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/CustomCommandLine.java @@ -32,6 +32,8 @@ import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.collect.nestedset.NestedSet; import com.google.devtools.build.lib.concurrent.BlazeInterners; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; +import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization; import com.google.devtools.build.lib.util.Fingerprint; import com.google.devtools.build.lib.util.LazyString; import com.google.devtools.build.lib.vfs.PathFragment; @@ -51,6 +53,7 @@ import javax.annotation.Nullable; /** A customizable, serializable class for building memory efficient command lines. */ @Immutable +@AutoCodec public final class CustomCommandLine extends CommandLine { private interface ArgvFragment { @@ -151,6 +154,7 @@ public final class CustomCommandLine extends CommandLine { * -> ["1:2:3"] * </pre> */ + @AutoCodec public static class VectorArg<T> { final boolean isNestedSet; final boolean isEmpty; @@ -159,7 +163,9 @@ public final class CustomCommandLine extends CommandLine { final String beforeEach; final String joinWith; - private VectorArg( + @AutoCodec.Instantiator + @VisibleForSerialization + VectorArg( boolean isNestedSet, boolean isEmpty, int count, @@ -180,28 +186,43 @@ public final class CustomCommandLine extends CommandLine { * <p>Call {@link SimpleVectorArg#mapped} to produce a vector arg that maps from a given type to * a string. */ + @AutoCodec public static class SimpleVectorArg<T> extends VectorArg<T> { private final Iterable<T> values; private SimpleVectorArg(Builder builder, @Nullable Collection<T> values) { - super( + this( false /* isNestedSet */, values == null || values.isEmpty(), values != null ? values.size() : 0, builder.formatEach, builder.beforeEach, - builder.joinWith); - this.values = values; + builder.joinWith, + values); } private SimpleVectorArg(Builder builder, @Nullable NestedSet<T> values) { - super( + this( true /* isNestedSet */, values == null || values.isEmpty(), -1 /* count */, builder.formatEach, builder.beforeEach, - builder.joinWith); + builder.joinWith, + values); + } + + @AutoCodec.Instantiator + @VisibleForSerialization + SimpleVectorArg( + boolean isNestedSet, + boolean isEmpty, + int count, + String formatEach, + String beforeEach, + String joinWith, + @Nullable Iterable<T> values) { + super(isNestedSet, isEmpty, count, formatEach, beforeEach, joinWith); this.values = values; } @@ -331,7 +352,8 @@ public final class CustomCommandLine extends CommandLine { } } - private static final class VectorArgFragment implements ArgvFragment { + @AutoCodec + static final class VectorArgFragment implements ArgvFragment { private static Interner<VectorArgFragment> interner = BlazeInterners.newStrongInterner(); private static final UUID FORMAT_EACH_UUID = UUID.fromString("f830781f-2e0d-4e3b-9b99-ece7f249e0f3"); @@ -346,7 +368,9 @@ public final class CustomCommandLine extends CommandLine { private final boolean hasBeforeEach; private final boolean hasJoinWith; - private VectorArgFragment( + @AutoCodec.Instantiator + @VisibleForSerialization + VectorArgFragment( boolean isNestedSet, boolean hasMapEach, boolean hasFormatEach, @@ -607,12 +631,14 @@ public final class CustomCommandLine extends CommandLine { } } - private static final class ExpandedTreeArtifactExecPathsArg - extends TreeArtifactExpansionArgvFragment { + @AutoCodec + static final class ExpandedTreeArtifactExecPathsArg extends TreeArtifactExpansionArgvFragment { private final Artifact treeArtifact; private static final UUID TREE_UUID = UUID.fromString("13b7626b-c77d-4a30-ad56-ff08c06b1cee"); - private ExpandedTreeArtifactExecPathsArg(Artifact treeArtifact) { + @AutoCodec.Instantiator + @VisibleForSerialization + ExpandedTreeArtifactExecPathsArg(Artifact treeArtifact) { Preconditions.checkArgument( treeArtifact.isTreeArtifact(), "%s is not a TreeArtifact", treeArtifact); this.treeArtifact = treeArtifact; @@ -1129,7 +1155,7 @@ public final class CustomCommandLine extends CommandLine { builder.arguments.addAll(other.arguments); return builder; } - + private final ImmutableList<Object> arguments; /** @@ -1142,14 +1168,14 @@ public final class CustomCommandLine extends CommandLine { private final Map<Artifact, TreeFileArtifact> substitutionMap; private CustomCommandLine(List<Object> arguments) { - this.arguments = ImmutableList.copyOf(arguments); - this.substitutionMap = null; + this(arguments, null); } - private CustomCommandLine( - List<Object> arguments, Map<Artifact, TreeFileArtifact> substitutionMap) { + @AutoCodec.Instantiator + @VisibleForSerialization + CustomCommandLine(List<Object> arguments, Map<Artifact, TreeFileArtifact> substitutionMap) { this.arguments = ImmutableList.copyOf(arguments); - this.substitutionMap = ImmutableMap.copyOf(substitutionMap); + this.substitutionMap = substitutionMap == null ? null : ImmutableMap.copyOf(substitutionMap); } /** diff --git a/src/main/java/com/google/devtools/build/lib/analysis/actions/ParameterFileWriteAction.java b/src/main/java/com/google/devtools/build/lib/analysis/actions/ParameterFileWriteAction.java index caeab2ca5a..03b2084064 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/actions/ParameterFileWriteAction.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/actions/ParameterFileWriteAction.java @@ -29,6 +29,8 @@ import com.google.devtools.build.lib.actions.ExecException; import com.google.devtools.build.lib.actions.ParameterFile.ParameterFileType; import com.google.devtools.build.lib.actions.UserExecException; import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable; +import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; +import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization; import com.google.devtools.build.lib.util.Fingerprint; import com.google.devtools.build.lib.util.ShellEscaper; import java.io.IOException; @@ -36,10 +38,9 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.nio.charset.Charset; -/** - * Action to write a parameter file for a {@link CommandLine}. - */ +/** Action to write a parameter file for a {@link CommandLine}. */ @Immutable // if commandLine and charset are immutable +@AutoCodec public final class ParameterFileWriteAction extends AbstractFileWriteAction { private static final String GUID = "45f678d8-e395-401e-8446-e795ccc6361f"; @@ -74,6 +75,7 @@ public final class ParameterFileWriteAction extends AbstractFileWriteAction { * @param type the type of the file * @param charset the charset of the file */ + @AutoCodec.Instantiator public ParameterFileWriteAction( ActionOwner owner, Iterable<Artifact> inputs, @@ -81,7 +83,7 @@ public final class ParameterFileWriteAction extends AbstractFileWriteAction { CommandLine commandLine, ParameterFileType type, Charset charset) { - super(owner, ImmutableList.copyOf(inputs), output, false); + super(owner, inputs, output, false); this.commandLine = commandLine; this.type = type; this.charset = charset; @@ -121,6 +123,11 @@ public final class ParameterFileWriteAction extends AbstractFileWriteAction { return new ParamFileWriter(arguments); } + @VisibleForSerialization + Artifact getOutput() { + return Iterables.getOnlyElement(outputs); + } + private class ParamFileWriter implements DeterministicWriter { private final Iterable<String> arguments; diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecProcessor.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecProcessor.java index 1df5f51451..d7c2e8a7fd 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecProcessor.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/AutoCodecProcessor.java @@ -49,8 +49,10 @@ import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; import javax.lang.model.util.ElementFilter; import javax.tools.Diagnostic; @@ -251,9 +253,9 @@ public class AutoCodecProcessor extends AbstractProcessor { TypeKind typeKind = parameter.asType().getKind(); serializeBuilder.addStatement( "$T unsafe_$L = ($T) $T.getInstance().get$L(input, $L_offset)", - parameter.asType(), + sanitizeTypeParameterOfGenerics(parameter.asType()), parameter.getSimpleName(), - parameter.asType(), + sanitizeTypeParameterOfGenerics(parameter.asType()), UnsafeProvider.class, typeKind.isPrimitive() ? firstLetterUpper(typeKind.toString().toLowerCase()) : "Object", parameter.getSimpleName()); @@ -276,6 +278,22 @@ public class AutoCodecProcessor extends AbstractProcessor { return env.getTypeUtils().isAssignable(t1, t2) || env.getTypeUtils().isAssignable(t2, t1); } + private TypeMirror sanitizeTypeParameterOfGenerics(TypeMirror type) { + if (type instanceof TypeVariable) { + return env.getTypeUtils().erasure(type); + } + if (!(type instanceof DeclaredType)) { + return type; + } + DeclaredType declaredType = (DeclaredType) type; + for (TypeMirror typeMirror : declaredType.getTypeArguments()) { + if (typeMirror instanceof TypeVariable) { + return env.getTypeUtils().erasure(type); + } + } + return type; + } + private String findGetterForClass(VariableElement parameter, TypeElement type) { List<ExecutableElement> methods = ElementFilter.methodsIn(env.getElementUtils().getAllMembers(type)); diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java index fea22ae876..5c78bed826 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/Marshallers.java @@ -35,6 +35,8 @@ import com.google.devtools.build.lib.skyframe.serialization.strings.StringCodecs import com.google.protobuf.AbstractMessage; import com.google.protobuf.ExtensionRegistryLite; import com.google.protobuf.ProtocolMessageEnum; +import com.squareup.javapoet.TypeName; +import java.nio.charset.Charset; import java.util.Collection; import java.util.Comparator; import java.util.LinkedHashMap; @@ -51,6 +53,7 @@ import javax.lang.model.type.DeclaredType; import javax.lang.model.type.PrimitiveType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; /** Class containing all {@link Marshaller} instances. */ class Marshallers { @@ -78,11 +81,22 @@ class Marshallers { void writeDeserializationCode(Context context) { SerializationCodeGenerator generator = getMatchingCodeGenerator(context.type); boolean needsNullHandling = context.canBeNull() && generator != contextMarshaller; + // Check to see if this declared type is generic or if it contains a generic. + TypeName contextTypeName = context.getTypeName(); + if (context.isDeclaredType() && !context.getDeclaredType().getTypeArguments().isEmpty()) { + for (TypeMirror paramTypeMirror : context.getDeclaredType().getTypeArguments()) { + if (paramTypeMirror instanceof TypeVariable) { + contextTypeName = TypeName.get(env.getTypeUtils().erasure(context.getDeclaredType())); + } + } + } else if (context.getTypeMirror() instanceof TypeVariable) { + contextTypeName = TypeName.get(env.getTypeUtils().erasure(context.getTypeMirror())); + } if (needsNullHandling) { - context.builder.addStatement("$T $L = null", context.getTypeName(), context.name); + context.builder.addStatement("$T $L = null", contextTypeName, context.name); context.builder.beginControlFlow("if (codedIn.readBool())"); } else { - context.builder.addStatement("$T $L", context.getTypeName(), context.name); + context.builder.addStatement("$T $L", contextTypeName, context.name); } generator.addDeserializationCode(context); if (needsNullHandling) { @@ -123,6 +137,11 @@ class Marshallers { .orElseThrow(() -> new IllegalArgumentException("No generator for: " + primitiveType)); } + // We're dealing with a generic. + if (type instanceof TypeVariable) { + return contextMarshaller; + } + // TODO(cpeyser): Refactor primitive handling from AutoCodecProcessor.java if (!(type instanceof DeclaredType)) { throw new IllegalArgumentException( @@ -476,11 +495,15 @@ class Marshallers { // Writes the target count to the stream so deserialization knows when to stop. context.builder.addStatement( "codedOut.writeInt32NoTag($T.size($L))", Iterables.class, context.name); + TypeMirror typeParameter = context.getDeclaredType().getTypeArguments().get(0); + if (typeParameter instanceof TypeVariable) { + typeParameter = ((TypeVariable) typeParameter).getUpperBound(); + } Context repeated = context.with( context.getDeclaredType().getTypeArguments().get(0), context.makeName("repeated")); - context.builder.beginControlFlow( - "for ($T $L : $L)", repeated.getTypeName(), repeated.name, context.name); + context.builder.beginControlFlow( + "for ($T $L : $L)", typeParameter, repeated.name, context.name); writeSerializationCode(repeated); context.builder.endControlFlow(); } @@ -489,14 +512,18 @@ class Marshallers { Context repeated = context.with( context.getDeclaredType().getTypeArguments().get(0), context.makeName("repeated")); - String builderName = context.makeName("builder"); - context.builder.addStatement( - "$T<$T> $L = new $T<>()", - ImmutableList.Builder.class, - repeated.getTypeName(), - builderName, - ImmutableList.Builder.class); - writeListDeserializationLoopAndBuild(context, repeated, builderName); + TypeMirror typeParameter = context.getDeclaredType().getTypeArguments().get(0); + if (typeParameter instanceof TypeVariable) { + typeParameter = ((TypeVariable) typeParameter).getUpperBound(); + } + String builderName = context.makeName("builder"); + context.builder.addStatement( + "$T<$T> $L = new $T<>()", + ImmutableList.Builder.class, + typeParameter, + builderName, + ImmutableList.Builder.class); + writeListDeserializationLoopAndBuild(context, repeated, builderName); } private final Marshaller iterableMarshaller = @@ -883,6 +910,9 @@ class Marshallers { private void addSerializationCodeForNestedSet(Context context) { TypeMirror typeParameter = context.getDeclaredType().getTypeArguments().get(0); + if (typeParameter instanceof TypeVariable) { + typeParameter = ((TypeVariable) typeParameter).getUpperBound(); + } String nestedSetCodec = context.makeName("nestedSetCodec"); context.builder.addStatement( "$T<$T> $L = new $T<>()", @@ -901,6 +931,9 @@ class Marshallers { private void addDeserializationCodeForNestedSet(Context context) { TypeMirror typeParameter = context.getDeclaredType().getTypeArguments().get(0); String nestedSetCodec = context.makeName("nestedSetCodec"); + if (typeParameter instanceof TypeVariable) { + typeParameter = ((TypeVariable) typeParameter).getUpperBound(); + } context.builder.addStatement( "$T<$T> $L = new $T<>()", NestedSetCodec.class, @@ -953,6 +986,31 @@ class Marshallers { } }; + private final Marshaller charsetMarshaller = + new Marshaller() { + @Override + public boolean matches(DeclaredType type) { + return matchesType(type, Charset.class); + } + + @Override + public void addSerializationCode(Context context) { + context.builder.addStatement( + "$T.asciiOptimized().serialize(context, $L.name(), codedOut)", + StringCodecs.class, + context.name); + } + + @Override + public void addDeserializationCode(Context context) { + context.builder.addStatement( + "$L = $T.forName($T.asciiOptimized().deserialize(context, codedIn))", + context.name, + Charset.class, + StringCodecs.class); + } + }; + private final ImmutableList<PrimitiveValueSerializationCodeGenerator> primitiveGenerators = ImmutableList.of( INT_CODE_GENERATOR, @@ -982,6 +1040,7 @@ class Marshallers { hashCodeMarshaller, protoMarshaller, iterableMarshaller, + charsetMarshaller, contextMarshaller); /** True when {@code type} has the same type as {@code clazz}. */ diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/SerializationCodeGenerator.java b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/SerializationCodeGenerator.java index 94690393ab..0cf644bd6e 100644 --- a/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/SerializationCodeGenerator.java +++ b/src/main/java/com/google/devtools/build/lib/skyframe/serialization/autocodec/SerializationCodeGenerator.java @@ -67,6 +67,14 @@ interface SerializationCodeGenerator { return (DeclaredType) type; } + boolean isDeclaredType() { + return type instanceof DeclaredType; + } + + TypeMirror getTypeMirror() { + return type; + } + /** Returns true if this Context represents a type that can be null */ boolean canBeNull() { return !(type instanceof PrimitiveType); |