DonateDeadCodeTransformation extends DonateCodeTransformation { @Override Stmt prepareStatementToDonate(IInjectionPoint injectionPoint, DonationContext donationContext, TransformationProbabilities probabilities, IRandom generator, ShadingLanguageVersion shadingLanguageVersion) { Map<String, String> substitution = new HashMap<>(); List<Stmt> donatedStmts = new ArrayList<>(); for (String name : asSortedList(donationContext.getFreeVariables().keySet())) { boolean dealtWithFreeVariable = false; Type type = donationContext.getFreeVariables().get(name); if (probabilities.substituteFreeVariable(generator)) { List<String> options = injectionPoint.scopeAtInjectionPoint().namesOfAllVariablesInScope() .stream() .filter(x -> injectionPoint.scopeAtInjectionPoint().lookupType(x).equals(type)) .collect(Collectors.toList()); options = options.stream().filter(x -> !donationContext.getDeclaredVariableNames().contains(x)).collect(Collectors.toList()); if (options.size() > 0) { substitution.put(name, options.get(generator.nextInt(options.size()))); dealtWithFreeVariable = true; } } if (!dealtWithFreeVariable) { String newName = "donor_replacement" + name; substitution.put(name, newName); final Type typeWithRestrictedQualifiers = dropQualifiersThatCannotBeUsedForLocalVariable(type); final Initializer initializer = getInitializer( injectionPoint, donationContext, typeWithRestrictedQualifiers, type.hasQualifier(TypeQualifier.CONST), generator, shadingLanguageVersion); final ImmutablePair<Type, ArrayInfo> baseTypeAndArrayInfo = Typer.getBaseTypeArrayInfo(typeWithRestrictedQualifiers); donatedStmts.add(new DeclarationStmt( new VariablesDeclaration(baseTypeAndArrayInfo.left, new VariableDeclInfo(newName, baseTypeAndArrayInfo.right, initializer)))); } } Stmt substitutedDonorFragment = donationContext.getDonorFragment(); new ApplySubstitution(substitution, substitutedDonorFragment); donatedStmts.add(substitutedDonorFragment); IfStmt donatedStmt = new IfStmt( new OpaqueExpressionGenerator(generator, generationParams, shadingLanguageVersion) .makeDeadCondition( new Fuzzer(new FuzzingContext(injectionPoint.scopeAtInjectionPoint()), shadingLanguageVersion, generator, generationParams)), new BlockStmt(donatedStmts, true), null); new RemoveImmediateCaseLabels(donatedStmt); if (!injectionPoint.inLoop()) { new RemoveImmediateContinueStatements(donatedStmt); } if (!(injectionPoint.inLoop() || injectionPoint.inSwitch())) { new RemoveImmediateBreakStatements(donatedStmt); } if (generationParams.getShaderKind() != ShaderKind.FRAGMENT) { new RemoveDiscardStatements(donatedStmt); } if (incompatibleReturnTypes(injectionPoint.getEnclosingFunction(), donationContext.getEnclosingFunction())) { new RemoveReturnStatements(donatedStmt); } return donatedStmt; } DonateDeadCodeTransformation(Function<IRandom, Boolean> probabilityOfDonation,
                                      File donorsDirectory,
                                      GenerationParams generationParams); @Override String getName(); static final String NAME; }
@Test public void prepareStatementToDonateTopLevelBreakRemovedWhenNecessary() throws Exception { final DonateDeadCodeTransformation dlc = getDummyTransformationObject(); final TranslationUnit donor = ParseHelper.parse("#version 310 es\n" + "void main() {\n" + " for (int i = 0; i < 10; i ++)\n" + " if (i > 5) break;\n" + "}\n"); final TranslationUnit reference = ParseHelper.parse("#version 310 es\n" + "void main() {\n" + " ;\n" + " for(int i = 0; i < 100; i++) {\n" + " switch (i) {\n" + " case 0:\n" + " i++;\n" + " default:\n" + " i++;\n" + " }\n" + " }" + "}\n"); for (IInjectionPoint injectionPoint : new InjectionPoints(reference, new RandomWrapper(0), item -> true).getAllInjectionPoints()) { final Stmt toDonate = ((ForStmt) donor.getMainFunction().getBody().getStmt(0)).getBody() .clone(); assert toDonate instanceof IfStmt; final DonationContext dc = new DonationContext(toDonate, new HashMap<>(), new ArrayList<>(), donor.getMainFunction()); final Stmt donated = dlc.prepareStatementToDonate(injectionPoint, dc, TransformationProbabilities.DEFAULT_PROBABILITIES, new RandomWrapper(0), ShadingLanguageVersion.ESSL_310); final boolean containsBreak = new CheckPredicateVisitor() { @Override public void visitBreakStmt(BreakStmt breakStmt) { predicateHolds(); } }.test(donated); assertEquals(containsBreak, injectionPoint.inLoop() || injectionPoint.inSwitch()); } }
@Test public void prepareStatementToDonateTopLevelContinueRemovedWhenNecessary() throws Exception { final DonateDeadCodeTransformation dlc = getDummyTransformationObject(); final TranslationUnit donor = ParseHelper.parse("#version 100\n" + "void main() {\n" + " for (int i = 0; i < 10; i ++)\n" + " if (i > 5) continue;\n" + "\n" + "}\n"); final TranslationUnit reference = ParseHelper.parse("#version 100\n" + "void main() {\n" + " ;\n" + " switch(0) {\n" + " case 1:\n" + " break;\n" + " default:\n" + " 1;\n" + " }\n" + " for(int i = 0; i < 100; i++) {\n" + " ;\n" + " }\n" + "}\n"); for (IInjectionPoint injectionPoint : new InjectionPoints(reference, new RandomWrapper(0), item -> true).getAllInjectionPoints()) { final Stmt toDonate = ((ForStmt) donor.getMainFunction().getBody().getStmt(0)).getBody() .clone(); assert toDonate instanceof IfStmt; final DonationContext dc = new DonationContext(toDonate, new HashMap<>(), new ArrayList<>(), donor.getMainFunction()); final Stmt donated = dlc.prepareStatementToDonate(injectionPoint, dc, TransformationProbabilities.DEFAULT_PROBABILITIES, new RandomWrapper(0), ShadingLanguageVersion.ESSL_100); final boolean containsContinue = new CheckPredicateVisitor() { @Override public void visitContinueStmt(ContinueStmt continueStmt) { predicateHolds(); } }.test(donated); assertEquals(containsContinue, injectionPoint.inLoop()); } }
@Test public void prepareStatementToDonateTopLevelCaseAndDefaultRemoved() throws Exception { final DonateDeadCodeTransformation dlc = getDummyTransformationObject(); final TranslationUnit donor = ParseHelper.parse("#version 310 es\n" + "void main() {\n" + " int x = 3;\n" + " switch (x) {\n" + " case 0:\n" + " x++;\n" + " default:\n" + " x++;\n" + " }\n" + "}\n"); final TranslationUnit reference = ParseHelper.parse("#version 310 es\n" + "void main() {\n" + " switch (0) {\n" + " case 1:\n" + " 1;\n" + " default:\n" + " 2;\n" + " }\n" + "}\n"); for (IInjectionPoint injectionPoint : new InjectionPoints(reference, new RandomWrapper(0), item -> true).getAllInjectionPoints()) { final Stmt toDonate = ((SwitchStmt) donor.getMainFunction().getBody().getStmt(1)).getBody() .clone(); DonationContext dc = new DonationContext(toDonate, new HashMap<>(), new ArrayList<>(), donor.getMainFunction()); final Stmt donated = dlc.prepareStatementToDonate(injectionPoint, dc, TransformationProbabilities.DEFAULT_PROBABILITIES, new RandomWrapper(0), ShadingLanguageVersion.ESSL_310); new StandardVisitor() { @Override public void visitDefaultCaseLabel(DefaultCaseLabel defaultCaseLabel) { fail(); } @Override public void visitExprCaseLabel(ExprCaseLabel exprCaseLabel) { fail(); } }.visit(donated); } }
@Test public void prepareStatementToDonateBreakFromLoopKept() throws Exception { final DonateDeadCodeTransformation dlc = getDummyTransformationObject(); final TranslationUnit donor = ParseHelper.parse("#version 100\n" + "void main() {\n" + " for (int i = 0; i < 10; i ++)\n" + " if (i > 5) break;\n" + "\n" + "}\n"); final TranslationUnit reference = ParseHelper.parse("#version 100\n" + "void main() {\n" + " ;\n" + " for(int i = 0; i < 100; i++) {\n" + " }\n" + "}\n"); for (IInjectionPoint injectionPoint : new InjectionPoints(reference, new RandomWrapper(0), item -> true).getAllInjectionPoints()) { final Stmt toDonate = donor.getMainFunction().getBody().getStmt(0).clone(); assert toDonate instanceof ForStmt; final DonationContext dc = new DonationContext(toDonate, new HashMap<>(), new ArrayList<>(), donor.getMainFunction()); final Stmt donated = dlc.prepareStatementToDonate(injectionPoint, dc, TransformationProbabilities.DEFAULT_PROBABILITIES, new RandomWrapper(0), ShadingLanguageVersion.ESSL_100); assertTrue(new CheckPredicateVisitor() { @Override public void visitBreakStmt(BreakStmt breakStmt) { predicateHolds(); } }.test(donated)); } }
@Test public void prepareStatementToDonateSwitchWithBreakAndDefaultKept() throws Exception { final DonateDeadCodeTransformation dlc = getDummyTransformationObject(); final TranslationUnit donor = ParseHelper.parse("#version 310 es\n" + "void main() {\n" + " switch (0) {\n" + " case 0:\n" + " 1;\n" + " break;\n" + " default:\n" + " 2;\n" + " }\n" + "}\n"); final TranslationUnit reference = ParseHelper.parse("#version 310 es\n" + "void main() {\n" + " ;\n" + " switch (0) {\n" + " case 1:\n" + " 1;\n" + " default:\n" + " 2;\n" + " }\n" + "}\n"); for (IInjectionPoint injectionPoint : new InjectionPoints(reference, new RandomWrapper(0), item -> true).getAllInjectionPoints()) { final Stmt toDonate = donor.getMainFunction().getBody().getStmt(0).clone(); assert toDonate instanceof SwitchStmt; final DonationContext dc = new DonationContext(toDonate, new HashMap<>(), new ArrayList<>(), donor.getMainFunction()); final Stmt donated = dlc.prepareStatementToDonate(injectionPoint, dc, TransformationProbabilities.DEFAULT_PROBABILITIES, new RandomWrapper(0), ShadingLanguageVersion.ESSL_310); new StandardVisitor() { private boolean foundBreak = false; private boolean foundCase = false; private boolean foundDefault = false; @Override public void visitBreakStmt(BreakStmt breakStmt) { assertFalse(foundBreak); foundBreak = true; } @Override public void visitExprCaseLabel(ExprCaseLabel exprCaseLabel) { assertFalse(foundCase); foundCase = true; } @Override public void visitDefaultCaseLabel(DefaultCaseLabel defaultCaseLabel) { assertFalse(foundDefault); foundDefault = true; } private void check(Stmt stmt) { visit(stmt); assertTrue(foundBreak); assertTrue(foundCase); assertTrue(foundDefault); } }; } }
@Test public void prepareStatementToDonateContinueInLoopKept() throws Exception { final DonateDeadCodeTransformation dlc = getDummyTransformationObject(); final TranslationUnit donor = ParseHelper.parse("#version 100\n" + "void main() {\n" + " for (int i = 0; i < 10; i ++)\n" + " if (i > 5) continue;\n" + "\n" + "}\n"); final TranslationUnit reference = ParseHelper.parse("#version 100\n" + "void main() {\n" + " ;\n" + " for(int i = 0; i < 100; i++) {\n" + " }\n" + "}\n"); for (IInjectionPoint injectionPoint : new InjectionPoints(reference, new RandomWrapper(0), item -> true).getAllInjectionPoints()) { final Stmt toDonate = donor.getMainFunction().getBody().getStmt(0).clone(); assert toDonate instanceof ForStmt; final DonationContext dc = new DonationContext(toDonate, new HashMap<>(), new ArrayList<>(), donor.getMainFunction()); final Stmt donated = dlc.prepareStatementToDonate(injectionPoint, dc, TransformationProbabilities.DEFAULT_PROBABILITIES, new RandomWrapper(0), ShadingLanguageVersion.ESSL_100); assertTrue(new CheckPredicateVisitor() { @Override public void visitContinueStmt(ContinueStmt continueStmt) { predicateHolds(); } }.test(donated)); } }