Agile and Efficient Domain-Specific Languages using Multi-stage Programming in Java Mint Edwin Westbrook, Mathias Ricken, and Walid Taha.

Slides:



Advertisements
Similar presentations
Optional Static Typing Guido van Rossum (with Paul Prescod, Greg Stein, and the types-SIG)
Advertisements

OO Programming in Java Objectives for today: Overriding the toString() method Polymorphism & Dynamic Binding Interfaces Packages and Class Path.
1 Programming Languages (CS 550) Mini Language Interpreter Jeremy R. Johnson.
Type Checking, Inference, & Elaboration CS153: Compilers Greg Morrisett.
CSE341: Programming Languages Lecture 2 Functions, Pairs, Lists Dan Grossman Winter 2013.
1 Mooly Sagiv and Greta Yorsh School of Computer Science Tel-Aviv University Modern Compiler Design.
Problem Solving 5 Using Java API for Searching and Sorting Applications ICS-201 Introduction to Computing II Semester 071.
Tim Sheard Oregon Graduate Institute Lecture 8: Operational Semantics of MetaML CSE 510 Section FSC Winter 2005 Winter 2005.
1 Compiler Construction Intermediate Code Generation.
1 Programming Languages (CS 550) Lecture Summary Functional Programming and Operational Semantics for Scheme Jeremy R. Johnson.
Getting started with ML ML is a functional programming language. ML is statically typed: The types of literals, values, expressions and functions in a.
INF 212 ANALYSIS OF PROG. LANGS Type Systems Instructors: Crista Lopes Copyright © Instructors.
Agile and Efficient Domain-Specific Languages using Multi-stage Programming in Java Mint Edwin Westbrook, Mathias Ricken, and Walid Taha.
Mint: A Multi-stage Extension of Java COMP 600 Mathias Ricken Rice University February 8, 2010.
Distributed Meta- Programming Rui Shi, Chiyan Chen and Hongwei Xi Boston University.
Tim Sheard Oregon Graduate Institute Lecture 4: Staging Interpreters CSE 510 Section FSC Winter 2004 Winter 2004.
Compiler Construction
CIS 101: Computer Programming and Problem Solving Lecture 8 Usman Roshan Department of Computer Science NJIT.
Introduction to ML - Part 2 Kenny Zhu. What is next? ML has a rich set of structured values Tuples: (17, true, “stuff”) Records: {name = “george”, age.
Distributed Meta- Programming (To appear GPCE’06) Rui Shi, Chiyan Chen and Hongwei Xi Boston University.
Alice in Action with Java
A Methodology for Generating Verified Combinatorial Circuits CSE 510 Section FSC Winter 2004 Winter 2004 Kiselyov, Swadi, Taha.
Functional programming: LISP Originally developed for symbolic computing First interactive, interpreted language Dynamic typing: values have types, variables.
CS0007: Introduction to Computer Programming Introduction to Arrays.
Code-Tuning By Jacob Shattuck. Code size/complexity vs computation resource utilization A classic example: Bubblesort A classic example: Bubblesort const.
Language Evaluation Criteria
Week 4-5 Java Programming. Loops What is a loop? Loop is code that repeats itself a certain number of times There are two types of loops: For loop Used.
Chapter TwelveModern Programming Languages1 Memory Locations For Variables.
Imperative Programming
Chapter 3 Introduction to Collections – Stacks Modified
Staging in Haskell What is Staging What does it Mean Using Template Haskell.
COMS W4115 Programming Languages & Translators Maria Ayako Taku COMS W PLT Columbia University 1 April 24, 2013 Functional Programming.
Adapted from Prof. Necula UCB CS 1641 Overview of COOL ICOM 4029 Lecture 2 ICOM 4029 Fall 2008.
1 Specialization Tools and Techniques for Systematic Optimization of System Software McNamee, Walpole, Pu, Cowan, Krasic, Goel, Wagle, Consel, Muller,
Recitation 4 Abstract classes, Interfaces. A Little More Geometry! Abstract Classes Shape x ____ y ____ Triangle area() base____ height ____ Circle area()
Hello.java Program Output 1 public class Hello { 2 public static void main( String [] args ) 3 { 4 System.out.println( “Hello!" ); 5 } // end method main.
CSC 580 – Theory of Programming Languages, Spring, 2009 Week 9: Functional Languages ML and Haskell, Dr. Dale E. Parson.
Interpretation Environments and Evaluation. CS 354 Spring Translation Stages Lexical analysis (scanning) Parsing –Recognizing –Building parse tree.
Formal Semantics Chapter Twenty-ThreeModern Programming Languages, 2nd ed.1.
CSE 425: Data Types I Data and Data Types Data may be more abstract than their representation –E.g., integer (unbounded) vs. 64-bit int (bounded) A language.
Mint: A Multi-stage Extension of Java Purdue University - Computer Science Colloquia Mathias Ricken Rice University March 15, 2010.
Design Patterns Gang Qian Department of Computer Science University of Central Oklahoma.
Semantics. Semantics is a precise definition of the meaning of a syntactically and type-wise correct program. Ideas of meaning: –Operational Semantics.
Edwin Westbrook, Mathias Ricken, Jun Inoue, Yilong Yao, Tamer Abdlatif, Walid Taha.
Implementing a Dependently Typed λ -Calculus Ali Assaf Abbie Desrosiers Alexandre Tomberg.
RUBY by Ryan Chase.
List Interface and Linked List Mrs. Furman March 25, 2010.
Agile and Efficient Domain-Specific Languages using Multi-stage Programming in Java Mint Edwin Westbrook, Mathias Ricken, and Walid Taha.
Java Annotations for Types and Expressions Mathias Ricken October 24, 2008 COMP 617 Seminar.
Advanced Functional Programming Tim Sheard 1 Lecture 17 Advanced Functional Programming Tim Sheard Oregon Graduate Institute of Science & Technology Lecture:
Quick Review of OOP Constructs Classes:  Data types for structured data and behavior  fields and methods Objects:  Variables whose data type is a class.
Terms and Rules II Professor Evan Korth New York University (All rights reserved)
Day 3: The Command and Visitor Patterns. Preliminaries The Java static type system uses simple rules to infer types for Java expressions. The inferred.
Announcements Assignment 2 Out Today Quiz today - so I need to shut up at 4:25 1.
Operational Semantics Mooly Sagiv Reference: Semantics with Applications Chapter 2 H. Nielson and F. Nielson
The PLA Model: On the Combination of Product-Line Analyses 강태준.
Operational Semantics of Scheme
Type Checking and Type Inference
Interpreters Study Semantics of Programming Languages through interpreters (Executable Specifications) cs7100(Prasad) L8Interp.
Env. Model Implementation
Tim Sheard Oregon Graduate Institute
Conditional Statements
The Metacircular Evaluator
Lecture 23 Pages : Separating Syntactic Analysis from Execution. We omit many details so you have to read the section in the book. The halting.
The Metacircular Evaluator
6.001 SICP Variations on a Scheme
Introduction to Data Structure
6.001 SICP Interpretation Parts of an interpreter
ICOM 4029 Fall 2003 Lecture 2 (Adapted from Prof. Necula UCB CS 164)
Rehearsal: Lazy Evaluation Infinite Streams in our lazy evaluator
Presentation transcript:

Agile and Efficient Domain-Specific Languages using Multi-stage Programming in Java Mint Edwin Westbrook, Mathias Ricken, and Walid Taha

Why Domain-Specific Languages? public int f () {... }

Benefits of DSLs: Productivity: write programs easier and faster Modularity: DSL implementation vs. programs Correctness: easier to see and fix bugs

DSLs Must Be Agile $ $

How to Implement DSLs? Interpreters: easier to write and modify Compilers: more efficiency Why can’t we have both?

Multi-Stage Programming Can turn your interpreter into a compiler By adding staging annotations Result: code-producing interpreter – Looks similar to original interpreter – Produces compiled code – No need to worry about compiler back-ends

Outline What is MSP? Writing a staged interpreter “Compiler optimizations” in MSP: – Dynamic type inference to reduce boxing/unboxing – Automatic loop parallelization Future Work: Monadic Staging

MSP Reduces the Cost of Abstractions MSP languages – provide constructs for runtime code generation – are statically typed: do not delay error checking until runtime

MSP in Mint Code has type Code Code built with brackets Code spliced with escapes `e Code compiled and run with run() method Code x = ; Code y = ; Integer z = y.run(); // z = 9

MSP Applications Sparse matrix multiplication – Specialize for elements of value 0 or 1 Array Views – Habanero Java’s way of mapping multiple dimensions into 1-dimensional array – Removal of index math Killer example: Staged interpreters

Staging an Interpreter Unstaged interpreter Staged interpreter (compiler) Input Program OutputInterpreter Input OutputRuntime Program Compiler Code

Unstaged Interpreter in Java Integer arithmetic, recursive unary functions Implementation – Interpreter and Composite design patterns

public interface Exp { public int eval(Env e, FEnv f); } public class Int implements Exp { private int _v; public Int(int value) { _v = value; } public int eval(Env e, FEnv f) { return _v; } } public class Add implements Exp { private Exp _left, _right; public Add(Exp l, Exp r) { _left = l; _right = r; } public int eval(Env e, FEnv f) { return _left.eval(e,f) + _right.eval(e,f); } Unstaged Interpreter in Java

// evaluate an expression Exp e = new Add(new Int(10), new Int(20)); int i = e.eval(env0, fenv0); // i = = 30 // create a function that can be evaluated for any x IntFun tenPlusX = new IntFun() { public int apply(int x) { Exp e = new Add(new Int(10), new Int(x)); int i = e.eval(env0, fenv0); return i; } }; int j = tenPlusX.apply(20); // j = = 30 Using the Unstaged Interpreter

public interface Exp { public separable Code eval(Env e, FEnv f); } public class Int implements Exp { private Code _v; public Int(final int value) { _v = ; } public separable Code eval(Env e, FEnv f) { return _v; } public class Add implements Exp { private Exp _left, _right; public Add(Exp l, Exp r) { _left = l; _right = r; } public separable Code eval(Env e, FEnv f) { return ; } Staged Interpreter

// evaluate an expression Exp e = new Add(new Int(10), new Int(20)); Code c = e.eval(env0, fenv0); // c = int i = c.run(); // i = 30 // create a function that can be evaluated for any x Code tenPlusXCode = <| new IntFun() { public int apply(final int x) { return `(new Add(new Int(10), new Int( )). eval(env0, fenv0)); } } |>; IntFun tenPlusX = tenPlusXCode.run(); int j = tenPlusX.apply(20); // j = = 30 Using the Staged Interpreter

// evaluate an expression Exp e = new Add(new Int(10), new Int(20)); Code c = e.eval(env0, fenv0); // c = int i = c.run(); // i = 30 // create a function that can be evaluated for any x Code tenPlusXCode = <| new IntFun() { public int apply(final int x) { return `(new Add(new Int(10), new Int( )). eval(env0, fenv0)); } } |>; IntFun tenPlusX = tenPlusXCode.run(); int j = tenPlusX.apply(20); // j = = 30 Using the Staged Interpreter <| new IntFun() { public int apply(final int x) { return 10 + x; } } |> 10 + x new Add(new Int(10), new Int( )). eval(env0, fenv0)

Framework for DSL Implementation Reflection-based S-expression parser – Works for all our DSLs (Ifz (Var x) (Int 1) (Mul (Var x) (App f (Sub (Var x) (Int 1))))) Abstract interpreter, compiler and runner – Work for all our DSLs – Template method design pattern to specify the variant behavior (e.g. which parser to use)

Compiler for Example DSL public class Compiler extends util.ACompiler { public Exp parse(String source) { return parser.LintParser.parse(Exp.class, source); } public Code getFunction(final Exp funBody) { return <| new IntFun() { public separable int apply(final int param) { return `(bindParameter(funBody, )); } } |>; }

Demo and Benchmarks: Integer Interpreter

Multiple Data Types Integer arithmetic, Boolean operations Unstaged interpreter returns Value Staged interpreter returns Code

public abstract class Value { public separable int intValue() { throw new Oops(); } public separable boolean booleanValue() { throw new Oops(); } } public class IntValue extends Value { private int _data; public IntValue(int data) { _data = data; } public separable int intValue() { return _data; } public String toString() { return _data+":IntValue"; } } Value Type and Subclass

public interface Exp { public separable Code eval(Env e, FEnv f); } public class Val implements Exp { private Code _value; public Val(final Value value) { _value = ; } public separable Code eval(Env e, FEnv f) { return _value; } Staged Interpreter with Value Type Cannot move the value from stage 0 to stage 1 this way (using cross-stage persistence, CSP). The Value type is not guaranteed to be code-free, and CSP of code could break type-safety (see Westbrook 2010).

public abstract class Value { /* … */ public separable abstract Code lift(); } public class IntValue extends Value { /* … */ private int _data; public separable Code lift() { final int lfData = _data; return ; } public class Val implements Exp { /* … */ private Code _value; public Val(final Value value) { _value = value.lift(); } } Lifting for the Value Type CSP of int, instead of CSP of Value.

Demo and Benchmarks: Interpreter with Multiple Data Types

Overhead from Boxing/Unboxing eval() always returns Code : public static class Add extends BinOp { public Add(Exp left, Exp right) { super(left, right); } public separable Code eval(Env e, FEnv f) { return <| (Value) new IntValue(`(_left.eval(e,f)).intValue() +`(_right.eval(e,f)).intValue()) |>; } Unnecessary in man cases!

Boxing/Unboxing Demo

Solution: “Staging the Value Type”

public interface Exp { public separable SValue eval(Env e, FEnv f); } public static class Add extends BinOp { //… public separable SValue eval(Env e, FEnv f) { return new SIntValue(<| `(_left.eval(e,f).intCodeValue()) + `(_right.eval(e,f).intCodeValue()) |>); }

Demo and Benchmarks: Dynamic Type Inference

Let Removes Code Duplication (Mul (… complex computation …) (… complex computation …)) (Let y (… complex computation …) (Mul y y))

Staging Let Expressions public static class Let implements Exp { // … public Value eval(Env e, FEnv f) { Env newenv = ext (e, _var, _rhs.eval (e, f)); return _body.eval (newenv, f); }

Naïve Staging of Let Expressions public static class Let implements Exp { // … public separable SValue eval(Env e, FEnv f) { Env newenv = ext (e, _var, _rhs.eval (e, f)); return _body.eval (newenv, f); } Causes code duplication!

Proper Staging of Let public static class Let implements Exp { // … public separable SValue eval(Env e, FEnv f) { SValue rhsVal = _rhs.eval (e, f); if (rhsVal instanceof SIntValue) { return new SCodeValue (<| let int temp = `(rhsVal.intCodeValue ()); `(_body.eval (ext (e, _var, new SIntValue( )), f).codeValue ())|>); } else if (rhsVal instanceof SBooleanValue) { //… } Loss of type information!

Demo: Code Duplication

Adding Loops and Mutable Arrays public static class ArrayValue extends Value { private Value[] _data; public ArrayValue(Value[] data) { _data = data; } public Value[] arrayValue() { return _data; } } public static class ASet implements Exp { public Exp _arr, _index, _val; public ASet(Exp arr, Exp index, Exp val) { _arr = arr; _index = index; _val = val; } public Value eval(Env e, FEnv f) { _arr.eval (e, f).arrayValue()[_index.eval (e, f).intValue()] = _val.eval (e, f); return new IntValue (0); }

Adding Loops and Mutable Arrays public static class For implements Exp { String _var; public Exp _bound, _body; public For(String var, Exp bound, Exp body) { _var = var; _bound = bound; _body = body; } public Value eval(Env e, FEnv f) { int bound = _bound.eval (e, f).intValue (); for (int i = 0; i < bound; ++i) { _body.eval (ext (e, _var, new IntValue (i)), f); } return new IntValue (0); }

Automatic Loop Parallelization for i = 0 to n-1 do B[i] = f(A[i]) for i = 0 to (n-1)/2 do B[i] = f(A[i]) for i = (n-1)/2 +1 to n-1 do B[i] = f(A[i])

Not That Easy… for i = 0 to n-1 do B[i] = f(B[i-1]) for i = 0 to (n-1)/2 do B[i] = f(B[i-1]) for i = (n-1)/2+1 to n-1 do B[i] = f(B[i-1]) Could set B[(n-1)/2 + 1] before B[(n-1)/2]! Could set B[(n-1)/2 + 1] before B[(n-1)/2]!

Embarrassingly Parallel Loops for i = 0 to n-1 do … = R[i] W[i] = … { Reads R } ∩ { Writes W } = ∅

public interface Exp { public separable Code eval(Env e, FEnv f); public separable RWSet rwSet (); } public class Int implements Exp { //… public RWSet rwSet () { return new RWSet (); } } public class Add implements Exp { //… public RWSet rwSet () { return _left.rwSet().union (_right.rwSet ()); } Implementation: rwSet Method

public class AGet implements Exp { //… public RWSet rwSet () { if (_arr instanceof Var) { return _index.rwSet().addR (((Var)_arr)._s); } else { return _index.rwSet().completeR (); } // similar for ASet Implementation: rwSet Method

Demo and Benchmarks: Automatic Loop Parallelization

Future Work: Monadic Staging Monads: powerful abstraction for interpreters – Hide “features” in monad – More modular, easier to add/change “features” abstract class M { X runMonad (Env e, FEnv f); static M ret (Y in); M bind (Fun > f); } interface Exp { M eval (); }

Future Work: Monadic Staging Idea: Staged Monads – Hide “staging-related features” – Modularity in staged interpreter – More information out of Let expressions…? abstract class SM { Code runMonad (Env e, FEnv f); // … } abstract class SMInt extends SM { Code runMonadInt (Env e, FEnv f); // … }

Conclusion MSP for DSL implementation – Agile: as simple as writing an interpreters – Efficient: performance of compiled code Many compiler optimizations Framework for implementing DSLs Available for download: