Assignment Data Flow Transformation

Pt

Introduction

In this assignment you will implement intra-procedural constant propagation and intra-procedural dead code elimination for a subset of Java. The goal is to better understand flow-sensitive data-flow transformations.

Reuse

As you have already seen in the lectures, constant propagation is very similar to interpretation. The main difference is that not all variables have constant values. So instead of only producing a single value, constant propagation should produce a program in which constant values have been folded and propagated where possible. Obviously you should be able to reuse a great deal from the interpreter you developed for the previous assignment. Also have a look at the constant propagation strategy for TIL in Chapter 6 of the examples in the manual.

Look at the same chapter to get inspiration for the dead code elimination strategy you should develop.

Restrictions

The transformations you will be developing are intra-procedural, which entails that they consider a single method at a time. In Java this means that assignments to fields and uses of fields should be considered as unknowns.

  • Values assigned to fields cannot be propagated past method calls, since method calls may assign to these fields
  • Assignments to fields are never dead since the object may be alive

Furthermore, you can may ignore control-flow constructs such as break, continue, and exceptions.

Testing

As usual, create unit tests for both transformations.

Setup

The following Stratego module is the basis for a constant propagation transformation transformation system. It reads in the compilation units declared on the command-line, parses them, applies propconst-compilation-unit to each, and then pretty-prints them. You can use the same setup as the basis for dead code elimination.

module java-propconst
imports libdryad
strategies

  main-java-propconst =
    xtc-multi-io-wrap(
      observables-wrap(propconst-java)
    )

  propconst-java =
    process-input-sources
    ; map(
        get-ast
        ; propconst-compilation-unit
        ; write-to
        ; xtc-transform(!"pp-java",pass-verbose)
      )

  /**
   * Loads Java source files in the Dryad repository.
   *
   * @type List(FILE) -> List(CompilationUnit Object)
   */
  process-input-sources =
    parse-java
    ; map(define-compilation-unit)
    ; dryad-reclassify
    ; map(dryad-type-checker)

strategies

  propconst-compilation-unit =
    id // your transformation here

The following make-propconst script can be used to compile the program.

#! /bin/sh

XTCFLAGS="$(pkg-config --variable=strcxtcflags dryad)"
STRCFLAGS="$(pkg-config --variable=strcflags dryad)"

strc -i java-propconst.str -m main-java-propconst $XTCFLAGS $STRCFLAGS --format-check -1

Application of java-propconst to one or more Java compilation units then proceeds as follows:

./java-propconst -i Factorial.java

This will print the transformed code to stdout.

The Transformations

Once you succeed in compiling and testing the template module above you can start implementing the constant propagation transformation and call it in the definition o propconst-compilation-unit. The transformation should traverse the code of the compilation unit until it finds method declarations. The bodies of these declarations should be transformed.

Template Testsuite

You can use the following template for your testsuite. The testing strategies allow you to test an arbitrary statement in your output program by labeling it with result:.

module test-java-propconst
imports java-propconst

strategies

  main-test-java-propconst =
    option-wrap(general-options,
      test-suite(!"WK10 assignment",
        observables-wrap(
          simple-tests
        )
      )
    )
    
strategies

  simple-tests = id
  ; test-compilation-unit(|
      "Evaluation to simple constant value"
    , "class Foo { public void foo() { int x = 3; result : x * x;} }"
    , ExprStm(Lit(Deci("9")))
    )
  ; test-compilation-unit(
     not(oncetd(?ExprName(Id("x"))))
    | "Evaluation to simple constant value"
    , "class Foo { public void foo() { int x = 3; int y; result : x * y;} }"
    )
  ; test-compilation-unit(
     oncetd(?ExprName(Id("y")))
    | "Evaluation to simple constant value"
    , "class Foo { public void foo() { int x = 3; int y; result : x * y;} }"
    )
    

/**
 * Testing utils
 */
strategies

  test-compilation-unit(check |msg, src) =
    apply-and-check(!msg
    , propconst-compilation-unit
      ; get-test-result             
    , <process-input> src   
    , check
    )
    
  test-compilation-unit(|msg, src, result) =
    apply-test(!msg
    , propconst-compilation-unit
      ; get-test-result
    , <process-input> src   
    , !result
    )

  get-test-result =
    oncetd(?Labeled(Id("result"), stm))
    ; !stm

  process-input =
    print-to
    ; ![<id>]
    ; parse-java
    ; map(define-compilation-unit)
    ; dryad-reclassify
    ; map(dryad-type-checker) 
    ; last
    ; get-ast

Script for compilation of the testsuite:

#! /bin/sh

# Add the Nix profile to the search path of pkg-config
export PKG_CONFIG_PATH=$HOME/.nix-profile/lib/pkgconfig:$PKG_CONFIG_PATH

XTCFLAGS="$(pkg-config --variable=strcxtcflags dryad)"
STRCFLAGS="$(pkg-config --variable=strcflags dryad)"

strc -i test-java-propconst.str -m main-test-java-propconst $XTCFLAGS $STRCFLAGS --format-check -1

Submission

Submit the Stratego modules along with any scripts and samples you have developed for building and testing.