diff options
58 files changed, 876 insertions, 310 deletions
diff --git a/jack-tests/Android.mk b/jack-tests/Android.mk index c982592..2255157 100644 --- a/jack-tests/Android.mk +++ b/jack-tests/Android.mk @@ -292,8 +292,7 @@ $(call declare-java7-test-with-name,java7/trywithresources/test001) $(call declare-java7-test-with-name,java7/trywithresources/test002) $(call declare-java7-test-with-name,java7/parser/literals/test001) $(call declare-java7-test-with-name,java7/parser/literals/test002) -# Known bug -#$(call declare-java7-test-with-name,java7/boxing/test001) +$(call declare-java7-test-with-name,java7/boxing/test001) # define global regression test include $(JACK_CLEAR_VARS) diff --git a/jack-tests/tests/com/android/jack/classpath/test003/jack/A.java b/jack-tests/tests/com/android/jack/classpath/test003/jack/A.java new file mode 100644 index 0000000..32109f6 --- /dev/null +++ b/jack-tests/tests/com/android/jack/classpath/test003/jack/A.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed 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 com.android.jack.classpath.test003.jack; + +import com.android.jack.classpath.test003.lib.HasInnersClasses; + +public class A { + + public static int get() { + return HasInnersClasses.value; + } + +} diff --git a/jack-tests/tests/com/android/jack/classpath/test003/lib/HasInnersClasses.java b/jack-tests/tests/com/android/jack/classpath/test003/lib/HasInnersClasses.java new file mode 100644 index 0000000..bc360c1 --- /dev/null +++ b/jack-tests/tests/com/android/jack/classpath/test003/lib/HasInnersClasses.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed 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 com.android.jack.classpath.test003.lib; + +public class HasInnersClasses { + + public static class InnerToDelete { + + } + + public static int value; + + static { + value = 3; + } +} diff --git a/jack/src/com/android/jack/CommandLine.java b/jack/src/com/android/jack/CommandLine.java index 3b4ba0c..3da2a03 100644 --- a/jack/src/com/android/jack/CommandLine.java +++ b/jack/src/com/android/jack/CommandLine.java @@ -20,6 +20,7 @@ import com.android.jack.frontend.FrontendCompilationException; import com.android.jack.load.JackLoadingException; import com.android.sched.util.TextUtils; import com.android.sched.util.UnrecoverableException; +import com.android.sched.util.codec.Parser.ValueDescription; import com.android.sched.util.config.ChainedException; import com.android.sched.util.config.ConfigurationException; import com.android.sched.util.config.GatherConfigBuilder; @@ -33,6 +34,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -171,6 +173,19 @@ public abstract class CommandLine { sb.append(" "); sb.append(property.getCodec().getUsage()); + // Value descriptions + List<ValueDescription> descriptions = property.getCodec().getValueDescriptions(); + if (descriptions.size() != 0) { + sb.append(" where"); + for (ValueDescription entry : descriptions) { + sb.append(TextUtils.LINE_SEPARATOR); + sb.append(" "); + sb.append(entry.getValue()); + sb.append(": "); + sb.append(entry.getDescription()); + } + } + System.out.println(sb); } } diff --git a/jack/src/com/android/jack/Jack.java b/jack/src/com/android/jack/Jack.java index 81d4bfe..7fb8d4e 100644 --- a/jack/src/com/android/jack/Jack.java +++ b/jack/src/com/android/jack/Jack.java @@ -226,7 +226,8 @@ import com.android.jack.transformations.flow.FlowNormalizer; import com.android.jack.transformations.flow.FlowNormalizerSchedulingSeparator; import com.android.jack.transformations.parent.DeclaredTypePackageChecker; import com.android.jack.transformations.parent.PackageChecker; -import com.android.jack.transformations.parent.ParentSetterChecker; +import com.android.jack.transformations.parent.ParentChecker; +import com.android.jack.transformations.parent.TypeParentChecker; import com.android.jack.transformations.renamepackage.PackageRenamer; import com.android.jack.transformations.rop.cast.RopCastLegalizer; import com.android.jack.transformations.threeaddresscode.ThreeAddressCodeBuilder; @@ -872,7 +873,7 @@ public abstract class Jack { } if (hasSanityChecks) { - planBuilder.append(ParentSetterChecker.class); + planBuilder.append(ParentChecker.class); } { @@ -1116,11 +1117,14 @@ public abstract class Jack { fieldPlan2.append(FieldAnnotationBuilder.class); } } + if (hasSanityChecks) { + typePlan5.append(TypeParentChecker.class); + } typePlan5.append(OneDexPerTypeWriter.class); } if (hasSanityChecks) { - planBuilder.append(ParentSetterChecker.class); + planBuilder.append(ParentChecker.class); { SubPlanBuilder<JDefinedClassOrInterface> typePlan = planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class); @@ -1151,7 +1155,7 @@ public abstract class Jack { appendMultiDexAndShrobStartPlan(planBuilder); if (hasSanityChecks) { - planBuilder.append(ParentSetterChecker.class); + planBuilder.append(ParentChecker.class); } { SubPlanBuilder<JDefinedClassOrInterface> typePlan7 = @@ -1378,7 +1382,7 @@ public abstract class Jack { appendMultiDexAndShrobStartPlan(planBuilder); if (hasSanityChecks) { - planBuilder.append(ParentSetterChecker.class); + planBuilder.append(ParentChecker.class); } { SubPlanBuilder<JDefinedClassOrInterface> typePlan3 = @@ -1510,11 +1514,14 @@ public abstract class Jack { fieldPlan2.append(FieldAnnotationBuilder.class); } } + if (hasSanityChecks) { + typePlan5.append(TypeParentChecker.class); + } typePlan5.append(OneDexPerTypeWriter.class); } if (hasSanityChecks) { - planBuilder.append(ParentSetterChecker.class); + planBuilder.append(ParentChecker.class); } } diff --git a/jack/src/com/android/jack/backend/dex/DexFileWriter.java b/jack/src/com/android/jack/backend/dex/DexFileWriter.java index b1bf575..4fc75a5 100644 --- a/jack/src/com/android/jack/backend/dex/DexFileWriter.java +++ b/jack/src/com/android/jack/backend/dex/DexFileWriter.java @@ -26,14 +26,14 @@ import com.android.sched.schedulable.Produce; import com.android.sched.schedulable.RunnableSchedulable; import com.android.sched.util.config.HasKeyId; import com.android.sched.util.config.ThreadConfig; -import com.android.sched.util.config.id.BooleanPropertyId; +import com.android.sched.util.config.id.ImplementationPropertyId; import com.android.sched.vfs.Container; import com.android.sched.vfs.OutputVDir; import javax.annotation.Nonnull; /** - * Write dex into a file. + * Write dex to a file. */ @HasKeyId @Description("Write dex into a file") @@ -43,8 +43,7 @@ import javax.annotation.Nonnull; public class DexFileWriter extends DexWriter implements RunnableSchedulable<JSession> { /** - * File name prefix of a {@code .dex} file automatically loaded in an - * archive. + * File name prefix of a {@code .dex} file automatically loaded in an archive. */ static final String DEX_PREFIX = "classes"; @@ -52,14 +51,10 @@ public class DexFileWriter extends DexWriter implements RunnableSchedulable<JSes public static final String DEX_FILENAME = DEX_PREFIX + DEX_FILE_EXTENSION; @Nonnull - public static final BooleanPropertyId MULTIDEX = BooleanPropertyId.create( - "jack.dex.output.multidex", "Enable MultiDex output") - .addDefaultValue(false); - - @Nonnull - public static final BooleanPropertyId MINIMAL_MAIN_DEX = BooleanPropertyId.create( - "jack.dex.output.multidex.minimalmaindex", - "Keep main dex file as small as possible in MultiDex mode").addDefaultValue(false); + public static final + ImplementationPropertyId<DexWritingTool> DEX_WRITING_POLICY = ImplementationPropertyId.create( + "jack.dex.output.policy", "Define which policy will be used to emit dex files", + DexWritingTool.class).addDefaultValue("single-dex"); @Nonnull private final OutputVDir outputVDir; @@ -77,8 +72,8 @@ public class DexFileWriter extends DexWriter implements RunnableSchedulable<JSes @Override public void run(@Nonnull JSession session) throws Exception { - DexWritingTool writingTool = new MergingDexWritingTool(outputVDir); - writingTool.write(); + DexWritingTool writingTool = ThreadConfig.get(DEX_WRITING_POLICY); + writingTool.write(outputVDir); } } diff --git a/jack/src/com/android/jack/backend/dex/DexWritingTool.java b/jack/src/com/android/jack/backend/dex/DexWritingTool.java index 5024a65..912d244 100644 --- a/jack/src/com/android/jack/backend/dex/DexWritingTool.java +++ b/jack/src/com/android/jack/backend/dex/DexWritingTool.java @@ -16,13 +16,28 @@ package com.android.jack.backend.dex; +import com.android.jack.Jack; +import com.android.jack.JackIOException; +import com.android.jack.Options; import com.android.jack.backend.dex.rop.CodeItemBuilder; import com.android.jack.dx.dex.DexOptions; import com.android.jack.dx.dex.file.DexFile; +import com.android.jack.dx.io.DexBuffer; +import com.android.jack.ir.ast.JDefinedClassOrInterface; +import com.android.jack.tools.merger.JackMerger; +import com.android.jack.tools.merger.MergeOverflow; import com.android.sched.util.config.ThreadConfig; +import com.android.sched.util.file.NotFileOrDirectoryException; +import com.android.sched.vfs.InputRootVDir; +import com.android.sched.vfs.InputVFile; import com.android.sched.vfs.OutputVDir; +import com.android.sched.vfs.OutputVFile; +import com.android.sched.vfs.VPath; +import java.io.BufferedOutputStream; import java.io.IOException; +import java.io.OutputStream; +import java.util.List; import javax.annotation.Nonnull; @@ -32,14 +47,8 @@ import javax.annotation.Nonnull; public abstract class DexWritingTool { @Nonnull - protected final OutputVDir outputVDir; - @Nonnull private final boolean forceJumbo = ThreadConfig.get(CodeItemBuilder.FORCE_JUMBO).booleanValue(); - public DexWritingTool(@Nonnull OutputVDir outputVDir) { - this.outputVDir = outputVDir; - } - @Nonnull protected DexFile createDexFile() { DexOptions options = new DexOptions(); @@ -47,6 +56,68 @@ public abstract class DexWritingTool { return new DexFile(options); } - public abstract void write() throws IOException; + public abstract void write(@Nonnull OutputVDir outputVDir) throws JackIOException; + + protected InputRootVDir getTypeDexDir() { + return (InputRootVDir) ThreadConfig.get(Options.TYPEDEX_DIR); + } + + protected void finishMerge(@Nonnull JackMerger merger, @Nonnull OutputVFile out) + throws JackIOException { + OutputStream os = null; + try { + try { + os = new BufferedOutputStream(out.openWrite()); + merger.finish(os); + } finally { + if (os != null) { + os.close(); + } + } + } catch (IOException e) { + throw new JackIOException("Cannot write to output dex " + out, e); + } + } + + protected void mergeDex(@Nonnull JackMerger merger, InputVFile inputDex) throws JackIOException, + MergeOverflow { + try { + merger.addDexFile(new DexBuffer(inputDex.openRead())); + } catch (IOException e) { + throw new JackIOException("Could not read Dex from " + inputDex, e); + } + } + protected OutputVFile getOutputDex(@Nonnull OutputVDir outputVDir, int dexCount) + throws JackIOException { + assert dexCount >= 1; + String dexName; + if (dexCount == 1) { + dexName = DexFileWriter.DEX_FILENAME; + } else { + dexName = DexFileWriter.DEX_PREFIX + dexCount + DexFileWriter.DEX_FILE_EXTENSION; + } + try { + return outputVDir.createOutputVFile(new VPath(dexName, '/')); + } catch (IOException e) { + throw new JackIOException("Cannot create dex file '" + dexName + "' in " + outputVDir, e); + } + } + + protected void fillDexLists(List<InputVFile> mainDexList, List<InputVFile> anyDexList) + throws JackIOException { + for (JDefinedClassOrInterface type : Jack.getSession().getTypesToEmit()) { + try { + InputVFile inputVFile = getTypeDexDir().getInputVFile(DexWriter.getFilePath(type)); + if (type.containsMarker(MainDexMarker.class)) { + mainDexList.add(inputVFile); + } else { + anyDexList.add(inputVFile); + } + } catch (NotFileOrDirectoryException e) { + throw new JackIOException("Error trying to read file for type '" + + Jack.getUserFriendlyFormatter().getName(type) + "'", e); + } + } + } } diff --git a/jack/src/com/android/jack/backend/dex/MergingDexWritingTool.java b/jack/src/com/android/jack/backend/dex/MergingDexWritingTool.java deleted file mode 100644 index 652e428..0000000 --- a/jack/src/com/android/jack/backend/dex/MergingDexWritingTool.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed 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 com.android.jack.backend.dex; - -import com.android.jack.Jack; -import com.android.jack.JackFileException; -import com.android.jack.JackIOException; -import com.android.jack.JackUserException; -import com.android.jack.Options; -import com.android.jack.dx.io.DexBuffer; -import com.android.jack.ir.ast.JDefinedClassOrInterface; -import com.android.jack.tools.merger.JackMerger; -import com.android.jack.tools.merger.MergeOverflow; -import com.android.sched.util.config.ThreadConfig; -import com.android.sched.util.file.NotFileOrDirectoryException; -import com.android.sched.util.location.Location; -import com.android.sched.vfs.InputOutputVFile; -import com.android.sched.vfs.InputRootVDir; -import com.android.sched.vfs.InputVDir; -import com.android.sched.vfs.InputVElement; -import com.android.sched.vfs.InputVFile; -import com.android.sched.vfs.OutputVDir; -import com.android.sched.vfs.OutputVFile; -import com.android.sched.vfs.VPath; - -import java.io.BufferedOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.List; - -import javax.annotation.Nonnegative; -import javax.annotation.Nonnull; - -/** - * A {@link DexWritingTool} that merges dex files, each one corresponding to a type. - */ -public class MergingDexWritingTool extends DexWritingTool { - - @Nonnull - private JackMerger merger; - @Nonnegative - private int dexCount = 1; - @Nonnull - private OutputVFile dexVFile; - - public MergingDexWritingTool(@Nonnull OutputVDir outputVDir) { - super(outputVDir); - merger = new JackMerger(createDexFile()); - try { - dexVFile = getNextOutputDex(); - } catch (IOException e) { - throw new JackIOException("Error creating output dex", e); - } - } - - @Override - public void write() { - - InputRootVDir dexFileVDir = (InputRootVDir) ThreadConfig.get(Options.TYPEDEX_DIR); - boolean isMultidex = ThreadConfig.get(DexFileWriter.MULTIDEX).booleanValue(); - - try { - if (isMultidex) { - - List<InputVFile> mainDexList = new ArrayList<InputVFile>(); - List<InputVFile> anyDexList = new ArrayList<InputVFile>(); - for (JDefinedClassOrInterface type : Jack.getSession().getTypesToEmit()) { - try { - InputVFile inputVFile = dexFileVDir.getInputVFile(DexWriter.getFilePath(type)); - if (type.containsMarker(MainDexMarker.class)) { - mainDexList.add(inputVFile); - } else { - anyDexList.add(inputVFile); - } - } catch (NotFileOrDirectoryException e) { - throw new JackFileException("Error trying to read file for type '" - + Jack.getUserFriendlyFormatter().getName(type) + "'", e); - } - } - - mergeDexesFromList(mainDexList, OverflowPolicy.MULTIDEX_MAIN_DEX); - - if (ThreadConfig.get(DexFileWriter.MINIMAL_MAIN_DEX).booleanValue()) { - finishMerge(merger, dexVFile, outputVDir.getLocation()); - dexVFile = getNextOutputDex(); - merger = new JackMerger(createDexFile()); - } - - assert anyDexList != null; - mergeDexesFromList(anyDexList, OverflowPolicy.MULTIDEX_ANY_DEX); - - } else { - - List<InputVFile> dexList = new ArrayList<InputVFile>(); - getAllDexFilesFromDir(dexFileVDir, dexList); - mergeDexesFromList(dexList, OverflowPolicy.SINGLE_DEX); - } - - finishMerge(merger, dexVFile, outputVDir.getLocation()); - } catch (IOException e) { - throw getWriteException(outputVDir.getLocation(), e); - } - } - - private void mergeDexesFromList(List<InputVFile> dexList, OverflowPolicy overflowPolicy) - throws IOException { - for (InputVFile currentDex : dexList) { - try { - merger.addDexFile(new DexBuffer(currentDex.openRead())); - } catch (IOException e) { - throw new JackIOException( - "Could not read Dex file '" + currentDex.getLocation().getDescription() + "'", e); - } catch (MergeOverflow e) { - switch (overflowPolicy) { - case SINGLE_DEX: - throw new JackUserException( - "Index overflow while merging dex files. Try using multidex.", e); - case MULTIDEX_MAIN_DEX: - throw new JackUserException( - "Too many classes in main dex. Index overflow while merging dex files.", e); - case MULTIDEX_ANY_DEX: - finishMerge(merger, dexVFile, outputVDir.getLocation()); - dexVFile = getNextOutputDex(); - merger = new JackMerger(createDexFile()); - break; - default: - throw new AssertionError(); - } - } - } - - } - - private void getAllDexFilesFromDir(@Nonnull InputVDir dexFileVDir, - @Nonnull List<InputVFile> dexFiles) { - for (InputVElement subFile : dexFileVDir.list()) { - if (subFile.isVDir()) { - getAllDexFilesFromDir((InputVDir) subFile, dexFiles); - } else if (subFile.getName().endsWith(DexFileWriter.DEX_FILE_EXTENSION)) { - dexFiles.add((InputOutputVFile) subFile); - } - } - } - - private void finishMerge(@Nonnull JackMerger merger, @Nonnull OutputVFile out, - @Nonnull Location outputLocation) { - OutputStream os; - try { - os = new BufferedOutputStream(out.openWrite()); - } catch (IOException e) { - throw new JackIOException("Failed to read intermediate dex", e); - } - try { - merger.finish(os); - os.close(); - } catch (IOException e) { - try { - os.close(); - } catch (IOException close) { - // let the Exception for the initial error be handled - } - throw getWriteException(outputLocation, e); - } - } - - private JackFileException getWriteException(@Nonnull Location outputLocation, - @Nonnull IOException e) { - return new JackFileException("Could not write Dex file to output '" - + outputLocation.getDescription() + "'", e); - } - - private OutputVFile getNextOutputDex() throws IOException { - assert dexCount >= 1; - if (dexCount == 1) { - dexCount++; - return outputVDir.createOutputVFile(new VPath(DexFileWriter.DEX_FILENAME, '/')); - } else { - return outputVDir.createOutputVFile( - new VPath(DexFileWriter.DEX_PREFIX + dexCount++ + DexFileWriter.DEX_FILE_EXTENSION, '/')); - } - } - - private static enum OverflowPolicy { - SINGLE_DEX, - MULTIDEX_MAIN_DEX, - MULTIDEX_ANY_DEX; - } - -} diff --git a/jack/src/com/android/jack/backend/dex/MinimalMultiDexWritingTool.java b/jack/src/com/android/jack/backend/dex/MinimalMultiDexWritingTool.java new file mode 100644 index 0000000..89b9cf7 --- /dev/null +++ b/jack/src/com/android/jack/backend/dex/MinimalMultiDexWritingTool.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed 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 com.android.jack.backend.dex; + +import com.android.jack.JackUserException; +import com.android.jack.tools.merger.JackMerger; +import com.android.jack.tools.merger.MergeOverflow; +import com.android.sched.util.codec.ImplementationName; +import com.android.sched.vfs.InputVFile; +import com.android.sched.vfs.OutputVDir; +import com.android.sched.vfs.OutputVFile; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Nonnull; + +/** + * A {@link DexWritingTool} that merges dex files, each one corresponding to a type, in several dex + * files, keeping the main dex as small as possible. + */ +@ImplementationName(iface = DexWritingTool.class, name = "minimal-multidex", description = + "allow emitting several dex files, keeping the first dex (main dex) as small as possible") +public class MinimalMultiDexWritingTool extends DexWritingTool { + + @Override + public void write(@Nonnull OutputVDir outputVDir) { + int dexCount = 1; + JackMerger merger = new JackMerger(createDexFile()); + OutputVFile outputDex = getOutputDex(outputVDir, dexCount++); + List<InputVFile> mainDexList = new ArrayList<InputVFile>(); + List<InputVFile> anyDexList = new ArrayList<InputVFile>(); + fillDexLists(mainDexList, anyDexList); + + for (InputVFile currentDex : mainDexList) { + try { + mergeDex(merger, currentDex); + } catch (MergeOverflow e) { + throw new JackUserException( + "Too many classes in main dex. Index overflow while merging dex files", e); + } + } + + finishMerge(merger, outputDex); + outputDex = getOutputDex(outputVDir, dexCount++); + merger = new JackMerger(createDexFile()); + + for (InputVFile currentDex : anyDexList) { + try { + mergeDex(merger, currentDex); + } catch (MergeOverflow e) { + finishMerge(merger, outputDex); + outputDex = getOutputDex(outputVDir, dexCount++); + merger = new JackMerger(createDexFile()); + } + } + + finishMerge(merger, outputDex); + } + +} diff --git a/jack/src/com/android/jack/backend/dex/SingleDexWritingTool.java b/jack/src/com/android/jack/backend/dex/SingleDexWritingTool.java new file mode 100644 index 0000000..0f01d24 --- /dev/null +++ b/jack/src/com/android/jack/backend/dex/SingleDexWritingTool.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed 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 com.android.jack.backend.dex; + +import com.android.jack.JackIOException; +import com.android.jack.JackUserException; +import com.android.jack.tools.merger.JackMerger; +import com.android.jack.tools.merger.MergeOverflow; +import com.android.sched.util.codec.ImplementationName; +import com.android.sched.vfs.InputOutputVFile; +import com.android.sched.vfs.InputVDir; +import com.android.sched.vfs.InputVElement; +import com.android.sched.vfs.InputVFile; +import com.android.sched.vfs.OutputVDir; +import com.android.sched.vfs.OutputVFile; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Nonnull; + +/** + * A {@link DexWritingTool} that merges dex files, each one corresponding to a type, to a single + * dex. + */ +@ImplementationName(iface = DexWritingTool.class, name = "single-dex", + description = "only emit one dex file") +public class SingleDexWritingTool extends DexWritingTool { + + @Override + public void write(@Nonnull OutputVDir outputVDir) throws JackIOException { + JackMerger merger = new JackMerger(createDexFile()); + OutputVFile outputDex = getOutputDex(outputVDir); + List<InputVFile> dexList = new ArrayList<InputVFile>(); + getAllDexFilesFromDir(getTypeDexDir(), dexList); + + for (InputVFile currentDex : dexList) { + try { + mergeDex(merger, currentDex); + } catch (MergeOverflow e) { + throw new JackUserException("Index overflow while merging dex files. Try using multidex", + e); + } + } + finishMerge(merger, outputDex); + } + + private void getAllDexFilesFromDir(@Nonnull InputVDir dexFileVDir, + @Nonnull List<InputVFile> dexFiles) { + for (InputVElement subFile : dexFileVDir.list()) { + if (subFile.isVDir()) { + getAllDexFilesFromDir((InputVDir) subFile, dexFiles); + } else if (subFile.getName().endsWith(DexFileWriter.DEX_FILE_EXTENSION)) { + dexFiles.add((InputOutputVFile) subFile); + } + } + } + + private OutputVFile getOutputDex(@Nonnull OutputVDir outputVDir) { + return getOutputDex(outputVDir, 1); + } +} diff --git a/jack/src/com/android/jack/backend/dex/StandardMultiDexWritingTool.java b/jack/src/com/android/jack/backend/dex/StandardMultiDexWritingTool.java new file mode 100644 index 0000000..86c0295 --- /dev/null +++ b/jack/src/com/android/jack/backend/dex/StandardMultiDexWritingTool.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed 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 com.android.jack.backend.dex; + +import com.android.jack.JackIOException; +import com.android.jack.JackUserException; +import com.android.jack.tools.merger.JackMerger; +import com.android.jack.tools.merger.MergeOverflow; +import com.android.sched.util.codec.ImplementationName; +import com.android.sched.vfs.InputVFile; +import com.android.sched.vfs.OutputVDir; +import com.android.sched.vfs.OutputVFile; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.Nonnull; + +/** + * A {@link DexWritingTool} that merges dex files, each one corresponding to a type, in several dex + * files. + */ +@ImplementationName(iface = DexWritingTool.class, name = "multidex", + description = "allow emitting several dex files") +public class StandardMultiDexWritingTool extends DexWritingTool { + + @Override + public void write(@Nonnull OutputVDir outputVDir) throws JackIOException { + int dexCount = 1; + JackMerger merger = new JackMerger(createDexFile()); + OutputVFile outputDex = getOutputDex(outputVDir, dexCount++); + List<InputVFile> mainDexList = new ArrayList<InputVFile>(); + List<InputVFile> anyDexList = new ArrayList<InputVFile>(); + fillDexLists(mainDexList, anyDexList); + + for (InputVFile currentDex : mainDexList) { + try { + mergeDex(merger, currentDex); + } catch (MergeOverflow e) { + throw new JackUserException( + "Too many classes in main dex. Index overflow while merging dex files", e); + } + } + + for (InputVFile currentDex : anyDexList) { + try { + mergeDex(merger, currentDex); + } catch (MergeOverflow e) { + finishMerge(merger, outputDex); + outputDex = getOutputDex(outputVDir, dexCount++); + merger = new JackMerger(createDexFile()); + } + } + + finishMerge(merger, outputDex); + } +} diff --git a/jack/src/com/android/jack/backend/jayce/JayceFileImporter.java b/jack/src/com/android/jack/backend/jayce/JayceFileImporter.java index f172d9b..a56afcc 100644 --- a/jack/src/com/android/jack/backend/jayce/JayceFileImporter.java +++ b/jack/src/com/android/jack/backend/jayce/JayceFileImporter.java @@ -24,6 +24,7 @@ import com.android.jack.ir.ast.JSession; import com.android.jack.ir.ast.JTypeLookupException; import com.android.jack.ir.ast.Resource; import com.android.jack.lookup.JLookup; +import com.android.sched.util.HasDescription; import com.android.sched.util.codec.EnumCodec; import com.android.sched.util.config.HasKeyId; import com.android.sched.util.config.ThreadConfig; @@ -65,9 +66,22 @@ public class JayceFileImporter { private static final char VPATH_SEPARATOR = JLookup.PACKAGE_SEPARATOR; - private enum CollisionPolicy { - KEEP_FIRST, - FAIL + private enum CollisionPolicy implements HasDescription { + KEEP_FIRST("keep the first element encountered"), + FAIL("fail when a collision occured"); + + @Nonnull + private String description; + + private CollisionPolicy(@Nonnull String description) { + this.description = description; + } + + @Override + @Nonnull + public String getDescription() { + return description; + } } @Nonnull diff --git a/jack/src/com/android/jack/ecj/loader/jast/JAstBinaryType.java b/jack/src/com/android/jack/ecj/loader/jast/JAstBinaryType.java index e8a06ba..d71297d 100644 --- a/jack/src/com/android/jack/ecj/loader/jast/JAstBinaryType.java +++ b/jack/src/com/android/jack/ecj/loader/jast/JAstBinaryType.java @@ -91,8 +91,14 @@ class JAstBinaryType implements IBinaryType { modifiers &= ~JModifier.ANONYMOUS_TYPE; JClassOrInterface enclosingType = jDeclaredType.getEnclosingType(); - if (enclosingType != null && !isAnonymous()) { - JAstBinaryType enclosing = classpathLocation.findType(enclosingType); + if (enclosingType != null && !isAnonymous() + && enclosingType instanceof JDefinedClassOrInterface) { + /* If the enclosing is not in the classpath, just skip. This should be with no bad consequence + * since ECJ is refusing to compile a source referencing an inner class when its enclosing + * class is missing. + */ + JAstBinaryType enclosing = + classpathLocation.findType((JDefinedClassOrInterface) enclosingType); if (enclosing != null) { if (LoaderUtils.isDeprecated(enclosing)) { modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly; @@ -227,14 +233,18 @@ class JAstBinaryType implements IBinaryType { for (JClassOrInterface jNested : members) { - /* According to a note in a comment on the interface, we have to filter out local types - * found in the member types list. Tests have shown that, in this note, "local" means also - * anonymous. - */ - JAstBinaryType nested = classpathLocation.findType(jNested); - assert nested != null; - if (!(nested.isAnonymous() || nested.isLocal())) { - nestedTypes.add(new JAstBinaryNestedType(nested.jDeclaredType)); + /* If the inner is not in the classpath, just skip it. This should not have consequence in + * Jack context, since we are unable to present the missing class to ECJ anyway. */ + if (jNested instanceof JDefinedClassOrInterface) { + /* According to a note in a comment on the interface, we have to filter out local types + * found in the member types list. Tests have shown that, in this note, "local" means also + * anonymous. + */ + JAstBinaryType nested = classpathLocation.findType((JDefinedClassOrInterface) jNested); + assert nested != null; + if (!(nested.isAnonymous() || nested.isLocal())) { + nestedTypes.add(new JAstBinaryNestedType(nested.jDeclaredType)); + } } } if (!nestedTypes.isEmpty()) { diff --git a/jack/src/com/android/jack/ecj/loader/jast/JAstClasspath.java b/jack/src/com/android/jack/ecj/loader/jast/JAstClasspath.java index b4290c5..60ee5aa 100644 --- a/jack/src/com/android/jack/ecj/loader/jast/JAstClasspath.java +++ b/jack/src/com/android/jack/ecj/loader/jast/JAstClasspath.java @@ -166,8 +166,8 @@ public class JAstClasspath extends ClasspathLocation { } @CheckForNull - JAstBinaryType findType(@Nonnull JType type) { - return new JAstBinaryType((JDefinedClassOrInterface) type, this); + JAstBinaryType findType(@Nonnull JDefinedClassOrInterface type) { + return new JAstBinaryType(type, this); } /** diff --git a/jack/src/com/android/jack/statistics/JNodeWatcher.java b/jack/src/com/android/jack/statistics/JNodeWatcher.java index ec85b0b..4d9c54e 100644 --- a/jack/src/com/android/jack/statistics/JNodeWatcher.java +++ b/jack/src/com/android/jack/statistics/JNodeWatcher.java @@ -84,7 +84,8 @@ public class JNodeWatcher implements ObjectWatcher<JNode> { /** * Install a {@link JNodeWatcher} */ - @ImplementationName(iface = WatcherInstaller.class, name = "jnode-alloc") + @ImplementationName(iface = WatcherInstaller.class, name = "jnode-alloc", + description = "record all JNode allocations") public static class JNodeWatcherInstaller implements WatcherInstaller { @Override public void install(@Nonnull Tracer tracer) { diff --git a/jack/src/com/android/jack/transformations/ast/TypeLegalizer.java b/jack/src/com/android/jack/transformations/ast/TypeLegalizer.java index bbd6190..7e2f69b 100644 --- a/jack/src/com/android/jack/transformations/ast/TypeLegalizer.java +++ b/jack/src/com/android/jack/transformations/ast/TypeLegalizer.java @@ -22,6 +22,7 @@ import com.android.jack.ir.SideEffectOperation; import com.android.jack.ir.ast.JAbsentArrayDimension; import com.android.jack.ir.ast.JArrayRef; import com.android.jack.ir.ast.JBinaryOperation; +import com.android.jack.ir.ast.JClass; import com.android.jack.ir.ast.JClassOrInterface; import com.android.jack.ir.ast.JConditionalExpression; import com.android.jack.ir.ast.JDoStatement; @@ -78,9 +79,13 @@ import javax.annotation.Nonnull; public class TypeLegalizer implements RunnableSchedulable<JMethod> { @Nonnull + private final JClass javaLangObject = + Jack.getSession().getPhantomLookup().getClass(CommonTypes.JAVA_LANG_OBJECT); + + @Nonnull private final Filter<JMethod> filter = ThreadConfig.get(Options.METHOD_FILTER); - static class TypeLegalizerVisitor extends JVisitor { + class TypeLegalizerVisitor extends JVisitor { @Nonnull private final TransformationRequest tr; @@ -146,7 +151,18 @@ public class TypeLegalizer implements RunnableSchedulable<JMethod> { @Override public void endVisit(@Nonnull JDynamicCastOperation cast) { - maybeBoxOrUnbox(cast.getExpr(), cast.getCastType()); + JExpression expr = cast.getExpr(); + if (cast.getExpr().getType().isSameType(javaLangObject) + && cast.getCastType() instanceof JPrimitiveType) { + assert cast.getCastType() != JPrimitiveTypeEnum.VOID.getType(); + + JDynamicCastOperation castToWrapperType = new JDynamicCastOperation(expr.getSourceInfo(), + ((JPrimitiveType) cast.getCastType()).getWrapperType(), + expr); + tr.append(new Replace(expr, castToWrapperType)); + expr = castToWrapperType; + } + maybeBoxOrUnbox(expr, cast.getCastType()); super.endVisit(cast); } diff --git a/jack/src/com/android/jack/transformations/parent/ParentSetterChecker.java b/jack/src/com/android/jack/transformations/parent/ParentChecker.java index 53bd662..984bc2d 100644 --- a/jack/src/com/android/jack/transformations/parent/ParentSetterChecker.java +++ b/jack/src/com/android/jack/transformations/parent/ParentChecker.java @@ -21,7 +21,6 @@ import com.android.jack.ir.ast.JSession; import com.android.jack.ir.ast.JVisitor; import com.android.jack.transformations.SanityChecks; import com.android.sched.item.Description; -import com.android.sched.item.Name; import com.android.sched.schedulable.RunnableSchedulable; import com.android.sched.schedulable.Support; @@ -30,18 +29,17 @@ import java.util.Stack; import javax.annotation.Nonnull; /** - * Check that parent of {@link JNode} are correctly set. + * Check that parents of {@link JNode}s are correctly set. */ -@Description("Check that parent of JNode are correctly set.") -@Name("ParentSetterChecker") +@Description("Check that parents of JNodes are correctly set.") @Support(SanityChecks.class) -public class ParentSetterChecker implements RunnableSchedulable<JSession> { +public class ParentChecker implements RunnableSchedulable<JSession> { - private static class ParentSetterCheckerVisitor extends JVisitor { + private static class ParentCheckerVisitor extends JVisitor { @Nonnull private final Stack<JNode> nodes = new Stack<JNode>(); - private ParentSetterCheckerVisitor() { + private ParentCheckerVisitor() { super(false /* needLoading */); } @@ -72,7 +70,7 @@ public class ParentSetterChecker implements RunnableSchedulable<JSession> { @Override public void run(@Nonnull JSession session) throws Exception { - ParentSetterCheckerVisitor checker = new ParentSetterCheckerVisitor(); + ParentCheckerVisitor checker = new ParentCheckerVisitor(); checker.accept(session); } }
\ No newline at end of file diff --git a/jack/src/com/android/jack/transformations/parent/TypeParentChecker.java b/jack/src/com/android/jack/transformations/parent/TypeParentChecker.java new file mode 100644 index 0000000..98470d9 --- /dev/null +++ b/jack/src/com/android/jack/transformations/parent/TypeParentChecker.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed 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 com.android.jack.transformations.parent; + +import com.android.jack.ir.ast.JDefinedClassOrInterface; +import com.android.jack.ir.ast.JNode; +import com.android.jack.ir.ast.JSession; +import com.android.jack.ir.ast.JVisitor; +import com.android.jack.transformations.SanityChecks; +import com.android.sched.item.Description; +import com.android.sched.schedulable.RunnableSchedulable; +import com.android.sched.schedulable.Support; + +import java.util.Stack; + +import javax.annotation.Nonnull; + +/** + * Check that parents of {@link JNode}s are correctly set, running on + * {@link JDefinedClassOrInterface}s. + */ +@Description( + "Check that parents of JNodes are correctly set, running on JDefinedClassOrInterfaces.") +@Support(SanityChecks.class) +public class TypeParentChecker implements RunnableSchedulable<JDefinedClassOrInterface> { + + private static class Visitor extends JVisitor { + @Nonnull + private final Stack<JNode> nodes = new Stack<JNode>(); + + private Visitor() { + super(false /* needLoading */); + } + + @Override + public boolean visit(@Nonnull JNode node) { + assert !(node instanceof JSession); + if (node instanceof JDefinedClassOrInterface) { + if (node.getParent() == null) { + throw new AssertionError( + "Parent of " + JDefinedClassOrInterface.class.getName() + " must not be null."); + } + } else { + if (node.getParent() != nodes.peek()) { + throw new AssertionError("Node with wrong parent."); + } + } + + nodes.push(node); + + return super.visit(node); + } + + @Override + public void endVisit(@Nonnull JNode node) { + nodes.pop(); + + super.endVisit(node); + } + } + + @Override + public void run(@Nonnull JDefinedClassOrInterface type) throws Exception { + Visitor checker = new Visitor(); + checker.accept(type); + } +}
\ No newline at end of file diff --git a/jack/src/com/android/jack/util/PackageCodec.java b/jack/src/com/android/jack/util/PackageCodec.java index 5532cee..2be9f3c 100644 --- a/jack/src/com/android/jack/util/PackageCodec.java +++ b/jack/src/com/android/jack/util/PackageCodec.java @@ -21,6 +21,9 @@ import com.android.sched.util.codec.CodecContext; import com.android.sched.util.codec.ParsingException; import com.android.sched.util.codec.StringCodec; +import java.util.Collections; +import java.util.List; + import javax.annotation.CheckForNull; import javax.annotation.Nonnull; @@ -38,6 +41,12 @@ public class PackageCodec implements StringCodec<String>{ @Override @Nonnull + public List<ValueDescription> getValueDescriptions() { + return Collections.<ValueDescription> emptyList(); + } + + @Override + @Nonnull public String parseString(@Nonnull CodecContext context, @Nonnull String string) { return string; } diff --git a/jack/src/com/android/jack/util/filter/SignatureCodec.java b/jack/src/com/android/jack/util/filter/SignatureCodec.java index 69776bc..dde1236 100644 --- a/jack/src/com/android/jack/util/filter/SignatureCodec.java +++ b/jack/src/com/android/jack/util/filter/SignatureCodec.java @@ -19,6 +19,9 @@ package com.android.jack.util.filter; import com.android.sched.util.codec.CodecContext; import com.android.sched.util.codec.StringCodec; +import java.util.Collections; +import java.util.List; + import javax.annotation.CheckForNull; import javax.annotation.Nonnull; @@ -36,6 +39,11 @@ public class SignatureCodec implements StringCodec<String>{ @Override @Nonnull + public List<ValueDescription> getValueDescriptions() { + return Collections.<ValueDescription> emptyList(); + } + @Override + @Nonnull public String parseString(@Nonnull CodecContext context, @Nonnull String string) { return string; } diff --git a/jack/tests/com/android/jack/ClasspathTest.java b/jack/tests/com/android/jack/ClasspathTest.java index e655f8d..dc521c9 100644 --- a/jack/tests/com/android/jack/ClasspathTest.java +++ b/jack/tests/com/android/jack/ClasspathTest.java @@ -16,6 +16,8 @@ package com.android.jack; +import junit.framework.Assert; + import org.junit.BeforeClass; import org.junit.Test; @@ -91,6 +93,41 @@ public class ClasspathTest { } @Test + public void test003() throws Exception { + File libOut = TestTools.createTempDir("ClasspathTest", "lib"); + + Options libOptions = TestTools.buildCommandLineArgs( + TestTools.getJackTestLibFolder("classpath/test003")); + libOptions.setJayceOutputDir(libOut); + TestTools.runCompilation(libOptions); + + { + // reference compilation + File testOut = TestTools.createTempDir("ClasspathTest", "test"); + Options testOptions = TestTools.buildCommandLineArgs( + TestTools.getJackTestsWithJackFolder("classpath/test003")); + testOptions.setJayceOutputDir(testOut); + testOptions.setClasspath(libOut.getAbsolutePath()); + TestTools.runCompilation(testOptions); + } + + { + // delete unused inner in classpath and check we can still compile with it + boolean deleted = + new File(libOut, + "com/android/jack/classpath/test003/lib/HasInnersClasses$InnerToDelete.jack") + .delete(); + Assert.assertTrue(deleted); + File testOut = TestTools.createTempDir("ClasspathTest", "test"); + Options testOptions = TestTools.buildCommandLineArgs( + TestTools.getJackTestsWithJackFolder("classpath/test003")); + testOptions.setJayceOutputDir(testOut); + testOptions.setClasspath(libOut.getAbsolutePath()); + TestTools.runCompilation(testOptions); + } + } + + @Test public void libOfLib() throws Exception { String defaultClasspath = TestTools.getDefaultBootclasspathString(); diff --git a/jack/tests/com/android/jack/multidex/MultiDexTests.java b/jack/tests/com/android/jack/multidex/MultiDexTests.java index da69bb3..0202116 100644 --- a/jack/tests/com/android/jack/multidex/MultiDexTests.java +++ b/jack/tests/com/android/jack/multidex/MultiDexTests.java @@ -55,7 +55,9 @@ public class MultiDexTests { File testFolder = TestTools.getJackTestsWithJackFolder("multidex/test001"); File out = TestTools.createTempDir("out", ""); - Options app1Options = createMultiDexEnabledOption(new File(testFolder, "config-001.jpp")); + Options app1Options = createCommonOptionsForMultiDex(new File(testFolder, "config-001.jpp")); + + app1Options.addProperty(DexFileWriter.DEX_WRITING_POLICY.getName(), "multidex"); TestTools.compileSourceToDex(app1Options, testFolder, TestTools.getDefaultBootclasspathString() + File.pathSeparator + annotations.getPath() + File.pathSeparator + frameworks.getPath(), @@ -72,9 +74,9 @@ public class MultiDexTests { File testFolder = TestTools.getJackTestsWithJackFolder("multidex/test001"); File out = TestTools.createTempDir("out", ""); - Options app1Options = createMultiDexEnabledOption(new File(testFolder, "config-001.jpp")); + Options app1Options = createCommonOptionsForMultiDex(new File(testFolder, "config-001.jpp")); - app1Options.addProperty(DexFileWriter.MINIMAL_MAIN_DEX.getName(), "true"); + app1Options.addProperty(DexFileWriter.DEX_WRITING_POLICY.getName(), "minimal-multidex"); TestTools.compileSourceToDex(app1Options, testFolder, TestTools.getDefaultBootclasspathString() + File.pathSeparator + annotations.getPath() + File.pathSeparator + frameworks.getPath(), @@ -93,9 +95,9 @@ public class MultiDexTests { File testFolder = TestTools.getJackTestsWithJackFolder("multidex/test001"); File out = TestTools.createTempDir("out", ""); - Options app1Options = createMultiDexEnabledOption(new File(testFolder, "config-003.jpp")); + Options app1Options = createCommonOptionsForMultiDex(new File(testFolder, "config-003.jpp")); - app1Options.addProperty(DexFileWriter.MINIMAL_MAIN_DEX.getName(), "true"); + app1Options.addProperty(DexFileWriter.DEX_WRITING_POLICY.getName(), "minimal-multidex"); TestTools.compileSourceToDex(app1Options, testFolder, TestTools.getDefaultBootclasspathString() + File.pathSeparator + annotations.getPath() + File.pathSeparator + frameworks.getPath(), @@ -109,11 +111,10 @@ public class MultiDexTests { return; } - private Options createMultiDexEnabledOption(@Nonnull File configFile) throws IOException { + private Options createCommonOptionsForMultiDex(@Nonnull File configFile) throws IOException { File tmpOut = TestTools.createTempDir("tmp", ""); Options app1Options = new Options(); app1Options.addProperty(Options.TYPEDEX_DIR.getName(), tmpOut.getPath()); - app1Options.addProperty(DexFileWriter.MULTIDEX.getName(), "true"); app1Options.addProperty(MultiDexLegacy.MULTIDEX_LEGACY.getName(), "true"); app1Options.addProperty(PreProcessor.ENABLE.getName(), "true"); app1Options.addProperty(PreProcessor.FILE.getName(), configFile.getAbsolutePath()); @@ -168,8 +169,9 @@ public class MultiDexTests { File testFolder = TestTools.getJackTestsWithJackFolder("multidex/test002"); File out = TestTools.createTempDir("out", ""); - Options app1Options = createMultiDexEnabledOption( + Options app1Options = createCommonOptionsForMultiDex( new File(testFolder,"config-001.jpp")); + app1Options.addProperty(DexFileWriter.DEX_WRITING_POLICY.getName(), "multidex"); TestTools.compileSourceToDex(app1Options, testFolder, TestTools.getDefaultBootclasspathString() + File.pathSeparator + annotations.getPath() + File.pathSeparator + frameworks.getPath() @@ -186,9 +188,9 @@ public class MultiDexTests { File testFolder = TestTools.getJackTestsWithJackFolder("multidex/test002"); File out = TestTools.createTempDir("out", ""); - Options app1Options = createMultiDexEnabledOption( + Options app1Options = createCommonOptionsForMultiDex( new File(testFolder,"config-001.jpp")); - app1Options.addProperty(DexFileWriter.MINIMAL_MAIN_DEX.getName(), "true"); + app1Options.addProperty(DexFileWriter.DEX_WRITING_POLICY.getName(), "minimal-multidex"); app1Options.addJayceImport(library); TestTools.compileSourceToDex(app1Options, testFolder, TestTools.getDefaultBootclasspathString() diff --git a/jack/tests/com/android/jack/shrob/ShrinkMultiDexTest.java b/jack/tests/com/android/jack/shrob/ShrinkMultiDexTest.java index 8d97f1f..4b2fc57 100644 --- a/jack/tests/com/android/jack/shrob/ShrinkMultiDexTest.java +++ b/jack/tests/com/android/jack/shrob/ShrinkMultiDexTest.java @@ -60,11 +60,11 @@ public class ShrinkMultiDexTest extends AbstractTest { new ProguardFlags(testFolder, "proguard.flags" + flagNumber)}; File refFolder = new File(testFolder, "refsShrinking"); Options options = new Options(); - options.addProperty(DexFileWriter.MULTIDEX.getName(), "true"); + options.addProperty(DexFileWriter.DEX_WRITING_POLICY.getName(), "multidex"); options.addProperty(MultiDexLegacy.MULTIDEX_LEGACY.getName(), "true"); options.addProperty(PreProcessor.ENABLE.getName(), "true"); - options.addProperty(PreProcessor.FILE.getName(), - new File(TestTools.getJackTestFolder("shrob"),"legacyMainDexClasses.jpp").getAbsolutePath()); + options.addProperty(PreProcessor.FILE.getName(), new File(TestTools.getJackTestFolder("shrob"), + "legacyMainDexClasses.jpp").getAbsolutePath()); TestTools.checkListingWhenMultiDex(options, bootclasspath, classpath, diff --git a/jack/tests/com/android/jack/statistics/BlockStatisticsOnCore.java b/jack/tests/com/android/jack/statistics/BlockStatisticsOnCore.java index 17acfa9..3ba6e52 100644 --- a/jack/tests/com/android/jack/statistics/BlockStatisticsOnCore.java +++ b/jack/tests/com/android/jack/statistics/BlockStatisticsOnCore.java @@ -24,7 +24,7 @@ import com.android.jack.ir.ast.JMethod; import com.android.jack.ir.ast.JSession; import com.android.jack.scheduling.adapter.JDefinedClassOrInterfaceAdapter; import com.android.jack.scheduling.adapter.JMethodAdapter; -import com.android.jack.transformations.parent.ParentSetterChecker; +import com.android.jack.transformations.parent.ParentChecker; import com.android.sched.scheduler.PlanBuilder; import com.android.sched.scheduler.Request; import com.android.sched.scheduler.SchedulableManager; @@ -89,7 +89,7 @@ public class BlockStatisticsOnCore { sr.addInitialTagOrMarker(JavaSourceIr.class); PlanBuilder<JSession> planBuilder = sr.getPlanBuilder(JSession.class); - planBuilder.append(ParentSetterChecker.class); + planBuilder.append(ParentChecker.class); SubPlanBuilder<JDefinedClassOrInterface> typePlan = planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class); SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class); methodPlan.append(BlockStatistics.class); diff --git a/jack/tests/com/android/jack/transformations/ast/ImplicitBlockTest.java b/jack/tests/com/android/jack/transformations/ast/ImplicitBlockTest.java index 74381e5..edfd77c 100644 --- a/jack/tests/com/android/jack/transformations/ast/ImplicitBlockTest.java +++ b/jack/tests/com/android/jack/transformations/ast/ImplicitBlockTest.java @@ -25,7 +25,7 @@ import com.android.jack.ir.ast.JMethod; import com.android.jack.ir.ast.JSession; import com.android.jack.scheduling.adapter.JDefinedClassOrInterfaceAdapter; import com.android.jack.scheduling.adapter.JMethodAdapter; -import com.android.jack.transformations.parent.ParentSetterChecker; +import com.android.jack.transformations.parent.ParentChecker; import com.android.jack.util.filter.SignatureMethodFilter; import com.android.sched.scheduler.PlanBuilder; import com.android.sched.scheduler.Request; @@ -120,7 +120,7 @@ public class ImplicitBlockTest { sr.addInitialTagOrMarker(JavaSourceIr.class); PlanBuilder<JSession> planBuilder = sr.getPlanBuilder(JSession.class); - planBuilder.append(ParentSetterChecker.class); + planBuilder.append(ParentChecker.class); SubPlanBuilder<JDefinedClassOrInterface> typePlan = planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class); SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class); methodPlan.append(ImplicitBlocks.class); diff --git a/jack/tests/com/android/jack/transformations/ast/SynchronizedTest.java b/jack/tests/com/android/jack/transformations/ast/SynchronizedTest.java index 551910b..47bb69f 100644 --- a/jack/tests/com/android/jack/transformations/ast/SynchronizedTest.java +++ b/jack/tests/com/android/jack/transformations/ast/SynchronizedTest.java @@ -32,7 +32,7 @@ import com.android.jack.ir.ast.JUnlock; import com.android.jack.ir.ast.JVariableRef; import com.android.jack.scheduling.adapter.JDefinedClassOrInterfaceAdapter; import com.android.jack.scheduling.adapter.JMethodAdapter; -import com.android.jack.transformations.parent.ParentSetterChecker; +import com.android.jack.transformations.parent.ParentChecker; import com.android.jack.util.filter.SignatureMethodFilter; import com.android.sched.scheduler.PlanBuilder; import com.android.sched.scheduler.Request; @@ -154,7 +154,7 @@ public class SynchronizedTest { sr.addInitialTagsOrMarkers(Jack.getJavaSourceInitialTagSet()); PlanBuilder<JSession> planBuilder = sr.getPlanBuilder(JSession.class); - planBuilder.append(ParentSetterChecker.class); + planBuilder.append(ParentChecker.class); SubPlanBuilder<JDefinedClassOrInterface> typePlan = planBuilder.appendSubPlan(JDefinedClassOrInterfaceAdapter.class); SubPlanBuilder<JMethod> methodPlan = typePlan.appendSubPlan(JMethodAdapter.class); diff --git a/jack/tests/com/android/jack/transformations/ast/TypeLegalizerTest.java b/jack/tests/com/android/jack/transformations/ast/TypeLegalizerTest.java index c0c5750..0207a4e 100644 --- a/jack/tests/com/android/jack/transformations/ast/TypeLegalizerTest.java +++ b/jack/tests/com/android/jack/transformations/ast/TypeLegalizerTest.java @@ -58,7 +58,7 @@ public class TypeLegalizerTest { parentSetter.accept(methodBody); TransformationRequest tr = new TransformationRequest(methodBody); - TypeLegalizer.TypeLegalizerVisitor visitor = new TypeLegalizer.TypeLegalizerVisitor(tr); + TypeLegalizer.TypeLegalizerVisitor visitor = new TypeLegalizer().new TypeLegalizerVisitor(tr); visitor.accept(methodBody); tr.commit(); diff --git a/sched/src/com/android/sched/item/ManagedItem.java b/sched/src/com/android/sched/item/ManagedItem.java index 3e69e75..dd42e28 100644 --- a/sched/src/com/android/sched/item/ManagedItem.java +++ b/sched/src/com/android/sched/item/ManagedItem.java @@ -16,13 +16,15 @@ package com.android.sched.item; +import com.android.sched.util.HasDescription; + import javax.annotation.CheckForNull; import javax.annotation.Nonnull; /** * Represents an {@link Item} composed of other items. */ -public class ManagedItem { +public class ManagedItem implements HasDescription { // Bitmap, representing this item in conjunction with @ComposedOf, inheritance or inner @CheckForNull protected long[] bitmap; @@ -62,6 +64,7 @@ public class ManagedItem { return name; } + @Override @Nonnull public String getDescription() { return description; diff --git a/sched/src/com/android/sched/marker/ManagedMarker.java b/sched/src/com/android/sched/marker/ManagedMarker.java index 3496f49..7b75f11 100644 --- a/sched/src/com/android/sched/marker/ManagedMarker.java +++ b/sched/src/com/android/sched/marker/ManagedMarker.java @@ -18,6 +18,7 @@ package com.android.sched.marker; import com.android.sched.item.Description; import com.android.sched.item.Items; +import com.android.sched.util.HasDescription; import com.android.sched.util.findbugs.SuppressFBWarnings; import com.android.sched.util.log.LoggerFactory; @@ -33,7 +34,7 @@ import javax.annotation.Nonnull; /** * Represents a {@link Marker} with all annotations extracted. */ -public class ManagedMarker { +public class ManagedMarker implements HasDescription { private static final Logger logger = LoggerFactory.getLogger(); // @Name @@ -108,6 +109,7 @@ public class ManagedMarker { return name; } + @Override @Nonnull public String getDescription() { return description; diff --git a/sched/src/com/android/sched/scheduler/ManagedSchedulable.java b/sched/src/com/android/sched/scheduler/ManagedSchedulable.java index fd0390d..24dae82 100644 --- a/sched/src/com/android/sched/scheduler/ManagedSchedulable.java +++ b/sched/src/com/android/sched/scheduler/ManagedSchedulable.java @@ -21,13 +21,14 @@ import com.android.sched.item.Description; import com.android.sched.item.Items; import com.android.sched.item.Synchronized; import com.android.sched.schedulable.Schedulable; +import com.android.sched.util.HasDescription; import javax.annotation.Nonnull; /** * Represents a {@link Schedulable} with all annotations and signatures extracted. */ -public abstract class ManagedSchedulable { +public abstract class ManagedSchedulable implements HasDescription { @Nonnull private final Class<? extends Schedulable> schedulable; @@ -92,6 +93,7 @@ public abstract class ManagedSchedulable { @Nonnull public abstract Class<? extends Component> getRunOn(); + @Override @Nonnull public String getDescription() { return description; diff --git a/sched/src/com/android/sched/scheduler/Plan.java b/sched/src/com/android/sched/scheduler/Plan.java index 6c6e945..8299f65 100644 --- a/sched/src/com/android/sched/scheduler/Plan.java +++ b/sched/src/com/android/sched/scheduler/Plan.java @@ -38,7 +38,7 @@ import javax.annotation.Nonnull; * * @param <T> the type of the root <i>data</i> */ -public class Plan<T extends Component> implements Iterable<PlanStep> { +public class Plan<T extends Component> implements Iterable<PlanStep> { @Nonnull private final Logger logger = LoggerFactory.getLogger(); diff --git a/sched/src/com/android/sched/util/HasDescription.java b/sched/src/com/android/sched/util/HasDescription.java new file mode 100644 index 0000000..095a703 --- /dev/null +++ b/sched/src/com/android/sched/util/HasDescription.java @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed 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 com.android.sched.util; + +import javax.annotation.Nonnull; + +/** + * Interface implemented by descriptive classes. + */ +public interface HasDescription { + @Nonnull + String getDescription(); +}
\ No newline at end of file diff --git a/sched/src/com/android/sched/util/codec/DoubleCodec.java b/sched/src/com/android/sched/util/codec/DoubleCodec.java index a2be42f..6fc2277 100644 --- a/sched/src/com/android/sched/util/codec/DoubleCodec.java +++ b/sched/src/com/android/sched/util/codec/DoubleCodec.java @@ -18,6 +18,9 @@ package com.android.sched.util.codec; import com.android.sched.util.config.ConfigurationError; +import java.util.Collections; +import java.util.List; + import javax.annotation.Nonnull; /** @@ -48,6 +51,12 @@ public class DoubleCodec implements StringCodec<Double> { @Override @Nonnull + public List<ValueDescription> getValueDescriptions() { + return Collections.<ValueDescription> emptyList(); + } + + @Override + @Nonnull public Double checkString(@Nonnull CodecContext context, @Nonnull String string) throws ParsingException { try { diff --git a/sched/src/com/android/sched/util/codec/EnumCodec.java b/sched/src/com/android/sched/util/codec/EnumCodec.java index 5c74e28..b31b245 100644 --- a/sched/src/com/android/sched/util/codec/EnumCodec.java +++ b/sched/src/com/android/sched/util/codec/EnumCodec.java @@ -16,8 +16,11 @@ package com.android.sched.util.codec; +import com.android.sched.util.HasDescription; import com.android.sched.util.codec.KeyValueCodec.Entry; +import java.util.List; + import javax.annotation.CheckForNull; import javax.annotation.Nonnull; @@ -31,12 +34,23 @@ public class EnumCodec<T extends Enum<T>> implements StringCodec<T> { KeyValueCodec<T> parser; public EnumCodec(@Nonnull T[] values) { + assert values.length > 0; + @SuppressWarnings("unchecked") Entry<T>[] entries = new Entry[values.length]; int idx = 0; - for (T value : values) { - entries[idx++] = new Entry<T>(value.name().replace('_', '-'), value); + if (values instanceof HasDescription[]) { + for (T value : values) { + entries[idx++] = + new Entry<T>(value.name().replace('_', '-'), value, + ((HasDescription) value).getDescription()); + } + } else { + for (T value : values) { + + entries[idx++] = new Entry<T>(value.name().replace('_', '-'), value); + } } parser = new KeyValueCodec<T>(entries); @@ -83,6 +97,12 @@ public class EnumCodec<T extends Enum<T>> implements StringCodec<T> { @Override @Nonnull + public List<ValueDescription> getValueDescriptions() { + return parser.getValueDescriptions(); + } + + @Override + @Nonnull public String formatValue(@Nonnull T value) { return parser.formatValue(value); } diff --git a/sched/src/com/android/sched/util/codec/FileOrDirCodec.java b/sched/src/com/android/sched/util/codec/FileOrDirCodec.java index 67e07a2..fa5d77a 100644 --- a/sched/src/com/android/sched/util/codec/FileOrDirCodec.java +++ b/sched/src/com/android/sched/util/codec/FileOrDirCodec.java @@ -16,9 +16,13 @@ package com.android.sched.util.codec; +import com.android.sched.util.codec.Parser.ValueDescription; import com.android.sched.util.file.FileOrDirectory.ChangePermission; import com.android.sched.util.file.FileOrDirectory.Existence; +import java.util.Collections; +import java.util.List; + import javax.annotation.Nonnull; /** @@ -81,4 +85,9 @@ public abstract class FileOrDirCodec { return sb.toString(); } } + + @Nonnull + public List<ValueDescription> getValueDescriptions() { + return Collections.<ValueDescription> emptyList(); + } } diff --git a/sched/src/com/android/sched/util/codec/ImplementationName.java b/sched/src/com/android/sched/util/codec/ImplementationName.java index 01a53fc..d072ca6 100644 --- a/sched/src/com/android/sched/util/codec/ImplementationName.java +++ b/sched/src/com/android/sched/util/codec/ImplementationName.java @@ -29,5 +29,6 @@ import java.lang.annotation.Target; public @interface ImplementationName { Class<?> iface(); String name(); + String description() default ""; Class<? extends ImplementationFilter> filter() default ImplementationAlwaysValid.class; } diff --git a/sched/src/com/android/sched/util/codec/KeyValueCodec.java b/sched/src/com/android/sched/util/codec/KeyValueCodec.java index 4f16b47..c8923fb 100644 --- a/sched/src/com/android/sched/util/codec/KeyValueCodec.java +++ b/sched/src/com/android/sched/util/codec/KeyValueCodec.java @@ -18,11 +18,14 @@ package com.android.sched.util.codec; import com.android.sched.util.config.ConfigurationError; +import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.HashSet; +import java.util.List; import java.util.Set; +import javax.annotation.CheckForNull; import javax.annotation.Nonnull; /** @@ -34,6 +37,8 @@ public class KeyValueCodec<T> implements StringCodec<T> { private boolean ignoreCase = false; @Nonnull private final Entry<T>[] entries; + @CheckForNull + private List<ValueDescription> descriptions; public KeyValueCodec(@Nonnull Entry<T>[] entries) { this.entries = Arrays.copyOf(entries, entries.length); @@ -86,6 +91,23 @@ public class KeyValueCodec<T> implements StringCodec<T> { @Override @Nonnull + public List<ValueDescription> getValueDescriptions() { + if (descriptions == null) { + descriptions = new ArrayList<ValueDescription>(entries.length); + + for (Entry<T> entry : entries) { + if (entry.description != null) { + descriptions.add(new ValueDescription(entry.key, entry.description)); + } + } + } + + assert descriptions != null; + return descriptions; + } + + @Override + @Nonnull public T checkString(@Nonnull CodecContext context, @Nonnull String string) throws ParsingException { if (ignoreCase) { @@ -153,11 +175,22 @@ public class KeyValueCodec<T> implements StringCodec<T> { String key; @Nonnull T value; + @CheckForNull + String description; public Entry (@Nonnull String key, @Nonnull T value) { this.key = key; this.value = value; } + + public Entry (@Nonnull String key, @Nonnull T value, @CheckForNull String description) { + this.key = key; + this.value = value; + + if (description != null && !description.isEmpty()) { + this.description = description; + } + } } @Override diff --git a/sched/src/com/android/sched/util/codec/KeywordsCodec.java b/sched/src/com/android/sched/util/codec/KeywordsCodec.java index d75d3c4..d990975 100644 --- a/sched/src/com/android/sched/util/codec/KeywordsCodec.java +++ b/sched/src/com/android/sched/util/codec/KeywordsCodec.java @@ -18,6 +18,8 @@ package com.android.sched.util.codec; import com.android.sched.util.codec.KeyValueCodec.Entry; +import java.util.List; + import javax.annotation.CheckForNull; import javax.annotation.Nonnull; @@ -29,12 +31,17 @@ public class KeywordsCodec implements StringCodec<String> { KeyValueCodec<String> parser; public KeywordsCodec(@Nonnull String[] keywords) { + this(keywords, new String[keywords.length]); + } + + public KeywordsCodec(@Nonnull String[] keywords, @Nonnull String[] descriptions) { @SuppressWarnings("unchecked") Entry<String>[] entries = new Entry[keywords.length]; int idx = 0; for (String keyword : keywords) { - entries[idx++] = new Entry<String>(keyword, keyword); + entries[idx] = new Entry<String>(keyword, keyword, descriptions[idx]); + idx++; } parser = new KeyValueCodec<String>(entries); @@ -81,6 +88,12 @@ public class KeywordsCodec implements StringCodec<String> { @Override @Nonnull + public List<ValueDescription> getValueDescriptions() { + return parser.getValueDescriptions(); + } + + @Override + @Nonnull public String formatValue(@Nonnull String value) { return parser.formatValue(value); } diff --git a/sched/src/com/android/sched/util/codec/ListCodec.java b/sched/src/com/android/sched/util/codec/ListCodec.java index 01d106e..25f5c75 100644 --- a/sched/src/com/android/sched/util/codec/ListCodec.java +++ b/sched/src/com/android/sched/util/codec/ListCodec.java @@ -237,6 +237,12 @@ public class ListCodec<T> implements StringCodec<List<T>> { @Override @Nonnull + public List<ValueDescription> getValueDescriptions() { + return parser.getValueDescriptions(); + } + + @Override + @Nonnull public String formatValue(@Nonnull List<T> list) { StringBuilder sb = new StringBuilder(); diff --git a/sched/src/com/android/sched/util/codec/LongCodec.java b/sched/src/com/android/sched/util/codec/LongCodec.java index cf9b8da..8bdd98c 100644 --- a/sched/src/com/android/sched/util/codec/LongCodec.java +++ b/sched/src/com/android/sched/util/codec/LongCodec.java @@ -18,6 +18,9 @@ package com.android.sched.util.codec; import com.android.sched.util.config.ConfigurationError; +import java.util.Collections; +import java.util.List; + import javax.annotation.Nonnull; /** @@ -52,6 +55,12 @@ public class LongCodec implements StringCodec<Long>{ @Override @Nonnull + public List<ValueDescription> getValueDescriptions() { + return Collections.<ValueDescription> emptyList(); + } + + @Override + @Nonnull public Long checkString(@Nonnull CodecContext context, @Nonnull String string) throws ParsingException { try { diff --git a/sched/src/com/android/sched/util/codec/Parser.java b/sched/src/com/android/sched/util/codec/Parser.java index 35871fd..0b72823 100644 --- a/sched/src/com/android/sched/util/codec/Parser.java +++ b/sched/src/com/android/sched/util/codec/Parser.java @@ -16,6 +16,10 @@ package com.android.sched.util.codec; +import com.android.sched.util.HasDescription; + +import java.util.List; + import javax.annotation.CheckForNull; import javax.annotation.Nonnull; @@ -49,4 +53,36 @@ public interface Parser<T> { */ @Nonnull public String getUsage(); + + /** + * @return a description for some possible values. + */ + @Nonnull + public List<ValueDescription> getValueDescriptions(); + + /** + * Description of a value. + */ + public static class ValueDescription implements HasDescription { + @Nonnull + private final String value; + @Nonnull + private final String description; + + public ValueDescription(@Nonnull String value, @Nonnull String description) { + this.value = value; + this.description = description; + } + + @Nonnull + public String getValue() { + return value; + } + + @Override + @Nonnull + public String getDescription() { + return description; + } + } } diff --git a/sched/src/com/android/sched/util/codec/PathCodec.java b/sched/src/com/android/sched/util/codec/PathCodec.java index a1b2485..c221fb7 100644 --- a/sched/src/com/android/sched/util/codec/PathCodec.java +++ b/sched/src/com/android/sched/util/codec/PathCodec.java @@ -18,6 +18,8 @@ package com.android.sched.util.codec; import java.io.File; +import java.util.Collections; +import java.util.List; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; @@ -33,6 +35,12 @@ public class PathCodec implements StringCodec<File> { } @Override + @Nonnull + public List<ValueDescription> getValueDescriptions() { + return Collections.<ValueDescription> emptyList(); + } + + @Override @CheckForNull public File checkString(@Nonnull CodecContext context, @Nonnull String value) { return null; diff --git a/sched/src/com/android/sched/util/codec/Selector.java b/sched/src/com/android/sched/util/codec/Selector.java index 3e4d90e..4b3046f 100644 --- a/sched/src/com/android/sched/util/codec/Selector.java +++ b/sched/src/com/android/sched/util/codec/Selector.java @@ -20,6 +20,7 @@ import com.google.common.base.Joiner; import com.android.sched.reflections.ReflectionFactory; import com.android.sched.reflections.ReflectionManager; +import com.android.sched.util.codec.Parser.ValueDescription; import com.android.sched.util.config.ConfigurationError; import com.android.sched.util.config.ReflectDefaultCtorFactory; @@ -47,6 +48,8 @@ public abstract class Selector<T> { private final Class<T> type; @CheckForNull private Map<String, Class<? extends T>> propertyValues; + @CheckForNull + private List<ValueDescription> descriptions; public Selector(@Nonnull Class<T> type) { this.type = type; @@ -69,9 +72,39 @@ public abstract class Selector<T> { } @Nonnull + public List<ValueDescription> getValueDescriptions() { + if (descriptions == null) { + ensureScan(); + assert propertyValues != null; + + descriptions = new ArrayList<ValueDescription>(propertyValues.size()); + + for (Class<? extends T> subClass : propertyValues.values()) { + ImplementationName value = subClass.getAnnotation(ImplementationName.class); + assert value != null; + + if (!value.description().isEmpty()) { + descriptions.add(new ValueDescription(value.name(), value.description())); + } + } + + Collections.sort(descriptions, new Comparator<ValueDescription>(){ + @Override + public int compare(ValueDescription o1, ValueDescription o2) { + return o1.getValue().compareToIgnoreCase(o2.getValue()); + }}); + + } + + assert descriptions != null; + return descriptions; + } + + @Nonnull public Class<? extends T> getClass(@Nonnull String string) throws ParsingException { ensureScan(); assert propertyValues != null; + Class<? extends T> value = propertyValues.get(string); if (value == null) { @@ -143,6 +176,7 @@ public abstract class Selector<T> { private synchronized void ensureScan() { if (propertyValues == null) { propertyValues = new HashMap<String, Class<? extends T>>(); + ReflectionManager reflectionManager = ReflectionFactory.getManager(); Set<Class<? extends T>> propertyValueClasses = reflectionManager.getSubTypesOf(type); propertyValueClasses.add(type); diff --git a/sched/src/com/android/sched/util/config/expression/Expression.java b/sched/src/com/android/sched/util/config/expression/Expression.java index d2fbf5d..4dc3c31 100644 --- a/sched/src/com/android/sched/util/config/expression/Expression.java +++ b/sched/src/com/android/sched/util/config/expression/Expression.java @@ -16,6 +16,7 @@ package com.android.sched.util.config.expression; +import com.android.sched.util.HasDescription; import com.android.sched.util.config.ConfigChecker; import com.android.sched.util.config.PropertyIdException; import com.android.sched.util.config.id.PropertyId; @@ -27,9 +28,7 @@ import javax.annotation.Nonnull; /** * Abstract class representing an expression. */ -public abstract class Expression { - @Nonnull - public abstract String getDescription(); +public abstract class Expression implements HasDescription { @Nonnull public abstract String getCause(@Nonnull ConfigChecker checker) throws PropertyIdException; diff --git a/sched/src/com/android/sched/util/config/id/PropertyId.java b/sched/src/com/android/sched/util/config/id/PropertyId.java index c2579ee..e567b4f 100644 --- a/sched/src/com/android/sched/util/config/id/PropertyId.java +++ b/sched/src/com/android/sched/util/config/id/PropertyId.java @@ -17,6 +17,7 @@ package com.android.sched.util.config.id; +import com.android.sched.util.HasDescription; import com.android.sched.util.codec.CodecContext; import com.android.sched.util.codec.ParsingException; import com.android.sched.util.codec.StringCodec; @@ -33,7 +34,7 @@ import javax.annotation.Nonnull; * An instance of this type identifies a particular configuration property. * @param <T> Type of the configuration property. */ -public class PropertyId<T> extends KeyId<T, String> { +public class PropertyId<T> extends KeyId<T, String> implements HasDescription { @Nonnull private final String description; @@ -105,6 +106,7 @@ public class PropertyId<T> extends KeyId<T, String> { return defaultValues; } + @Override @Nonnull public String getDescription() { return description; diff --git a/sched/src/com/android/sched/util/location/Location.java b/sched/src/com/android/sched/util/location/Location.java index 2fa2fed..f3a2208 100644 --- a/sched/src/com/android/sched/util/location/Location.java +++ b/sched/src/com/android/sched/util/location/Location.java @@ -16,12 +16,10 @@ package com.android.sched.util.location; -import javax.annotation.Nonnull; +import com.android.sched.util.HasDescription; /** * Base class to describe a location. */ -public abstract class Location { - @Nonnull - public abstract String getDescription(); +public abstract class Location implements HasDescription { } diff --git a/sched/src/com/android/sched/util/log/StatisticOnlyTracer.java b/sched/src/com/android/sched/util/log/StatisticOnlyTracer.java index 81095e5..a3c2be1 100644 --- a/sched/src/com/android/sched/util/log/StatisticOnlyTracer.java +++ b/sched/src/com/android/sched/util/log/StatisticOnlyTracer.java @@ -60,7 +60,8 @@ import javax.annotation.Nonnull; /** * Tracer implementation which only collects statistics on a pseudo-single event. */ -@ImplementationName(iface = Tracer.class, name = "stat-only") +@ImplementationName(iface = Tracer.class, name = "stat-only", + description = "collect statistics without event information") public final class StatisticOnlyTracer implements Tracer { @Nonnull private final Logger logger = LoggerFactory.getLogger(); diff --git a/sched/src/com/android/sched/util/log/stats/Statistic.java b/sched/src/com/android/sched/util/log/stats/Statistic.java index 93d2535..0ece4eb 100644 --- a/sched/src/com/android/sched/util/log/stats/Statistic.java +++ b/sched/src/com/android/sched/util/log/stats/Statistic.java @@ -18,6 +18,7 @@ package com.android.sched.util.log.stats; import com.google.common.collect.Iterators; +import com.android.sched.util.HasDescription; import com.android.sched.util.codec.Formatter; import com.android.sched.util.codec.ToStringFormatter; import com.android.sched.util.table.DataHeader; @@ -29,7 +30,7 @@ import javax.annotation.Nonnull; /** * Represents a statistic. */ -public abstract class Statistic implements DataHeader { +public abstract class Statistic implements DataHeader, HasDescription { @Nonnull private final StatisticId<? extends Statistic> id; @@ -44,9 +45,6 @@ public abstract class Statistic implements DataHeader { return id; } - @Nonnull - public abstract String getDescription(); - @Override @Nonnull public String toString() { diff --git a/sched/src/com/android/sched/util/log/stats/StatisticId.java b/sched/src/com/android/sched/util/log/stats/StatisticId.java index 30444c5..181e5d0 100644 --- a/sched/src/com/android/sched/util/log/stats/StatisticId.java +++ b/sched/src/com/android/sched/util/log/stats/StatisticId.java @@ -16,6 +16,7 @@ package com.android.sched.util.log.stats; +import com.android.sched.util.HasDescription; import com.android.sched.util.config.ReflectFactory; import java.util.Collection; @@ -29,7 +30,7 @@ import javax.annotation.Nonnull; * * @param <T> Type of the statistic. */ -public class StatisticId<T extends Statistic> { +public class StatisticId<T extends Statistic> implements HasDescription { @Nonnull private static Map<Class<? extends Statistic>, Statistic> dummies = new ConcurrentHashMap<Class<? extends Statistic>, Statistic>(); @@ -75,6 +76,7 @@ public class StatisticId<T extends Statistic> { return name; } + @Override @Nonnull public String getDescription() { return description; diff --git a/sched/src/com/android/sched/util/log/tracer/ProbeManagerCodec.java b/sched/src/com/android/sched/util/log/tracer/ProbeManagerCodec.java index 2b20ef2..7a5b471 100644 --- a/sched/src/com/android/sched/util/log/tracer/ProbeManagerCodec.java +++ b/sched/src/com/android/sched/util/log/tracer/ProbeManagerCodec.java @@ -83,6 +83,12 @@ public class ProbeManagerCodec implements StringCodec<ProbeManager> { @Override @Nonnull + public List<com.android.sched.util.codec.Parser.ValueDescription> getValueDescriptions() { + return parser.getValueDescriptions(); + } + + @Override + @Nonnull public String formatValue(@Nonnull ProbeManager data) { return parser.formatValue(data.getProbes()); } diff --git a/sched/src/com/android/sched/util/log/tracer/filter/EventFilter.java b/sched/src/com/android/sched/util/log/tracer/filter/EventFilter.java index c2eb616..7586046 100644 --- a/sched/src/com/android/sched/util/log/tracer/filter/EventFilter.java +++ b/sched/src/com/android/sched/util/log/tracer/filter/EventFilter.java @@ -16,6 +16,7 @@ package com.android.sched.util.log.tracer.filter; +import com.android.sched.util.HasDescription; import com.android.sched.util.log.EventType; import javax.annotation.Nonnull; @@ -23,8 +24,6 @@ import javax.annotation.Nonnull; /** * Interface of a {@link EventType} filter. */ -public interface EventFilter { +public interface EventFilter extends HasDescription { public boolean isEnabled(@Nonnull EventType type); - @Nonnull - public String getDescription(); } diff --git a/sched/src/com/android/sched/util/log/tracer/probe/Probe.java b/sched/src/com/android/sched/util/log/tracer/probe/Probe.java index d311e9f..df937e5 100644 --- a/sched/src/com/android/sched/util/log/tracer/probe/Probe.java +++ b/sched/src/com/android/sched/util/log/tracer/probe/Probe.java @@ -16,6 +16,8 @@ package com.android.sched.util.log.tracer.probe; +import com.android.sched.util.HasDescription; + import javax.annotation.CheckForNull; import javax.annotation.Nonnegative; import javax.annotation.Nonnull; @@ -23,7 +25,7 @@ import javax.annotation.Nonnull; /** * Abstract class for a Probe. */ -public abstract class Probe implements Comparable<Probe> { +public abstract class Probe implements Comparable<Probe>, HasDescription { public static final int MAX_PRIORITY = 0; public static final int MIN_PRIORITY = 12; @@ -55,6 +57,7 @@ public abstract class Probe implements Comparable<Probe> { this.priority = priority; } + @Override @Nonnull public String getDescription() { return this.description; diff --git a/sched/src/com/android/sched/util/log/tracer/probe/ThreadTimeProbe.java b/sched/src/com/android/sched/util/log/tracer/probe/ThreadTimeProbe.java index 1a180f2..f1d2de9 100644 --- a/sched/src/com/android/sched/util/log/tracer/probe/ThreadTimeProbe.java +++ b/sched/src/com/android/sched/util/log/tracer/probe/ThreadTimeProbe.java @@ -27,7 +27,7 @@ import javax.annotation.Nonnull; /** * Probe which take the usage of per thread CPU time. */ -@ImplementationName(iface = Probe.class, name = "thread-time") +@ImplementationName(iface = Probe.class, name = "thread-cpu-time") public class ThreadTimeProbe extends TimeNanosProbe { @Nonnull private final ThreadMXBean threadMXBean; diff --git a/sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java b/sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java index 78fd9b8..af85d00 100644 --- a/sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java +++ b/sched/src/com/android/sched/util/log/tracer/watcher/AllocationWatcher.java @@ -89,7 +89,8 @@ public class AllocationWatcher implements ObjectWatcher<Object> { /** * Install a {@link AllocationWatcher} */ - @ImplementationName(iface = WatcherInstaller.class, name = "object-alloc") + @ImplementationName(iface = WatcherInstaller.class, name = "object-alloc", + description = "record object and array allocations globally") public static class AllocationWatcherInstaller implements WatcherInstaller { @Override public void install(@Nonnull Tracer tracer) { diff --git a/sched/src/com/android/sched/util/log/tracer/watcher/ArrayListWatcher.java b/sched/src/com/android/sched/util/log/tracer/watcher/ArrayListWatcher.java index 76db58a..65862a0 100644 --- a/sched/src/com/android/sched/util/log/tracer/watcher/ArrayListWatcher.java +++ b/sched/src/com/android/sched/util/log/tracer/watcher/ArrayListWatcher.java @@ -152,7 +152,8 @@ public class ArrayListWatcher implements ObjectWatcher<ArrayList<?>> { /** * Install a {@link ArrayListWatcher} */ - @ImplementationName(iface = WatcherInstaller.class, name = "arraylist-capacity") + @ImplementationName(iface = WatcherInstaller.class, name = "arraylist-capacity", + description = "record state of the array backed by ArrayList") public static class ArrayListWatcherInstaller implements WatcherInstaller { @Override public void install(@Nonnull Tracer tracer) { diff --git a/sched/src/com/android/sched/util/log/tracer/watcher/DetailedAllocationWatcher.java b/sched/src/com/android/sched/util/log/tracer/watcher/DetailedAllocationWatcher.java index f8a97e3..0349359 100644 --- a/sched/src/com/android/sched/util/log/tracer/watcher/DetailedAllocationWatcher.java +++ b/sched/src/com/android/sched/util/log/tracer/watcher/DetailedAllocationWatcher.java @@ -122,7 +122,8 @@ public class DetailedAllocationWatcher implements ObjectWatcher<Object> { /** * Install a {@link DetailedAllocationWatcher} */ - @ImplementationName(iface = WatcherInstaller.class, name = "detailed-object-alloc") + @ImplementationName(iface = WatcherInstaller.class, name = "detailed-object-alloc", + description = "record object and array allocations type by type") public static class DetailedAllocationWatcherInstaller implements WatcherInstaller { @Override public void install(@Nonnull Tracer tracer) { diff --git a/sched/src/com/android/sched/util/table/Report.java b/sched/src/com/android/sched/util/table/Report.java index 32b75d5..7c0e8d9 100644 --- a/sched/src/com/android/sched/util/table/Report.java +++ b/sched/src/com/android/sched/util/table/Report.java @@ -16,6 +16,8 @@ package com.android.sched.util.table; +import com.android.sched.util.HasDescription; + import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; @@ -26,7 +28,7 @@ import javax.annotation.Nonnull; /** * A collection of {@link Table}s. */ -public class Report implements Iterable<Table> { +public class Report implements Iterable<Table>, HasDescription { @Nonnull private final String name; @Nonnull @@ -63,6 +65,7 @@ public class Report implements Iterable<Table> { return name; } + @Override @Nonnull public String getDescription() { return description; diff --git a/sched/src/com/android/sched/util/table/Table.java b/sched/src/com/android/sched/util/table/Table.java index 5468dc6..6f1b02f 100644 --- a/sched/src/com/android/sched/util/table/Table.java +++ b/sched/src/com/android/sched/util/table/Table.java @@ -16,6 +16,7 @@ package com.android.sched.util.table; +import com.android.sched.util.HasDescription; import com.android.sched.util.codec.Formatter; import java.util.Iterator; @@ -26,7 +27,7 @@ import javax.annotation.Nonnull; /** * Interface representing a table. */ -public interface Table extends Iterable<Iterable<String>> { +public interface Table extends Iterable<Iterable<String>>, HasDescription { @Nonnull public Formatter<?>[] getFormatters(); @@ -34,6 +35,7 @@ public interface Table extends Iterable<Iterable<String>> { public String getName(); public void setName(@Nonnull String name); + @Override @Nonnull public String getDescription(); public void setDescription(@Nonnull String description); |