Php Inspections (EA Extended): if-conditions optimization

13
Php Inspections (EA Extended)*: If-statements optimization * Intelligent Static Code Analyzer for JetBrains IDEs Vladimir Reznichenko Karlsruhe, 20 October 2016

Transcript of Php Inspections (EA Extended): if-conditions optimization

Page 1: Php Inspections (EA Extended): if-conditions optimization

Php Inspections (EA Extended)*:If-statements optimization

* Intelligent Static Code Analyzer for JetBrains IDEs

Vladimir Reznichenko Karlsruhe, 20 October 2016

Page 2: Php Inspections (EA Extended): if-conditions optimization

What is Static Code Analysis about?

Static code analysis is about finding defects in source code *:

● Code Style violations (formatting, naming conventions and etc.);● Implementation Defects (bugs, portability, performance and etc.);● Security Issues (CVEs, API usage and etc.);● Code Duplication;● Code Metrics (e.g. Complexity, UTs coverage and etc.);

* and bytecode (e.g. FindBugs)

Page 3: Php Inspections (EA Extended): if-conditions optimization

Php Inspections (EA Extended): what’s covered?

Page 4: Php Inspections (EA Extended): if-conditions optimization

Challenges we met

● If-statements analysis:○ Execution costs estimation;○ Interconnected conditions; if (is_array($a) && $a[0] > 0) ;○ Variadic constructions, booleans, identical sub-expressions detection and more;

● exceptions handling workflow analysis:○ Simulation of the workflow for running analysis;○ PhpDoc parsing: PHP is not supporting “throws” declarations;○ Nested catch and finally has implementation issues in older PHP versions;

● analysis performance:○ Concurrency (inspections are running in several independent threads);○ GC: memory optimization (VisualVM, data structures);○ Avoid low-performing analysis, stop as early as possible;

Page 5: Php Inspections (EA Extended): if-conditions optimization

Challenges we met

● If-statements analysis:○ Execution costs estimation;○ Interconnected conditions;○ Variadic constructions, booleans, identical sub-expressions detection and more;

Page 6: Php Inspections (EA Extended): if-conditions optimization

If-statements analysis: patterns

● Execution costs: if ($var->method($a) && $b > 0) ;● Identical operands: if ($a !== $a) ;● Ambiguous type checks: if ($a instanceof \Date || $a instanceof \DateInterface) ;● If ($a instanceof \DateInterface && null !== $a) ;● Variadic constructions: if (isset($a) && isset($b)) ; => if (isset($a, $b)) ;● Hardcoded booleans: if ($a > 0 || true) ;● Confusing conditions: if ($a > 0 || $a <= 0 && $a > $minValue) ;● Duplicated expressions in elseif and nested ifs:● If (is_array($a) || is_string($a)) {● If (is_array($a) && count($a) > 0) ;● }

Page 7: Php Inspections (EA Extended): if-conditions optimization

Execution costs estimation: idea

The challenge has a name: “Shortest path problem” from Graphs theory (Discrete mathematics).

Applying the problem e.g. to “if ($var->method($a) && $a > 0) ;” we have 2 paths:

● $var->method($a) ○ Method lookup ;○ Calls stack: push and pop ;○ Complex operation, therefore high execution costs ;

● $a > 0○ Primitive operation, therefore low execution costs ;

Page 8: Php Inspections (EA Extended): if-conditions optimization

Execution costs estimation: example

Let’s take more common case: if-else construct.

If (<conditions>) { <operation 1>; } else { <operation 2>; }

Formula for if-else construction cost estimation will be*:

C(<if-else>) = C(<conditions>) + max(C(<operation 1>), C(<operation 2>))

* The theory of parsing, translation, and compiling

Page 9: Php Inspections (EA Extended): if-conditions optimization

Execution costs estimation: C() function

This is most important part: which weight to assign to different constructs?

For this you need know your compiler/interpreter internals and language capabilities.

Example weights specific for PHP:● Binary/Unary operations: 0 ; (primitive operations)● Array access: +1 (hash-maps based arrays implementation) ;● Method/function reference: +5 (call stack invocation) ;● Lambdas: +10 (no JIT compiler, dynamically allocated) ;● etc.

Page 10: Php Inspections (EA Extended): if-conditions optimization

Code samples: hooking into IDEpublic class NotOptimalIfConditionsInspection extends BasePhpInspection {

@Override public PsiElementVisitor buildVisitor(@NotNull final ProblemsHolder holder, boolean isOnTheFly) { return new BasePhpElementVisitor() { public void visitPhpIf(If ifStatement) { /* we are visiting a branch of AST-tree here, analyze it */ }

/* other visitors here */ }; }

}

Page 11: Php Inspections (EA Extended): if-conditions optimization

Code samples: processing conditionsLinkedList<PsiElement> conditions = <extraction_method>(ifStatement.getCondition(), operationHolder);if (null != conditions ) { allConditions.addAll(conditions); /* invoke strategies */ conditions.clear();}

for (ElseIf objElseIf : ifStatement.getElseIfBranches()) { conditions = <extraction_method>(objElseIf.getCondition(), operationHolder); if (null != conditions) { allConditions.addAll(conditions); /* invoke strategies */ conditions.clear(); }}<nested_ifs_duplicates_strategy>(allConditions, ifStatement);

Page 12: Php Inspections (EA Extended): if-conditions optimization

Code samples: execution costs estimation

How to calculate execution costs for expression “$a->getConfig()[‘waf’]”

if (expression instanceof ArrayAccessExpression) {

final ArrayAccessExpression arrayAccess = (ArrayAccessExpression) expression; final ArrayIndex arrayIndex = arrayAccess.getIndex();

int ownCosts = getExpressionCost(arrayAccess.getValue()); /* recursion: $a->getConfig() -> 5 */ if (null != arrayIndex) { ownCosts += getExpressionCost(arrayIndex.getValue()); /* recursion: ‘waf’ -> 0 */ }

return (1 + ownCosts); /* -> 6 */

}

Page 13: Php Inspections (EA Extended): if-conditions optimization

Thank you