changeset 1872:38b5c364c630 8.0-b65

Automated merge with ssh://jpgodine@jfxsrc.us.oracle.com//javafx/8.0/MASTER/jfx//rt
author jpgodine@JPGODINE-LAP.st-users.us.oracle.com
date Tue, 13 Nov 2012 09:56:06 -0800
parents 952f2115ae99 5ca1d6e4604d
children 5047d4016211 6948b1cc29c5
files javafx-ui-common/src/com/sun/javafx/tk/DummyToolkit.java javafx-ui-common/src/com/sun/javafx/tk/Toolkit.java javafx-ui-common/src/javafx/scene/Scene.java javafx-ui-common/src/javafx/scene/text/Text.java test-stub-toolkit/src/com/sun/javafx/pgstub/StubToolkit.java
diffstat 138 files changed, 14505 insertions(+), 687 deletions(-) [+]
line wrap: on
line diff
--- a/.classpath	Fri Nov 09 23:27:23 2012 +0000
+++ b/.classpath	Tue Nov 13 09:56:06 2012 -0800
@@ -21,9 +21,12 @@
 	<classpathentry kind="src" path="javafx-ui-controls/build/builders"/>
 	<classpathentry kind="src" path="javafx-util-converter/src"/>
 	<classpathentry kind="src" path="javafx-util-converter/test"/>
+	<classpathentry kind="src" path="decora-compiler/build/gensrc"/>
+	<classpathentry kind="src" path="decora-compiler/src"/>
 	<classpathentry kind="src" path="test-stub-toolkit/src"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
+	<classpathentry kind="lib" path="../import/antlr-3.1.3/antlr-3.1.3/lib/antlr-3.1.3.jar"/>
 	<classpathentry kind="src" path="/rt-closed"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/.classpath	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="src" path="build/gensrc"/>
+	<classpathentry kind="src" path="test"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/antlr"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.USER_LIBRARY/junit"/>
+	<classpathentry kind="output" path="build/classes"/>
+</classpath>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/.project	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>decora-compiler</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/build.xml	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+  ~ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+  ~
+  ~ This code is free software; you can redistribute it and/or modify it
+  ~ under the terms of the GNU General Public License version 2 only, as
+  ~ published by the Free Software Foundation.  Oracle designates this
+  ~ particular file as subject to the "Classpath" exception as provided
+  ~ by Oracle in the LICENSE file that accompanied this code.
+  ~
+  ~ This code is distributed in the hope that it will be useful, but WITHOUT
+  ~ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  ~ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  ~ version 2 for more details (a copy is included in the LICENSE file that
+  ~ accompanied this code).
+  ~
+  ~ You should have received a copy of the GNU General Public License version
+  ~ 2 along with this work; if not, write to the Free Software Foundation,
+  ~ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+  ~
+  ~ Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+  ~ or visit www.oracle.com if you need additional information or have any
+  ~ questions.
+  -->
+
+<project name="decora-compiler" default="jar" basedir=".">
+  <description>Builds, tests, and runs the project decora-compiler.</description>
+
+  <import file="../build-defs.xml"/>
+
+  <property name="base.dir" value="${basedir}"/>
+
+  <property name="antlr.grammar.pkg" value="com/sun/scenario/effect/compiler"/>
+  <property name="antlr.grammar.file" value="${base.dir}/src/${antlr.grammar.pkg}/JSL.g"/>
+  <property name="antlr.generated.dir" value="${base.dir}/build/gensrc/${antlr.grammar.pkg}"/>
+
+  <target name="check-parser">
+    <uptodate property="parser.uptodate"
+              srcfile="${antlr.grammar.file}"
+              targetfile="${antlr.generated.dir}/JSLParser.java" />
+  </target>
+
+  <target name="compile-parser" depends="check-parser" unless="parser.uptodate">
+    <mkdir dir="${antlr.generated.dir}"/>
+    <java fork="yes" classname="org.antlr.Tool" classpath="${import.antlr.classpath}">
+      <arg value="-Xconversiontimeout"/>
+      <arg value="20000"/>
+      <arg value="-fo"/>
+      <arg value="${antlr.generated.dir}"/>
+      <arg value="-lib"/>
+      <arg value="${antlr.generated.dir}"/>
+      <arg value="${antlr.grammar.file}"/>
+    </java>
+  </target>
+
+  <target name="jar" depends="init,compile-parser">
+    <build-project>
+      <addedsrcdirs>
+        <pathelement location="build/gensrc"/>
+      </addedsrcdirs>
+      <addedsrcfiles>
+        <fileset dir="build/gensrc" excludes="${build.classes.excludes}"/>
+      </addedsrcfiles>
+    </build-project>
+  </target>
+
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/nbproject/project.xml	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.ant.freeform</type>
+    <configuration>
+        <general-data xmlns="http://www.netbeans.org/ns/freeform-project/1">
+            <!-- Do not use Project Properties customizer when editing this file manually. -->
+            <name>decora-compiler</name>
+            <properties>
+                <property-file>../base.properties</property-file>
+                <property-file>project.properties</property-file>
+                <property-file>../common.properties</property-file>
+            </properties>
+            <folders>
+                <source-folder>
+                    <label>Source Packages</label>
+                    <type>java</type>
+                    <location>${src.dir}</location>
+                </source-folder>
+                <source-folder>
+                    <label>Generated Sources</label>
+                    <type>java</type>
+                    <location>build/gensrc</location>
+                </source-folder>
+                <source-folder>
+                    <label>Test Packages</label>
+                    <type>java</type>
+                    <location>${test.dir}</location>
+                </source-folder>
+            </folders>
+            <ide-actions>
+                <action name="build">
+                    <target>jar</target>
+                </action>
+                <action name="clean">
+                    <target>clean</target>
+                </action>
+                <action name="test">
+                    <target>test</target>
+                </action>
+                <action name="rebuild">
+                    <target>clean</target>
+                    <target>jar</target>
+                </action>
+                <action name="run.single">
+                    <target>test-single</target>
+                    <context>
+                        <property>run.file</property>
+                        <folder>${test.dir}</folder>
+                        <pattern>\.java$</pattern>
+                        <format>relative-path</format>
+                        <arity>
+                            <one-file-only/>
+                        </arity>
+                    </context>
+                </action>
+                <action name="test.single">
+                    <target>test-single</target>
+                    <context>
+                        <property>run.file</property>
+                        <folder>${test.dir}</folder>
+                        <pattern>\.java$</pattern>
+                        <format>relative-path</format>
+                        <arity>
+                            <one-file-only/>
+                        </arity>
+                    </context>
+                </action>
+            </ide-actions>
+            <export>
+                <type>jar</type>
+                <location>dist/decora-compiler.jar</location>
+                <build-target>jar</build-target>
+            </export>
+            <export>
+                <type>jar</type>
+                <location>dist/decora-compiler.jar</location>
+                <build-target>jar</build-target>
+            </export>
+            <export>
+                <type>folder</type>
+                <location>${build.test.classes.dir}</location>
+                <build-target>jar</build-target>
+            </export>
+            <view>
+                <items>
+                    <source-folder style="packages">
+                        <label>Source Packages</label>
+                        <location>${src.dir}</location>
+                    </source-folder>
+                    <source-folder style="packages">
+                        <label>Generated Sources</label>
+                        <location>build/gensrc</location>
+                    </source-folder>
+                    <source-folder style="packages">
+                        <label>Test Packages</label>
+                        <location>${test.dir}</location>
+                    </source-folder>
+                    <source-file>
+                        <location>build.xml</location>
+                    </source-file>
+                </items>
+                <context-menu>
+                    <ide-action name="build"/>
+                    <ide-action name="rebuild"/>
+                    <ide-action name="clean"/>
+                    <ide-action name="test"/>
+                </context-menu>
+            </view>
+            <subprojects/>
+        </general-data>
+        <java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/2">
+            <compilation-unit>
+                <package-root>${src.dir}</package-root>
+                <classpath mode="compile">${javac.classpath}:${build.classes.dir}</classpath>
+                <built-to>dist/decora-compiler.jar</built-to>
+                <source-level>1.5</source-level>
+            </compilation-unit>
+            <compilation-unit>
+                <package-root>build/gensrc</package-root>
+                <classpath mode="compile">${javac.classpath}:${build.classes.dir}</classpath>
+                <built-to>dist/decora-compiler.jar</built-to>
+                <source-level>1.5</source-level>
+            </compilation-unit>
+            <compilation-unit>
+                <package-root>${test.dir}</package-root>
+                <unit-tests/>
+                <classpath mode="compile">${javac.test.classpath}</classpath>
+                <built-to>${build.test.classes.dir}</built-to>
+                <source-level>1.5</source-level>
+            </compilation-unit>
+        </java-data>
+    </configuration>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/project.properties	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,4 @@
+javac.classpath=\
+    ${runtime.deps.dir}/antlr277.jar:\
+    ${runtime.deps.dir}/antlr-runtime.jar:\
+    ${runtime.deps.dir}/stringtemplate.jar
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/JSL.g	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,662 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle  and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+grammar JSL;
+
+options {
+    backtrack=true;
+}
+
+tokens {
+    STAR  = '*'  ;
+    SLASH = '/'  ;
+    PLUS  = '+'  ;
+    DASH  = '-'  ;
+    LT    = '<'  ;
+    GT    = '>'  ;
+    LTEQ  = '<=' ;
+    GTEQ  = '>=' ;
+    EQEQ  = '==' ;
+    NEQ   = '!=' ;
+    AND   = '&&' ;
+    XOR   = '^^' ;
+    OR    = '||' ;
+    INC   = '++' ;
+    DEC   = '--' ;
+
+    STAREQ  = '*=' ;
+    SLASHEQ = '/=' ;
+    PLUSEQ  = '+=' ;
+    DASHEQ  = '-=' ;
+
+    LEFT_PAREN    = '(' ;
+    RIGHT_PAREN   = ')' ;
+    LEFT_BRACKET  = '[' ;
+    RIGHT_BRACKET = ']' ;
+    LEFT_BRACE    = '{' ;
+    RIGHT_BRACE   = '}' ;
+
+    LEFT_FRENCH   = '<<' ;
+    RIGHT_FRENCH  = '>>' ;
+
+    DOT           = '.' ;
+    COMMA         = ',' ;
+    EQUAL         = '=' ;
+    BANG          = '!' ;
+    TILDE         = '~' ;
+    QUESTION      = '?' ;
+    COLON         = ':' ;
+    SEMICOLON     = ';' ;
+
+    IF    = 'if'    ;
+    ELSE  = 'else'  ;
+    WHILE = 'while' ;
+    DO    = 'do'    ;
+    FOR   = 'for'   ;
+
+    UNROLL = 'unroll' ;
+
+    CONTINUE = 'continue' ;
+    BREAK    = 'break'    ;
+    DISCARD  = 'discard'  ;
+    RETURN   = 'return'   ;
+
+    VOID = 'void' ;
+}
+
+@header {
+    package com.sun.scenario.effect.compiler;
+
+    import com.sun.scenario.effect.compiler.model.*;
+    import com.sun.scenario.effect.compiler.tree.*;
+}
+
+@lexer::header {
+    package com.sun.scenario.effect.compiler;
+}
+
+@lexer::members {
+    // allow tests to turn on quiet mode, to reduce spewage
+    public static boolean quiet;
+
+    public void emitErrorMessage(String error) {
+        if (quiet) return;
+        super.emitErrorMessage(error);
+    }
+}
+
+@members {
+    private SymbolTable symbols = new SymbolTable();
+    private TreeMaker tm = new TreeMaker(symbols);
+
+    public SymbolTable getSymbolTable() {
+        return symbols;
+    }
+
+    // fail on first error for now
+    // TODO: collect errors and recover...
+    protected void mismatch(IntStream input, int tokenType, BitSet follow) throws RecognitionException {
+        MismatchedTokenException ex = new MismatchedTokenException(tokenType, input);
+        System.err.println("Token mismatch at " + ex.line + ":" + ex.charPositionInLine);
+        throw ex;
+    }
+    
+    public void recoverFromMismatchedSet(IntStream input, int ttype, BitSet follow)
+        throws RecognitionException {
+        throw new MissingTokenException(ttype, input, null);
+    }
+}
+
+@rulecatch {
+    catch (RecognitionException ex) {
+        throw ex;
+    }
+}
+
+field_selection returns [String fields]
+        : r=RGBA_FIELDS { $fields = $r.text; }
+        | x=XYZW_FIELDS { $fields = $x.text; }
+        ;
+
+primary_expression returns [Expr expr]
+        : IDENTIFIER    { $expr = tm.variable($IDENTIFIER.text); }
+        | INTCONSTANT   { $expr = tm.literal(Type.INT, Integer.valueOf($INTCONSTANT.text)); }
+        | FLOATCONSTANT { $expr = tm.literal(Type.FLOAT, Float.valueOf($FLOATCONSTANT.text)); }
+        | BOOLCONSTANT  { $expr = tm.literal(Type.BOOL, Boolean.valueOf($BOOLCONSTANT.text)); }
+        | LEFT_PAREN e=expression RIGHT_PAREN { $expr = tm.parenExpr($e.expr); }
+        ;
+
+primary_or_call returns [Expr expr]
+        : e=primary_expression { $expr = $e.expr; }
+        | f=function_call      { $expr = $f.expr; }
+        ;
+
+//
+// TODO: not sure how to do this properly without mutual left-recursion;
+// for now we hack it to allow:
+//   arr[3].rgb
+//   arr[3]
+//   val.rgb
+//   val++
+//   val--
+//   val
+// but not things like:
+//   arr[3].r++
+//
+postfix_expression returns [Expr expr]
+        : e=primary_or_call LEFT_BRACKET ae=expression RIGHT_BRACKET fs=field_selection
+              { $expr = tm.fieldSelect(tm.arrayAccess($e.expr, $ae.expr), $fs.fields); }
+        | e=primary_or_call LEFT_BRACKET ae=expression RIGHT_BRACKET
+              { $expr = tm.arrayAccess($e.expr, $ae.expr); }
+        | e=primary_or_call fs=field_selection
+              { $expr = tm.fieldSelect($e.expr, $fs.fields); }
+        | e=primary_or_call INC
+              { $expr = tm.unary(UnaryOpType.INC, $e.expr); }
+        | e=primary_or_call DEC
+              { $expr = tm.unary(UnaryOpType.DEC, $e.expr); }
+        | e=primary_or_call
+              { $expr = $e.expr; }
+        ;
+
+// From the GLSL spec...
+// Grammar Note: Constructors look like functions, but lexical
+// analysis recognized most of them as keywords.  They are now
+// recognized through "type_specifier".
+
+function_call returns [Expr expr]
+        : id=IDENTIFIER LEFT_PAREN p=function_call_parameter_list? RIGHT_PAREN
+            {
+                $expr = tm.call($id.text, p!=null ? $p.exprList : null);
+            }
+        | ts=type_specifier LEFT_PAREN p=function_call_parameter_list? RIGHT_PAREN
+            {
+                Type type = Type.fromToken($ts.text);
+                $expr = tm.vectorCtor(type, p!=null ? $p.exprList : null);
+            }
+        ;
+        
+function_call_parameter_list returns [List<Expr> exprList = new ArrayList<Expr>()]
+        : a=assignment_expression { $exprList.add($a.expr); }
+          (COMMA a=assignment_expression {$exprList.add($a.expr); }
+          )*
+        ;
+        
+unary_expression returns [Expr expr]
+        : p=postfix_expression     { $expr = $p.expr; }
+        | INC   u=unary_expression { $expr = tm.unary(UnaryOpType.INC,     $u.expr); }
+        | DEC   u=unary_expression { $expr = tm.unary(UnaryOpType.DEC,     $u.expr); }
+        | PLUS  u=unary_expression { $expr = tm.unary(UnaryOpType.PLUS,    $u.expr); }
+        | DASH  u=unary_expression { $expr = tm.unary(UnaryOpType.MINUS,   $u.expr); }
+        | BANG  u=unary_expression { $expr = tm.unary(UnaryOpType.NOT,     $u.expr); }
+        ;
+
+// From the GLSL spec...
+// Grammar Note:  No traditional style type casts.
+
+// From the GLSL spec...
+// Grammar Note:  No '*' or '&' unary ops.  Pointers are not supported.
+
+multiplicative_expression returns [Expr expr]
+        : a=unary_expression { $expr = $a.expr; }
+          (STAR  b=multiplicative_expression { $expr = tm.binary(BinaryOpType.MUL, $expr, $b.expr); }
+          |SLASH b=multiplicative_expression { $expr = tm.binary(BinaryOpType.DIV, $expr, $b.expr); }
+          )*
+        ;
+        
+additive_expression returns [Expr expr]
+        : a=multiplicative_expression { $expr = $a.expr; }
+          (PLUS b=multiplicative_expression { $expr = tm.binary(BinaryOpType.ADD, $expr, $b.expr); }
+          |DASH b=multiplicative_expression { $expr = tm.binary(BinaryOpType.SUB, $expr, $b.expr); }
+          )*
+        ;
+
+relational_expression returns [Expr expr]
+        : a=additive_expression { $expr = $a.expr; }
+          (LTEQ b=additive_expression { $expr = tm.binary(BinaryOpType.LTEQ, $expr, $b.expr); }
+          |GTEQ b=additive_expression { $expr = tm.binary(BinaryOpType.GTEQ, $expr, $b.expr); }
+          |LT   b=additive_expression { $expr = tm.binary(BinaryOpType.LT,   $expr, $b.expr); }
+          |GT   b=additive_expression { $expr = tm.binary(BinaryOpType.GT,   $expr, $b.expr); }
+          )*
+        ;
+
+equality_expression returns [Expr expr]
+        : a=relational_expression { $expr = $a.expr; }
+          (EQEQ b=relational_expression { $expr = tm.binary(BinaryOpType.EQEQ, $expr, $b.expr); }
+          | NEQ b=relational_expression { $expr = tm.binary(BinaryOpType.NEQ,  $expr, $b.expr); }
+          )*
+        ;
+        
+logical_and_expression returns [Expr expr]
+        : a=equality_expression { $expr = $a.expr; }
+          (AND b=equality_expression { $expr = tm.binary(BinaryOpType.AND, $expr, $b.expr); }
+          )*
+        ;
+        
+logical_xor_expression returns [Expr expr]
+        : a=logical_and_expression { $expr = $a.expr; }
+          (XOR b=logical_and_expression { $expr = tm.binary(BinaryOpType.XOR, $expr, $b.expr); }
+          )*
+        ;
+        
+logical_or_expression returns [Expr expr]
+        : a=logical_xor_expression { $expr = $a.expr; }
+          (OR b=logical_xor_expression { $expr = tm.binary(BinaryOpType.OR, $expr, $b.expr); }
+          )*
+        ;
+        
+ternary_part
+        : QUESTION expression COLON assignment_expression
+        ;
+
+// TODO: handle ternary
+conditional_expression returns [Expr expr]
+        : a=logical_or_expression ternary_part? { $expr = $a.expr; }
+        ;
+
+assignment_expression returns [Expr expr]
+        : a=unary_expression op=assignment_operator b=assignment_expression
+              { $expr = tm.binary(BinaryOpType.forSymbol($op.text), $a.expr, $b.expr); }
+        | c=conditional_expression
+              { $expr = $c.expr; }
+        ;
+
+assignment_operator
+        : EQUAL
+        | STAREQ
+        | SLASHEQ
+        | PLUSEQ
+        | DASHEQ
+        ;
+
+// TODO: handle expression lists?
+//expression returns [List<Expr> exprList = new ArrayList<Expr>()]
+//        : e=assignment_expression { $exprList.add($e.expr); }
+//          (COMMA e=assignment_expression { $exprList.add($e.expr); })*
+//        ;
+
+expression returns [Expr expr]
+        : e=assignment_expression { $expr = $e.expr; }
+        ;
+
+function_prototype returns [Function func]
+        : t=type_specifier id=IDENTIFIER LEFT_PAREN p=parameter_declaration_list? RIGHT_PAREN
+            {
+                Type type = Type.fromToken($t.text);
+                $func = symbols.declareFunction($id.text, type, (p != null) ? $p.paramList : null);
+            }
+        ;
+        
+parameter_declaration returns [Param param]
+        : t=type_specifier id=IDENTIFIER
+            {
+                Type type = Type.fromToken($t.text);
+                $param = new Param($id.text, type);
+            }
+        ;
+
+parameter_declaration_list returns [List<Param> paramList = new ArrayList<Param>()]
+        : p=parameter_declaration { $paramList.add($p.param); }
+          (COMMA p=parameter_declaration { $paramList.add($p.param); } )*
+        ;
+        
+declaration_identifier_and_init returns [String name, Expr arrayInit, Expr init]
+        : id=IDENTIFIER { $name = $id.text; }
+          (LEFT_BRACKET ae=constant_expression { $arrayInit = $ae.expr; } RIGHT_BRACKET)?
+          (EQUAL e=initializer { $init = $e.expr; })?
+        ;
+
+single_declaration returns [VarDecl decl]
+        : t=fully_specified_type d=declaration_identifier_and_init
+          {
+              int arraySize = -1;
+              Expr ainit = $d.arrayInit;
+              if (ainit != null) {
+                  if (ainit instanceof LiteralExpr) {
+                      Object val = ((LiteralExpr)ainit).getValue();
+                      if (!(val instanceof Integer)) {
+                          throw new RuntimeException("Array size must be an integer");
+                      }
+                      arraySize = ((Integer)val).intValue();
+                  } else if (ainit instanceof VariableExpr) {
+                      Variable var = ((VariableExpr)ainit).getVariable();
+                      Object val = var.getConstValue();
+                      if (!(val instanceof Integer) || var.getQualifier() != Qualifier.CONST) {
+                          throw new RuntimeException("Array size must be a constant integer");
+                      }
+                      arraySize = ((Integer)val).intValue();
+                  }
+              }
+
+              Object constValue = null;
+              if ($t.qual == Qualifier.CONST) {
+                  Expr cinit = $d.init;
+                  if (cinit == null) {
+                      throw new RuntimeException("Constant value must be initialized");
+                  }
+                  // TODO: for now, allow some basic expressions on the rhs
+                  // of the constant declaration...
+                  //if (!(cinit instanceof LiteralExpr)) {
+                  //    throw new RuntimeException("Constant initializer must be a literal (for now)");
+                  //}
+                  Type ctype = cinit.getResultType();
+                  if (ctype != $t.type) {
+                      throw new RuntimeException("Constant type must match that of initializer");
+                  }
+                  if (cinit instanceof LiteralExpr) {
+                      constValue = ((LiteralExpr)cinit).getValue();
+                  } else {
+                      // TODO: This is gross, but to support complex constant
+                      // initializers (such as "const FOO = BAR / 42.0;") we
+                      // will just save the full text of the rhs and hope that
+                      // the backend does the right thing with it.  The real
+                      // solution obviously would be to evaluate the expression
+                      // now and reduce it to a single value.
+                      constValue = $d.init.toString();
+                  }
+              }
+
+              Variable var =
+                  symbols.declareVariable($d.name,
+                                          $t.type, $t.qual, $t.precision,
+                                          arraySize, constValue);
+              $decl = tm.varDecl(var, $d.init);
+          }
+        ;
+        
+declaration returns [List<VarDecl> declList = new ArrayList<VarDecl>()]
+        : s=single_declaration { $declList.add($s.decl); }
+          (COMMA d=declaration_identifier_and_init
+          {
+              Variable base = $s.decl.getVariable();
+              Variable var =
+                  symbols.declareVariable($d.name,
+                                          base.getType(),
+                                          base.getQualifier(),
+                                          base.getPrecision());
+              $declList.add(tm.varDecl(var, $d.init));
+          }
+          )* SEMICOLON
+        ;
+        
+// From GLSL spec...
+// Grammar Note:  No 'enum', or 'typedef'. 
+
+fully_specified_type returns [Qualifier qual, Precision precision, Type type]
+        : tq=type_qualifier tp=type_precision ts=type_specifier
+            {
+                $qual = Qualifier.fromToken($tq.text);
+                $precision = Precision.fromToken($tp.text);
+                $type = Type.fromToken($ts.text);
+            }
+        | tq=type_qualifier ts=type_specifier
+            {
+                $qual = Qualifier.fromToken($tq.text);
+                $type = Type.fromToken($ts.text);
+            }
+        | tp=type_precision ts=type_specifier
+            {
+                $precision = Precision.fromToken($tp.text);
+                $type = Type.fromToken($ts.text);
+            }
+        | ts=type_specifier
+            {
+                $type = Type.fromToken($ts.text);
+            }
+        ;
+        
+type_qualifier
+        : 'const'
+        | 'param'
+        ;
+
+type_precision
+        : 'lowp'
+        | 'mediump'
+        | 'highp'
+        ;
+        
+type_specifier
+        : type_specifier_nonarray array_brackets?
+        ;
+        
+array_brackets
+        : LEFT_BRACKET constant_expression RIGHT_BRACKET
+        ;
+       
+type_specifier_nonarray
+        : TYPE
+        | VOID
+        ;
+        
+initializer returns [Expr expr]
+        : e=assignment_expression { $expr = $e.expr; }
+        ;
+        
+declaration_statement returns [Stmt stmt]
+        : d=declaration { $stmt = tm.declStmt($d.declList); }
+        ;
+        
+statement returns [Stmt stmt]
+        : c=compound_statement { $stmt = $c.stmt; }
+        | s=simple_statement   { $stmt = $s.stmt; }
+        ;
+
+// From GLSL spec...
+// Grammar Note:  No labeled statements; 'goto' is not supported. 
+
+simple_statement returns [Stmt stmt]
+        : d=declaration_statement { $stmt = $d.stmt; }
+        | e=expression_statement  { $stmt = $e.stmt; }
+        | s=selection_statement   { $stmt = $s.stmt; }
+        | i=iteration_statement   { $stmt = $i.stmt; }
+        | j=jump_statement        { $stmt = $j.stmt; }
+        ;
+        
+compound_statement returns [Stmt stmt]
+@init {
+    List<Stmt> stmtList = new ArrayList<Stmt>();
+}
+        : LEFT_BRACE (s=statement { stmtList.add($s.stmt); })* RIGHT_BRACE
+          { $stmt = tm.compoundStmt(stmtList); }
+        ;
+        
+statement_no_new_scope returns [Stmt stmt]
+        : c=compound_statement_no_new_scope { $stmt = $c.stmt; }
+        | s=simple_statement                { $stmt = $s.stmt; }
+        ;
+        
+compound_statement_no_new_scope returns [Stmt stmt]
+@init {
+    List<Stmt> stmtList = new ArrayList<Stmt>();
+}
+        : LEFT_BRACE (s=statement { stmtList.add($s.stmt); })* RIGHT_BRACE
+          { $stmt = tm.compoundStmt(stmtList); }
+        ;
+        
+expression_statement returns [Stmt stmt]
+        : SEMICOLON              { $stmt = tm.exprStmt(null); }
+        | e=expression SEMICOLON { $stmt = tm.exprStmt($e.expr); }
+        ;
+        
+constant_expression returns [Expr expr]
+        : c=conditional_expression { $expr = $c.expr; }
+        ;
+
+selection_statement returns [Stmt stmt]
+        : IF LEFT_PAREN e=expression RIGHT_PAREN a=statement (ELSE b=statement)?
+              { $stmt = tm.selectStmt($e.expr, $a.stmt, (b != null) ? $b.stmt : null); }
+        ;
+
+// TODO: implement second half?
+condition returns [Expr expr]
+        : e=expression {$expr = $e.expr; }
+//        | fully_specified_type IDENTIFIER EQUAL initializer
+        ;
+
+iteration_statement returns [Stmt stmt]
+        : WHILE LEFT_PAREN c=condition RIGHT_PAREN snns=statement_no_new_scope
+              { $stmt = tm.whileStmt($c.expr, $snns.stmt); }
+        | DO s=statement WHILE LEFT_PAREN e=expression RIGHT_PAREN SEMICOLON
+              { $stmt = tm.doWhileStmt($s.stmt, $e.expr); }
+        | u=unroll_modifier FOR LEFT_PAREN init=for_init_statement rem=for_rest_statement RIGHT_PAREN snns=statement_no_new_scope
+              { $stmt = tm.forStmt($init.stmt, $rem.cond, $rem.expr, $snns.stmt, $u.max, $u.check); }
+        | FOR LEFT_PAREN init=for_init_statement rem=for_rest_statement RIGHT_PAREN snns=statement_no_new_scope
+              { $stmt = tm.forStmt($init.stmt, $rem.cond, $rem.expr, $snns.stmt, -1, -1); }
+        ;
+
+unroll_modifier returns [int max, int check]
+        : UNROLL LEFT_PAREN m=INTCONSTANT COMMA c=INTCONSTANT RIGHT_PAREN
+              { $max = Integer.valueOf($m.text); $check = Integer.valueOf($c.text); }
+        ;
+
+for_init_statement returns [Stmt stmt]
+        : e=expression_statement  { $stmt = $e.stmt; }
+        | d=declaration_statement { $stmt = $d.stmt; }
+        ;
+        
+for_rest_statement returns [Expr cond, Expr expr]
+        : c=condition SEMICOLON e=expression? { $cond = $c.expr; if (e != null) $expr = $e.expr; }
+        | SEMICOLON e=expression? { if (e != null) $expr = $e.expr; }
+        ;
+        
+jump_statement returns [Stmt stmt]
+        : CONTINUE SEMICOLON            { $stmt = tm.continueStmt(); }
+        | BREAK SEMICOLON               { $stmt = tm.breakStmt(); }
+        | DISCARD SEMICOLON             { $stmt = tm.discardStmt(); }
+        | RETURN SEMICOLON              { $stmt = tm.returnStmt(null); }
+        | RETURN e=expression SEMICOLON { $stmt = tm.returnStmt($e.expr); }
+        ;
+        
+// From GLSL spec...
+// Grammar Note:  No 'goto'.  Gotos are not supported. 
+
+translation_unit returns [ProgramUnit prog]
+@init {
+    List<ExtDecl> declList = new ArrayList<ExtDecl>();
+}
+        : (e=external_declaration { declList.addAll($e.res); } )+
+            { $prog = tm.programUnit(declList); }
+        ;
+        
+external_declaration returns [List<ExtDecl> res = new ArrayList<ExtDecl>()]
+        : f=function_definition { $res.add($f.def); }
+        | d=declaration         { $res.addAll($d.declList); }
+        | g=glue_block          { $res.add($g.block); }
+        ;
+
+// From GLSL spec...
+// Grammar Note:  No 'switch'.  Switch statements not supported. 
+
+function_definition returns [FuncDef def]
+@init {
+	symbols.enterFrame();
+}
+        : p=function_prototype s=compound_statement_no_new_scope { $def = tm.funcDef($p.func, $s.stmt); }
+        ;
+finally {
+        symbols.exitFrame();
+}
+
+glue_block returns [GlueBlock block]
+        : g=GLUE_BLOCK { $block = tm.glueBlock($g.text.substring(2, $g.text.length()-2)); }
+        ;
+
+TYPE
+        : 'float2'
+        | 'float3'
+        | 'float4'
+        | 'float'
+        | 'int2'
+        | 'int3'
+        | 'int4'
+        | 'int'
+        | 'bool2'
+        | 'bool3'
+        | 'bool4'
+        | 'bool'
+        | 'sampler'
+        | 'lsampler'
+        | 'fsampler'
+        ;
+
+BOOLCONSTANT
+        : 'true'
+        | 'false'
+        ;
+
+RGBA_FIELDS
+        : DOT RFIELD RFIELD RFIELD RFIELD
+        | DOT RFIELD RFIELD RFIELD
+        | DOT RFIELD RFIELD
+        | DOT RFIELD
+        ;
+
+fragment
+RFIELD   : 'r' | 'g' | 'b' | 'a' ;
+
+XYZW_FIELDS
+        : DOT XFIELD XFIELD XFIELD XFIELD
+        | DOT XFIELD XFIELD XFIELD
+        | DOT XFIELD XFIELD
+        | DOT XFIELD
+        ;
+
+fragment
+XFIELD   : 'x' | 'y' | 'z' | 'w' ;
+
+IDENTIFIER
+        : LETTER (LETTER|DIGIT)*
+        ;
+
+fragment
+LETTER
+        : '$'
+        | 'A'..'Z'
+        | 'a'..'z'
+        | '_'
+        ;
+
+INTCONSTANT : ('0' | '1'..'9' DIGIT*) ;
+
+FLOATCONSTANT
+        : DIGIT+ '.' DIGIT*
+        |  '.' DIGIT+
+	;
+
+fragment
+DIGIT   : '0'..'9' ;
+
+WS  :  (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;}
+    ;
+
+COMMENT
+    :   '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;}
+    ;
+
+LINE_COMMENT
+    : '//' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;}
+    ;
+
+GLUE_BLOCK
+    : LEFT_FRENCH .* RIGHT_FRENCH
+    ;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/JSLC.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,480 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import com.sun.scenario.effect.compiler.backend.hw.ES2Backend;
+import com.sun.scenario.effect.compiler.backend.hw.HLSLBackend;
+import com.sun.scenario.effect.compiler.backend.prism.PrismBackend;
+import com.sun.scenario.effect.compiler.backend.sw.java.JSWBackend;
+import com.sun.scenario.effect.compiler.backend.sw.me.MEBackend;
+import com.sun.scenario.effect.compiler.backend.sw.sse.SSEBackend;
+import com.sun.scenario.effect.compiler.tree.ProgramUnit;
+import org.antlr.runtime.ANTLRInputStream;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.stringtemplate.CommonGroupLoader;
+import org.antlr.stringtemplate.StringTemplateGroup;
+
+/**
+ */
+public class JSLC {
+
+    public static final int OUT_NONE     = (0 << 0);
+    public static final int OUT_D3D      = (1 << 0);
+    public static final int OUT_ES2      = (1 << 1);
+    public static final int OUT_JAVA     = (1 << 2);
+    public static final int OUT_PRISM    = (1 << 3);
+
+    public static final int OUT_SSE_JAVA        = (1 << 4);
+    public static final int OUT_SSE_NATIVE      = (1 << 5);
+    public static final int OUT_ME_JAVA         = (1 << 6);
+    public static final int OUT_ME_NATIVE       = (1 << 7);
+
+    public static final int OUT_ME       = OUT_ME_JAVA | OUT_ME_NATIVE;
+    public static final int OUT_SSE      = OUT_SSE_JAVA | OUT_SSE_NATIVE;
+
+    public static final int OUT_SW_PEERS   = OUT_JAVA | OUT_SSE;
+    public static final int OUT_HW_PEERS   = OUT_PRISM;
+    public static final int OUT_HW_SHADERS = OUT_D3D | OUT_ES2;
+    public static final int OUT_ALL        = OUT_SW_PEERS | OUT_HW_PEERS | OUT_HW_SHADERS;
+
+    private static final String rootPkg = "com/sun/scenario/effect";
+    
+    static {
+        CommonGroupLoader loader = new CommonGroupLoader(rootPkg + "/compiler/backend", null);
+        StringTemplateGroup.registerGroupLoader(loader);
+    }
+
+    public static class OutInfo {
+        public String basePath;
+        public String filePrefix;
+        public String fileSuffix;
+    }
+
+    public static class ParserInfo {
+        public JSLParser parser;
+        public ProgramUnit program;
+
+        public ParserInfo(JSLParser parser, ProgramUnit program) {
+            this.parser = parser;
+            this.program = program;
+        }
+    }
+
+    public static ParserInfo getParserInfo(String source) throws Exception {
+        return getParserInfo(new ByteArrayInputStream(source.getBytes()));
+    }
+
+    public static ParserInfo getParserInfo(InputStream stream) throws Exception {
+        JSLParser parser = parse(stream);
+        ProgramUnit program = parser.translation_unit();
+        return new ParserInfo(parser, program);
+    }
+
+    /**
+     * If userRootDir is provided by the user, then we will output all files
+     * under that directory, for example if rootDir=/foo/bar:
+     *   /foo/bar/ + rootPkg + /impl/sw/java
+     *   /foo/bar/ + rootPkg + /impl/sw/sse
+     *   /foo/bar/ + rootPkg + /impl/sw/me
+     *   /foo/bar/ + rootPkg + /impl/hw/d3d/hlsl
+     *   /foo/bar/ + rootPkg + /impl/es2/glsl
+     *   /foo/bar/ + rootPkg + /impl/prism/ps
+     * 
+     * Otherwise, we use the layout currently expected by decora-runtime
+     * for core effects:
+     *   ../decora-jsw/build/gensrc/     + rootPkg + /impl/sw/java
+     *   ../decora-sse/build/gensrc/     + rootPkg + /impl/sw/sse
+     *   ../decora-me/build/gensrc/      + rootPkg + /impl/sw/me
+     *   ../decora-d3d/build/gensrc/     + rootPkg + /impl/hw/d3d/hlsl
+     *   ../decora-es2/build/gensrc/     + rootPkg + /impl/es2/glsl
+     *   ../decora-prism-ps/build/gensrc/+ rootPkg + /impl/prism/ps
+     */
+    private static Map<Integer, String> initDefaultInfoMap() {
+        Map<Integer, String> infoMap = new HashMap<Integer, String>();
+        infoMap.put(OUT_D3D,        "decora-d3d/build/gensrc/{pkg}/impl/hw/d3d/hlsl/{name}.hlsl");
+        infoMap.put(OUT_ES2,        "decora-es2/build/gensrc/{pkg}/impl/es2/glsl/{name}.frag");
+        infoMap.put(OUT_JAVA,       "decora-jsw/build/gensrc/{pkg}/impl/sw/java/JSW{name}Peer.java");
+        infoMap.put(OUT_PRISM,      "decora-prism-ps/build/gensrc/{pkg}/impl/prism/ps/PPS{name}Peer.java");
+        infoMap.put(OUT_SSE_JAVA,   "decora-sse/build/gensrc/{pkg}/impl/sw/sse/SSE{name}Peer.java");
+        infoMap.put(OUT_ME_JAVA,    "decora-me/build/gensrc/{pkg}/impl/sw/me/ME{name}Peer.java");
+        infoMap.put(OUT_SSE_NATIVE, "decora-sse-native/build/gensrc/SSE{name}Peer.cc");
+        infoMap.put(OUT_ME_NATIVE,  "decora-me-native/build/gensrc/ME{name}Peer.cc");
+        return infoMap;
+    }
+
+    public static ParserInfo compile(JSLCInfo jslcinfo,
+                                     String str,
+                                     long sourceTime)
+        throws Exception
+    {
+        return compile(jslcinfo,
+                       new ByteArrayInputStream(str.getBytes()), sourceTime);
+    }
+
+    public static ParserInfo compile(JSLCInfo jslcinfo, File file)
+        throws Exception
+    {
+        return compile(jslcinfo, new FileInputStream(file), file.lastModified());
+    }
+
+    public static JSLParser parse(String str)
+        throws Exception
+    {
+        return parse(new ByteArrayInputStream(str.getBytes()));
+    }
+
+    private static JSLParser parse(InputStream stream)
+        throws Exception
+    {
+        // Read input
+        ANTLRInputStream input = new ANTLRInputStream(stream);
+
+        // Lexer
+        JSLLexer lexer = new JSLLexer(input);
+        CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+        // Parser and AST construction
+        return new JSLParser(tokens);
+    }
+
+    private static ParserInfo compile(JSLCInfo jslcinfo,
+                                      InputStream stream,
+                                      long sourceTime)
+        throws Exception
+    {
+        return compile(jslcinfo, stream, sourceTime, null);
+    }
+
+    private static ParserInfo compile(JSLCInfo jslcinfo,
+                                      InputStream stream,
+                                      long sourceTime,
+                                      ParserInfo pinfo)
+        throws Exception
+    {
+        int outTypes = jslcinfo.outTypes;
+        String interfaceName = jslcinfo.interfaceName;
+        String peerName = jslcinfo.peerName;
+        String shaderName = jslcinfo.shaderName;
+        if (peerName == null) peerName = shaderName;
+
+        // Compiler
+        if ((outTypes & OUT_D3D) != 0) {
+            File outFile = jslcinfo.getOutputFile(OUT_D3D);
+            if (jslcinfo.force || outOfDate(outFile, sourceTime)) {
+                if (pinfo == null) pinfo = getParserInfo(stream);
+                HLSLBackend hlslBackend = new HLSLBackend(pinfo.parser, pinfo.program);
+                write(hlslBackend.getShader(), outFile);
+            }
+        }
+
+        if ((outTypes & OUT_ES2) != 0) {
+            File outFile = jslcinfo.getOutputFile(OUT_ES2);
+            if (jslcinfo.force || outOfDate(outFile, sourceTime)) {
+                if (pinfo == null) pinfo = getParserInfo(stream);
+                ES2Backend es2Backend = new ES2Backend(pinfo.parser, pinfo.program);
+                write(es2Backend.getShader(), outFile);
+            }
+        }
+
+        if ((outTypes & OUT_JAVA) != 0) {
+            File outFile = jslcinfo.getOutputFile(OUT_JAVA);
+            if (jslcinfo.force || outOfDate(outFile, sourceTime)) {
+                if (pinfo == null) pinfo = getParserInfo(stream);
+                JSWBackend javaBackend = new JSWBackend(pinfo.parser, pinfo.program);
+                String genCode = javaBackend.getGenCode(shaderName, peerName, interfaceName);
+                write(genCode, outFile);
+            }
+        }
+        
+        if ((outTypes & OUT_SSE) != 0) {
+            File outFile = jslcinfo.getOutputFile(OUT_SSE_JAVA);
+            // TODO: native code is always generated into the same
+            // destination directory for now; need to make this more flexible
+            File genCFile = jslcinfo.getOutputFile(OUT_SSE_NATIVE);
+
+            boolean outFileStale = outOfDate(outFile, sourceTime);
+            boolean genCFileStale = outOfDate(genCFile, sourceTime);
+            if (jslcinfo.force || outFileStale || genCFileStale) {
+                if (pinfo == null) pinfo = getParserInfo(stream);
+                SSEBackend sseBackend = new SSEBackend(pinfo.parser, pinfo.program);
+                SSEBackend.GenCode gen =
+                    sseBackend.getGenCode(shaderName, peerName, interfaceName);
+
+                // write impl class
+                if (outFileStale) {
+                    write(gen.javaCode, outFile);
+                }
+
+                // write impl native code
+                if (genCFileStale) {
+                    write(gen.nativeCode, genCFile);
+                }
+            }
+        }
+        
+        if ((outTypes & OUT_ME) != 0) {
+            File outFile = jslcinfo.getOutputFile(OUT_ME_JAVA);
+            // TODO: native code is always generated into the same
+            // destination directory for now; need to make this more flexible
+            File genCFile = jslcinfo.getOutputFile(OUT_ME_NATIVE);
+
+            boolean outFileStale = outOfDate(outFile, sourceTime);
+            boolean genCFileStale = outOfDate(genCFile, sourceTime);
+            if (jslcinfo.force || outFileStale || genCFileStale) {
+                if (pinfo == null) pinfo = getParserInfo(stream);
+                MEBackend sseBackend = new MEBackend(pinfo.parser, pinfo.program);
+                MEBackend.GenCode gen =
+                    sseBackend.getGenCode(shaderName, peerName, interfaceName);
+
+                // write impl class
+                if (outFileStale) {
+                    write(gen.javaCode, outFile);
+                }
+
+                // write impl native code
+                if (genCFileStale) {
+                    write(gen.nativeCode, genCFile);
+                }
+            }
+        }
+        
+        if ((outTypes & OUT_PRISM) != 0) {
+            File outFile = jslcinfo.getOutputFile(OUT_PRISM);
+            if (jslcinfo.force || outOfDate(outFile, sourceTime)) {
+                if (pinfo == null) pinfo = getParserInfo(stream);
+                PrismBackend prismBackend = new PrismBackend(pinfo.parser, pinfo.program);
+                String genCode = prismBackend.getGlueCode(shaderName, peerName, interfaceName);
+                write(genCode, outFile);
+            }
+        }
+
+        return pinfo;
+    }
+
+    public static boolean outOfDate(File outFile, long sourceTime) {
+        if (sourceTime < outFile.lastModified()) {
+            return false;
+        }
+        return true;
+    }
+
+    public static void write(String str, File outFile) throws Exception {
+        File outDir = outFile.getParentFile();
+        if (!outDir.exists()) {
+            outDir.mkdirs();
+        }
+        FileWriter fw = null;
+        try {
+            fw = new FileWriter(outFile);
+            fw.write(str);
+            fw.flush();
+        } finally {
+            if (fw != null) {
+                fw.close();
+            }
+        }
+    }
+
+    public static class JSLCInfo {
+        public int outTypes;
+        public boolean force;
+        public String outDir;
+        public List<String> srcDirs = new ArrayList<String>();
+        public String shaderName;
+        public String peerName;
+        public String interfaceName;
+        public String pkgName = rootPkg;
+        public Map<Integer, String> outNameMap = initDefaultInfoMap();
+
+        private String extraOpts;
+
+        public JSLCInfo() {
+        }
+
+        public JSLCInfo(String extraOpts) {
+            this.extraOpts = extraOpts;
+        }
+
+        public void usage(PrintStream out) {
+            StackTraceElement callers[] = Thread.currentThread().getStackTrace();
+            String prog = callers[callers.length - 1].getClassName();
+            String prefix0 = "Usage: java "+prog+" ";
+            String prefix1 = "";
+            for (int i = 0; i < prefix0.length(); i++) prefix1 += " ";
+            out.println(prefix0+"[-d3d | -es2 | -java | -sse | -me | -sw | -hw | -all]");
+            out.println(prefix1+"[-o <outdir>] [-i <srcdir>]");
+            out.println(prefix1+"[-name <name>] [-ifname <interface name>]");
+            if (extraOpts != null) {
+                out.println(prefix1+extraOpts);
+            }
+        }
+
+        public void error(String error) {
+            System.err.println(error);
+            usage(System.err);
+            System.exit(1);
+        }
+
+        public void parseAllArgs(String args[]) {
+            int index = parseArgs(args);
+            if (index != args.length) {
+                error("unrecognized argument: "+args[index]);
+            }
+        }
+
+        public int parseArgs(String args[]) {
+            int i = 0;
+            while (i < args.length) {
+                int consumed = parseArg(args, i);
+                if (consumed < 0) {
+                    usage(System.err);
+                    System.exit(1);
+                } else if (consumed == 0) {
+                    break;
+                }
+                i += consumed;
+            }
+            return i;
+        }
+
+        public int parseArg(String args[], int index) {
+            String arg = args[index++];
+            if (arg.equals("-force")) {
+                force = true;
+            } else if (arg.equals("-d3d")) {
+                outTypes |= OUT_D3D;
+            } else if (arg.equals("-es2")) {
+                outTypes |= OUT_ES2;
+            } else if (arg.equals("-java")) {
+                outTypes |= OUT_JAVA;
+            } else if (arg.equals("-sse")) {
+                outTypes |= OUT_SSE;
+            } else if (arg.equals("-me")) {
+                outTypes |= OUT_ME;
+            } else if (arg.equals("-sw")) {
+                outTypes = OUT_SW_PEERS;
+            } else if (arg.equals("-hw")) {
+                outTypes = OUT_HW_PEERS | OUT_HW_SHADERS;
+            } else if (arg.equals("-all")) {
+                outTypes = OUT_ALL;
+            } else if (arg.equals("-help")) {
+                usage(System.out);
+                System.exit(0);
+            } else {
+                try {
+                    // options with 1 argument
+                    if (arg.equals("-o")) {
+                        outDir = args[index];
+                    } else if (arg.equals("-i")) {
+                        srcDirs.add(args[index]);
+                    } else if (arg.equals("-name")) {
+                        shaderName = args[index];
+                    } else if (arg.equals("-ifname")) {
+                        interfaceName = args[index];
+                    } else if (arg.equals("-pkg")) {
+                        pkgName = args[index];
+                    } else {
+                        return 0;
+                    }
+                } catch (ArrayIndexOutOfBoundsException e) {
+                    return -1;
+                }
+                return 2;
+            }
+            return 1;
+        }
+
+        public File getJSLFile() {
+            return getJSLFile(shaderName);
+        }
+
+        public File getJSLFile(String jslBaseName) {
+            return getInputFile(jslBaseName + ".jsl");
+        }
+
+        public File getInputFile(String filename) {
+            if (srcDirs.isEmpty()) {
+                File f = new File(filename);
+                if (f.exists()) {
+                    return f;
+                }
+            } else {
+                for (String dir : srcDirs) {
+                    File f = new File(dir, filename);
+                    if (f.exists()) {
+                        return f;
+                    }
+                }
+            }
+
+            error("Input file not found: "+filename);
+            // NOTREACHED
+            return null;
+        }
+
+        public File getOutputFile(String outName) {
+            String name = peerName;
+            if (name == null) name = shaderName;
+
+            outName = outName.replace("{pkg}", pkgName);
+            outName = outName.replace("{name}", peerName == null ? shaderName : peerName);
+            return outDir == null ? new File(outName) : new File(outDir, outName);
+        }
+
+        public File getOutputFile(int outType) {
+            return getOutputFile(outNameMap.get(outType));
+        }
+    }
+
+    public static void main(String[] args) throws Exception {
+        JSLCInfo jslcinfo = new JSLCInfo("<inputfile>");
+        int index = jslcinfo.parseArgs(args);
+
+        if (index != args.length - 1) {
+            jslcinfo.error("Must specify one input file");
+        }
+        String arg = args[index];
+        if (!arg.endsWith(".jsl") || arg.length() < 5) {
+            jslcinfo.error("Input file name must end with '.jsl'");
+        }
+        File inFile = jslcinfo.getInputFile(arg);
+        if (jslcinfo.shaderName == null) {
+            jslcinfo.shaderName = arg.substring(0, arg.length()-4);
+        }
+
+        compile(jslcinfo, inFile);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/hw/ES2Backend.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.hw;
+
+import java.util.HashMap;
+import java.util.Map;
+import com.sun.scenario.effect.compiler.JSLParser;
+import com.sun.scenario.effect.compiler.model.Precision;
+import com.sun.scenario.effect.compiler.tree.FuncDef;
+import com.sun.scenario.effect.compiler.tree.ProgramUnit;
+
+/**
+ */
+public class ES2Backend extends GLSLBackend {
+
+    public ES2Backend(JSLParser parser, ProgramUnit program) {
+        super(parser, program);
+    }
+
+    // GLSL v1.10 no longer has gl_TexCoord*; these are now passed in
+    // from vertex shader as texCoord0/1
+    private static final Map<String, String> varMap = new HashMap<String, String>();
+    static {
+        varMap.put("pos0",     "texCoord0");
+        varMap.put("pos1",     "texCoord1");
+        varMap.put("color",    "gl_FragColor");
+        varMap.put("jsl_vertexColor", "perVertexColor");
+    }
+
+    private static final Map<String, String> funcMap = new HashMap<String, String>();
+    static {
+        funcMap.put("sample", "texture2D");
+        funcMap.put("ddx", "dFdx");
+        funcMap.put("ddy", "dFdy");
+        funcMap.put("intcast", "int");
+    }
+
+    @Override
+    protected String getVar(String v) {
+        String s = varMap.get(v);
+        return (s != null) ? s : v;
+    }
+
+    @Override
+    protected String getFuncName(String f) {
+        String s = funcMap.get(f);
+        return (s != null) ? s : f;
+    }
+
+    @Override
+    protected String getPrecision(Precision p) {
+        return p.name();
+    }
+
+    @Override
+    public void visitFuncDef(FuncDef d) {
+        // this is a hack to help force the return value of certain Prism
+        // shader functions to have lower precision
+        String name = d.getFunction().getName();
+        if ("mask".equals(name) || "paint".equals(name)) {
+            output("LOWP ");
+        }
+        super.visitFuncDef(d);
+    }
+
+    @Override
+    protected String getHeader() {
+        StringBuilder sb = new StringBuilder();
+        // For the time being we are attempting to generate fragment programs
+        // that will run on the desktop and on OpenGL ES 2.0 devices.
+        // For OpenGL ES 2.0, fragment programs are required to specify the
+        // precision for all variables.  Also for ES 2.0, the default GLSL
+        // version is 1.00, so implicitly we are using "#version 100" for
+        // that case.  We are not yet taking advantage of language features
+        // above (desktop GLSL) version 1.10 so we can get away with not
+        // including the #version directive here (it will implicitly be
+        // "#version 110" for the desktop case).  It appears that the
+        // desktop and ES versions of the GLSL spec may continue to be
+        // developed independently (see section 10.23 in the GLSL ES spec),
+        // so if we ever need to use a higher version for one case or the
+        // other, it will get awkward since the #version string has to be
+        // the first thing in the file (i.e., you can't put it inside the
+        // "#ifdef GL_ES" section).
+        // TODO: We are currently using highp across the board just to be
+        // safe, but there are likely many variables that could live with
+        // mediump or lowp; should experiment with using lower precision
+        // by default...
+        sb.append("#ifdef GL_ES\n");
+        sb.append("#extension GL_OES_standard_derivatives : enable\n");
+        sb.append("precision highp float;\n");
+        sb.append("precision highp int;\n");
+        sb.append("#define HIGHP highp\n");
+        sb.append("#define MEDIUMP mediump\n");
+        sb.append("#define LOWP lowp\n");
+        sb.append("#else\n");
+        sb.append("#define HIGHP\n");
+        sb.append("#define MEDIUMP\n");
+        sb.append("#define LOWP\n");
+        sb.append("#endif\n");
+
+        // output varying value declarations (passed from the vertex shader)
+        if (maxTexCoordIndex >= 0) {
+            sb.append("varying vec2 texCoord0;\n");
+        }
+        if (maxTexCoordIndex >= 1) {
+            sb.append("varying vec2 texCoord1;\n");
+        }
+        if (isVertexColorReferenced) {
+            sb.append("varying LOWP vec4 perVertexColor;\n");
+        }
+
+        // output special pixcoord offset uniform variable declaration
+        // at the top of the program, if needed
+        if (isPixcoordReferenced) {
+            sb.append("uniform vec4 jsl_pixCoordOffset;\n");
+            sb.append("vec2 pixcoord = vec2(\n");
+            sb.append("    gl_FragCoord.x-jsl_pixCoordOffset.x,\n");
+            sb.append("    ((jsl_pixCoordOffset.z-gl_FragCoord.y)*jsl_pixCoordOffset.w)-jsl_pixCoordOffset.y);\n");
+        }
+
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/hw/GLSLBackend.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.hw;
+
+import java.util.HashMap;
+import java.util.Map;
+import com.sun.scenario.effect.compiler.JSLParser;
+import com.sun.scenario.effect.compiler.model.Qualifier;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.tree.ProgramUnit;
+
+/**
+ */
+public class GLSLBackend extends SLBackend {
+
+    public GLSLBackend(JSLParser parser, ProgramUnit program) {
+        super(parser, program);
+    }
+
+    private static final Map<String, String> qualMap = new HashMap<String, String>();
+    static {
+        qualMap.put("const", "const");
+        qualMap.put("param", "uniform");
+    }
+    
+    private static final Map<String, String> typeMap = new HashMap<String, String>();
+    static {
+        typeMap.put("void",    "void");
+        typeMap.put("float",   "float");
+        typeMap.put("float2",  "vec2");
+        typeMap.put("float3",  "vec3");
+        typeMap.put("float4",  "vec4");
+        typeMap.put("int",     "int");
+        typeMap.put("int2",    "ivec2");
+        typeMap.put("int3",    "ivec3");
+        typeMap.put("int4",    "ivec4");
+        typeMap.put("bool",    "bool");
+        typeMap.put("bool2",   "bvec2");
+        typeMap.put("bool3",   "bvec3");
+        typeMap.put("bool4",   "bvec4");
+        typeMap.put("sampler", "sampler2D");
+        typeMap.put("lsampler","sampler2D");
+        typeMap.put("fsampler","sampler2D");
+    }
+    
+    private static final Map<String, String> varMap = new HashMap<String, String>();
+    static {
+        varMap.put("pos0", "gl_TexCoord[0].st");
+        varMap.put("pos1", "gl_TexCoord[1].st");
+        varMap.put("color", "gl_FragColor");
+        varMap.put("jsl_vertexColor", "gl_Color");
+    }
+
+    private static final Map<String, String> funcMap = new HashMap<String, String>();
+    static {
+        funcMap.put("sample", "jsl_sample");
+        funcMap.put("ddx", "dFdx");
+        funcMap.put("ddy", "dFdy");
+        funcMap.put("intcast", "int");
+        funcMap.put("any", "any");
+        funcMap.put("length", "length");
+    }
+
+    @Override
+    protected String getType(Type t) {
+        return typeMap.get(t.toString());
+    }
+
+    @Override
+    protected String getQualifier(Qualifier q) {
+        return qualMap.get(q.toString());
+    }
+
+    @Override
+    protected String getVar(String v) {
+        String s = varMap.get(v);
+        return (s != null) ? s : v;
+    }
+
+    @Override
+    protected String getFuncName(String f) {
+        String s = funcMap.get(f);
+        return (s != null) ? s : f;
+    }
+
+    @Override
+    protected String getHeader() {
+        StringBuilder sb = new StringBuilder();
+
+        // output special pixcoord offset uniform variable declaration
+        // at the top of the program
+        // TODO: this should be included only if the program makes use
+        // of the special pixcoord variable (it's wasteful otherwise)...
+        sb.append("uniform float jsl_pixCoordYOffset;\n");
+        sb.append("vec2 pixcoord = vec2(gl_FragCoord.x, jsl_pixCoordYOffset-gl_FragCoord.y);\n");
+        
+        // also output helper function that handles the y-flip
+        // needed to account for OpenGL's lower-left origin
+        // TODO: this is really gross, but the Java2D/RSL backend needs
+        // the y-flip, while the Java2D/JOGL backend does not; so for now
+        // we use this jsl_posValueYFlip uniform variable to control whether
+        // to flip or not...
+        sb.append("uniform vec2 jsl_posValueYFlip;\n");
+        sb.append("vec4 jsl_sample(sampler2D img, vec2 pos) {\n");
+        sb.append("    pos.y = (jsl_posValueYFlip.x - pos.y) * jsl_posValueYFlip.y;\n");
+        sb.append("    return texture2D(img, pos);\n");
+        sb.append("}\n");
+
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/hw/HLSLBackend.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.hw;
+
+import java.util.HashMap;
+import java.util.Map;
+import com.sun.scenario.effect.compiler.JSLParser;
+import com.sun.scenario.effect.compiler.model.BaseType;
+import com.sun.scenario.effect.compiler.model.Function;
+import com.sun.scenario.effect.compiler.model.Qualifier;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.model.Variable;
+import com.sun.scenario.effect.compiler.tree.Expr;
+import com.sun.scenario.effect.compiler.tree.FuncDef;
+import com.sun.scenario.effect.compiler.tree.ProgramUnit;
+import com.sun.scenario.effect.compiler.tree.VarDecl;
+
+/**
+ */
+public class HLSLBackend extends SLBackend {
+
+    public HLSLBackend(JSLParser parser, ProgramUnit program) {
+        super(parser, program);
+    }
+
+    private static final Map<String, String> qualMap = new HashMap<String, String>();
+    static {
+        qualMap.put("const", "");
+        qualMap.put("param", "");
+    }
+    
+    private static final Map<String, String> typeMap = new HashMap<String, String>();
+    static {
+        typeMap.put("void",    "void");
+        typeMap.put("float",   "float");
+        typeMap.put("float2",  "float2");
+        typeMap.put("float3",  "float3");
+        typeMap.put("float4",  "float4");
+        typeMap.put("int",     "int");
+        typeMap.put("int2",    "int2");
+        typeMap.put("int3",    "int3");
+        typeMap.put("int4",    "int4");
+        typeMap.put("bool",    "bool");
+        typeMap.put("bool2",   "bool2");
+        typeMap.put("bool3",   "bool3");
+        typeMap.put("bool4",   "bool4");
+        typeMap.put("sampler", "sampler2D");
+        typeMap.put("lsampler","sampler2D");
+        typeMap.put("fsampler","sampler2D");
+    }
+    
+    private static final Map<String, String> varMap = new HashMap<String, String>();
+    static {
+    }
+
+    private static final Map<String, String> funcMap = new HashMap<String, String>();
+    static {
+        funcMap.put("sample", "tex2D");
+        funcMap.put("fract", "frac");
+        funcMap.put("mix", "lerp");
+        funcMap.put("mod", "fmod");
+        funcMap.put("intcast", "int");
+        funcMap.put("any", "any");
+        funcMap.put("length", "length");
+    }
+
+    @Override
+    protected String getType(Type t) {
+        return typeMap.get(t.toString());
+    }
+
+    @Override
+    protected String getQualifier(Qualifier q) {
+        return qualMap.get(q.toString());
+    }
+
+    @Override
+    protected String getVar(String v) {
+        String s = varMap.get(v);
+        return (s != null) ? s : v;
+    }
+
+    @Override
+    protected String getFuncName(String f) {
+        String s = funcMap.get(f);
+        return (s != null) ? s : f;
+    }
+    
+    @Override
+    public void visitFuncDef(FuncDef d) {
+        Function func = d.getFunction();
+        if (func.getName().equals("main")) {
+            output(getType(func.getReturnType()) + " " + func.getName() + "(");
+            // TODO: it would be better if we scanned the whole JSL program
+            // to see if pos0 or pos1 are used anywhere, but for now there
+            // doesn't seem to be any harm in blindly declaring both here...
+            for (int i = 0; i < 2; i++) {
+                output("in float2 pos" + i + " : TEXCOORD" + i + ",\n");
+            }
+            // TODO: only need this if pixcoord is referenced somewhere
+            // in the JSL program...
+            output("in float2 pixcoord : VPOS,\n");
+            output("in float4 jsl_vertexColor : COLOR0,\n");
+            output("out float4 color : COLOR0");
+            output(") ");
+            scan(d.getStmt());
+        } else {
+            super.visitFuncDef(d);
+        }
+    }
+    
+    @Override
+    public void visitVarDecl(VarDecl d) {
+        Variable var = d.getVariable();
+        Type type = var.getType();
+        Qualifier qual = var.getQualifier();
+        if (qual == Qualifier.PARAM && type.getBaseType() == BaseType.INT) {
+            // TODO: It seems that constant integer registers have limitations
+            // in SM 3.0... For example, the max number of integer registers
+            // (those specified with i#) is 16; in PS 2.0 these were limited
+            // to flow control instructions only, but according to MSDN this
+            // restriction went away with PS 3.0.  However, bad things happen
+            // at runtime if we output:
+            //     int variableName : register(c0);
+            // (not sure what the problem is, but bad values seem to be
+            // uploaded if we use SetPixelShaderConstantI() in this case), and
+            // if we use i# instead:
+            //     int variableName : register(i0);
+            // the compiler will say this is invalid (it won't complain if
+            // we actually used it in a loop expression though).  Until this
+            // problem is better understood, we can work around it by
+            // declaring these params as float variants, e.g.:
+            //     float variableName : register(c0);
+            // and using SetPixelShaderConstantF() instead.
+            String t;
+            switch (type) {
+            case INT:
+                t = "float";
+                break;
+            case INT2:
+                t = "float2";
+                break;
+            case INT3:
+                t = "float3";
+                break;
+            case INT4:
+                t = "float4";
+                break;
+            default:
+                throw new InternalError();
+            }
+            output(t + " " + var.getName());
+        } else if (qual == Qualifier.CONST) {
+            // use #define-style definition
+            output("#define " + var.getName());
+        } else {
+            output(getType(type) + " " + var.getName());
+        }
+        Expr init = d.getInit();
+        if (init != null) {
+            if (qual == Qualifier.CONST) {
+                // use #define-style definition (no '=', wrap in
+                // parens for safety)
+                output(" (");
+                scan(init);
+                output(")");
+            } else {
+                output(" = ");
+                scan(init);
+            }
+        }
+        if (var.isArray()) {
+            output("[" + var.getArraySize() + "]");
+        }
+        if (qual == Qualifier.PARAM) {
+            char c = (type.getBaseType() == BaseType.SAMPLER) ? 's' : 'c';
+            output(" : register(" + c + var.getReg() + ")");
+        }
+        if (qual == Qualifier.CONST) {
+            // use #define-style definition (no closing ';')
+            output("\n");
+        } else {
+            output(";\n");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/hw/SLBackend.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.hw;
+
+import com.sun.scenario.effect.compiler.JSLParser;
+import com.sun.scenario.effect.compiler.model.BinaryOpType;
+import com.sun.scenario.effect.compiler.model.Function;
+import com.sun.scenario.effect.compiler.model.Param;
+import com.sun.scenario.effect.compiler.model.Precision;
+import com.sun.scenario.effect.compiler.model.Qualifier;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.model.Variable;
+import com.sun.scenario.effect.compiler.tree.ArrayAccessExpr;
+import com.sun.scenario.effect.compiler.tree.BinaryExpr;
+import com.sun.scenario.effect.compiler.tree.BreakStmt;
+import com.sun.scenario.effect.compiler.tree.CallExpr;
+import com.sun.scenario.effect.compiler.tree.CompoundStmt;
+import com.sun.scenario.effect.compiler.tree.ContinueStmt;
+import com.sun.scenario.effect.compiler.tree.DeclStmt;
+import com.sun.scenario.effect.compiler.tree.DiscardStmt;
+import com.sun.scenario.effect.compiler.tree.DoWhileStmt;
+import com.sun.scenario.effect.compiler.tree.Expr;
+import com.sun.scenario.effect.compiler.tree.ExprStmt;
+import com.sun.scenario.effect.compiler.tree.FieldSelectExpr;
+import com.sun.scenario.effect.compiler.tree.ForStmt;
+import com.sun.scenario.effect.compiler.tree.FuncDef;
+import com.sun.scenario.effect.compiler.tree.LiteralExpr;
+import com.sun.scenario.effect.compiler.tree.ParenExpr;
+import com.sun.scenario.effect.compiler.tree.ProgramUnit;
+import com.sun.scenario.effect.compiler.tree.ReturnStmt;
+import com.sun.scenario.effect.compiler.tree.SelectStmt;
+import com.sun.scenario.effect.compiler.tree.Stmt;
+import com.sun.scenario.effect.compiler.tree.TreeScanner;
+import com.sun.scenario.effect.compiler.tree.UnaryExpr;
+import com.sun.scenario.effect.compiler.tree.VarDecl;
+import com.sun.scenario.effect.compiler.tree.VariableExpr;
+import com.sun.scenario.effect.compiler.tree.VectorCtorExpr;
+import com.sun.scenario.effect.compiler.tree.WhileStmt;
+
+/**
+ */
+public abstract class SLBackend extends TreeScanner {
+
+    private JSLParser parser;
+    private StringBuilder sb = new StringBuilder();
+    private Variable unrollVar = null;
+    private int unrollIndex = -1;
+    protected boolean isPixcoordReferenced;
+    protected boolean isVertexColorReferenced;
+    protected int maxTexCoordIndex = -1;
+    
+    protected SLBackend(JSLParser parser, ProgramUnit program) {
+        this.parser = parser;
+        scan(program);
+    }
+    
+    protected final void output(String s) {
+        sb.append(s);
+    }
+    
+    public final String getShader() {
+        return getHeader() + sb.toString();
+    }
+
+    protected final JSLParser getParser() {
+        return parser;
+    }
+
+    /**
+     * Returns the String that will be included at the top of the resulting
+     * shader code.  This method is called after the entire program has been
+     * scanned, so it provides a way for a subclass to customize the header
+     * (for example, to include declarations for "special" variables such
+     * as pos1 based on whether they were referenced somewhere in the JSL
+     * code).  The default implementation returns an empty string, but
+     * subclasses may override this to provide different behavior.
+     */
+    protected String getHeader() {
+        return "";
+    }
+
+    protected String getPrecision(Precision p) {
+        return null;
+    }
+
+    protected abstract String getType(Type t);
+    
+    protected abstract String getQualifier(Qualifier q);
+    
+    protected abstract String getVar(String v);
+    
+    protected abstract String getFuncName(String f);
+
+    @Override
+    public void visitArrayAccessExpr(ArrayAccessExpr e) {
+        scan(e.getExpr());
+        output("[");
+        boolean needsScan = true;
+        if (unrollVar != null) {
+            // TODO: this is flimsy...
+            if (e.getIndex() instanceof VariableExpr) {
+                VariableExpr vexpr = (VariableExpr)e.getIndex();
+                if (vexpr.getVariable() == unrollVar) {
+                    output("" + unrollIndex);
+                    needsScan = false;
+                }
+            }
+        }
+        if (needsScan) {
+            scan(e.getIndex());
+        }
+        output("]");
+    }
+
+    @Override
+    public void visitBinaryExpr(BinaryExpr e) {
+        scan(e.getLeft());
+        output(" " + e.getOp() + " ");
+        scan(e.getRight());
+    }
+
+    @Override
+    public void visitBreakStmt(BreakStmt s) {
+        output("break;");
+    }
+
+    @Override
+    public void visitCallExpr(CallExpr e) {
+        output(getFuncName(e.getFunction().getName()) + "(");
+        boolean first = true;
+        for (Expr param : e.getParams()) {
+            if (first) {
+                first = false;
+            } else {
+                output(", ");
+            }
+            scan(param);
+        }
+        output(")");
+    }
+
+    @Override
+    public void visitCompoundStmt(CompoundStmt s) {
+        output("{\n");
+        super.visitCompoundStmt(s);
+        output("}\n");
+    }
+
+    @Override
+    public void visitContinueStmt(ContinueStmt s) {
+        output("continue;");
+    }
+
+    @Override
+    public void visitDeclStmt(DeclStmt s) {
+        super.visitDeclStmt(s);
+    }
+
+    @Override
+    public void visitDiscardStmt(DiscardStmt s) {
+        output("discard;");
+    }
+
+    @Override
+    public void visitDoWhileStmt(DoWhileStmt s) {
+        output("do ");
+        scan(s.getStmt());
+        output(" while (");
+        scan(s.getExpr());
+        output(");");
+    }
+
+    @Override
+    public void visitExprStmt(ExprStmt s) {
+        scan(s.getExpr());
+        output(";\n");
+    }
+
+    @Override
+    public void visitFieldSelectExpr(FieldSelectExpr e) {
+        scan(e.getExpr());
+        output("." + e.getFields());
+    }
+
+    @Override
+    public void visitForStmt(ForStmt s) {
+        boolean unroll = s.getUnrollMax() > 0;
+        if (unroll) {
+            if (unrollVar != null) {
+                throw new RuntimeException("Unrolling of nested 'for' loops not yet supported");
+            }
+            
+            // TODO: This is very flimsy code; to make this work for real we
+            // will need much more validation of conditions, etc...
+            String maxName = null;
+            Expr cond = s.getCondition();
+            if (cond instanceof BinaryExpr) {
+                BinaryExpr bcond = (BinaryExpr)cond;
+                if (bcond.getOp() != BinaryOpType.LT) {
+                    throw new RuntimeException("Condition must be '<' in order to unroll 'for' loop (for now)");
+                }
+                Expr left = bcond.getLeft();
+                if (left instanceof VariableExpr) {
+                    VariableExpr vexpr = (VariableExpr)left;
+                    Variable var = vexpr.getVariable();
+                    if (var.getType() != Type.INT) {
+                        throw new RuntimeException("Condition LHS must be integer variable in order to unroll 'for' loop (for now)");
+                    }
+                    unrollVar = var;
+                } else {
+                    throw new RuntimeException("Condition LHS must be integer variable in order to unroll 'for' loop (for now)");
+                }
+                Expr right = bcond.getRight();
+                if (right instanceof VariableExpr) {
+                    VariableExpr vexpr = (VariableExpr)right;
+                    Variable var = vexpr.getVariable();
+                    maxName = var.getName();
+                } else if (s.getUnrollCheck() > 0) {
+                    throw new RuntimeException("Condition RHS must be variable in order to unroll 'for' loop");
+                }
+                // TODO: verify that last expression is postfix-increment
+            } else {
+                throw new RuntimeException("Invalid unrollable 'for' loop condition");
+            }
+            int max = s.getUnrollMax();
+            int check = max - s.getUnrollCheck();
+            for (int i = 0; i < s.getUnrollMax(); i++) {
+                if (i >= check) {
+                    output("if (" + i + " < " + maxName + ")\n");
+                }
+                unrollIndex = i;
+                scan(s.getStmt());
+            }
+            unrollVar = null;
+            unrollIndex = -1;
+        } else {
+            output("for (");
+            scan(s.getInit());
+            scan(s.getCondition());
+            output(";");
+            scan(s.getExpr());
+            output(")");
+            scan(s.getStmt());
+        }
+    }
+
+    @Override
+    public void visitFuncDef(FuncDef d) {
+        Function func = d.getFunction();
+        output(getType(func.getReturnType()) + " " + func.getName() + "(");
+        boolean first = true;
+        for (Param param : func.getParams()) {
+            if (first) {
+                first = false;
+            } else {
+                output(", ");
+            }
+            output(getType(param.getType()) + " " + param.getName());
+        }
+        output(") ");
+        scan(d.getStmt());
+    }
+
+    @Override
+    public void visitLiteralExpr(LiteralExpr e) {
+        output(e.getValue().toString());
+    }
+
+    @Override
+    public void visitParenExpr(ParenExpr e) {
+        output("(");
+        scan(e.getExpr());
+        output(")");
+    }
+    
+    @Override
+    public void visitProgramUnit(ProgramUnit p) {
+        super.visitProgramUnit(p);
+    }
+
+    @Override
+    public void visitReturnStmt(ReturnStmt s) {
+        output("return");
+        Expr ret = s.getExpr();
+        if (ret != null) {
+            output(" ");
+            scan(s.getExpr());
+        }
+        output(";\n");
+    }
+
+    @Override
+    public void visitSelectStmt(SelectStmt s) {
+        output("if (");
+        scan(s.getIfExpr());
+        output(")");
+        scan(s.getThenStmt());
+        Stmt e = s.getElseStmt();
+        if (e != null) {
+            output(" else ");
+            scan(e);
+        }
+    }
+
+    @Override
+    public void visitUnaryExpr(UnaryExpr e) {
+        output(e.getOp().toString());
+        scan(e.getExpr());
+    }
+
+    @Override
+    public void visitVarDecl(VarDecl d) {
+        Variable var = d.getVariable();
+        Qualifier qual = var.getQualifier();
+        if (qual != null) {
+            output(getQualifier(qual) + " ");
+        }
+        Precision precision = var.getPrecision();
+        if (precision != null) {
+            String precisionStr = getPrecision(precision);
+            if (precisionStr != null) {
+                output(precisionStr + " ");
+            }
+        }
+        output(getType(var.getType()) + " " + var.getName());
+        if (var.isArray()) {
+            output("[" + var.getArraySize() + "]");
+        }
+        Expr init = d.getInit();
+        if (init != null) {
+            output(" = ");
+            scan(init);
+        }
+        output(";\n");
+    }
+
+    @Override
+    public void visitVariableExpr(VariableExpr e) {
+        String varName = e.getVariable().getName();
+        if (varName.equals("pixcoord")) {
+            isPixcoordReferenced = true;
+        } else if (varName.equals("pos0")) {
+            maxTexCoordIndex = Math.max(maxTexCoordIndex, 0);
+        } else if (varName.equals("pos1")) {
+            maxTexCoordIndex = Math.max(maxTexCoordIndex, 1);
+        } else if (varName.equals("jsl_vertexColor")) {
+            isVertexColorReferenced = true;
+        }
+        output(getVar(varName));
+    }
+
+    @Override
+    public void visitVectorCtorExpr(VectorCtorExpr e) {
+        output(getType(e.getType()));
+        output("(");
+        boolean first = true;
+        for (Expr param : e.getParams()) {
+            if (first) {
+                first = false;
+            } else {
+                output(", ");
+            }
+            scan(param);
+        }
+        output(")");
+    }
+
+    @Override
+    public void visitWhileStmt(WhileStmt s) {
+        output("while (");
+        scan(s.getCondition());
+        output(")");
+        scan(s.getStmt());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/j2d/jogl/JOGLBackend.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.j2d.jogl;
+
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Map;
+import com.sun.scenario.effect.compiler.JSLParser;
+import com.sun.scenario.effect.compiler.model.BaseType;
+import com.sun.scenario.effect.compiler.model.Qualifier;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.model.Variable;
+import com.sun.scenario.effect.compiler.tree.GlueBlock;
+import com.sun.scenario.effect.compiler.tree.ProgramUnit;
+import com.sun.scenario.effect.compiler.tree.TreeScanner;
+import org.antlr.stringtemplate.StringTemplate;
+import org.antlr.stringtemplate.StringTemplateGroup;
+import org.antlr.stringtemplate.language.DefaultTemplateLexer;
+
+/**
+ */
+public class JOGLBackend extends TreeScanner {
+
+    private JSLParser parser;
+    private StringBuilder usercode = new StringBuilder();
+    
+    public JOGLBackend(JSLParser parser, ProgramUnit program) {
+        this.parser = parser;
+        scan(program);
+    }
+    
+    private StringTemplate getTemplate(String type) {
+        Reader template = new InputStreamReader(getClass().getResourceAsStream(type + "Glue.stg"));
+        StringTemplateGroup group = new StringTemplateGroup(template, DefaultTemplateLexer.class);
+        return group.getInstanceOf("glue");
+    }
+    
+    public String getGlueCode(String effectName,
+                              String peerName,
+                              String interfaceName)
+    {
+        Map<String, Variable> vars = parser.getSymbolTable().getGlobalVariables();
+        StringBuilder interfaceDecl = new StringBuilder();
+        StringBuilder samplerLinear = new StringBuilder();
+        StringBuilder samplerInit = new StringBuilder();
+        StringBuilder paramInit = new StringBuilder();
+        StringBuilder paramUpdate = new StringBuilder();
+
+        // include some special code that is only needed in the OGL case
+        // to account for the lower-left origin
+        String pixCoordUpdate =
+            "float yoff = (float)getDestNativeBounds().height;\n" +
+            "shader.setConstant(\"jsl_pixCoordYOffset\", yoff);\n" +
+            "shader.setConstant(\"jsl_posValueYFlip\", 0f, -1f);\n";
+        paramUpdate.append(pixCoordUpdate);
+
+        for (Variable v : vars.values()) {
+            if (v.getQualifier() == Qualifier.PARAM) {
+                String vname = v.getName();
+                if (v.getType().getBaseType() == BaseType.SAMPLER) {
+                    samplerInit.append("samplers.put(\"" + vname + "\", " + v.getReg() + ");\n");
+                    if (v.getType() == Type.LSAMPLER || v.getType() == Type.FSAMPLER) {
+                        samplerLinear.append("case " + v.getReg() + ":\n");
+                        samplerLinear.append("    return true;\n");
+                    }
+                } else {
+                    String accName = v.getAccessorName();
+                    paramInit.append("params.put(\"" + vname + "\", " + v.getReg() + ");\n");
+                    if (v.isArray()) {
+                        paramUpdate.append("shader.setConstants(\"" + vname);
+                        paramUpdate.append("\", " + accName + "(), 0, ");
+                        paramUpdate.append(accName + "ArrayLength());\n");
+                    } else if (v.getType().isVector()) {
+                        paramUpdate.append(v.getType().getBaseType().toString());
+                        paramUpdate.append("[] " + vname + "_tmp = ");
+                        paramUpdate.append(accName + "();\n");
+                        paramUpdate.append("shader.setConstant(\"" + vname + "\"");
+                        for (int i = 0; i < v.getType().getNumFields(); i++) {
+                            paramUpdate.append(", " + vname + "_tmp[" + i + "]");
+                        }
+                        paramUpdate.append(");\n");
+                    } else {
+                        paramUpdate.append("shader.setConstant(\"" + vname);
+                        paramUpdate.append("\", " + accName + "());\n");
+                    }
+                }
+            }
+        }
+
+        int numSamplers = parser.getSymbolTable().getNumSamplers();
+        String superClass;
+        if (numSamplers == 0) {
+            superClass = "JOGLZeroSamplerPeer";
+        } else if (numSamplers == 1) {
+            superClass = "JOGLOneSamplerPeer";
+        } else if (numSamplers == 2) {
+            superClass = "JOGLTwoSamplerPeer";
+        } else {
+            throw new RuntimeException("Must use zero, one, or two samplers (for now)");
+        }
+        
+        if (interfaceName != null) {
+            interfaceDecl.append("implements "+interfaceName);
+        }
+
+        StringTemplate glue = getTemplate("JOGL");
+        glue.setAttribute("effectName", effectName);
+        glue.setAttribute("peerName", peerName);
+        glue.setAttribute("superClass", superClass);
+        glue.setAttribute("interfaceDecl", interfaceDecl.toString());
+        glue.setAttribute("usercode", usercode.toString());
+        glue.setAttribute("samplerLinear", samplerLinear.toString());
+        glue.setAttribute("samplerInit", samplerInit.toString());
+        glue.setAttribute("paramInit", paramInit.toString());
+        glue.setAttribute("paramUpdate", paramUpdate.toString());
+        return glue.toString();
+    }
+
+    @Override
+    public void visitGlueBlock(GlueBlock b) {
+        usercode.append(b.getText());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/j2d/jogl/JOGLGlue.stg	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,82 @@
+group JOGLGlue;
+
+glue(effectName,peerName,superClass,interfaceDecl,
+     usercode,samplerLinear,samplerInit,paramInit,paramUpdate) ::= <<
+/*
+ * Copyright (c) 2008, 2011, Oracle  and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * This file was generated by JSLC -- DO NOT EDIT MANUALLY!
+ */
+
+package com.sun.scenario.effect.impl.j2d.jogl;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.util.HashMap;
+import com.sun.scenario.effect.$effectName$;
+import com.sun.scenario.effect.FilterContext;
+import com.sun.scenario.effect.impl.BufferUtil;
+import com.sun.scenario.effect.impl.Renderer;
+import com.sun.scenario.effect.impl.hw.Shader;
+import com.sun.scenario.effect.impl.state.*;
+import com.sun.javafx.geom.Rectangle;
+
+public class JOGL$peerName$Peer extends $superClass$ $interfaceDecl$ {
+
+    public JOGL$peerName$Peer(FilterContext fctx, Renderer r, String shaderName) {
+        super(fctx, r, shaderName);
+    }
+
+    @Override
+    protected final $effectName$ getEffect() {
+        return ($effectName$)super.getEffect();
+    }
+
+    $usercode$
+     
+    @Override
+    protected boolean isSamplerLinear(int i) {
+        switch (i) {
+        $samplerLinear$
+        default:
+            return false;
+        }
+    }
+
+    @Override
+    protected Shader createShader() {
+        HashMap<String, Integer> samplers = new HashMap<String, Integer>();
+        $samplerInit$
+        HashMap<String, Integer> params = new HashMap<String, Integer>();
+        $paramInit$
+        return getRenderer().getDelegate().createShader(getShaderName(), samplers, params);
+    }
+
+    @Override
+    protected void updateShader(Shader shader) {
+        $paramUpdate$
+    }
+}
+
+>>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/j2d/rsl/RSLBackend.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.sun.scenario.effect.compiler.backend.j2d.rsl;
+
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Map;
+import com.sun.scenario.effect.compiler.JSLParser;
+import com.sun.scenario.effect.compiler.model.BaseType;
+import com.sun.scenario.effect.compiler.model.Qualifier;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.model.Variable;
+import com.sun.scenario.effect.compiler.tree.GlueBlock;
+import com.sun.scenario.effect.compiler.tree.ProgramUnit;
+import com.sun.scenario.effect.compiler.tree.TreeScanner;
+import org.antlr.stringtemplate.StringTemplate;
+import org.antlr.stringtemplate.StringTemplateGroup;
+import org.antlr.stringtemplate.language.DefaultTemplateLexer;
+
+/**
+ */
+public class RSLBackend extends TreeScanner {
+
+    private JSLParser parser;
+    private StringBuilder usercode = new StringBuilder();
+
+    public RSLBackend(JSLParser parser, ProgramUnit program) {
+        this.parser = parser;
+        scan(program);
+    }
+
+    private StringTemplate getTemplate(String type) {
+        Reader template = new InputStreamReader(getClass().getResourceAsStream(type + "Glue.stg"));
+        StringTemplateGroup group = new StringTemplateGroup(template, DefaultTemplateLexer.class);
+        return group.getInstanceOf("glue");
+    }
+
+    public String getGlueCode(String effectName,
+                              String peerName,
+                              String interfaceName)
+    {
+        Map<String, Variable> vars = parser.getSymbolTable().getGlobalVariables();
+        StringBuilder interfaceDecl = new StringBuilder();
+        StringBuilder samplerLinear = new StringBuilder();
+        StringBuilder samplerInit = new StringBuilder();
+        StringBuilder paramInit = new StringBuilder();
+        StringBuilder paramUpdate = new StringBuilder();
+
+        // include some special code that is only needed in the OGL case
+        String pixCoordUpdate =
+            "if (shader.getClass().getSimpleName().startsWith(\"OGL\")) {\n" +
+            "    float yoff = (float)getDestNativeBounds().height;\n" +
+            "    shader.setConstant(\"jsl_pixCoordYOffset\", yoff);\n" +
+            "    shader.setConstant(\"jsl_posValueYFlip\", 1f, 1f);\n" +
+            "}\n";
+        paramUpdate.append(pixCoordUpdate);
+
+        for (Variable v : vars.values()) {
+            if (v.getQualifier() == Qualifier.PARAM) {
+                String vname = v.getName();
+                if (v.getType().getBaseType() == BaseType.SAMPLER) {
+                    samplerInit.append("samplers.put(\"" + vname + "\", " + v.getReg() + ");\n");
+                    if (v.getType() == Type.LSAMPLER || v.getType() == Type.FSAMPLER) {
+                        samplerLinear.append("case " + v.getReg() + ":\n");
+                        samplerLinear.append("    return true;\n");
+                    }
+                } else {
+                    String accName = v.getAccessorName();
+                    paramInit.append("params.put(\"" + vname + "\", " + v.getReg() + ");\n");
+                    if (v.isArray()) {
+                        paramUpdate.append("shader.setConstants(\"" + vname);
+                        paramUpdate.append("\", " + accName + "(), 0, ");
+                        paramUpdate.append(accName + "ArrayLength());\n");
+                    } else if (v.getType().isVector()) {
+                        paramUpdate.append(v.getType().getBaseType().toString());
+                        paramUpdate.append("[] " + vname + "_tmp = ");
+                        paramUpdate.append(accName + "();\n");
+                        paramUpdate.append("shader.setConstant(\"" + vname + "\"");
+                        for (int i = 0; i < v.getType().getNumFields(); i++) {
+                            paramUpdate.append(", " + vname + "_tmp[" + i + "]");
+                        }
+                        paramUpdate.append(");\n");
+                    } else {
+                        paramUpdate.append("shader.setConstant(\"" + vname);
+                        paramUpdate.append("\", " + accName + "());\n");
+                    }
+                }
+            }
+        }
+
+        int numSamplers = parser.getSymbolTable().getNumSamplers();
+        String superClass;
+        if (numSamplers == 0) {
+            superClass = "RSLZeroSamplerPeer";
+        } else if (numSamplers == 1) {
+            superClass = "RSLOneSamplerPeer";
+        } else if (numSamplers == 2) {
+            superClass = "RSLTwoSamplerPeer";
+        } else {
+            throw new RuntimeException("Must use zero, one, or two samplers (for now)");
+        }
+
+        if (interfaceName != null) {
+            interfaceDecl.append("implements "+interfaceName);
+        }
+
+        StringTemplate glue = getTemplate("RSL");
+        glue.setAttribute("effectName", effectName);
+        glue.setAttribute("peerName", peerName);
+        glue.setAttribute("superClass", superClass);
+        glue.setAttribute("interfaceDecl", interfaceDecl.toString());
+        glue.setAttribute("usercode", usercode.toString());
+        glue.setAttribute("samplerLinear", samplerLinear.toString());
+        glue.setAttribute("samplerInit", samplerInit.toString());
+        glue.setAttribute("paramInit", paramInit.toString());
+        glue.setAttribute("paramUpdate", paramUpdate.toString());
+        return glue.toString();
+    }
+
+    @Override
+    public void visitGlueBlock(GlueBlock b) {
+        usercode.append(b.getText());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/j2d/rsl/RSLGlue.stg	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,81 @@
+group RSLGlue;
+
+glue(effectName,peerName,superClass,interfaceDecl,
+     usercode,samplerLinear,samplerInit,paramInit,paramUpdate) ::= <<
+/*
+ * Copyright (c) 2008, 2011, Oracle  and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * This file was generated by JSLC -- DO NOT EDIT MANUALLY!
+ */
+
+package com.sun.scenario.effect.impl.j2d.rsl;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.util.HashMap;
+import com.sun.scenario.effect.$effectName$;
+import com.sun.scenario.effect.FilterContext;
+import com.sun.scenario.effect.impl.BufferUtil;
+import com.sun.scenario.effect.impl.Renderer;
+import com.sun.scenario.effect.impl.hw.Shader;
+import com.sun.scenario.effect.impl.state.*;
+import com.sun.javafx.geom.Rectangle;
+
+public class RSL$peerName$Peer extends $superClass$ $interfaceDecl$ {
+
+    public RSL$peerName$Peer(FilterContext fctx, Renderer r, String shaderName) {
+        super(fctx, r, shaderName);
+    }
+
+    @Override
+    protected final $effectName$ getEffect() {
+        return ($effectName$)super.getEffect();
+    }
+
+    $usercode$
+     
+    @Override
+    protected boolean isSamplerLinear(int i) {
+        switch (i) {
+        $samplerLinear$
+        default:
+            return false;
+        }
+    }
+
+    @Override
+    protected Shader createShader() {
+        HashMap<String, Integer> samplers = new HashMap<String, Integer>();
+        $samplerInit$
+        HashMap<String, Integer> params = new HashMap<String, Integer>();
+        $paramInit$
+        return getRenderer().getDelegate().createShader(getShaderName(), samplers, params);
+    }
+
+    @Override
+    protected void updateShader(Shader shader) {
+        $paramUpdate$
+    }
+}
+>>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/prism/PrismBackend.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.prism;
+
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Map;
+import com.sun.scenario.effect.compiler.JSLParser;
+import com.sun.scenario.effect.compiler.model.BaseType;
+import com.sun.scenario.effect.compiler.model.Qualifier;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.model.Variable;
+import com.sun.scenario.effect.compiler.tree.GlueBlock;
+import com.sun.scenario.effect.compiler.tree.ProgramUnit;
+import com.sun.scenario.effect.compiler.tree.TreeScanner;
+import com.sun.scenario.effect.compiler.tree.VariableExpr;
+import org.antlr.stringtemplate.StringTemplate;
+import org.antlr.stringtemplate.StringTemplateGroup;
+import org.antlr.stringtemplate.language.DefaultTemplateLexer;
+
+/**
+ */
+public class PrismBackend extends TreeScanner {
+
+    private JSLParser parser;
+    private StringBuilder usercode = new StringBuilder();
+    private boolean isPixcoordReferenced = false;
+    
+    public PrismBackend(JSLParser parser, ProgramUnit program) {
+        this.parser = parser;
+        scan(program);
+    }
+    
+    private StringTemplate getTemplate(String type) {
+        Reader template = new InputStreamReader(getClass().getResourceAsStream(type + "Glue.stg"));
+        StringTemplateGroup group = new StringTemplateGroup(template, DefaultTemplateLexer.class);
+        return group.getInstanceOf("glue");
+    }
+    
+    public String getGlueCode(String effectName,
+                              String peerName,
+                              String interfaceName)
+    {
+        Map<String, Variable> vars = parser.getSymbolTable().getGlobalVariables();
+        StringBuilder interfaceDecl = new StringBuilder();
+        StringBuilder samplerLinear = new StringBuilder();
+        StringBuilder samplerInit = new StringBuilder();
+        StringBuilder paramInit = new StringBuilder();
+        StringBuilder paramUpdate = new StringBuilder();
+
+        for (Variable v : vars.values()) {
+            if (v.getQualifier() == Qualifier.PARAM) {
+                String vname = v.getName();
+                if (v.getType().getBaseType() == BaseType.SAMPLER) {
+                    samplerInit.append("samplers.put(\"" + vname + "\", " + v.getReg() + ");\n");
+                    if (v.getType() == Type.LSAMPLER || v.getType() == Type.FSAMPLER) {
+                        samplerLinear.append("case " + v.getReg() + ":\n");
+                        samplerLinear.append("    return true;\n");
+                    }
+                } else {
+                    String accName = v.getAccessorName();
+                    paramInit.append("params.put(\"" + vname + "\", " + v.getReg() + ");\n");
+                    if (v.isArray()) {
+                        paramUpdate.append("shader.setConstants(\"" + vname);
+                        paramUpdate.append("\", " + accName + "(), 0, ");
+                        paramUpdate.append(accName + "ArrayLength());\n");
+                    } else if (v.getType().isVector()) {
+                        paramUpdate.append(v.getType().getBaseType().toString());
+                        paramUpdate.append("[] " + vname + "_tmp = ");
+                        paramUpdate.append(accName + "();\n");
+                        paramUpdate.append("shader.setConstant(\"" + vname + "\"");
+                        for (int i = 0; i < v.getType().getNumFields(); i++) {
+                            paramUpdate.append(", " + vname + "_tmp[" + i + "]");
+                        }
+                        paramUpdate.append(");\n");
+                    } else {
+                        paramUpdate.append("shader.setConstant(\"" + vname);
+                        paramUpdate.append("\", " + accName + "());\n");
+                    }
+                }
+            }
+        }
+
+        int numSamplers = parser.getSymbolTable().getNumSamplers();
+        String superClass;
+        if (numSamplers == 0) {
+            superClass = "PPSZeroSamplerPeer";
+        } else if (numSamplers == 1) {
+            superClass = "PPSOneSamplerPeer";
+        } else if (numSamplers == 2) {
+            superClass = "PPSTwoSamplerPeer";
+        } else {
+            throw new RuntimeException("Must use zero, one, or two samplers (for now)");
+        }
+
+        if (interfaceName != null) {
+            interfaceDecl.append("implements "+interfaceName);
+        }
+
+        StringTemplate glue = getTemplate("Prism");
+        glue.setAttribute("effectName", effectName);
+        glue.setAttribute("peerName", peerName);
+        glue.setAttribute("superClass", superClass);
+        glue.setAttribute("interfaceDecl", interfaceDecl.toString());
+        glue.setAttribute("usercode", usercode.toString());
+        glue.setAttribute("samplerLinear", samplerLinear.toString());
+        glue.setAttribute("samplerInit", samplerInit.toString());
+        glue.setAttribute("paramInit", paramInit.toString());
+        glue.setAttribute("paramUpdate", paramUpdate.toString());
+        glue.setAttribute("isPixcoordUsed", isPixcoordReferenced);
+        return glue.toString();
+    }
+
+    @Override
+    public void visitGlueBlock(GlueBlock b) {
+        usercode.append(b.getText());
+    }
+
+    @Override
+    public void visitVariableExpr(VariableExpr e) {
+        String varName = e.getVariable().getName();
+        if (varName.equals("pixcoord")) {
+            isPixcoordReferenced = true;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/prism/PrismGlue.stg	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,85 @@
+group PrismGlue;
+
+glue(effectName,peerName,superClass,interfaceDecl,
+     usercode,samplerLinear,samplerInit,
+     paramInit,paramUpdate,isPixcoordUsed) ::= <<
+/*
+ * Copyright (c) 2008, 2011, Oracle  and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * This file was generated by JSLC -- DO NOT EDIT MANUALLY!
+ */
+
+package com.sun.scenario.effect.impl.prism.ps;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.util.HashMap;
+import com.sun.prism.ps.Shader;
+import com.sun.scenario.effect.$effectName$;
+import com.sun.scenario.effect.Effect;
+import com.sun.scenario.effect.FilterContext;
+import com.sun.scenario.effect.impl.BufferUtil;
+import com.sun.scenario.effect.impl.Renderer;
+import com.sun.scenario.effect.impl.state.*;
+import com.sun.javafx.geom.Rectangle;
+
+public class PPS$peerName$Peer extends $superClass$ $interfaceDecl$ {
+
+    public PPS$peerName$Peer(FilterContext fctx, Renderer r, String shaderName) {
+        super(fctx, r, shaderName);
+    }
+
+    @Override
+    protected final $effectName$ getEffect() {
+        return ($effectName$)super.getEffect();
+    }
+
+    $usercode$
+     
+    @Override
+    protected boolean isSamplerLinear(int i) {
+        switch (i) {
+        $samplerLinear$
+        default:
+            return false;
+        }
+    }
+
+    @Override
+    protected Shader createShader() {
+        HashMap<String, Integer> samplers = new HashMap<String, Integer>();
+        $samplerInit$
+        HashMap<String, Integer> params = new HashMap<String, Integer>();
+        $paramInit$
+        return getRenderer().createShader(getShaderName(), samplers, params,
+                                          $isPixcoordUsed$);
+    }
+
+    @Override
+    protected void updateShader(Shader shader) {
+        $paramUpdate$
+    }
+}
+
+>>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/java/JSWBackend.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,290 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.sw.java;
+
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import com.sun.scenario.effect.compiler.JSLParser;
+import com.sun.scenario.effect.compiler.model.BaseType;
+import com.sun.scenario.effect.compiler.model.Qualifier;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.model.Variable;
+import com.sun.scenario.effect.compiler.tree.FuncDef;
+import com.sun.scenario.effect.compiler.tree.ProgramUnit;
+import com.sun.scenario.effect.compiler.tree.TreeScanner;
+import org.antlr.stringtemplate.StringTemplate;
+import org.antlr.stringtemplate.StringTemplateGroup;
+import org.antlr.stringtemplate.language.DefaultTemplateLexer;
+
+/**
+ */
+public class JSWBackend extends TreeScanner {
+
+    private final JSLParser parser;
+    private final String body;
+
+    public JSWBackend(JSLParser parser, ProgramUnit program) {
+        // TODO: will be removed once we clean up static usage
+        resetStatics();
+
+        this.parser = parser;
+        
+        JSWTreeScanner scanner = new JSWTreeScanner();
+        scanner.scan(program);
+        this.body = scanner.getResult();
+    }
+    
+    public final String getGenCode(String effectName,
+                                   String peerName,
+                                   String interfaceName)
+    {
+        Map<String, Variable> vars = parser.getSymbolTable().getGlobalVariables();
+        StringBuilder interfaceDecl = new StringBuilder();
+        StringBuilder constants = new StringBuilder();
+        StringBuilder samplers = new StringBuilder();
+        StringBuilder cleanup = new StringBuilder();
+        StringBuilder srcRects = new StringBuilder();
+        StringBuilder posDecls = new StringBuilder();
+        StringBuilder pixInitY = new StringBuilder();
+        StringBuilder pixInitX = new StringBuilder();
+        StringBuilder posIncrY = new StringBuilder();
+        StringBuilder posInitY = new StringBuilder();
+        StringBuilder posIncrX = new StringBuilder();
+        StringBuilder posInitX = new StringBuilder();
+
+        // TODO: only need to declare these if pixcoord is referenced
+        // somewhere in the program...
+        pixInitY.append("float pixcoord_y = (float)dy;\n");
+        pixInitX.append("float pixcoord_x = (float)dx;\n");
+        
+        for (Variable v : vars.values()) {
+            if (v.getQualifier() == Qualifier.CONST && v.getConstValue() == null) {
+                // this must be a special built-in variable (e.g. pos0);
+                // these are handled elsewhere, so just continue...
+                continue;
+            }
+            
+            Type t = v.getType();
+            BaseType bt = t.getBaseType();
+            if (v.getQualifier() != null && bt != BaseType.SAMPLER) {
+                String vtype = bt.toString();
+                String vname = v.getName();
+                String accName = v.getAccessorName();
+                if (v.isArray()) {
+                    // TODO: we currently assume that param arrays will be
+                    // stored in NIO Int/FloatBuffers, but the inner loop
+                    // expects to access them as Java arrays, so we convert
+                    // here; this is obviously bad for performance, so we need
+                    // to come up with a better system soon...
+                    String bufType = (bt == BaseType.FLOAT) ?
+                        "FloatBuffer" : "IntBuffer";
+                    String bufName = vname + "_buf";
+                    String arrayName = vname + "_arr";
+                    constants.append(bufType + " " + bufName + " = " + accName + "();\n");
+                    constants.append(vtype + "[] " + arrayName);
+                    constants.append(" = new " + vtype + "[");
+                    constants.append(bufName + ".capacity()];\n");
+                    constants.append(bufName + ".get(" + arrayName + ");\n");
+                } else {
+                    if (t.isVector()) {
+                        String arrayName = vname + "_arr";
+                        constants.append(vtype + "[] " + arrayName + " = " + accName + "();\n");
+                        constants.append(vtype + " ");
+                        for (int i = 0; i < t.getNumFields(); i++) {
+                            if (i > 0) {
+                                constants.append(", ");
+                            }
+                            constants.append(vname + getSuffix(i) + " = " + arrayName + "[" + i + "]");
+                        }
+                        constants.append(";\n");
+                    } else {
+                        constants.append(vtype + " " + vname);
+                        if (v.getQualifier() == Qualifier.CONST) {
+                            constants.append(" = " + v.getConstValue());
+                        } else {
+                            constants.append(" = " + accName + "()");
+                        }
+                        constants.append(";\n");
+                    }
+                }
+            } else if (v.getQualifier() == Qualifier.PARAM && bt == BaseType.SAMPLER) {
+                int i = v.getReg();
+                if (t == Type.FSAMPLER) {
+                    samplers.append("FloatMap src" + i + " = (FloatMap)getSamplerData(" + i + ");\n");
+                    samplers.append("int src" + i + "x = 0;\n");
+                    samplers.append("int src" + i + "y = 0;\n");
+                    samplers.append("int src" + i + "w = src" + i + ".getWidth();\n");
+                    samplers.append("int src" + i + "h = src" + i + ".getHeight();\n");
+                    samplers.append("int src" + i + "scan = src" + i + ".getWidth();\n");
+                    samplers.append("float[] " + v.getName() + " = src" + i + ".getData();\n");
+                    samplers.append("float " + v.getName() + "_vals[] = new float[4];\n");
+
+                    // TODO: for now, assume [0,0,1,1]
+                    srcRects.append("float[] src" + i + "Rect = new float[] {0,0,1,1};\n");
+                } else {
+                    if (t == Type.LSAMPLER) {
+                        samplers.append("HeapImage src" + i + " = (HeapImage)inputs[" + i + "].getUntransformedImage();\n");
+                    } else {
+                        samplers.append("HeapImage src" + i + " = (HeapImage)inputs[" + i + "].getTransformedImage(dstBounds);\n");
+                        cleanup.append("inputs[" + i + "].releaseTransformedImage(src" + i + ");\n");
+                    }
+                    samplers.append("int src" + i + "x = 0;\n");
+                    samplers.append("int src" + i + "y = 0;\n");
+                    samplers.append("int src" + i + "w = src" + i + ".getPhysicalWidth();\n");
+                    samplers.append("int src" + i + "h = src" + i + ".getPhysicalHeight();\n");
+                    samplers.append("int src" + i + "scan = src" + i + ".getScanlineStride();\n");
+                    samplers.append("int[] " + v.getName() + " =\n");
+                    samplers.append("    src" + i + ".getPixelArray();\n");
+
+                    samplers.append("Rectangle src" + i + "Bounds = new Rectangle(");
+                    samplers.append("src" + i + "x, ");
+                    samplers.append("src" + i + "y, ");
+                    samplers.append("src" + i + "w, ");
+                    samplers.append("src" + i + "h);\n");
+                    if (t == Type.LSAMPLER) {
+                        samplers.append("Rectangle src" + i + "InputBounds = inputs[" + i + "].getUntransformedBounds();\n");
+                        samplers.append("BaseTransform src" + i + "Transform = inputs[" + i + "].getTransform();\n");
+                    } else {
+                        samplers.append("Rectangle src" + i + "InputBounds = inputs[" + i + "].getTransformedBounds(dstBounds);\n");
+                        samplers.append("BaseTransform src" + i + "Transform = BaseTransform.IDENTITY_TRANSFORM;\n");
+                    }
+                    samplers.append("setInputBounds(" + i + ", src" + i + "InputBounds);\n");
+                    samplers.append("setInputNativeBounds(" + i + ", src" + i + "Bounds);\n");
+
+                    if (t == Type.LSAMPLER) {
+                        samplers.append("float " + v.getName() + "_vals[] = new float[4];\n");
+                    }
+
+                    // the source rect decls need to come after all calls to
+                    // setInput[Native]Bounds() for all inputs (since the
+                    // getSourceRegion() impl may need to query the bounds of
+                    // other inputs, as is the case in PhongLighting)...
+                    srcRects.append("float[] src" + i + "Rect = new float[4];\n");
+                    // Note that we only allocate 4 floats here because none
+                    // of the loops can deal with fully mapped inputs.  Only
+                    // shaders that declare LSAMPLERs would require mapped
+                    // inputs and so far that is only Perspective and
+                    // Displacement, both of which override getTC() and return
+                    // only 4 values.
+                    srcRects.append("getTextureCoordinates(" + i + ", src" + i + "Rect,\n");
+                    srcRects.append("                      src" + i + "InputBounds.x, src" + i + "InputBounds.y,\n");
+                    srcRects.append("                      src" + i + "w, src" + i + "h,\n");
+                    srcRects.append("                      dstBounds, src" + i + "Transform);\n");
+                }
+
+                posDecls.append("float inc" + i + "_x = (src" + i + "Rect[2] - src" + i + "Rect[0]) / dstw;\n");
+                posDecls.append("float inc" + i + "_y = (src" + i + "Rect[3] - src" + i + "Rect[1]) / dsth;\n");
+
+                posInitY.append("float pos" + i + "_y = src" + i + "Rect[1] + inc" + i + "_y*0.5f;\n");
+                posInitX.append("float pos" + i + "_x = src" + i + "Rect[0] + inc" + i + "_x*0.5f;\n");
+                posIncrX.append("pos" + i + "_x += inc" + i + "_x;\n");
+                posIncrY.append("pos" + i + "_y += inc" + i + "_y;\n");
+            }
+        }
+        
+        if (interfaceName != null) {
+            interfaceDecl.append("implements "+interfaceName);
+        }
+
+        Reader template = new InputStreamReader(getClass().getResourceAsStream("JSWGlue.stg"));
+        StringTemplateGroup group = new StringTemplateGroup(template, DefaultTemplateLexer.class);
+        StringTemplate glue = group.getInstanceOf("glue");
+        glue.setAttribute("effectName", effectName);
+        glue.setAttribute("peerName", peerName);
+        glue.setAttribute("interfaceDecl", interfaceDecl.toString());
+        glue.setAttribute("usercode", usercode.toString());
+        glue.setAttribute("samplers", samplers.toString());
+        glue.setAttribute("cleanup", cleanup.toString());
+        glue.setAttribute("srcRects", srcRects.toString());
+        glue.setAttribute("constants", constants.toString());
+        glue.setAttribute("posDecls", posDecls.toString());
+        glue.setAttribute("pixInitY", pixInitY.toString());
+        glue.setAttribute("pixInitX", pixInitX.toString());
+        glue.setAttribute("posIncrY", posIncrY.toString());
+        glue.setAttribute("posInitY", posInitY.toString());
+        glue.setAttribute("posIncrX", posIncrX.toString());
+        glue.setAttribute("posInitX", posInitX.toString());
+        glue.setAttribute("body", body);
+        return glue.toString();
+    }
+    
+    // TODO: need better mechanism for querying fields
+    private static char[] fields = {'x', 'y', 'z', 'w'};
+    public static String getSuffix(int i) {
+        return "_" + fields[i];
+    }
+
+    static int getFieldIndex(char field) {
+        switch (field) {
+        case 'r':
+        case 'x':
+            return 0;
+        case 'g':
+        case 'y':
+            return 1;
+        case 'b':
+        case 'z':
+            return 2;
+        case 'a':
+        case 'w':
+            return 3;
+        default:
+            throw new InternalError();
+        }
+    }
+    
+    // TODO: these shouldn't be implemented as a static method
+    private static Map<String, FuncDef> funcDefs = new HashMap<String, FuncDef>();
+    static void putFuncDef(FuncDef def) {
+        funcDefs.put(def.getFunction().getName(), def);
+    }
+    static FuncDef getFuncDef(String name) {
+        return funcDefs.get(name);
+    }
+    
+    private static Set<String> resultVars = new HashSet<String>();
+    static boolean isResultVarDeclared(String vname) {
+        return resultVars.contains(vname);
+    }
+    static void declareResultVar(String vname) {
+        resultVars.add(vname);
+    }
+    
+    private static StringBuilder usercode = new StringBuilder();
+    static void addGlueBlock(String block) {
+        usercode.append(block);
+    }
+    
+    private static void resetStatics() {
+        funcDefs.clear();
+        resultVars.clear();
+        usercode = new StringBuilder();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/java/JSWCallScanner.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.sw.java;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import com.sun.scenario.effect.compiler.model.BaseType;
+import com.sun.scenario.effect.compiler.model.FuncImpl;
+import com.sun.scenario.effect.compiler.model.Function;
+import com.sun.scenario.effect.compiler.model.Param;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.model.Variable;
+import com.sun.scenario.effect.compiler.tree.ArrayAccessExpr;
+import com.sun.scenario.effect.compiler.tree.BinaryExpr;
+import com.sun.scenario.effect.compiler.tree.CallExpr;
+import com.sun.scenario.effect.compiler.tree.Expr;
+import com.sun.scenario.effect.compiler.tree.FieldSelectExpr;
+import com.sun.scenario.effect.compiler.tree.LiteralExpr;
+import com.sun.scenario.effect.compiler.tree.ParenExpr;
+import com.sun.scenario.effect.compiler.tree.TreeScanner;
+import com.sun.scenario.effect.compiler.tree.UnaryExpr;
+import com.sun.scenario.effect.compiler.tree.VariableExpr;
+import com.sun.scenario.effect.compiler.tree.VectorCtorExpr;
+
+import static com.sun.scenario.effect.compiler.backend.sw.java.JSWBackend.*;
+
+/*
+ * How should we translate function calls?  For now we will inline
+ * everything, i.e. expand function bodies directly into the loop body.
+ * 
+ * The approach... For an ExprStmt or VarDecl (with initializer),
+ * walk down the tree and see if there are any function calls.
+ * For each function call, inline the function implementation prior
+ * to the statement output.  The statement will then refer to
+ * the output variables from the inlined function, rather than
+ * the function call itself.
+ * 
+ * First declare the result variables using the name of the
+ * called function and a field suffix, if needed; for example:
+ *     float3 val = sample(...).rgb;
+ * ==>
+ *     float sample_res_r, sample_res_g, sample_res_b;
+ * 
+ * Inside the inlined function, assign parameter expressions to
+ * temporary variables, using the name of the declared parameters
+ * as a guide; for example:
+ *     float val = min(foo+0.25, 1.0);
+ * ==>
+ *     float min_res;
+ *     {
+ *         float a_tmp = foo + 0.25f;
+ *         float b_tmp = 1.0f;
+ *         min_res = (a_tmp < b_tmp) a_tmp : b_tmp;
+ *     }
+ * 
+ * In a future version, references to scalar variables and literals
+ * could easily be inlined; for example:
+ *     float val = min(foo+0.25*bar, 1.0);
+ * ==>
+ *     float min_res;
+ *     {
+ *         float a_tmp = foo + 0.25f * bar;
+ *         min_res = (a_tmp < 1.0f) a_tmp : 1.0f;
+ *     }
+ * 
+ * Note that this system will likely produce less-than-efficient
+ * Java code in many cases; for now we're just trying to get things
+ * functional, and performance improvements will certainly come later.
+ * 
+ * 
+ * Example #1:
+ *     float3 val = scale * sample(baseImg, pos + off.xy).rgb;
+ * ==>
+ *     float sample_res_r, sample_res_g, sample_res_b;
+ *     {
+ *         float pos_x_tmp = pos_x + off_x;
+ *         float pos_y_tmp = pos_y + off_y;
+ *         int baseImg_tmp =
+ *             baseImg[(int)(pos_y_tmp*srch*srcscan) + (int)(pos_x_tmp*srcw)];
+ *         sample_res_r = (((baseImg_tmp >>  16) & 0xff) / 255f);
+ *         sample_res_g = (((baseImg_tmp >>   8) & 0xff) / 255f);
+ *         sample_res_b = (((baseImg_tmp       ) & 0xff) / 255f);
+ *     }
+ *     float val_r = scale * sample_res_r;
+ *     float val_g = scale * sample_res_g;
+ *     float val_b = scale * sample_res_b;
+ * 
+ * Example #2:
+ *     float val = scale * clamp(foo, 0.0, 1.0);
+ * ==>
+ *     float clamp_res;
+ *     {
+ *         float val_tmp = foo;
+ *         float min_tmp = 0.0f;
+ *         float max_tmp = 1.0f;
+ *         if (val_tmp < min_tmp) clamp_res = min_tmp;
+ *         else if (val_tmp > max_tmp) clamp_res = max_tmp;
+ *         else clamp_res = val_tmp;
+ *     }
+ *     float val = scale * clamp_res;
+ */
+class JSWCallScanner extends TreeScanner {
+    private StringBuilder sb;
+    private boolean inCallExpr = false;
+    private Set<Integer> selectedFields = null;
+    private boolean inFieldSelect = false;
+    private char selectedField = 'x';
+    private boolean inVectorOp = false;
+    private int vectorIndex = 0;
+
+    private void output(String s) {
+        if (sb == null) {
+            sb = new StringBuilder();
+        }
+        sb.append(s);
+    }
+
+    String getResult() {
+        return (sb != null) ? sb.toString() : null;
+    }
+
+    @Override
+    public void visitCallExpr(CallExpr e) {
+        if (inCallExpr) {
+            throw new InternalError("Nested function calls not yet supported");
+        }
+
+        Function func = e.getFunction();
+        Type t = func.getReturnType();
+        String vtype = t.getBaseType().toString();
+        String vname = func.getName();
+        Set<Integer> fields = selectedFields;
+        if (t.isVector()) {
+            if (fields == null) {
+                fields = new HashSet<Integer>();
+                for (int i = 0; i < t.getNumFields(); i++) {
+                    fields.add(i);
+                }
+            }
+        }
+        if (!JSWBackend.isResultVarDeclared(vname)) {
+            // only declare result variables if they haven't been already
+            // TODO: there's a bug here; suppose a function like
+            // min(float,float) is inlined, then later we inline
+            // min(float3,float3), the second time we'll think we already have
+            // declared the result variables, but min_res_y/z won't be there...
+            JSWBackend.declareResultVar(vname);
+            if (t.isVector()) {
+                output(vtype + " ");
+                boolean first = true;
+                for (Integer f : fields) {
+                    if (first) {
+                        first = false;
+                    } else {
+                        output(", ");
+                    }
+                    output(vname + "_res" + getSuffix(f));
+                }
+                output(";\n");
+            } else {
+                output(vtype + " " + vname + "_res;\n");
+            }
+        }
+
+        inCallExpr = true;
+        output("{\n");
+        List<Param> params = func.getParams();
+        List<Expr> argExprs = e.getParams();
+        for (int i = 0; i < params.size(); i++) {
+            Param param = params.get(i);
+            String pname = param.getName();
+            Type ptype = param.getType();
+            BaseType pbasetype = ptype.getBaseType();
+            if (pbasetype == BaseType.SAMPLER) {
+                // skip these for now
+                continue;
+            }
+            if (ptype.isVector()) {
+                inVectorOp = true;
+                for (int j = 0; j < ptype.getNumFields(); j++) {
+                    vectorIndex = j;
+                    output(pbasetype.toString());
+                    output(" ");
+                    output(pname + "_tmp" + getSuffix(j) + " = ");
+                    scan(argExprs.get(i));
+                    output(";\n");
+                }
+                inVectorOp = false;
+            } else {
+                output(pbasetype.toString());
+                output(" ");
+                output(pname + "_tmp = ");
+                scan(argExprs.get(i));
+                output(";\n");
+            }
+        }
+
+        FuncImpl impl = JSWFuncImpls.get(func);
+        if (impl != null) {
+            // core (built-in) function
+            String preamble = impl.getPreamble(argExprs);
+            if (preamble != null) {
+                output(preamble);
+            }
+
+            if (t.isVector()) {
+                for (Integer f : fields) {
+                    output(vname + "_res" + getSuffix(f) + " = ");
+                    output(impl.toString(f, argExprs));
+                    output(";\n");
+                }
+            } else {
+                output(vname + "_res = ");
+                output(impl.toString(0, argExprs));
+                output(";\n");
+            }
+        } else {
+            // user-defined function
+            JSWTreeScanner scanner = new JSWTreeScanner(func.getName());
+            scanner.scan(JSWBackend.getFuncDef(func.getName()).getStmt());
+            output(scanner.getResult());
+        }
+
+        output("\n}\n");
+        inCallExpr = false;
+    }
+
+    @Override
+    public void visitArrayAccessExpr(ArrayAccessExpr e) {
+        if (inCallExpr) {
+            if (e.getExpr() instanceof VariableExpr &&
+                e.getIndex() instanceof VariableExpr)
+            {
+                VariableExpr ve = (VariableExpr)e.getExpr();
+                VariableExpr ie = (VariableExpr)e.getIndex();
+                output(ve.getVariable().getName());
+                output("_arr[" + ie.getVariable().getName());
+                output(" * " + ve.getVariable().getType().getNumFields());
+                output(" + " + getFieldIndex(selectedField) + "]");
+            } else {
+                throw new InternalError("Array access only supports variable expr/index (for now)");
+            }
+        } else {
+            super.visitArrayAccessExpr(e);
+        }
+    }
+
+    @Override
+    public void visitBinaryExpr(BinaryExpr e) {
+        if (inCallExpr) {
+            scan(e.getLeft());
+            output(" " + e.getOp() + " ");
+            scan(e.getRight());
+        } else {
+            super.visitBinaryExpr(e);
+        }
+    }
+
+    @Override
+    public void visitFieldSelectExpr(FieldSelectExpr e) {
+        if (inCallExpr) {
+            if (e.getFields().length() == 1) {
+                selectedField = e.getFields().charAt(0);
+            } else {
+                int index = inVectorOp ? vectorIndex : 0;
+                selectedField = e.getFields().charAt(index);
+            }
+            inFieldSelect = true;
+            scan(e.getExpr());
+            inFieldSelect = false;
+        } else {
+            selectedFields = getFieldSet(e.getFields());
+            super.visitFieldSelectExpr(e);
+            selectedFields = null;
+        }
+    }
+
+    private static Set<Integer> getFieldSet(String fields) {
+        Set<Integer> fieldSet = new HashSet<Integer>();
+        for (int i = 0; i < fields.length(); i++) {
+            fieldSet.add(getFieldIndex(fields.charAt(i)));
+        }
+        return fieldSet;
+    }
+
+    @Override
+    public void visitLiteralExpr(LiteralExpr e) {
+        if (inCallExpr) {
+            output(e.getValue().toString());
+            if (e.getValue() instanceof Float) {
+                output("f");
+            }
+        } else {
+            super.visitLiteralExpr(e);
+        }
+    }
+
+    @Override
+    public void visitParenExpr(ParenExpr e) {
+        if (inCallExpr) {
+            output("(");
+            scan(e.getExpr());
+            output(")");
+        } else {
+            super.visitParenExpr(e);
+        }
+    }
+
+    @Override
+    public void visitUnaryExpr(UnaryExpr e) {
+        if (inCallExpr) {
+            output(e.getOp().toString());
+            scan(e.getExpr());
+        } else {
+            super.visitUnaryExpr(e);
+        }
+    }
+
+    @Override
+    public void visitVariableExpr(VariableExpr e) {
+        if (inCallExpr) {
+            Variable var = e.getVariable();
+            output(var.getName());
+            if (var.isParam()) {
+                output("_tmp");
+            }
+            if (var.getType().isVector()) {
+                if (inFieldSelect) {
+                    output(getSuffix(getFieldIndex(selectedField)));
+                } else if (inVectorOp) {
+                    output(getSuffix(vectorIndex));
+                } else {
+                    throw new InternalError("TBD");
+                }
+            }
+        } else {
+            super.visitVariableExpr(e);
+        }
+    }
+
+    @Override
+    public void visitVectorCtorExpr(VectorCtorExpr e) {
+        // TODO: this will likely work for simple variables and literals,
+        // but we need something more for embedded function calls, etc...
+        scan(e.getParams().get(vectorIndex));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/java/JSWFuncImpls.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.sw.java;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import com.sun.scenario.effect.compiler.model.CoreSymbols;
+import com.sun.scenario.effect.compiler.model.FuncImpl;
+import com.sun.scenario.effect.compiler.model.Function;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.tree.Expr;
+import com.sun.scenario.effect.compiler.tree.VariableExpr;
+
+import static com.sun.scenario.effect.compiler.model.Type.*;
+
+/**
+ * Contains the pure Java implementations for all core (built-in) functions.
+ */
+class JSWFuncImpls {
+
+    private static Map<Function, FuncImpl> funcs = new HashMap<Function, FuncImpl>();
+    
+    static FuncImpl get(Function func) {
+        return funcs.get(func);
+    }
+    
+    static {
+        // float4 sample(sampler s, float2 loc)
+        declareFunctionSample(SAMPLER);
+
+        // float4 sample(lsampler s, float2 loc)
+        declareFunctionSample(LSAMPLER);
+
+        // float4 sample(fsampler s, float2 loc)
+        declareFunctionSample(FSAMPLER);
+
+        // int intcast(float x)
+        declareFunctionIntCast();
+
+        // <ftype> min(<ftype> x, <ftype> y)
+        // <ftype> min(<ftype> x, float y)
+        declareOverloadsMinMax("min", "(x_tmp$1 < y_tmp$2) ? x_tmp$1 : y_tmp$2");
+
+        // <ftype> max(<ftype> x, <ftype> y)
+        // <ftype> max(<ftype> x, float y)
+        declareOverloadsMinMax("max", "(x_tmp$1 > y_tmp$2) ? x_tmp$1 : y_tmp$2");
+
+        // <ftype> clamp(<ftype> val, <ftype> min, <ftype> max)
+        // <ftype> clamp(<ftype> val, float min, float max)
+        declareOverloadsClamp();
+
+        // <ftype> smoothstep(<ftype> min, <ftype> max, <ftype> val)
+        // <ftype> smoothstep(float min, float max, <ftype> val)
+        declareOverloadsSmoothstep();
+
+        // <ftype> abs(<ftype> x)
+        declareOverloadsSimple("abs", "Math.abs(x_tmp$1)");
+
+        // <ftype> floor(<ftype> x)
+        declareOverloadsSimple("floor", "(float)Math.floor(x_tmp$1)");
+
+        // <ftype> ceil(<ftype> x)
+        declareOverloadsSimple("ceil", "(float)Math.ceil(x_tmp$1)");
+
+        // <ftype> fract(<ftype> x)
+        declareOverloadsSimple("fract", "(x_tmp$1 - (float)Math.floor(x_tmp$1))");
+
+        // <ftype> sign(<ftype> x)
+        declareOverloadsSimple("sign", "Math.signum(x_tmp$1)");
+
+        // <ftype> sqrt(<ftype> x)
+        declareOverloadsSimple("sqrt", "(float)Math.sqrt(x_tmp$1)");
+
+        // <ftype> sin(<ftype> x)
+        declareOverloadsSimple("sin", "(float)Math.sin(x_tmp$1)");
+
+        // <ftype> cos(<ftype> x)
+        declareOverloadsSimple("cos", "(float)Math.cos(x_tmp$1)");
+
+        // <ftype> tan(<ftype> x)
+        declareOverloadsSimple("tan", "(float)Math.tan(x_tmp$1)");
+
+        // <ftype> pow(<ftype> x, <ftype> y)
+        declareOverloadsSimple2("pow", "(float)Math.pow(x_tmp$1, y_tmp$2)");
+
+        // <ftype> mod(<ftype> x, <ftype> y)
+        // <ftype> mod(<ftype> x, float y)
+        declareOverloadsMinMax("mod", "(x_tmp$1 % y_tmp$2)");
+
+        // float dot(<ftype> x, <ftype> y)
+        declareOverloadsDot();
+
+        // float distance(<ftype> x, <ftype> y)
+        declareOverloadsDistance();
+
+        // <ftype> mix(<ftype> x, <ftype> y, <ftype> a)
+        // <ftype> mix(<ftype> x, <ftype> y, float a)
+        declareOverloadsMix();
+        
+        // <ftype> normalize(<ftype> x)
+        declareOverloadsNormalize();
+
+        // <ftype> ddx(<ftype> p)
+        declareOverloadsSimple("ddx", "<ddx() not implemented for sw backends>");
+
+        // <ftype> ddy(<ftype> p)
+        declareOverloadsSimple("ddy", "<ddy() not implemented for sw backends>");
+    }
+    
+    private static void declareFunction(FuncImpl impl,
+                                        String name, Type... ptypes)
+    {
+        Function f = CoreSymbols.getFunction(name, Arrays.asList(ptypes));
+        if (f == null) {
+            throw new InternalError("Core function not found (have you declared the function in CoreSymbols?)");
+        }
+        funcs.put(f, impl);
+    }
+    
+    /**
+     * Used to declare sample function:
+     *   float4 sample([l,f]sampler s, float2 loc)
+     */
+    private static void declareFunctionSample(final Type type) {
+        FuncImpl fimpl = new FuncImpl() {
+            @Override
+            public String getPreamble(List<Expr> params) {
+                String s = getSamplerName(params);
+                // TODO: this bounds checking is way too costly...
+                String p = getPosName(params);
+                if (type == LSAMPLER) {
+                    return
+                        "lsample(" + s + ", loc_tmp_x, loc_tmp_y,\n" +
+                        "        " + p + "w, " + p + "h, " + p + "scan,\n" +
+                        "        " + s + "_vals);\n";
+                } else if (type == FSAMPLER) {
+                    return
+                        "fsample(" + s + ", loc_tmp_x, loc_tmp_y,\n" +
+                        "        " + p + "w, " + p + "h, " + p + "scan,\n" +
+                        "        " + s + "_vals);\n";
+                } else {
+                    return
+                        "int " + s + "_tmp;\n" +
+                        "if (loc_tmp_x >= 0 && loc_tmp_y >= 0) {\n" +
+                        "    int iloc_tmp_x = (int)(loc_tmp_x*" + p + "w);\n" +
+                        "    int iloc_tmp_y = (int)(loc_tmp_y*" + p + "h);\n" +
+                        "    boolean out =\n" +
+                        "        iloc_tmp_x >= " + p + "w ||\n" +
+                        "        iloc_tmp_y >= " + p + "h;\n" +
+                        "    " + s + "_tmp = out ? 0 :\n" +
+                        "        " + s + "[iloc_tmp_y*" + p + "scan + iloc_tmp_x];\n" +
+                        "} else {\n" +
+                        "    " + s + "_tmp = 0;\n" +
+                        "}\n";
+                }
+            }
+            public String toString(int i, List<Expr> params) {
+                String s = getSamplerName(params);
+                if (type == LSAMPLER || type == FSAMPLER) {
+                    return (i < 0 || i > 3) ? null : s + "_vals[" + i + "]";
+                } else {
+                    switch (i) {
+                    case 0:
+                        return "(((" + s + "_tmp >>  16) & 0xff) / 255f)";
+                    case 1:
+                        return "(((" + s + "_tmp >>   8) & 0xff) / 255f)";
+                    case 2:
+                        return "(((" + s + "_tmp       ) & 0xff) / 255f)";
+                    case 3:
+                        return "(((" + s + "_tmp >>> 24)       ) / 255f)";
+                    default:
+                        return null;
+                    }
+                }
+            }
+            private String getSamplerName(List<Expr> params) {
+                VariableExpr e = (VariableExpr)params.get(0);
+                return e.getVariable().getName();
+            }
+            private String getPosName(List<Expr> params) {
+                VariableExpr e = (VariableExpr)params.get(0);
+                return "src" + e.getVariable().getReg();
+            }
+        };
+        declareFunction(fimpl, "sample", type, FLOAT2);
+    }
+
+    /**
+     * Used to declare intcast function:
+     *   int intcast(float x)
+     */
+    private static void declareFunctionIntCast() {
+        FuncImpl fimpl = new FuncImpl() {
+            public String toString(int i, List<Expr> params) {
+                return "((int)x_tmp)";
+            }
+        };
+        declareFunction(fimpl, "intcast", FLOAT);
+    }
+
+    /**
+     * Used to declare simple functions of the following form: 
+     *   <ftype> name(<ftype> x)
+     */
+    private static void declareOverloadsSimple(String name, final String pattern) {
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? JSWBackend.getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type);
+        }
+    }
+
+    /**
+     * Used to declare simple two parameter functions of the following form:
+     *   <ftype> name(<ftype> x, <ftype> y)
+     */
+    private static void declareOverloadsSimple2(String name, final String pattern) {
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            // declare (vectype,vectype) variants
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? JSWBackend.getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type);
+        }
+    }
+
+    /**
+     * Used to declare normalize functions of the following form: 
+     *   <ftype> normalize(<ftype> x)
+     */
+    private static void declareOverloadsNormalize() {
+        final String name = "normalize";
+        final String pattern = "x_tmp$1 / denom";
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            int n = type.getNumFields();
+            final String preamble;
+            if (n == 1) {
+                preamble = "float denom = x_tmp;\n";
+            } else {
+                String     s  =    "(x_tmp_x * x_tmp_x)";
+                           s += "+\n(x_tmp_y * x_tmp_y)";
+                if (n > 2) s += "+\n(x_tmp_z * x_tmp_z)";
+                if (n > 3) s += "+\n(x_tmp_w * x_tmp_w)";
+                preamble = "float denom = (float)Math.sqrt(" + s + ");\n";
+            }
+            
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                @Override
+                public String getPreamble(List<Expr> params) {
+                    return preamble;
+                }
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? JSWBackend.getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type);
+        }
+    }
+
+    /**
+     * Used to declare dot functions of the following form: 
+     *   float dot(<ftype> x, <ftype> y)
+     */
+    private static void declareOverloadsDot() {
+        final String name = "dot";
+        for (final Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            int n = type.getNumFields();
+            String s;
+            if (n == 1) {
+                s = "(x_tmp * y_tmp)";
+            } else {
+                           s  =    "(x_tmp_x * y_tmp_x)";
+                           s += "+\n(x_tmp_y * y_tmp_y)";
+                if (n > 2) s += "+\n(x_tmp_z * y_tmp_z)";
+                if (n > 3) s += "+\n(x_tmp_w * y_tmp_w)";
+            }
+            final String str = s;
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    return str;
+                }
+            };
+            declareFunction(fimpl, name, type, type);
+        }
+    }
+
+    /**
+     * Used to declare distance functions of the following form: 
+     *   float distance(<ftype> x, <ftype> y)
+     */
+    private static void declareOverloadsDistance() {
+        final String name = "distance";
+        for (final Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            int n = type.getNumFields();
+            String s;
+            if (n == 1) {
+                s = "(x_tmp - y_tmp) * (x_tmp - y_tmp)";
+            } else {
+                           s  =    "((x_tmp_x - y_tmp_x) * (x_tmp_x - y_tmp_x))";
+                           s += "+\n((x_tmp_y - y_tmp_y) * (x_tmp_y - y_tmp_y))";
+                if (n > 2) s += "+\n((x_tmp_z - y_tmp_z) * (x_tmp_z - y_tmp_z))";
+                if (n > 3) s += "+\n((x_tmp_w - y_tmp_w) * (x_tmp_w - y_tmp_w))";
+            }
+            final String str = "(float)Math.sqrt(" + s + ")";
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    return str;
+                }
+            };
+            declareFunction(fimpl, name, type, type);
+        }
+    }
+
+    /**
+     * Used to declare min/max functions of the following form:
+     *   <ftype> name(<ftype> x, <ftype> y)
+     *   <ftype> name(<ftype> x, float y)
+     * 
+     * TODO: this is currently geared to simple functions like
+     * min and max; we should make this more general...
+     */
+    private static void declareOverloadsMinMax(String name, final String pattern) {
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            // declare (vectype,vectype) variants
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? JSWBackend.getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type);
+            
+            if (type == FLOAT) {
+                continue;
+            }
+            
+            // declare (vectype,float) variants
+            fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = JSWBackend.getSuffix(i);
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", "");
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, FLOAT);
+        }
+    }
+
+    /**
+     * Used to declare clamp functions of the following form:
+     *   <ftype> clamp(<ftype> val, <ftype> min, <ftype> max)
+     *   <ftype> clamp(<ftype> val, float min, float max)
+     */
+    private static void declareOverloadsClamp() {
+        final String name = "clamp";
+        final String pattern =
+            "(val_tmp$1 < min_tmp$2) ? min_tmp$2 : \n" +
+            "(val_tmp$1 > max_tmp$2) ? max_tmp$2 : val_tmp$1";
+        
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            // declare (vectype,vectype,vectype) variants
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? JSWBackend.getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type, type);
+            
+            if (type == FLOAT) {
+                continue;
+            }
+            
+            // declare (vectype,float,float) variants
+            fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = JSWBackend.getSuffix(i);
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", "");
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, FLOAT, FLOAT);
+        }
+    }
+
+    /**
+     * Used to declare smoothstep functions of the following form:
+     *   <ftype> smoothstep(<ftype> min, <ftype> max, <ftype> val)
+     *   <ftype> smoothstep(float min, float max, <ftype> val)
+     */
+    private static void declareOverloadsSmoothstep() {
+        final String name = "smoothstep";
+        // TODO - the smoothstep function is defined to use Hermite interpolation
+        final String pattern =
+            "(val_tmp$1 < min_tmp$2) ? 0.0f : \n" +
+            "(val_tmp$1 > max_tmp$2) ? 1.0f : \n" +
+            "(val_tmp$1 / (max_tmp$2 - min_tmp$2))";
+        
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            // declare (vectype,vectype,vectype) variants
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? JSWBackend.getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type, type);
+            
+            if (type == FLOAT) {
+                continue;
+            }
+            
+            // declare (float,float,vectype) variants
+            fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = JSWBackend.getSuffix(i);
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", "");
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, FLOAT, FLOAT, type);
+        }
+    }
+    
+    /**
+     * Used to declare mix functions of the following form:
+     *   <ftype> mix(<ftype> x, <ftype> y, <ftype> a)
+     *   <ftype> mix(<ftype> x, <ftype> y, float a)
+     */
+    private static void declareOverloadsMix() {
+        final String name = "mix";
+        final String pattern =
+            "(x_tmp$1 * (1.0f - a_tmp$2) + y_tmp$1 * a_tmp$2)";
+        
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            // declare (vectype,vectype,vectype) variants
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? JSWBackend.getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type, type);
+            
+            if (type == FLOAT) {
+                continue;
+            }
+            
+            // declare (vectype,vectype,float) variants
+            fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = JSWBackend.getSuffix(i);
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", "");
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type, FLOAT);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/java/JSWGlue.stg	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,128 @@
+group JSWGlue;
+
+glue(effectName,peerName,interfaceDecl,
+     usercode,samplers,cleanup,srcRects,constants,
+     pixInitY,pixInitX,posDecls,posInitY,posIncrY,posInitX,posIncrX,
+     body) ::= <<
+/*
+ * Copyright (c) 2008, 2011, Oracle  and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * This file was generated by JSLC -- DO NOT EDIT MANUALLY!
+ */
+
+package com.sun.scenario.effect.impl.sw.java;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import com.sun.scenario.effect.Effect;
+import com.sun.scenario.effect.FilterContext;
+import com.sun.scenario.effect.FloatMap;
+import com.sun.scenario.effect.ImageData;
+import com.sun.scenario.effect.$effectName$;
+import com.sun.scenario.effect.impl.BufferUtil;
+import com.sun.scenario.effect.impl.HeapImage;
+import com.sun.scenario.effect.impl.Renderer;
+import com.sun.scenario.effect.impl.state.*;
+import com.sun.javafx.geom.Rectangle;
+import com.sun.javafx.geom.transform.BaseTransform;
+
+public class JSW$peerName$Peer extends JSWEffectPeer $interfaceDecl$ {
+
+    public JSW$peerName$Peer(FilterContext fctx, Renderer r, String uniqueName) {
+        super(fctx, r, uniqueName);
+    }
+
+    @Override
+    protected final $effectName$ getEffect() {
+        return ($effectName$)super.getEffect();
+    }
+
+    $usercode$
+
+    @Override
+    public ImageData filter(Effect effect,
+                            BaseTransform transform,
+                            Rectangle outputClip,
+                            ImageData... inputs)
+    {
+        setEffect(effect);
+        Rectangle dstBounds = getResultBounds(transform, outputClip, inputs);
+        setDestBounds(dstBounds);
+
+        // TODO: for now, all input images must be TYPE_INT_ARGB_PRE
+        $samplers$
+
+        $srcRects$
+
+        final int dstx = 0;
+        final int dsty = 0;
+        final int dstw = dstBounds.width;
+        final int dsth = dstBounds.height;
+
+        HeapImage dst = (HeapImage)getRenderer().getCompatibleImage(dstw, dsth);
+        setDestNativeBounds(dst.getPhysicalWidth(), dst.getPhysicalHeight());
+        int dstscan = dst.getScanlineStride();
+        int[] dstPixels = dst.getPixelArray();
+        
+        int dyi;
+        float color_x, color_y, color_z, color_w;
+
+        $constants$
+
+        $posDecls$
+
+        $posInitY$
+        for (int dy = dsty; dy < dsty+dsth; dy++) {
+            $pixInitY$
+            dyi = dy*dstscan;
+
+            $posInitX$
+            for (int dx = dstx; dx < dstx+dstw; dx++) {
+                $pixInitX$
+
+                $body$
+
+                if (color_w < 0f) color_w = 0f; else if (color_w > 1f) color_w = 1f;
+                if (color_x < 0f) color_x = 0f; else if (color_x > color_w) color_x = color_w;
+                if (color_y < 0f) color_y = 0f; else if (color_y > color_w) color_y = color_w;
+                if (color_z < 0f) color_z = 0f; else if (color_z > color_w) color_z = color_w;
+                dstPixels[dyi+dx] =
+                    ((int)(color_x * 0xff) << 16) |
+                    ((int)(color_y * 0xff) <<  8) |
+                    ((int)(color_z * 0xff) <<  0) |
+                    ((int)(color_w * 0xff) << 24);
+
+                $posIncrX$
+            }
+
+            $posIncrY$
+        }
+
+        $cleanup$
+
+        return new ImageData(getFilterContext(), dst, dstBounds);
+    }
+}
+
+>>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/java/JSWTreeScanner.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.sw.java;
+
+import com.sun.scenario.effect.compiler.model.Function;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.model.Variable;
+import com.sun.scenario.effect.compiler.tree.*;
+import static com.sun.scenario.effect.compiler.backend.sw.java.JSWBackend.getFieldIndex;
+import static com.sun.scenario.effect.compiler.backend.sw.java.JSWBackend.getSuffix;
+
+/**
+ */
+class JSWTreeScanner extends TreeScanner {
+
+    private final String funcName;
+    private final StringBuilder sb = new StringBuilder();
+
+    private boolean inVectorOp = false;
+    private int vectorIndex = 0;
+    private boolean inFieldSelect = false;
+    private char selectedField = 'x';
+    
+    JSWTreeScanner() {
+        this(null);
+    }
+    
+    JSWTreeScanner(String funcName) {
+        this.funcName = funcName;
+    }
+    
+    private void output(String s) {
+        sb.append(s);
+    }
+    
+    String getResult() {
+        return (sb != null) ? sb.toString() : null;
+    }
+    
+    @Override
+    public void visitArrayAccessExpr(ArrayAccessExpr e) {
+        if (e.getExpr() instanceof VariableExpr &&
+            e.getIndex() instanceof VariableExpr)
+        {
+            VariableExpr ve = (VariableExpr)e.getExpr();
+            VariableExpr ie = (VariableExpr)e.getIndex();
+            output(ve.getVariable().getName());
+            output("_arr[" + ie.getVariable().getName());
+            output(" * " + ve.getVariable().getType().getNumFields());
+            output(" + " + getFieldIndex(selectedField) + "]");
+        } else {
+            throw new InternalError("Array access only supports variable expr/index (for now)");
+        }
+    }
+
+    @Override
+    public void visitBinaryExpr(BinaryExpr e) {
+        scan(e.getLeft());
+        output(" " + e.getOp() + " ");
+        scan(e.getRight());
+    }
+
+    @Override
+    public void visitBreakStmt(BreakStmt s) {
+        output("break;");
+    }
+
+    @Override
+    public void visitCallExpr(CallExpr e) {
+        Function func = e.getFunction();
+        output(func.getName() + "_res");
+        if (func.getReturnType().isVector()) {
+            // TODO: this needs more thought
+            if (inFieldSelect) {
+                output(getSuffix(getFieldIndex(selectedField)));
+            } else if (inVectorOp) {
+                output(getSuffix(vectorIndex));
+            } else {
+                throw new InternalError("TBD");
+            }
+        }
+    }
+
+    @Override
+    public void visitCompoundStmt(CompoundStmt s) {
+        output("{\n");
+        super.visitCompoundStmt(s);
+        output("}\n");
+    }
+
+    @Override
+    public void visitContinueStmt(ContinueStmt s) {
+        output("continue;");
+    }
+
+    @Override
+    public void visitDeclStmt(DeclStmt s) {
+        super.visitDeclStmt(s);
+    }
+
+    @Override
+    public void visitDiscardStmt(DiscardStmt s) {
+        // TODO: not yet implemented
+    }
+
+    @Override
+    public void visitDoWhileStmt(DoWhileStmt s) {
+        output("do ");
+        scan(s.getStmt());
+        output(" while (");
+        scan(s.getExpr());
+        output(");");
+    }
+
+    @Override
+    public void visitExprStmt(ExprStmt s) {
+        Expr expr = s.getExpr();
+        
+        outputPreambles(expr);
+
+        Type t = expr.getResultType();
+        if (t.isVector()) {
+            inVectorOp = true;
+            for (int i = 0; i < t.getNumFields(); i++) {
+                vectorIndex = i;
+                scan(s.getExpr());
+                output(";\n");
+            }
+            inVectorOp = false;
+        } else {
+            scan(s.getExpr());
+            output(";\n");
+        }
+    }
+
+    @Override
+    public void visitFieldSelectExpr(FieldSelectExpr e) {
+        if (e.getFields().length() == 1) {
+            selectedField = e.getFields().charAt(0);
+        } else {
+            int index = inVectorOp ? vectorIndex : 0;
+            selectedField = e.getFields().charAt(index);
+        }
+        inFieldSelect = true;
+        scan(e.getExpr());
+        inFieldSelect = false;
+    }
+    
+    @Override
+    public void visitForStmt(ForStmt s) {
+        output("for (");
+        scan(s.getInit());
+        scan(s.getCondition());
+        output(";");
+        scan(s.getExpr());
+        output(")");
+        scan(s.getStmt());
+    }
+
+    @Override
+    public void visitFuncDef(FuncDef d) {
+        if (d.getFunction().getName().equals("main")) {
+            scan(d.getStmt());
+        } else {
+            // TODO: this is a hacky approach to saving func defs, which
+            // will be inlined later at point of use)...
+            JSWBackend.putFuncDef(d);
+        }
+    }
+    
+    @Override
+    public void visitGlueBlock(GlueBlock b) {
+        JSWBackend.addGlueBlock(b.getText());
+    }
+
+    @Override
+    public void visitLiteralExpr(LiteralExpr e) {
+        output(e.getValue().toString());
+        if (e.getValue() instanceof Float) {
+            output("f");
+        }
+    }
+    
+    @Override
+    public void visitParenExpr(ParenExpr e) {
+        output("(");
+        scan(e.getExpr());
+        output(")");
+    }
+
+    @Override
+    public void visitProgramUnit(ProgramUnit p) {
+        super.visitProgramUnit(p);
+    }
+
+    @Override
+    public void visitReturnStmt(ReturnStmt s) {
+        Expr expr = s.getExpr();
+        if (expr == null) {
+            throw new InternalError("Empty return not yet implemented");
+        }
+        if (funcName == null) {
+            throw new RuntimeException("Return statement not expected");
+        }
+        
+        Type t = expr.getResultType();
+        if (t.isVector()) {
+            inVectorOp = true;
+            for (int i = 0; i < t.getNumFields(); i++) {
+                vectorIndex = i;
+                output(funcName + "_res" + JSWBackend.getSuffix(i) + " = ");
+                scan(s.getExpr());
+                output(";\n");
+            }
+            inVectorOp = false;
+        } else {
+            output(funcName + "_res = ");
+            scan(s.getExpr());
+            output(";\n");
+        }
+    }
+
+    @Override
+    public void visitSelectStmt(SelectStmt s) {
+        output("if (");
+        scan(s.getIfExpr());
+        output(")");
+        scan(s.getThenStmt());
+        Stmt e = s.getElseStmt();
+        if (e != null) {
+            output(" else ");
+            scan(e);
+        }
+    }
+
+    @Override
+    public void visitUnaryExpr(UnaryExpr e) {
+        output(e.getOp().toString());
+        scan(e.getExpr());
+    }
+    
+    @Override
+    public void visitVarDecl(VarDecl d) {
+        Variable var = d.getVariable();
+        if (var.getQualifier() != null) {
+            // these will be declared separately outside the loop body
+            return;
+        }
+
+        outputPreambles(d);
+        
+        Type t = var.getType();
+        if (t.isVector()) {
+            inVectorOp = true;
+            for (int i = 0; i < t.getNumFields(); i++) {
+                output(t.getBaseType().toString() + " ");
+                output(var.getName() + getSuffix(i));
+                Expr init = d.getInit();
+                if (init != null) {
+                    output(" = ");
+                    vectorIndex = i;
+                    scan(init);
+                }
+                output(";\n");
+            }
+            inVectorOp = false;
+        } else {
+            output(t.toString() + " " + var.getName());
+            Expr init = d.getInit();
+            if (init != null) {
+                output(" = ");
+                scan(init);
+            }
+            output(";\n");
+        }
+    }
+
+    @Override
+    public void visitVariableExpr(VariableExpr e) {
+        Variable var = e.getVariable();
+        output(var.getName());
+        if (var.isParam()) {
+            output("_tmp");
+        }
+        if (var.getType().isVector()) {
+            if (inFieldSelect) {
+                output(getSuffix(getFieldIndex(selectedField)));
+            } else if (inVectorOp) {
+                output(getSuffix(vectorIndex));
+            } else {
+                throw new InternalError("TBD");
+            }
+        }
+    }
+
+    @Override
+    public void visitVectorCtorExpr(VectorCtorExpr e) {
+        // TODO: this will likely work for simple variables and literals,
+        // but we need something more for embedded function calls, etc...
+        scan(e.getParams().get(vectorIndex));
+    }
+
+    @Override
+    public void visitWhileStmt(WhileStmt s) {
+        output("while (");
+        scan(s.getCondition());
+        output(")");
+        scan(s.getStmt());
+    }
+    
+    private void outputPreambles(Tree tree) {
+        JSWCallScanner scanner = new JSWCallScanner();
+        scanner.scan(tree);
+        String res = scanner.getResult();
+        if (res != null) {
+            output(scanner.getResult());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/me/MEBackend.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,359 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.sw.me;
+
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import com.sun.scenario.effect.compiler.JSLParser;
+import com.sun.scenario.effect.compiler.model.BaseType;
+import com.sun.scenario.effect.compiler.model.Qualifier;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.model.Variable;
+import com.sun.scenario.effect.compiler.tree.FuncDef;
+import com.sun.scenario.effect.compiler.tree.ProgramUnit;
+import com.sun.scenario.effect.compiler.tree.TreeScanner;
+import org.antlr.stringtemplate.StringTemplate;
+import org.antlr.stringtemplate.StringTemplateGroup;
+import org.antlr.stringtemplate.language.DefaultTemplateLexer;
+
+/**
+ */
+public class MEBackend extends TreeScanner {
+
+    private final JSLParser parser;
+    private final String body;
+
+    public MEBackend(JSLParser parser, ProgramUnit program) {
+        // TODO: will be removed once we clean up static usage
+        resetStatics();
+
+        this.parser = parser;
+        
+        METreeScanner scanner = new METreeScanner();
+        scanner.scan(program);
+        this.body = scanner.getResult();
+    }
+    
+    public static class GenCode {
+        public String javaCode;
+        public String nativeCode;
+    }
+
+    private static void appendGetRelease(StringBuilder get,
+                                         StringBuilder rel,
+                                         String ctype,
+                                         String cbufName, String jarrayName)
+    {
+        get.append("j" + ctype + " *" + cbufName + " = (j" + ctype + " *)");
+        get.append("env->GetPrimitiveArrayCritical(" + jarrayName + ", 0);\n");
+        get.append("if (" + cbufName + " == NULL) return;\n");
+        rel.append("env->ReleasePrimitiveArrayCritical(" + jarrayName + ", " + cbufName + ", JNI_ABORT);\n");
+    }
+
+    public final GenCode getGenCode(String effectName,
+                                    String peerName,
+                                    String interfaceName)
+    {
+        Map<String, Variable> vars = parser.getSymbolTable().getGlobalVariables();
+        StringBuilder interfaceDecl = new StringBuilder();
+        StringBuilder constants = new StringBuilder();
+        StringBuilder samplers = new StringBuilder();
+        StringBuilder srcRects = new StringBuilder();
+        StringBuilder posDecls = new StringBuilder();
+        StringBuilder pixInitY = new StringBuilder();
+        StringBuilder pixInitX = new StringBuilder();
+        StringBuilder posIncrY = new StringBuilder();
+        StringBuilder posInitY = new StringBuilder();
+        StringBuilder posIncrX = new StringBuilder();
+        StringBuilder posInitX = new StringBuilder();
+        StringBuilder jparams = new StringBuilder();
+        StringBuilder jparamDecls = new StringBuilder();
+        StringBuilder cparamDecls = new StringBuilder();
+        StringBuilder arrayGet = new StringBuilder();
+        StringBuilder arrayRelease = new StringBuilder();
+
+        appendGetRelease(arrayGet, arrayRelease, "int", "dst", "dst_arr");
+        
+        // TODO: only need to declare these if pixcoord is referenced
+        // somewhere in the program...
+        pixInitY.append("float pixcoord_y = (float)dy;\n");
+        pixInitX.append("float pixcoord_x = (float)dx;\n");
+        
+        for (Variable v : vars.values()) {
+            if (v.getQualifier() == Qualifier.CONST && v.getConstValue() == null) {
+                // this must be a special built-in variable (e.g. pos0);
+                // these are handled elsewhere, so just continue...
+                continue;
+            }
+            
+            Type t = v.getType();
+            BaseType bt = t.getBaseType();
+            String vtype = bt.toString();
+            String vname = v.getName();
+            if (v.getQualifier() != null && bt != BaseType.SAMPLER) {
+                String accName = v.getAccessorName();
+                if (v.isArray()) {
+                    // TODO: we currently assume that param arrays will be
+                    // stored in NIO Int/FloatBuffers, but the inner loop
+                    // expects to access them as Java arrays, so we convert
+                    // here; this is obviously bad for performance, so we need
+                    // to come up with a better system soon...
+                    String bufType = (bt == BaseType.FLOAT) ?
+                        "FloatBuffer" : "IntBuffer";
+                    String bufName = vname + "_buf";
+                    String arrayName = vname + "_arr";
+                    constants.append(bufType + " " + bufName + " = " + accName + "();\n");
+                    constants.append(vtype + "[] " + arrayName);
+                    constants.append(" = new " + vtype + "[");
+                    constants.append(bufName + ".capacity()];\n");
+                    constants.append(bufName + ".get(" + arrayName + ");\n");
+                    jparams.append(",\n");
+                    jparams.append(arrayName);
+                    jparamDecls.append(",\n");
+                    jparamDecls.append(vtype + "[] " + vname);
+                    cparamDecls.append(",\n");
+                    cparamDecls.append("j" + vtype + "Array " + vname);
+                    appendGetRelease(arrayGet, arrayRelease, vtype, arrayName, vname);
+                } else {
+                    if (t.isVector()) {
+                        String arrayName = vname + "_arr";
+                        constants.append(vtype + "[] " + arrayName + " = " + accName + "();\n");
+                        jparams.append(",\n");
+                        jparamDecls.append(",\n");
+                        cparamDecls.append(",\n");
+                        for (int i = 0; i < t.getNumFields(); i++) {
+                            if (i > 0) {
+                                jparams.append(", ");
+                                jparamDecls.append(", ");
+                                cparamDecls.append(", ");
+                            }
+                            String vn = vname + getSuffix(i);
+                            jparams.append(arrayName + "[" + i + "]");
+                            jparamDecls.append(vtype + " " + vn);
+                            cparamDecls.append("j" + vtype + " " + vn);
+                        }
+                    } else {
+                        constants.append(vtype + " " + vname);
+                        if (v.getQualifier() == Qualifier.CONST) {
+                            constants.append(" = " + v.getConstValue());
+                        } else {
+                            constants.append(" = " + accName + "()");
+                        }
+                        constants.append(";\n");
+                        jparams.append(",\n");
+                        jparams.append(vname);
+                        jparamDecls.append(",\n");
+                        jparamDecls.append(vtype + " " + vname);
+                        cparamDecls.append(",\n");
+                        cparamDecls.append("j" + vtype + " " + vname);
+                    }
+                }
+            } else if (v.getQualifier() == Qualifier.PARAM && bt == BaseType.SAMPLER) {
+                int i = v.getReg();
+                if (t == Type.FSAMPLER) {
+                    samplers.append("FloatMap src" + i + " = (FloatMap)getSamplerData(" + i + ");\n");
+                    samplers.append("int src" + i + "x = 0;\n");
+                    samplers.append("int src" + i + "y = 0;\n");
+                    samplers.append("int src" + i + "w = src" + i + ".getWidth();\n");
+                    samplers.append("int src" + i + "h = src" + i + ".getHeight();\n");
+                    samplers.append("int src" + i + "scan = src" + i + ".getWidth();\n");
+                    samplers.append("float[] " + vname + " = src" + i + ".getData();\n");
+
+                    // TODO: for now, assume [0,0,1,1]
+                    srcRects.append("float[] src" + i + "Rect = new float[] {0,0,1,1};\n");
+                    
+                    jparams.append(",\n");
+                    jparams.append(vname);
+                    
+                    jparamDecls.append(",\n");
+                    jparamDecls.append("float[] " + vname + "_arr");
+                    
+                    cparamDecls.append(",\n");
+                    cparamDecls.append("jfloatArray " + vname + "_arr");
+                    
+                    appendGetRelease(arrayGet, arrayRelease, "float", vname, vname + "_arr");
+                } else {
+                    samplers.append("BufferedImage src" + i + " = (BufferedImage)inputs[" + i + "].getImage();\n");
+                    samplers.append("int src" + i + "x = 0;\n");
+                    samplers.append("int src" + i + "y = 0;\n");
+                    samplers.append("int src" + i + "w = src" + i + ".getWidth();\n");
+                    samplers.append("int src" + i + "h = src" + i + ".getHeight();\n");
+                    samplers.append("int src" + i + "scan = src" + i + ".getWidth();\n");
+                    samplers.append("int[] " + vname + " =\n");
+                    samplers.append("    ((DataBufferInt)src" + i + ".getRaster().getDataBuffer()).getData();\n");
+
+                    samplers.append("Rectangle src" + i + "Bounds = new Rectangle(");
+                    samplers.append("src" + i + "x, ");
+                    samplers.append("src" + i + "y, ");
+                    samplers.append("src" + i + "w, ");
+                    samplers.append("src" + i + "h);\n");
+                    samplers.append("setInputBounds(" + i + ", inputs[" + i + "].getBounds());\n");
+                    samplers.append("setInputNativeBounds(" + i + ", src" + i + "Bounds);\n");
+
+                    if (t == Type.LSAMPLER) {
+                        arrayGet.append("float " + vname + "_vals[4];\n");
+                    }
+
+                    // the source rect decls need to come after all calls to
+                    // setInput[Native]Bounds() for all inputs (since the
+                    // getSourceRegion() impl may need to query the bounds of
+                    // other inputs, as is the case in PhongLighting)...
+                    srcRects.append("float[] src" + i + "Rect = getSourceRegion(" + i + ");\n");
+                    
+                    jparams.append(",\n");
+                    jparams.append(vname);
+                    
+                    jparamDecls.append(",\n");
+                    jparamDecls.append("int[] " + vname + "_arr");
+                    
+                    cparamDecls.append(",\n");
+                    cparamDecls.append("jintArray " + vname + "_arr");
+                    
+                    appendGetRelease(arrayGet, arrayRelease, "int", vname, vname + "_arr");
+                }
+
+                posDecls.append("float inc" + i + "_x = (src" + i + "Rect_x2 - src" + i + "Rect_x1) / dstw;\n");
+                posDecls.append("float inc" + i + "_y = (src" + i + "Rect_y2 - src" + i + "Rect_y1) / dsth;\n");
+
+                posInitY.append("float pos" + i + "_y = src" + i + "Rect_y1 + inc" + i + "_y*0.5f;\n");
+                posInitX.append("float pos" + i + "_x = src" + i + "Rect_x1 + inc" + i + "_x*0.5f;\n");
+                posIncrX.append("pos" + i + "_x += inc" + i + "_x;\n");
+                posIncrY.append("pos" + i + "_y += inc" + i + "_y;\n");
+
+                jparams.append(",\n");
+                jparams.append("src" + i + "Rect[0], src" + i + "Rect[1],\n");
+                jparams.append("src" + i + "Rect[2], src" + i + "Rect[3],\n");
+                jparams.append("src" + i + "w, src" + i + "h, src" + i + "scan");
+                
+                jparamDecls.append(",\n");
+                jparamDecls.append("float src" + i + "Rect_x1, float src" + i + "Rect_y1,\n");
+                jparamDecls.append("float src" + i + "Rect_x2, float src" + i + "Rect_y2,\n");
+                jparamDecls.append("int src" + i + "w, int src" + i + "h, int src" + i + "scan");
+
+                cparamDecls.append(",\n");
+                cparamDecls.append("jfloat src" + i + "Rect_x1, jfloat src" + i + "Rect_y1,\n");
+                cparamDecls.append("jfloat src" + i + "Rect_x2, jfloat src" + i + "Rect_y2,\n");
+                cparamDecls.append("jint src" + i + "w, jint src" + i + "h, jint src" + i + "scan");
+            }
+        }
+
+        if (interfaceName != null) {
+            interfaceDecl.append("implements "+interfaceName);
+        }
+
+        Reader template = new InputStreamReader(getClass().getResourceAsStream("MEJavaGlue.stg"));
+        StringTemplateGroup group = new StringTemplateGroup(template, DefaultTemplateLexer.class);
+        StringTemplate jglue = group.getInstanceOf("glue");
+        jglue.setAttribute("effectName", effectName);
+        jglue.setAttribute("peerName", peerName);
+        jglue.setAttribute("interfaceDecl", interfaceDecl.toString());
+        jglue.setAttribute("usercode", usercode.toString());
+        jglue.setAttribute("samplers", samplers.toString());
+        jglue.setAttribute("srcRects", srcRects.toString());
+        jglue.setAttribute("constants", constants.toString());
+        jglue.setAttribute("params", jparams.toString());
+        jglue.setAttribute("paramDecls", jparamDecls.toString());
+
+        template = new InputStreamReader(getClass().getResourceAsStream("MENativeGlue.stg"));
+        group = new StringTemplateGroup(template, DefaultTemplateLexer.class);
+        StringTemplate cglue = group.getInstanceOf("glue");
+        cglue.setAttribute("peerName", peerName);
+        cglue.setAttribute("jniName", peerName.replace("_", "_1"));
+        cglue.setAttribute("paramDecls", cparamDecls.toString());
+        cglue.setAttribute("arrayGet", arrayGet.toString());
+        cglue.setAttribute("arrayRelease", arrayRelease.toString());
+        cglue.setAttribute("posDecls", posDecls.toString());
+        cglue.setAttribute("pixInitY", pixInitY.toString());
+        cglue.setAttribute("pixInitX", pixInitX.toString());
+        cglue.setAttribute("posIncrY", posIncrY.toString());
+        cglue.setAttribute("posInitY", posInitY.toString());
+        cglue.setAttribute("posIncrX", posIncrX.toString());
+        cglue.setAttribute("posInitX", posInitX.toString());
+        cglue.setAttribute("body", body);
+        
+        GenCode gen = new GenCode();
+        gen.javaCode = jglue.toString();
+        gen.nativeCode = cglue.toString();
+        return gen;
+    }
+    
+    // TODO: need better mechanism for querying fields
+    private static char[] fields = {'x', 'y', 'z', 'w'};
+    public static String getSuffix(int i) {
+        return "_" + fields[i];
+    }
+
+    static int getFieldIndex(char field) {
+        switch (field) {
+        case 'r':
+        case 'x':
+            return 0;
+        case 'g':
+        case 'y':
+            return 1;
+        case 'b':
+        case 'z':
+            return 2;
+        case 'a':
+        case 'w':
+            return 3;
+        default:
+            throw new InternalError();
+        }
+    }
+    
+    // TODO: these shouldn't be implemented as a static method
+    private static Map<String, FuncDef> funcDefs = new HashMap<String, FuncDef>();
+    static void putFuncDef(FuncDef def) {
+        funcDefs.put(def.getFunction().getName(), def);
+    }
+    static FuncDef getFuncDef(String name) {
+        return funcDefs.get(name);
+    }
+    
+    private static Set<String> resultVars = new HashSet<String>();
+    static boolean isResultVarDeclared(String vname) {
+        return resultVars.contains(vname);
+    }
+    static void declareResultVar(String vname) {
+        resultVars.add(vname);
+    }
+    
+    private static StringBuilder usercode = new StringBuilder();
+    static void addGlueBlock(String block) {
+        usercode.append(block);
+    }
+    
+    private static void resetStatics() {
+        funcDefs.clear();
+        resultVars.clear();
+        usercode = new StringBuilder();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/me/MECallScanner.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.sw.me;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import com.sun.scenario.effect.compiler.model.BaseType;
+import com.sun.scenario.effect.compiler.model.FuncImpl;
+import com.sun.scenario.effect.compiler.model.Function;
+import com.sun.scenario.effect.compiler.model.Param;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.model.Variable;
+import com.sun.scenario.effect.compiler.tree.ArrayAccessExpr;
+import com.sun.scenario.effect.compiler.tree.BinaryExpr;
+import com.sun.scenario.effect.compiler.tree.CallExpr;
+import com.sun.scenario.effect.compiler.tree.Expr;
+import com.sun.scenario.effect.compiler.tree.FieldSelectExpr;
+import com.sun.scenario.effect.compiler.tree.LiteralExpr;
+import com.sun.scenario.effect.compiler.tree.ParenExpr;
+import com.sun.scenario.effect.compiler.tree.TreeScanner;
+import com.sun.scenario.effect.compiler.tree.UnaryExpr;
+import com.sun.scenario.effect.compiler.tree.VariableExpr;
+import com.sun.scenario.effect.compiler.tree.VectorCtorExpr;
+
+import static com.sun.scenario.effect.compiler.backend.sw.me.MEBackend.*;
+
+/*
+ * How should we translate function calls?  For now we will inline
+ * everything, i.e. expand function bodies directly into the loop body.
+ * 
+ * The approach... For an ExprStmt or VarDecl (with initializer),
+ * walk down the tree and see if there are any function calls.
+ * For each function call, inline the function implementation prior
+ * to the statement output.  The statement will then refer to
+ * the output variables from the inlined function, rather than
+ * the function call itself.
+ * 
+ * First declare the result variables using the name of the
+ * called function and a field suffix, if needed; for example:
+ *     float3 val = sample(...).rgb;
+ * ==>
+ *     float sample_res_r, sample_res_g, sample_res_b;
+ * 
+ * Inside the inlined function, assign parameter expressions to
+ * temporary variables, using the name of the declared parameters
+ * as a guide; for example:
+ *     float val = min(foo+0.25, 1.0);
+ * ==>
+ *     float min_res;
+ *     {
+ *         float a_tmp = foo + 0.25f;
+ *         float b_tmp = 1.0f;
+ *         min_res = (a_tmp < b_tmp) a_tmp : b_tmp;
+ *     }
+ * 
+ * In a future version, references to scalar variables and literals
+ * could easily be inlined; for example:
+ *     float val = min(foo+0.25*bar, 1.0);
+ * ==>
+ *     float min_res;
+ *     {
+ *         float a_tmp = foo + 0.25f * bar;
+ *         min_res = (a_tmp < 1.0f) a_tmp : 1.0f;
+ *     }
+ * 
+ * Note that this system will likely produce less-than-efficient
+ * Java code in many cases; for now we're just trying to get things
+ * functional, and performance improvements will certainly come later.
+ * 
+ * 
+ * Example #1:
+ *     float3 val = scale * sample(baseImg, pos + off.xy).rgb;
+ * ==>
+ *     float sample_res_r, sample_res_g, sample_res_b;
+ *     {
+ *         float pos_x_tmp = pos_x + off_x;
+ *         float pos_y_tmp = pos_y + off_y;
+ *         int baseImg_tmp =
+ *             baseImg[(int)(pos_y_tmp*srch*srcscan) + (int)(pos_x_tmp*srcw)];
+ *         sample_res_r = (((baseImg_tmp >>  16) & 0xff) / 255f);
+ *         sample_res_g = (((baseImg_tmp >>   8) & 0xff) / 255f);
+ *         sample_res_b = (((baseImg_tmp       ) & 0xff) / 255f);
+ *     }
+ *     float val_r = scale * sample_res_r;
+ *     float val_g = scale * sample_res_g;
+ *     float val_b = scale * sample_res_b;
+ * 
+ * Example #2:
+ *     float val = scale * clamp(foo, 0.0, 1.0);
+ * ==>
+ *     float clamp_res;
+ *     {
+ *         float val_tmp = foo;
+ *         float min_tmp = 0.0f;
+ *         float max_tmp = 1.0f;
+ *         if (val_tmp < min_tmp) clamp_res = min_tmp;
+ *         else if (val_tmp > max_tmp) clamp_res = max_tmp;
+ *         else clamp_res = val_tmp;
+ *     }
+ *     float val = scale * clamp_res;
+ */
+class MECallScanner extends TreeScanner {
+    private StringBuilder sb;
+    private boolean inCallExpr = false;
+    private Set<Integer> selectedFields = null;
+    private boolean inFieldSelect = false;
+    private char selectedField = 'x';
+    private boolean inVectorOp = false;
+    private int vectorIndex = 0;
+
+    private void output(String s) {
+        if (sb == null) {
+            sb = new StringBuilder();
+        }
+        sb.append(s);
+    }
+
+    String getResult() {
+        return (sb != null) ? sb.toString() : null;
+    }
+
+    @Override
+    public void visitCallExpr(CallExpr e) {
+        if (inCallExpr) {
+            throw new InternalError("Nested function calls not yet supported");
+        }
+
+        Function func = e.getFunction();
+        Type t = func.getReturnType();
+        String vtype = t.getBaseType().toString();
+        String vname = func.getName();
+        Set<Integer> fields = selectedFields;
+        if (t.isVector()) {
+            if (fields == null) {
+                fields = new HashSet<Integer>();
+                for (int i = 0; i < t.getNumFields(); i++) {
+                    fields.add(i);
+                }
+            }
+        }
+        if (!MEBackend.isResultVarDeclared(vname)) {
+            // only declare result variables if they haven't been already
+            // TODO: there's a bug here; suppose a function like
+            // min(float,float) is inlined, then later we inline
+            // min(float3,float3), the second time we'll think we already have
+            // declared the result variables, but min_res_y/z won't be there...
+            MEBackend.declareResultVar(vname);
+            if (t.isVector()) {
+                output(vtype + " ");
+                boolean first = true;
+                for (Integer f : fields) {
+                    if (first) {
+                        first = false;
+                    } else {
+                        output(", ");
+                    }
+                    output(vname + "_res" + getSuffix(f));
+                }
+                output(";\n");
+            } else {
+                output(vtype + " " + vname + "_res;\n");
+            }
+        }
+
+        inCallExpr = true;
+        output("{\n");
+        List<Param> params = func.getParams();
+        List<Expr> argExprs = e.getParams();
+        for (int i = 0; i < params.size(); i++) {
+            Param param = params.get(i);
+            String pname = param.getName();
+            Type ptype = param.getType();
+            BaseType pbasetype = ptype.getBaseType();
+            if (pbasetype == BaseType.SAMPLER) {
+                // skip these for now
+                continue;
+            }
+            if (ptype.isVector()) {
+                inVectorOp = true;
+                for (int j = 0; j < ptype.getNumFields(); j++) {
+                    vectorIndex = j;
+                    output(pbasetype.toString());
+                    output(" ");
+                    output(pname + "_tmp" + getSuffix(j) + " = ");
+                    scan(argExprs.get(i));
+                    output(";\n");
+                }
+                inVectorOp = false;
+            } else {
+                output(pbasetype.toString());
+                output(" ");
+                output(pname + "_tmp = ");
+                scan(argExprs.get(i));
+                output(";\n");
+            }
+        }
+
+        FuncImpl impl = MEFuncImpls.get(func);
+        if (impl != null) {
+            // core (built-in) function
+            String preamble = impl.getPreamble(argExprs);
+            if (preamble != null) {
+                output(preamble);
+            }
+
+            if (t.isVector()) {
+                for (Integer f : fields) {
+                    output(vname + "_res" + getSuffix(f) + " = ");
+                    output(impl.toString(f, argExprs));
+                    output(";\n");
+                }
+            } else {
+                output(vname + "_res = ");
+                output(impl.toString(0, argExprs));
+                output(";\n");
+            }
+        } else {
+            // user-defined function
+            METreeScanner scanner = new METreeScanner(func.getName());
+            scanner.scan(MEBackend.getFuncDef(func.getName()).getStmt());
+            output(scanner.getResult());
+        }
+
+        output("\n}\n");
+        inCallExpr = false;
+    }
+
+    @Override
+    public void visitArrayAccessExpr(ArrayAccessExpr e) {
+        if (inCallExpr) {
+            if (e.getExpr() instanceof VariableExpr &&
+                e.getIndex() instanceof VariableExpr)
+            {
+                VariableExpr ve = (VariableExpr)e.getExpr();
+                VariableExpr ie = (VariableExpr)e.getIndex();
+                output(ve.getVariable().getName());
+                output("_arr[" + ie.getVariable().getName());
+                output(" * " + ve.getVariable().getType().getNumFields());
+                output(" + " + getFieldIndex(selectedField) + "]");
+            } else {
+                throw new InternalError("Array access only supports variable expr/index (for now)");
+            }
+        } else {
+            super.visitArrayAccessExpr(e);
+        }
+    }
+
+    @Override
+    public void visitBinaryExpr(BinaryExpr e) {
+        if (inCallExpr) {
+            scan(e.getLeft());
+            output(" " + e.getOp() + " ");
+            scan(e.getRight());
+        } else {
+            super.visitBinaryExpr(e);
+        }
+    }
+
+    @Override
+    public void visitFieldSelectExpr(FieldSelectExpr e) {
+        if (inCallExpr) {
+            if (e.getFields().length() == 1) {
+                selectedField = e.getFields().charAt(0);
+            } else {
+                int index = inVectorOp ? vectorIndex : 0;
+                selectedField = e.getFields().charAt(index);
+            }
+            inFieldSelect = true;
+            scan(e.getExpr());
+            inFieldSelect = false;
+        } else {
+            selectedFields = getFieldSet(e.getFields());
+            super.visitFieldSelectExpr(e);
+            selectedFields = null;
+        }
+    }
+
+    private static Set<Integer> getFieldSet(String fields) {
+        Set<Integer> fieldSet = new HashSet<Integer>();
+        for (int i = 0; i < fields.length(); i++) {
+            fieldSet.add(getFieldIndex(fields.charAt(i)));
+        }
+        return fieldSet;
+    }
+
+    @Override
+    public void visitLiteralExpr(LiteralExpr e) {
+        if (inCallExpr) {
+            output(e.getValue().toString());
+            if (e.getValue() instanceof Float) {
+                output("f");
+            }
+        } else {
+            super.visitLiteralExpr(e);
+        }
+    }
+
+    @Override
+    public void visitParenExpr(ParenExpr e) {
+        if (inCallExpr) {
+            output("(");
+            scan(e.getExpr());
+            output(")");
+        } else {
+            super.visitParenExpr(e);
+        }
+    }
+
+    @Override
+    public void visitUnaryExpr(UnaryExpr e) {
+        if (inCallExpr) {
+            output(e.getOp().toString());
+            scan(e.getExpr());
+        } else {
+            super.visitUnaryExpr(e);
+        }
+    }
+
+    @Override
+    public void visitVariableExpr(VariableExpr e) {
+        if (inCallExpr) {
+            Variable var = e.getVariable();
+            output(var.getName());
+            if (var.isParam()) {
+                output("_tmp");
+            }
+            if (var.getType().isVector()) {
+                if (inFieldSelect) {
+                    output(getSuffix(getFieldIndex(selectedField)));
+                } else if (inVectorOp) {
+                    output(getSuffix(vectorIndex));
+                } else {
+                    throw new InternalError("TBD");
+                }
+            }
+        } else {
+            super.visitVariableExpr(e);
+        }
+    }
+
+    @Override
+    public void visitVectorCtorExpr(VectorCtorExpr e) {
+        // TODO: this will likely work for simple variables and literals,
+        // but we need something more for embedded function calls, etc...
+        scan(e.getParams().get(vectorIndex));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/me/MEFuncImpls.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,552 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.sw.me;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import com.sun.scenario.effect.compiler.model.CoreSymbols;
+import com.sun.scenario.effect.compiler.model.FuncImpl;
+import com.sun.scenario.effect.compiler.model.Function;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.tree.Expr;
+import com.sun.scenario.effect.compiler.tree.VariableExpr;
+
+import static com.sun.scenario.effect.compiler.backend.sw.me.MEBackend.*;
+import static com.sun.scenario.effect.compiler.model.Type.*;
+
+/**
+ * Contains the C/fixed-point implementations for all core (built-in) functions.
+ */
+class MEFuncImpls {
+
+    private static Map<Function, FuncImpl> funcs = new HashMap<Function, FuncImpl>();
+    
+    static FuncImpl get(Function func) {
+        return funcs.get(func);
+    }
+    
+    static {
+        // float4 sample(sampler s, float2 loc)
+        declareFunctionSample(SAMPLER);
+
+        // float4 sample(lsampler s, float2 loc)
+        declareFunctionSample(LSAMPLER);
+
+        // float4 sample(fsampler s, float2 loc)
+        declareFunctionSample(FSAMPLER);
+
+        // int intcast(float x)
+        declareFunctionIntCast();
+        
+        // <ftype> min(<ftype> x, <ftype> y)
+        // <ftype> min(<ftype> x, float y)
+        declareOverloadsMinMax("min", "((x_tmp$1 < y_tmp$2) ? x_tmp$1 : y_tmp$2)");
+
+        // <ftype> max(<ftype> x, <ftype> y)
+        // <ftype> max(<ftype> x, float y)
+        declareOverloadsMinMax("max", "((x_tmp$1 > y_tmp$2) ? x_tmp$1 : y_tmp$2)");
+
+        // <ftype> clamp(<ftype> val, <ftype> min, <ftype> max)
+        // <ftype> clamp(<ftype> val, float min, float max)
+        declareOverloadsClamp();
+
+        // <ftype> smoothstep(<ftype> min, <ftype> max, <ftype> val)
+        // <ftype> smoothstep(float min, float max, <ftype> val)
+        declareOverloadsSmoothstep();
+
+        // <ftype> abs(<ftype> x)
+        declareOverloadsSimple("abs", "abs(x_tmp$1)");
+
+        // <ftype> floor(<ftype> x)
+        declareOverloadsSimple("floor", "floor(x_tmp$1)");
+
+        // <ftype> ceil(<ftype> x)
+        declareOverloadsSimple("ceil", "ceil(x_tmp$1)");
+
+        // <ftype> fract(<ftype> x)
+        declareOverloadsSimple("fract", "(x_tmp$1 - floor(x_tmp$1))");
+
+        // <ftype> sign(<ftype> x)
+        declareOverloadsSimple("sign", "((x_tmp$1 < 0.f) ? -1.f : (x_tmp$1 > 0.f) ? 1.f : 0.f)");
+
+        // <ftype> sqrt(<ftype> x)
+        declareOverloadsSimple("sqrt", "sqrt(x_tmp$1)");
+
+        // <ftype> sin(<ftype> x)
+        declareOverloadsSimple("sin", "sin(x_tmp$1)");
+
+        // <ftype> cos(<ftype> x)
+        declareOverloadsSimple("cos", "cos(x_tmp$1)");
+
+        // <ftype> tan(<ftype> x)
+        declareOverloadsSimple("tan", "tan(x_tmp$1)");
+
+        // <ftype> pow(<ftype> x, <ftype> y)
+        declareOverloadsSimple2("pow", "pow(x_tmp$1, y_tmp$2)");
+
+        // <ftype> mod(<ftype> x, <ftype> y)
+        // <ftype> mod(<ftype> x, float y)
+        declareOverloadsMinMax("mod", "(x_tmp$1 % y_tmp$2)");
+
+        // float dot(<ftype> x, <ftype> y)
+        declareOverloadsDot();
+
+        // float distance(<ftype> x, <ftype> y)
+        declareOverloadsDistance();
+
+        // <ftype> mix(<ftype> x, <ftype> y, <ftype> a)
+        // <ftype> mix(<ftype> x, <ftype> y, float a)
+        declareOverloadsMix();
+        
+        // <ftype> normalize(<ftype> x)
+        declareOverloadsNormalize();
+
+        // <ftype> ddx(<ftype> p)
+        declareOverloadsSimple("ddx", "<ddx() not implemented for sw backends>");
+
+        // <ftype> ddy(<ftype> p)
+        declareOverloadsSimple("ddy", "<ddy() not implemented for sw backends>");
+    }
+    
+    private static void declareFunction(FuncImpl impl,
+                                        String name, Type... ptypes)
+    {
+        Function f = CoreSymbols.getFunction(name, Arrays.asList(ptypes));
+        if (f == null) {
+            throw new InternalError("Core function not found (have you declared the function in CoreSymbols?)");
+        }
+        funcs.put(f, impl);
+    }
+    
+    /**
+     * Used to declare sample function:
+     *   float4 sample([l,f]sampler s, float2 loc)
+     */
+    private static void declareFunctionSample(final Type type) {
+        FuncImpl fimpl = new FuncImpl() {
+            @Override
+            public String getPreamble(List<Expr> params) {
+                String s = getSamplerName(params);
+                // TODO: this bounds checking is way too costly...
+                String p = getPosName(params);
+                if (type == LSAMPLER) {
+                    return
+                        "lsample(" + s + ", loc_tmp_x, loc_tmp_y,\n" +
+                        "        " + p + "w, " + p + "h, " + p + "scan,\n" +
+                        "        " + s + "_vals);\n";
+                } else if (type == FSAMPLER) {
+                    return
+                        "float *" + s + "_arr_tmp = NULL;\n" +
+                        "int iloc_tmp = 0;\n" +
+                        "if (loc_tmp_x >= 0 && loc_tmp_y >= 0) {\n" +
+                        "    int iloc_tmp_x = (int)(loc_tmp_x*" + p + "w);\n" +
+                        "    int iloc_tmp_y = (int)(loc_tmp_y*" + p + "h);\n" +
+                        "    jboolean out =\n" +
+                        "        iloc_tmp_x >= " + p + "w ||\n" +
+                        "        iloc_tmp_y >= " + p + "h;\n" +
+                        "    if (!out) {\n" +
+                        "        "+ s + "_arr_tmp = " + s + ";\n" +
+                        "        iloc_tmp = 4 * (iloc_tmp_y*" + p + "scan + iloc_tmp_x);\n" +
+                        "    }\n" +
+                        "}\n";
+                } else {
+                    return
+                        "int " + s + "_tmp;\n" +
+                        "if (loc_tmp_x >= 0 && loc_tmp_y >= 0) {\n" +
+                        "    int iloc_tmp_x = (int)(loc_tmp_x*" + p + "w);\n" +
+                        "    int iloc_tmp_y = (int)(loc_tmp_y*" + p + "h);\n" +
+                        "    jboolean out =\n" +
+                        "        iloc_tmp_x >= " + p + "w ||\n" +
+                        "        iloc_tmp_y >= " + p + "h;\n" +
+                        "    " + s + "_tmp = out ? 0 :\n" +
+                        "        " + s + "[iloc_tmp_y*" + p + "scan + iloc_tmp_x];\n" +
+                        "} else {\n" +
+                        "    " + s + "_tmp = 0;\n" +
+                        "}\n";
+                }
+            }
+            public String toString(int i, List<Expr> params) {
+                String s = getSamplerName(params);
+                if (type == LSAMPLER) {
+                    return (i < 0 || i > 3) ? null : s + "_vals[" + i + "]";
+                } else if (type == FSAMPLER) {
+                    String arr = s + "_arr_tmp";
+                    switch (i) {
+                    case 0:
+                        return arr + " == NULL ? 0.f : " + arr + "[iloc_tmp]";
+                    case 1:
+                        return arr + " == NULL ? 0.f : " + arr + "[iloc_tmp+1]";
+                    case 2:
+                        return arr + " == NULL ? 0.f : " + arr + "[iloc_tmp+2]";
+                    case 3:
+                        return arr + " == NULL ? 0.f : " + arr + "[iloc_tmp+3]";
+                    default:
+                        return null;
+                    }
+                } else {
+                    switch (i) {
+                    case 0:
+                        return "(((" + s + "_tmp >> 16) & 0xff) / 255.f)";
+                    case 1:
+                        return "(((" + s + "_tmp >>  8) & 0xff) / 255.f)";
+                    case 2:
+                        return "(((" + s + "_tmp      ) & 0xff) / 255.f)";
+                    case 3:
+                        return "(((" + s + "_tmp >> 24) & 0xff) / 255.f)";
+                    default:
+                        return null;
+                    }
+                }
+            }
+            private String getSamplerName(List<Expr> params) {
+                VariableExpr e = (VariableExpr)params.get(0);
+                return e.getVariable().getName();
+            }
+            private String getPosName(List<Expr> params) {
+                VariableExpr e = (VariableExpr)params.get(0);
+                return "src" + e.getVariable().getReg();
+            }
+        };
+        declareFunction(fimpl, "sample", type, FLOAT2);
+    }
+
+    /**
+     * Used to declare intcast function:
+     *   int intcast(float x)
+     */
+    private static void declareFunctionIntCast() {
+        FuncImpl fimpl = new FuncImpl() {
+            public String toString(int i, List<Expr> params) {
+                return "((int)x_tmp)";
+            }
+        };
+        declareFunction(fimpl, "intcast", FLOAT);
+    }
+
+    /**
+     * Used to declare simple functions of the following form: 
+     *   <ftype> name(<ftype> x)
+     */
+    private static void declareOverloadsSimple(String name, final String pattern) {
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type);
+        }
+    }
+    
+    /**
+     * Used to declare simple two parameter functions of the following form:
+     *   <ftype> name(<ftype> x, <ftype> y)
+     */
+    private static void declareOverloadsSimple2(String name, final String pattern) {
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            // declare (vectype,vectype) variants
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type);
+        }
+    }
+
+    /**
+     * Used to declare normalize functions of the following form: 
+     *   <ftype> normalize(<ftype> x)
+     */
+    private static void declareOverloadsNormalize() {
+        final String name = "normalize";
+        final String pattern = "x_tmp$1 / denom";
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            int n = type.getNumFields();
+            final String preamble;
+            if (n == 1) {
+                preamble = "float denom = x_tmp;\n";
+            } else {
+                String     s  =    "(x_tmp_x * x_tmp_x)";
+                           s += "+\n(x_tmp_y * x_tmp_y)";
+                if (n > 2) s += "+\n(x_tmp_z * x_tmp_z)";
+                if (n > 3) s += "+\n(x_tmp_w * x_tmp_w)";
+                preamble = "float denom = sqrt(" + s + ");\n";
+            }
+            
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                @Override
+                public String getPreamble(List<Expr> params) {
+                    return preamble;
+                }
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type);
+        }
+    }
+
+    /**
+     * Used to declare dot functions of the following form: 
+     *   float dot(<ftype> x, <ftype> y)
+     */
+    private static void declareOverloadsDot() {
+        final String name = "dot";
+        for (final Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            int n = type.getNumFields();
+            String s;
+            if (n == 1) {
+                s = "(x_tmp * y_tmp)";
+            } else {
+                           s  =    "(x_tmp_x * y_tmp_x)";
+                           s += "+\n(x_tmp_y * y_tmp_y)";
+                if (n > 2) s += "+\n(x_tmp_z * y_tmp_z)";
+                if (n > 3) s += "+\n(x_tmp_w * y_tmp_w)";
+            }
+            final String str = s;
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    return str;
+                }
+            };
+            declareFunction(fimpl, name, type, type);
+        }
+    }
+    
+    /**
+     * Used to declare distance functions of the following form: 
+     *   float distance(<ftype> x, <ftype> y)
+     */
+    private static void declareOverloadsDistance() {
+        final String name = "distance";
+        for (final Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            int n = type.getNumFields();
+            String s;
+            if (n == 1) {
+                s = "(x_tmp - y_tmp) * (x_tmp - y_tmp)";
+            } else {
+                           s  =    "((x_tmp_x - y_tmp_x) * (x_tmp_x - y_tmp_x))";
+                           s += "+\n((x_tmp_y - y_tmp_y) * (x_tmp_y - y_tmp_y))";
+                if (n > 2) s += "+\n((x_tmp_z - y_tmp_z) * (x_tmp_z - y_tmp_z))";
+                if (n > 3) s += "+\n((x_tmp_w - y_tmp_w) * (x_tmp_w - y_tmp_w))";
+            }
+            final String str = "sqrt(" + s + ")";
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    return str;
+                }
+            };
+            declareFunction(fimpl, name, type, type);
+        }
+    }
+    
+    /**
+     * Used to declare min/max functions of the following form:
+     *   <ftype> name(<ftype> x, <ftype> y)
+     *   <ftype> name(<ftype> x, float y)
+     * 
+     * TODO: this is currently geared to simple functions like
+     * min and max; we should make this more general...
+     */
+    private static void declareOverloadsMinMax(String name, final String pattern) {
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            // declare (vectype,vectype) variants
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type);
+            
+            if (type == FLOAT) {
+                continue;
+            }
+            
+            // declare (vectype,float) variants
+            fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = getSuffix(i);
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", "");
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, FLOAT);
+        }
+    }
+
+    /**
+     * Used to declare clamp functions of the following form:
+     *   <ftype> clamp(<ftype> val, <ftype> min, <ftype> max)
+     *   <ftype> clamp(<ftype> val, float min, float max)
+     */
+    private static void declareOverloadsClamp() {
+        final String name = "clamp";
+        final String pattern =
+            "(val_tmp$1 < min_tmp$2) ? min_tmp$2 : \n" +
+            "(val_tmp$1 > max_tmp$2) ? max_tmp$2 : val_tmp$1";
+        
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            // declare (vectype,vectype,vectype) variants
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type, type);
+            
+            if (type == FLOAT) {
+                continue;
+            }
+            
+            // declare (vectype,float,float) variants
+            fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = getSuffix(i);
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", "");
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, FLOAT, FLOAT);
+        }
+    }
+
+    /**
+     * Used to declare smoothstep functions of the following form:
+     *   <ftype> smoothstep(<ftype> min, <ftype> max, <ftype> val)
+     *   <ftype> smoothstep(float min, float max, <ftype> val)
+     */
+    private static void declareOverloadsSmoothstep() {
+        final String name = "smoothstep";
+        // TODO - the smoothstep function is defined to use Hermite interpolation
+        final String pattern =
+            "(val_tmp$1 < min_tmp$2) ? 0.0f : \n" +
+            "(val_tmp$1 > max_tmp$2) ? 1.0f : \n" +
+            "(val_tmp$1 / (max_tmp$2 - min_tmp$2))";
+        
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            // declare (vectype,vectype,vectype) variants
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type, type);
+            
+            if (type == FLOAT) {
+                continue;
+            }
+            
+            // declare (float,float,vectype) variants
+            fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = getSuffix(i);
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", "");
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, FLOAT, FLOAT, type);
+        }
+    }
+    
+    /**
+     * Used to declare mix functions of the following form:
+     *   <ftype> mix(<ftype> x, <ftype> y, <ftype> a)
+     *   <ftype> mix(<ftype> x, <ftype> y, float a)
+     */
+    private static void declareOverloadsMix() {
+        final String name = "mix";
+        final String pattern =
+            "(x_tmp$1 * (1.0f - a_tmp$2) + y_tmp$1 * a_tmp$2)";
+        
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            // declare (vectype,vectype,vectype) variants
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type, type);
+            
+            if (type == FLOAT) {
+                continue;
+            }
+            
+            // declare (vectype,vectype,float) variants
+            fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = getSuffix(i);
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", "");
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type, FLOAT);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/me/MEJavaGlue.stg	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,99 @@
+group MEJavaGlue;
+
+glue(effectName,peerName,interfaceDecl,
+     usercode,samplers,srcRects,constants,params,paramDecls) ::= <<
+/*
+ * Copyright (c) 2008, 2011, Oracle  and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * This file was generated by JSLC -- DO NOT EDIT MANUALLY!
+ */
+
+package com.sun.scenario.effect.impl.sw.me;
+
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import com.sun.scenario.effect.Effect;
+import com.sun.scenario.effect.FilterContext;
+import com.sun.scenario.effect.FloatMap;
+import com.sun.scenario.effect.ImageData;
+import com.sun.scenario.effect.$effectName$;
+import com.sun.scenario.effect.impl.BufferUtil;
+import com.sun.scenario.effect.impl.Renderer;
+import com.sun.scenario.effect.impl.state.*;
+import com.sun.javafx.geom.AffineTransform;
+import com.sun.javafx.geom.Rectangle;
+
+public class ME$peerName$Peer extends MEEffectPeer $interfaceName$ {
+
+    public ME$peerName$Peer(FilterContext fctx, Renderer r, String uniqueName) {
+        super(fctx, r, uniqueName);
+    }
+
+    @Override
+    protected final $effectName$ getEffect() {
+        return ($effectName$)super.getEffect();
+    }
+
+    $usercode$
+
+    @Override
+    public ImageData filter(Effect effect,
+                            AffineTransform transform,
+                            ImageData... inputs)
+    {
+        setEffect(effect);
+        setDestBounds(getResultBounds(transform, inputs));
+
+        // TODO: for now, all input images must be TYPE_INT_ARGB_PRE
+        $samplers$
+
+        $srcRects$
+
+        Rectangle dstBounds = getDestBounds();
+        final int dstx = 0;
+        final int dsty = 0;
+        final int dstw = dstBounds.width;
+        final int dsth = dstBounds.height;
+
+        BufferedImage dst = getDestImageFromPool(dstw, dsth);
+        setDestNativeBounds(dst.getWidth(), dst.getHeight());
+        int dstscan = dst.getWidth();
+        int[] dstPixels = ((DataBufferInt)dst.getRaster().getDataBuffer()).getData();
+        
+        $constants$
+
+        filter(dstPixels, dstx, dsty, dstw, dsth, dstscan$params$);
+
+        return new ImageData(getFilterContext(), dst, dstBounds);
+    }
+
+    private static native void filter(int[] dstPixels,
+                                      int dstx, int dsty,
+                                      int dstw, int dsth,
+                                      int dstscan$paramDecls$);
+}
+>>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/me/MENativeGlue.stg	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,81 @@
+group MENativeGlue;
+
+glue(peerName,jniName,paramDecls,arrayGet,arrayRelease,
+     pixInitY,pixInitX,posDecls,posInitY,posIncrY,posInitX,posIncrX,
+     body) ::= <<
+/*
+ * Copyright (c) 2008, 2011, Oracle  and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * This file was generated by JSLC -- DO NOT EDIT MANUALLY!
+ */
+
+#include <jni.h>
+#include <math.h>
+#include "MEUtils.h"
+#include "com_sun_scenario_effect_impl_sw_me_ME$peerName$Peer.h"
+
+JNIEXPORT void JNICALL
+Java_com_sun_scenario_effect_impl_sw_me_ME$jniName$Peer_filter
+  (JNIEnv *env, jclass klass,
+   jintArray dst_arr,
+   jint dstx, jint dsty, jint dstw, jint dsth, jint dstscan$paramDecls$)
+{
+    int dyi;
+    float color_x, color_y, color_z, color_w;
+
+    $arrayGet$
+
+    $posDecls$
+
+    $posInitY$
+    for (int dy = dsty; dy < dsty+dsth; dy++) {
+        $pixInitY$
+        dyi = dy*dstscan;
+
+        $posInitX$
+        for (int dx = dstx; dx < dstx+dstw; dx++) {
+            $pixInitX$
+
+            $body$
+
+            if (color_w < 0.f) color_w = 0.f; else if (color_w > 1.f) color_w = 1.f;
+            if (color_x < 0.f) color_x = 0.f; else if (color_x > color_w) color_x = color_w;
+            if (color_y < 0.f) color_y = 0.f; else if (color_y > color_w) color_y = color_w;
+            if (color_z < 0.f) color_z = 0.f; else if (color_z > color_w) color_z = color_w;
+            dst[dyi+dx] =
+                ((int)(color_x * 0xff) << 16) |
+                ((int)(color_y * 0xff) <<  8) |
+                ((int)(color_z * 0xff) <<  0) |
+                ((int)(color_w * 0xff) << 24);
+
+            $posIncrX$
+        }
+
+        $posIncrY$
+    }
+
+    $arrayRelease$
+}
+
+>>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/me/METreeScanner.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.sw.me;
+
+import com.sun.scenario.effect.compiler.model.Function;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.model.Variable;
+import com.sun.scenario.effect.compiler.tree.*;
+import static com.sun.scenario.effect.compiler.backend.sw.me.MEBackend.getFieldIndex;
+import static com.sun.scenario.effect.compiler.backend.sw.me.MEBackend.getSuffix;
+
+/**
+ */
+class METreeScanner extends TreeScanner {
+
+    private final String funcName;
+    private final StringBuilder sb = new StringBuilder();
+
+    private boolean inVectorOp = false;
+    private int vectorIndex = 0;
+    private boolean inFieldSelect = false;
+    private char selectedField = 'x';
+    
+    METreeScanner() {
+        this(null);
+    }
+    
+    METreeScanner(String funcName) {
+        this.funcName = funcName;
+    }
+    
+    private void output(String s) {
+        sb.append(s);
+    }
+    
+    String getResult() {
+        return (sb != null) ? sb.toString() : null;
+    }
+    
+    @Override
+    public void visitArrayAccessExpr(ArrayAccessExpr e) {
+        if (e.getExpr() instanceof VariableExpr &&
+            e.getIndex() instanceof VariableExpr)
+        {
+            VariableExpr ve = (VariableExpr)e.getExpr();
+            VariableExpr ie = (VariableExpr)e.getIndex();
+            output(ve.getVariable().getName());
+            output("_arr[" + ie.getVariable().getName());
+            output(" * " + ve.getVariable().getType().getNumFields());
+            output(" + " + getFieldIndex(selectedField) + "]");
+        } else {
+            throw new InternalError("Array access only supports variable expr/index (for now)");
+        }
+    }
+
+    @Override
+    public void visitBinaryExpr(BinaryExpr e) {
+        scan(e.getLeft());
+        output(" " + e.getOp() + " ");
+        scan(e.getRight());
+    }
+
+    @Override
+    public void visitBreakStmt(BreakStmt s) {
+        output("break;");
+    }
+
+    @Override
+    public void visitCallExpr(CallExpr e) {
+        Function func = e.getFunction();
+        output(func.getName() + "_res");
+        if (func.getReturnType().isVector()) {
+            // TODO: this needs more thought
+            if (inFieldSelect) {
+                output(getSuffix(getFieldIndex(selectedField)));
+            } else if (inVectorOp) {
+                output(getSuffix(vectorIndex));
+            } else {
+                throw new InternalError("TBD");
+            }
+        }
+    }
+
+    @Override
+    public void visitCompoundStmt(CompoundStmt s) {
+        output("{\n");
+        super.visitCompoundStmt(s);
+        output("}\n");
+    }
+
+    @Override
+    public void visitContinueStmt(ContinueStmt s) {
+        output("continue;");
+    }
+
+    @Override
+    public void visitDeclStmt(DeclStmt s) {
+        super.visitDeclStmt(s);
+    }
+
+    @Override
+    public void visitDiscardStmt(DiscardStmt s) {
+        // TODO: not yet implemented
+    }
+
+    @Override
+    public void visitDoWhileStmt(DoWhileStmt s) {
+        output("do ");
+        scan(s.getStmt());
+        output(" while (");
+        scan(s.getExpr());
+        output(");");
+    }
+
+    @Override
+    public void visitExprStmt(ExprStmt s) {
+        Expr expr = s.getExpr();
+        
+        outputPreambles(expr);
+
+        Type t = expr.getResultType();
+        if (t.isVector()) {
+            inVectorOp = true;
+            for (int i = 0; i < t.getNumFields(); i++) {
+                vectorIndex = i;
+                scan(s.getExpr());
+                output(";\n");
+            }
+            inVectorOp = false;
+        } else {
+            scan(s.getExpr());
+            output(";\n");
+        }
+    }
+
+    @Override
+    public void visitFieldSelectExpr(FieldSelectExpr e) {
+        if (e.getFields().length() == 1) {
+            selectedField = e.getFields().charAt(0);
+        } else {
+            int index = inVectorOp ? vectorIndex : 0;
+            selectedField = e.getFields().charAt(index);
+        }
+        inFieldSelect = true;
+        scan(e.getExpr());
+        inFieldSelect = false;
+    }
+    
+    @Override
+    public void visitForStmt(ForStmt s) {
+        output("for (");
+        scan(s.getInit());
+        scan(s.getCondition());
+        output(";");
+        scan(s.getExpr());
+        output(")");
+        scan(s.getStmt());
+    }
+
+    @Override
+    public void visitFuncDef(FuncDef d) {
+        if (d.getFunction().getName().equals("main")) {
+            scan(d.getStmt());
+        } else {
+            // TODO: this is a hacky approach to saving func defs, which
+            // will be inlined later at point of use)...
+            MEBackend.putFuncDef(d);
+        }
+    }
+    
+    @Override
+    public void visitGlueBlock(GlueBlock b) {
+        MEBackend.addGlueBlock(b.getText());
+    }
+
+    @Override
+    public void visitLiteralExpr(LiteralExpr e) {
+        output(e.getValue().toString());
+        if (e.getValue() instanceof Float) {
+            output("f");
+        }
+    }
+    
+    @Override
+    public void visitParenExpr(ParenExpr e) {
+        output("(");
+        scan(e.getExpr());
+        output(")");
+    }
+
+    @Override
+    public void visitProgramUnit(ProgramUnit p) {
+        super.visitProgramUnit(p);
+    }
+
+    @Override
+    public void visitReturnStmt(ReturnStmt s) {
+        Expr expr = s.getExpr();
+        if (expr == null) {
+            throw new InternalError("Empty return not yet implemented");
+        }
+        if (funcName == null) {
+            throw new RuntimeException("Return statement not expected");
+        }
+        
+        Type t = expr.getResultType();
+        if (t.isVector()) {
+            inVectorOp = true;
+            for (int i = 0; i < t.getNumFields(); i++) {
+                vectorIndex = i;
+                output(funcName + "_res" + getSuffix(i) + " = ");
+                scan(s.getExpr());
+                output(";\n");
+            }
+            inVectorOp = false;
+        } else {
+            output(funcName + "_res = ");
+            scan(s.getExpr());
+            output(";\n");
+        }
+    }
+
+    @Override
+    public void visitSelectStmt(SelectStmt s) {
+        output("if (");
+        scan(s.getIfExpr());
+        output(")");
+        scan(s.getThenStmt());
+        Stmt e = s.getElseStmt();
+        if (e != null) {
+            output(" else ");
+            scan(e);
+        }
+    }
+
+    @Override
+    public void visitUnaryExpr(UnaryExpr e) {
+        output(e.getOp().toString());
+        scan(e.getExpr());
+    }
+    
+    @Override
+    public void visitVarDecl(VarDecl d) {
+        Variable var = d.getVariable();
+        if (var.getQualifier() != null) {
+            // these will be declared separately outside the loop body
+            return;
+        }
+
+        outputPreambles(d);
+        
+        Type t = var.getType();
+        if (t.isVector()) {
+            inVectorOp = true;
+            for (int i = 0; i < t.getNumFields(); i++) {
+                output(t.getBaseType().toString() + " ");
+                output(var.getName() + getSuffix(i));
+                Expr init = d.getInit();
+                if (init != null) {
+                    output(" = ");
+                    vectorIndex = i;
+                    scan(init);
+                }
+                output(";\n");
+            }
+            inVectorOp = false;
+        } else {
+            output(t.toString() + " " + var.getName());
+            Expr init = d.getInit();
+            if (init != null) {
+                output(" = ");
+                scan(init);
+            }
+            output(";\n");
+        }
+    }
+
+    @Override
+    public void visitVariableExpr(VariableExpr e) {
+        Variable var = e.getVariable();
+        output(var.getName());
+        if (var.isParam()) {
+            output("_tmp");
+        }
+        if (var.getType().isVector()) {
+            if (inFieldSelect) {
+                output(getSuffix(getFieldIndex(selectedField)));
+            } else if (inVectorOp) {
+                output(getSuffix(vectorIndex));
+            } else {
+                throw new InternalError("TBD");
+            }
+        }
+    }
+
+    @Override
+    public void visitVectorCtorExpr(VectorCtorExpr e) {
+        // TODO: this will likely work for simple variables and literals,
+        // but we need something more for embedded function calls, etc...
+        scan(e.getParams().get(vectorIndex));
+    }
+
+    @Override
+    public void visitWhileStmt(WhileStmt s) {
+        output("while (");
+        scan(s.getCondition());
+        output(")");
+        scan(s.getStmt());
+    }
+    
+    private void outputPreambles(Tree tree) {
+        MECallScanner scanner = new MECallScanner();
+        scanner.scan(tree);
+        String res = scanner.getResult();
+        if (res != null) {
+            output(scanner.getResult());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/sse/SSEBackend.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,405 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.sw.sse;
+
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import com.sun.scenario.effect.compiler.JSLParser;
+import com.sun.scenario.effect.compiler.model.BaseType;
+import com.sun.scenario.effect.compiler.model.Qualifier;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.model.Variable;
+import com.sun.scenario.effect.compiler.tree.FuncDef;
+import com.sun.scenario.effect.compiler.tree.ProgramUnit;
+import com.sun.scenario.effect.compiler.tree.TreeScanner;
+import org.antlr.stringtemplate.StringTemplate;
+import org.antlr.stringtemplate.StringTemplateGroup;
+import org.antlr.stringtemplate.language.DefaultTemplateLexer;
+
+/**
+ */
+public class SSEBackend extends TreeScanner {
+
+    private final JSLParser parser;
+    private final String body;
+
+    public SSEBackend(JSLParser parser, ProgramUnit program) {
+        // TODO: will be removed once we clean up static usage
+        resetStatics();
+
+        this.parser = parser;
+        
+        SSETreeScanner scanner = new SSETreeScanner();
+        scanner.scan(program);
+        this.body = scanner.getResult();
+    }
+    
+    public static class GenCode {
+        public String javaCode;
+        public String nativeCode;
+    }
+
+    private static void appendGetRelease(StringBuilder get,
+                                         StringBuilder rel,
+                                         String ctype,
+                                         String cbufName, String jarrayName)
+    {
+        get.append("j" + ctype + " *" + cbufName + " = (j" + ctype + " *)");
+        get.append("env->GetPrimitiveArrayCritical(" + jarrayName + ", 0);\n");
+        get.append("if (" + cbufName + " == NULL) return;\n");
+        rel.append("env->ReleasePrimitiveArrayCritical(" + jarrayName + ", " + cbufName + ", JNI_ABORT);\n");
+    }
+
+    private static SortedSet<Variable> getSortedVars(Collection<Variable> unsortedVars) {
+        Comparator<Variable> c = new Comparator<Variable>() {
+            public int compare(Variable v0, Variable v1) {
+                return v0.getName().compareTo(v1.getName());
+            }
+        };
+        SortedSet<Variable> sortedVars = new TreeSet<Variable>(c);
+        sortedVars.addAll(unsortedVars);
+        return sortedVars;
+    }
+
+    public final GenCode getGenCode(String effectName,
+                                    String peerName,
+                                    String interfaceName)
+    {
+        Map<String, Variable> vars = parser.getSymbolTable().getGlobalVariables();
+        StringBuilder interfaceDecl = new StringBuilder();
+        StringBuilder constants = new StringBuilder();
+        StringBuilder samplers = new StringBuilder();
+        StringBuilder cleanup = new StringBuilder();
+        StringBuilder srcRects = new StringBuilder();
+        StringBuilder posDecls = new StringBuilder();
+        StringBuilder pixInitY = new StringBuilder();
+        StringBuilder pixInitX = new StringBuilder();
+        StringBuilder posIncrY = new StringBuilder();
+        StringBuilder posInitY = new StringBuilder();
+        StringBuilder posIncrX = new StringBuilder();
+        StringBuilder posInitX = new StringBuilder();
+        StringBuilder jparams = new StringBuilder();
+        StringBuilder jparamDecls = new StringBuilder();
+        StringBuilder cparamDecls = new StringBuilder();
+        StringBuilder arrayGet = new StringBuilder();
+        StringBuilder arrayRelease = new StringBuilder();
+
+        appendGetRelease(arrayGet, arrayRelease, "int", "dst", "dst_arr");
+        
+        // TODO: only need to declare these if pixcoord is referenced
+        // somewhere in the program...
+        pixInitY.append("float pixcoord_y = (float)dy;\n");
+        pixInitX.append("float pixcoord_x = (float)dx;\n");
+
+        // this step isn't strictly necessary but helps give some predictability
+        // to the generated jar/nativelib so that the method signatures have
+        // a consistent parameter ordering on all platforms for each build,
+        // which may help debugging (see RT-4475)
+        SortedSet<Variable> sortedVars = getSortedVars(vars.values());
+        for (Variable v : sortedVars) {
+            if (v.getQualifier() == Qualifier.CONST && v.getConstValue() == null) {
+                // this must be a special built-in variable (e.g. pos0);
+                // these are handled elsewhere, so just continue...
+                continue;
+            }
+            
+            Type t = v.getType();
+            BaseType bt = t.getBaseType();
+            String vtype = bt.toString();
+            String vname = v.getName();
+            if (v.getQualifier() != null && bt != BaseType.SAMPLER) {
+                String accName = v.getAccessorName();
+                if (v.isArray()) {
+                    // TODO: we currently assume that param arrays will be
+                    // stored in NIO Int/FloatBuffers, but the inner loop
+                    // expects to access them as Java arrays, so we convert
+                    // here; this is obviously bad for performance, so we need
+                    // to come up with a better system soon...
+                    String bufType = (bt == BaseType.FLOAT) ?
+                        "FloatBuffer" : "IntBuffer";
+                    String bufName = vname + "_buf";
+                    String arrayName = vname + "_arr";
+                    constants.append(bufType + " " + bufName + " = " + accName + "();\n");
+                    constants.append(vtype + "[] " + arrayName);
+                    constants.append(" = new " + vtype + "[");
+                    constants.append(bufName + ".capacity()];\n");
+                    constants.append(bufName + ".get(" + arrayName + ");\n");
+                    jparams.append(",\n");
+                    jparams.append(arrayName);
+                    jparamDecls.append(",\n");
+                    jparamDecls.append(vtype + "[] " + vname);
+                    cparamDecls.append(",\n");
+                    cparamDecls.append("j" + vtype + "Array " + vname);
+                    appendGetRelease(arrayGet, arrayRelease, vtype, arrayName, vname);
+                } else {
+                    if (t.isVector()) {
+                        String arrayName = vname + "_arr";
+                        constants.append(vtype + "[] " + arrayName + " = " + accName + "();\n");
+                        jparams.append(",\n");
+                        jparamDecls.append(",\n");
+                        cparamDecls.append(",\n");
+                        for (int i = 0; i < t.getNumFields(); i++) {
+                            if (i > 0) {
+                                jparams.append(", ");
+                                jparamDecls.append(", ");
+                                cparamDecls.append(", ");
+                            }
+                            String vn = vname + getSuffix(i);
+                            jparams.append(arrayName + "[" + i + "]");
+                            jparamDecls.append(vtype + " " + vn);
+                            cparamDecls.append("j" + vtype + " " + vn);
+                        }
+                    } else {
+                        constants.append(vtype + " " + vname);
+                        if (v.getQualifier() == Qualifier.CONST) {
+                            constants.append(" = " + v.getConstValue());
+                        } else {
+                            constants.append(" = " + accName + "()");
+                        }
+                        constants.append(";\n");
+                        jparams.append(",\n");
+                        jparams.append(vname);
+                        jparamDecls.append(",\n");
+                        jparamDecls.append(vtype + " " + vname);
+                        cparamDecls.append(",\n");
+                        cparamDecls.append("j" + vtype + " " + vname);
+                    }
+                }
+            } else if (v.getQualifier() == Qualifier.PARAM && bt == BaseType.SAMPLER) {
+                int i = v.getReg();
+                if (t == Type.FSAMPLER) {
+                    samplers.append("FloatMap src" + i + " = (FloatMap)getSamplerData(" + i + ");\n");
+                    samplers.append("int src" + i + "x = 0;\n");
+                    samplers.append("int src" + i + "y = 0;\n");
+                    samplers.append("int src" + i + "w = src" + i + ".getWidth();\n");
+                    samplers.append("int src" + i + "h = src" + i + ".getHeight();\n");
+                    samplers.append("int src" + i + "scan = src" + i + ".getWidth();\n");
+                    samplers.append("float[] " + vname + " = src" + i + ".getData();\n");
+
+                    arrayGet.append("float " + vname + "_vals[4];\n");
+
+                    // TODO: for now, assume [0,0,1,1]
+                    srcRects.append("float[] src" + i + "Rect = new float[] {0,0,1,1};\n");
+                    
+                    jparams.append(",\n");
+                    jparams.append(vname);
+                    
+                    jparamDecls.append(",\n");
+                    jparamDecls.append("float[] " + vname + "_arr");
+                    
+                    cparamDecls.append(",\n");
+                    cparamDecls.append("jfloatArray " + vname + "_arr");
+                    
+                    appendGetRelease(arrayGet, arrayRelease, "float", vname, vname + "_arr");
+                } else {
+                    if (t == Type.LSAMPLER) {
+                        samplers.append("HeapImage src" + i + " = (HeapImage)inputs[" + i + "].getUntransformedImage();\n");
+                    } else {
+                        samplers.append("HeapImage src" + i + " = (HeapImage)inputs[" + i + "].getTransformedImage(dstBounds);\n");
+                        cleanup.append("inputs[" + i + "].releaseTransformedImage(src" + i + ");\n");
+                    }
+                    samplers.append("int src" + i + "x = 0;\n");
+                    samplers.append("int src" + i + "y = 0;\n");
+                    samplers.append("int src" + i + "w = src" + i + ".getPhysicalWidth();\n");
+                    samplers.append("int src" + i + "h = src" + i + ".getPhysicalHeight();\n");
+                    samplers.append("int src" + i + "scan = src" + i + ".getScanlineStride();\n");
+                    samplers.append("int[] " + vname + " =\n");
+                    samplers.append("    src" + i + ".getPixelArray();\n");
+
+                    samplers.append("Rectangle src" + i + "Bounds = new Rectangle(");
+                    samplers.append("src" + i + "x, ");
+                    samplers.append("src" + i + "y, ");
+                    samplers.append("src" + i + "w, ");
+                    samplers.append("src" + i + "h);\n");
+                    if (t == Type.LSAMPLER) {
+                        samplers.append("Rectangle src" + i + "InputBounds = inputs[" + i + "].getUntransformedBounds();\n");
+                        samplers.append("BaseTransform src" + i + "Transform = inputs[" + i + "].getTransform();\n");
+                    } else {
+                        samplers.append("Rectangle src" + i + "InputBounds = inputs[" + i + "].getTransformedBounds(dstBounds);\n");
+                        samplers.append("BaseTransform src" + i + "Transform = BaseTransform.IDENTITY_TRANSFORM;\n");
+                    }
+                    samplers.append("setInputBounds(" + i + ", src" + i + "InputBounds);\n");
+                    samplers.append("setInputNativeBounds(" + i + ", src" + i + "Bounds);\n");
+
+                    if (t == Type.LSAMPLER) {
+                        arrayGet.append("float " + vname + "_vals[4];\n");
+                    }
+
+                    // the source rect decls need to come after all calls to
+                    // setInput[Native]Bounds() for all inputs (since the
+                    // getSourceRegion() impl may need to query the bounds of
+                    // other inputs, as is the case in PhongLighting)...
+                    srcRects.append("float[] src" + i + "Rect = new float[4];\n");
+                    // Note that we only allocate 4 floats here because none
+                    // of the loops can deal with fully mapped inputs.  Only
+                    // shaders that declare LSAMPLERs would require mapped
+                    // inputs and so far that is only Perspective and
+                    // Displacement, both of which override getTC() and return
+                    // only 4 values.
+                    srcRects.append("getTextureCoordinates(" + i + ", src" + i + "Rect,\n");
+                    srcRects.append("                      src" + i + "InputBounds.x, src" + i + "InputBounds.y,\n");
+                    srcRects.append("                      src" + i + "w, src" + i + "h,\n");
+                    srcRects.append("                      dstBounds, src" + i + "Transform);\n");
+
+                    jparams.append(",\n");
+                    jparams.append(vname);
+                    
+                    jparamDecls.append(",\n");
+                    jparamDecls.append("int[] " + vname + "_arr");
+                    
+                    cparamDecls.append(",\n");
+                    cparamDecls.append("jintArray " + vname + "_arr");
+                    
+                    appendGetRelease(arrayGet, arrayRelease, "int", vname, vname + "_arr");
+                }
+
+                posDecls.append("float inc" + i + "_x = (src" + i + "Rect_x2 - src" + i + "Rect_x1) / dstw;\n");
+                posDecls.append("float inc" + i + "_y = (src" + i + "Rect_y2 - src" + i + "Rect_y1) / dsth;\n");
+
+                posInitY.append("float pos" + i + "_y = src" + i + "Rect_y1 + inc" + i + "_y*0.5f;\n");
+                posInitX.append("float pos" + i + "_x = src" + i + "Rect_x1 + inc" + i + "_x*0.5f;\n");
+                posIncrX.append("pos" + i + "_x += inc" + i + "_x;\n");
+                posIncrY.append("pos" + i + "_y += inc" + i + "_y;\n");
+
+                jparams.append(",\n");
+                jparams.append("src" + i + "Rect[0], src" + i + "Rect[1],\n");
+                jparams.append("src" + i + "Rect[2], src" + i + "Rect[3],\n");
+                jparams.append("src" + i + "w, src" + i + "h, src" + i + "scan");
+                
+                jparamDecls.append(",\n");
+                jparamDecls.append("float src" + i + "Rect_x1, float src" + i + "Rect_y1,\n");
+                jparamDecls.append("float src" + i + "Rect_x2, float src" + i + "Rect_y2,\n");
+                jparamDecls.append("int src" + i + "w, int src" + i + "h, int src" + i + "scan");
+
+                cparamDecls.append(",\n");
+                cparamDecls.append("jfloat src" + i + "Rect_x1, jfloat src" + i + "Rect_y1,\n");
+                cparamDecls.append("jfloat src" + i + "Rect_x2, jfloat src" + i + "Rect_y2,\n");
+                cparamDecls.append("jint src" + i + "w, jint src" + i + "h, jint src" + i + "scan");
+            }
+        }
+
+        if (interfaceName != null) {
+            interfaceDecl.append("implements "+interfaceName);
+        }
+
+        Reader template = new InputStreamReader(getClass().getResourceAsStream("SSEJavaGlue.stg"));
+        StringTemplateGroup group = new StringTemplateGroup(template, DefaultTemplateLexer.class);
+        StringTemplate jglue = group.getInstanceOf("glue");
+        jglue.setAttribute("effectName", effectName);
+        jglue.setAttribute("peerName", peerName);
+        jglue.setAttribute("interfaceDecl", interfaceDecl.toString());
+        jglue.setAttribute("usercode", usercode.toString());
+        jglue.setAttribute("samplers", samplers.toString());
+        jglue.setAttribute("cleanup", cleanup.toString());
+        jglue.setAttribute("srcRects", srcRects.toString());
+        jglue.setAttribute("constants", constants.toString());
+        jglue.setAttribute("params", jparams.toString());
+        jglue.setAttribute("paramDecls", jparamDecls.toString());
+
+        template = new InputStreamReader(getClass().getResourceAsStream("SSENativeGlue.stg"));
+        group = new StringTemplateGroup(template, DefaultTemplateLexer.class);
+        StringTemplate cglue = group.getInstanceOf("glue");
+        cglue.setAttribute("peerName", peerName);
+        cglue.setAttribute("jniName", peerName.replace("_", "_1"));
+        cglue.setAttribute("paramDecls", cparamDecls.toString());
+        cglue.setAttribute("arrayGet", arrayGet.toString());
+        cglue.setAttribute("arrayRelease", arrayRelease.toString());
+        cglue.setAttribute("posDecls", posDecls.toString());
+        cglue.setAttribute("pixInitY", pixInitY.toString());
+        cglue.setAttribute("pixInitX", pixInitX.toString());
+        cglue.setAttribute("posIncrY", posIncrY.toString());
+        cglue.setAttribute("posInitY", posInitY.toString());
+        cglue.setAttribute("posIncrX", posIncrX.toString());
+        cglue.setAttribute("posInitX", posInitX.toString());
+        cglue.setAttribute("body", body);
+        
+        GenCode gen = new GenCode();
+        gen.javaCode = jglue.toString();
+        gen.nativeCode = cglue.toString();
+        return gen;
+    }
+    
+    // TODO: need better mechanism for querying fields
+    private static char[] fields = {'x', 'y', 'z', 'w'};
+    public static String getSuffix(int i) {
+        return "_" + fields[i];
+    }
+
+    static int getFieldIndex(char field) {
+        switch (field) {
+        case 'r':
+        case 'x':
+            return 0;
+        case 'g':
+        case 'y':
+            return 1;
+        case 'b':
+        case 'z':
+            return 2;
+        case 'a':
+        case 'w':
+            return 3;
+        default:
+            throw new InternalError();
+        }
+    }
+    
+    // TODO: these shouldn't be implemented as a static method
+    private static Map<String, FuncDef> funcDefs = new HashMap<String, FuncDef>();
+    static void putFuncDef(FuncDef def) {
+        funcDefs.put(def.getFunction().getName(), def);
+    }
+    static FuncDef getFuncDef(String name) {
+        return funcDefs.get(name);
+    }
+    
+    private static Set<String> resultVars = new HashSet<String>();
+    static boolean isResultVarDeclared(String vname) {
+        return resultVars.contains(vname);
+    }
+    static void declareResultVar(String vname) {
+        resultVars.add(vname);
+    }
+    
+    private static StringBuilder usercode = new StringBuilder();
+    static void addGlueBlock(String block) {
+        usercode.append(block);
+    }
+    
+    private static void resetStatics() {
+        funcDefs.clear();
+        resultVars.clear();
+        usercode = new StringBuilder();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/sse/SSECallScanner.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,371 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.sw.sse;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import com.sun.scenario.effect.compiler.model.BaseType;
+import com.sun.scenario.effect.compiler.model.FuncImpl;
+import com.sun.scenario.effect.compiler.model.Function;
+import com.sun.scenario.effect.compiler.model.Param;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.model.Variable;
+import com.sun.scenario.effect.compiler.tree.ArrayAccessExpr;
+import com.sun.scenario.effect.compiler.tree.BinaryExpr;
+import com.sun.scenario.effect.compiler.tree.CallExpr;
+import com.sun.scenario.effect.compiler.tree.Expr;
+import com.sun.scenario.effect.compiler.tree.FieldSelectExpr;
+import com.sun.scenario.effect.compiler.tree.LiteralExpr;
+import com.sun.scenario.effect.compiler.tree.ParenExpr;
+import com.sun.scenario.effect.compiler.tree.TreeScanner;
+import com.sun.scenario.effect.compiler.tree.UnaryExpr;
+import com.sun.scenario.effect.compiler.tree.VariableExpr;
+import com.sun.scenario.effect.compiler.tree.VectorCtorExpr;
+
+import static com.sun.scenario.effect.compiler.backend.sw.sse.SSEBackend.*;
+
+/*
+ * How should we translate function calls?  For now we will inline
+ * everything, i.e. expand function bodies directly into the loop body.
+ * 
+ * The approach... For an ExprStmt or VarDecl (with initializer),
+ * walk down the tree and see if there are any function calls.
+ * For each function call, inline the function implementation prior
+ * to the statement output.  The statement will then refer to
+ * the output variables from the inlined function, rather than
+ * the function call itself.
+ * 
+ * First declare the result variables using the name of the
+ * called function and a field suffix, if needed; for example:
+ *     float3 val = sample(...).rgb;
+ * ==>
+ *     float sample_res_r, sample_res_g, sample_res_b;
+ * 
+ * Inside the inlined function, assign parameter expressions to
+ * temporary variables, using the name of the declared parameters
+ * as a guide; for example:
+ *     float val = min(foo+0.25, 1.0);
+ * ==>
+ *     float min_res;
+ *     {
+ *         float a_tmp = foo + 0.25f;
+ *         float b_tmp = 1.0f;
+ *         min_res = (a_tmp < b_tmp) a_tmp : b_tmp;
+ *     }
+ * 
+ * In a future version, references to scalar variables and literals
+ * could easily be inlined; for example:
+ *     float val = min(foo+0.25*bar, 1.0);
+ * ==>
+ *     float min_res;
+ *     {
+ *         float a_tmp = foo + 0.25f * bar;
+ *         min_res = (a_tmp < 1.0f) a_tmp : 1.0f;
+ *     }
+ * 
+ * Note that this system will likely produce less-than-efficient
+ * Java code in many cases; for now we're just trying to get things
+ * functional, and performance improvements will certainly come later.
+ * 
+ * 
+ * Example #1:
+ *     float3 val = scale * sample(baseImg, pos + off.xy).rgb;
+ * ==>
+ *     float sample_res_r, sample_res_g, sample_res_b;
+ *     {
+ *         float pos_x_tmp = pos_x + off_x;
+ *         float pos_y_tmp = pos_y + off_y;
+ *         int baseImg_tmp =
+ *             baseImg[(int)(pos_y_tmp*srch*srcscan) + (int)(pos_x_tmp*srcw)];
+ *         sample_res_r = (((baseImg_tmp >>  16) & 0xff) / 255f);
+ *         sample_res_g = (((baseImg_tmp >>   8) & 0xff) / 255f);
+ *         sample_res_b = (((baseImg_tmp       ) & 0xff) / 255f);
+ *     }
+ *     float val_r = scale * sample_res_r;
+ *     float val_g = scale * sample_res_g;
+ *     float val_b = scale * sample_res_b;
+ * 
+ * Example #2:
+ *     float val = scale * clamp(foo, 0.0, 1.0);
+ * ==>
+ *     float clamp_res;
+ *     {
+ *         float val_tmp = foo;
+ *         float min_tmp = 0.0f;
+ *         float max_tmp = 1.0f;
+ *         if (val_tmp < min_tmp) clamp_res = min_tmp;
+ *         else if (val_tmp > max_tmp) clamp_res = max_tmp;
+ *         else clamp_res = val_tmp;
+ *     }
+ *     float val = scale * clamp_res;
+ */
+class SSECallScanner extends TreeScanner {
+    private StringBuilder sb;
+    private boolean inCallExpr = false;
+    private Set<Integer> selectedFields = null;
+    private boolean inFieldSelect = false;
+    private char selectedField = 'x';
+    private boolean inVectorOp = false;
+    private int vectorIndex = 0;
+
+    private void output(String s) {
+        if (sb == null) {
+            sb = new StringBuilder();
+        }
+        sb.append(s);
+    }
+
+    String getResult() {
+        return (sb != null) ? sb.toString() : null;
+    }
+
+    @Override
+    public void visitCallExpr(CallExpr e) {
+        if (inCallExpr) {
+            throw new InternalError("Nested function calls not yet supported");
+        }
+
+        Function func = e.getFunction();
+        Type t = func.getReturnType();
+        String vtype = t.getBaseType().toString();
+        String vname = func.getName();
+        Set<Integer> fields = selectedFields;
+        if (t.isVector()) {
+            if (fields == null) {
+                fields = new HashSet<Integer>();
+                for (int i = 0; i < t.getNumFields(); i++) {
+                    fields.add(i);
+                }
+            }
+        }
+        if (!SSEBackend.isResultVarDeclared(vname)) {
+            // only declare result variables if they haven't been already
+            // TODO: there's a bug here; suppose a function like
+            // min(float,float) is inlined, then later we inline
+            // min(float3,float3), the second time we'll think we already have
+            // declared the result variables, but min_res_y/z won't be there...
+            SSEBackend.declareResultVar(vname);
+            if (t.isVector()) {
+                output(vtype + " ");
+                boolean first = true;
+                for (Integer f : fields) {
+                    if (first) {
+                        first = false;
+                    } else {
+                        output(", ");
+                    }
+                    output(vname + "_res" + getSuffix(f));
+                }
+                output(";\n");
+            } else {
+                output(vtype + " " + vname + "_res;\n");
+            }
+        }
+
+        inCallExpr = true;
+        output("{\n");
+        List<Param> params = func.getParams();
+        List<Expr> argExprs = e.getParams();
+        for (int i = 0; i < params.size(); i++) {
+            Param param = params.get(i);
+            String pname = param.getName();
+            Type ptype = param.getType();
+            BaseType pbasetype = ptype.getBaseType();
+            if (pbasetype == BaseType.SAMPLER) {
+                // skip these for now
+                continue;
+            }
+            if (ptype.isVector()) {
+                inVectorOp = true;
+                for (int j = 0; j < ptype.getNumFields(); j++) {
+                    vectorIndex = j;
+                    output(pbasetype.toString());
+                    output(" ");
+                    output(pname + "_tmp" + getSuffix(j) + " = ");
+                    scan(argExprs.get(i));
+                    output(";\n");
+                }
+                inVectorOp = false;
+            } else {
+                output(pbasetype.toString());
+                output(" ");
+                output(pname + "_tmp = ");
+                scan(argExprs.get(i));
+                output(";\n");
+            }
+        }
+
+        FuncImpl impl = SSEFuncImpls.get(func);
+        if (impl != null) {
+            // core (built-in) function
+            String preamble = impl.getPreamble(argExprs);
+            if (preamble != null) {
+                output(preamble);
+            }
+
+            if (t.isVector()) {
+                for (Integer f : fields) {
+                    output(vname + "_res" + getSuffix(f) + " = ");
+                    output(impl.toString(f, argExprs));
+                    output(";\n");
+                }
+            } else {
+                output(vname + "_res = ");
+                output(impl.toString(0, argExprs));
+                output(";\n");
+            }
+        } else {
+            // user-defined function
+            SSETreeScanner scanner = new SSETreeScanner(func.getName());
+            scanner.scan(SSEBackend.getFuncDef(func.getName()).getStmt());
+            output(scanner.getResult());
+        }
+
+        output("\n}\n");
+        inCallExpr = false;
+    }
+
+    @Override
+    public void visitArrayAccessExpr(ArrayAccessExpr e) {
+        if (inCallExpr) {
+            if (e.getExpr() instanceof VariableExpr &&
+                e.getIndex() instanceof VariableExpr)
+            {
+                VariableExpr ve = (VariableExpr)e.getExpr();
+                VariableExpr ie = (VariableExpr)e.getIndex();
+                output(ve.getVariable().getName());
+                output("_arr[" + ie.getVariable().getName());
+                output(" * " + ve.getVariable().getType().getNumFields());
+                output(" + " + getFieldIndex(selectedField) + "]");
+            } else {
+                throw new InternalError("Array access only supports variable expr/index (for now)");
+            }
+        } else {
+            super.visitArrayAccessExpr(e);
+        }
+    }
+
+    @Override
+    public void visitBinaryExpr(BinaryExpr e) {
+        if (inCallExpr) {
+            scan(e.getLeft());
+            output(" " + e.getOp() + " ");
+            scan(e.getRight());
+        } else {
+            super.visitBinaryExpr(e);
+        }
+    }
+
+    @Override
+    public void visitFieldSelectExpr(FieldSelectExpr e) {
+        if (inCallExpr) {
+            if (e.getFields().length() == 1) {
+                selectedField = e.getFields().charAt(0);
+            } else {
+                int index = inVectorOp ? vectorIndex : 0;
+                selectedField = e.getFields().charAt(index);
+            }
+            inFieldSelect = true;
+            scan(e.getExpr());
+            inFieldSelect = false;
+        } else {
+            selectedFields = getFieldSet(e.getFields());
+            super.visitFieldSelectExpr(e);
+            selectedFields = null;
+        }
+    }
+
+    private static Set<Integer> getFieldSet(String fields) {
+        Set<Integer> fieldSet = new HashSet<Integer>();
+        for (int i = 0; i < fields.length(); i++) {
+            fieldSet.add(getFieldIndex(fields.charAt(i)));
+        }
+        return fieldSet;
+    }
+
+    @Override
+    public void visitLiteralExpr(LiteralExpr e) {
+        if (inCallExpr) {
+            output(e.getValue().toString());
+            if (e.getValue() instanceof Float) {
+                output("f");
+            }
+        } else {
+            super.visitLiteralExpr(e);
+        }
+    }
+
+    @Override
+    public void visitParenExpr(ParenExpr e) {
+        if (inCallExpr) {
+            output("(");
+            scan(e.getExpr());
+            output(")");
+        } else {
+            super.visitParenExpr(e);
+        }
+    }
+
+    @Override
+    public void visitUnaryExpr(UnaryExpr e) {
+        if (inCallExpr) {
+            output(e.getOp().toString());
+            scan(e.getExpr());
+        } else {
+            super.visitUnaryExpr(e);
+        }
+    }
+
+    @Override
+    public void visitVariableExpr(VariableExpr e) {
+        if (inCallExpr) {
+            Variable var = e.getVariable();
+            output(var.getName());
+            if (var.isParam()) {
+                output("_tmp");
+            }
+            if (var.getType().isVector()) {
+                if (inFieldSelect) {
+                    output(getSuffix(getFieldIndex(selectedField)));
+                } else if (inVectorOp) {
+                    output(getSuffix(vectorIndex));
+                } else {
+                    throw new InternalError("TBD");
+                }
+            }
+        } else {
+            super.visitVariableExpr(e);
+        }
+    }
+
+    @Override
+    public void visitVectorCtorExpr(VectorCtorExpr e) {
+        // TODO: this will likely work for simple variables and literals,
+        // but we need something more for embedded function calls, etc...
+        scan(e.getParams().get(vectorIndex));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/sse/SSEFuncImpls.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,528 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.sw.sse;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import com.sun.scenario.effect.compiler.model.CoreSymbols;
+import com.sun.scenario.effect.compiler.model.FuncImpl;
+import com.sun.scenario.effect.compiler.model.Function;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.tree.Expr;
+import com.sun.scenario.effect.compiler.tree.VariableExpr;
+
+import static com.sun.scenario.effect.compiler.backend.sw.sse.SSEBackend.*;
+import static com.sun.scenario.effect.compiler.model.Type.*;
+
+/**
+ * Contains the C/SSE implementations for all core (built-in) functions.
+ */
+class SSEFuncImpls {
+
+    private static Map<Function, FuncImpl> funcs = new HashMap<Function, FuncImpl>();
+    
+    static FuncImpl get(Function func) {
+        return funcs.get(func);
+    }
+    
+    static {
+        // float4 sample(sampler s, float2 loc)
+        declareFunctionSample(SAMPLER);
+
+        // float4 sample(lsampler s, float2 loc)
+        declareFunctionSample(LSAMPLER);
+
+        // float4 sample(fsampler s, float2 loc)
+        declareFunctionSample(FSAMPLER);
+
+        // int intcast(float x)
+        declareFunctionIntCast();
+        
+        // <ftype> min(<ftype> x, <ftype> y)
+        // <ftype> min(<ftype> x, float y)
+        declareOverloadsMinMax("min", "((x_tmp$1 < y_tmp$2) ? x_tmp$1 : y_tmp$2)");
+
+        // <ftype> max(<ftype> x, <ftype> y)
+        // <ftype> max(<ftype> x, float y)
+        declareOverloadsMinMax("max", "((x_tmp$1 > y_tmp$2) ? x_tmp$1 : y_tmp$2)");
+
+        // <ftype> clamp(<ftype> val, <ftype> min, <ftype> max)
+        // <ftype> clamp(<ftype> val, float min, float max)
+        declareOverloadsClamp();
+
+        // <ftype> smoothstep(<ftype> min, <ftype> max, <ftype> val)
+        // <ftype> smoothstep(float min, float max, <ftype> val)
+        declareOverloadsSmoothstep();
+
+        // <ftype> abs(<ftype> x)
+        declareOverloadsSimple("abs", "fabs(x_tmp$1)");
+
+        // <ftype> floor(<ftype> x)
+        declareOverloadsSimple("floor", "floor(x_tmp$1)");
+
+        // <ftype> ceil(<ftype> x)
+        declareOverloadsSimple("ceil", "ceil(x_tmp$1)");
+
+        // <ftype> fract(<ftype> x)
+        declareOverloadsSimple("fract", "(x_tmp$1 - floor(x_tmp$1))");
+
+        // <ftype> sign(<ftype> x)
+        declareOverloadsSimple("sign", "((x_tmp$1 < 0.f) ? -1.f : (x_tmp$1 > 0.f) ? 1.f : 0.f)");
+
+        // <ftype> sqrt(<ftype> x)
+        declareOverloadsSimple("sqrt", "sqrt(x_tmp$1)");
+
+        // <ftype> sin(<ftype> x)
+        declareOverloadsSimple("sin", "sin(x_tmp$1)");
+
+        // <ftype> cos(<ftype> x)
+        declareOverloadsSimple("cos", "cos(x_tmp$1)");
+
+        // <ftype> tan(<ftype> x)
+        declareOverloadsSimple("tan", "tan(x_tmp$1)");
+
+        // <ftype> pow(<ftype> x, <ftype> y)
+        declareOverloadsSimple2("pow", "pow(x_tmp$1, y_tmp$2)");
+
+        // <ftype> mod(<ftype> x, <ftype> y)
+        // <ftype> mod(<ftype> x, float y)
+        declareOverloadsMinMax("mod", "(x_tmp$1 % y_tmp$2)");
+
+        // float dot(<ftype> x, <ftype> y)
+        declareOverloadsDot();
+
+        // float distance(<ftype> x, <ftype> y)
+        declareOverloadsDistance();
+
+        // <ftype> mix(<ftype> x, <ftype> y, <ftype> a)
+        // <ftype> mix(<ftype> x, <ftype> y, float a)
+        declareOverloadsMix();
+        
+        // <ftype> normalize(<ftype> x)
+        declareOverloadsNormalize();
+
+        // <ftype> ddx(<ftype> p)
+        declareOverloadsSimple("ddx", "<ddx() not implemented for sw backends>");
+
+        // <ftype> ddy(<ftype> p)
+        declareOverloadsSimple("ddy", "<ddy() not implemented for sw backends>");
+    }
+    
+    private static void declareFunction(FuncImpl impl,
+                                        String name, Type... ptypes)
+    {
+        Function f = CoreSymbols.getFunction(name, Arrays.asList(ptypes));
+        if (f == null) {
+            throw new InternalError("Core function not found (have you declared the function in CoreSymbols?)");
+        }
+        funcs.put(f, impl);
+    }
+    
+    /**
+     * Used to declare sample function:
+     *   float4 sample([l,f]sampler s, float2 loc)
+     */
+    private static void declareFunctionSample(final Type type) {
+        FuncImpl fimpl = new FuncImpl() {
+            @Override
+            public String getPreamble(List<Expr> params) {
+                String s = getSamplerName(params);
+                // TODO: this bounds checking is way too costly...
+                String p = getPosName(params);
+                if (type == LSAMPLER) {
+                    return
+                        "lsample(" + s + ", loc_tmp_x, loc_tmp_y,\n" +
+                        "        " + p + "w, " + p + "h, " + p + "scan,\n" +
+                        "        " + s + "_vals);\n";
+                } else if (type == FSAMPLER) {
+                    return
+                        "fsample(" + s + ", loc_tmp_x, loc_tmp_y,\n" +
+                        "        " + p + "w, " + p + "h, " + p + "scan,\n" +
+                        "        " + s + "_vals);\n";
+                } else {
+                    return
+                        "int " + s + "_tmp;\n" +
+                        "if (loc_tmp_x >= 0 && loc_tmp_y >= 0) {\n" +
+                        "    int iloc_tmp_x = (int)(loc_tmp_x*" + p + "w);\n" +
+                        "    int iloc_tmp_y = (int)(loc_tmp_y*" + p + "h);\n" +
+                        "    jboolean out =\n" +
+                        "        iloc_tmp_x >= " + p + "w ||\n" +
+                        "        iloc_tmp_y >= " + p + "h;\n" +
+                        "    " + s + "_tmp = out ? 0 :\n" +
+                        "        " + s + "[iloc_tmp_y*" + p + "scan + iloc_tmp_x];\n" +
+                        "} else {\n" +
+                        "    " + s + "_tmp = 0;\n" +
+                        "}\n";
+                }
+            }
+            public String toString(int i, List<Expr> params) {
+                String s = getSamplerName(params);
+                if (type == LSAMPLER || type == FSAMPLER) {
+                    return (i < 0 || i > 3) ? null : s + "_vals[" + i + "]";
+                } else {
+                    switch (i) {
+                    case 0:
+                        return "(((" + s + "_tmp >> 16) & 0xff) / 255.f)";
+                    case 1:
+                        return "(((" + s + "_tmp >>  8) & 0xff) / 255.f)";
+                    case 2:
+                        return "(((" + s + "_tmp      ) & 0xff) / 255.f)";
+                    case 3:
+                        return "(((" + s + "_tmp >> 24) & 0xff) / 255.f)";
+                    default:
+                        return null;
+                    }
+                }
+            }
+            private String getSamplerName(List<Expr> params) {
+                VariableExpr e = (VariableExpr)params.get(0);
+                return e.getVariable().getName();
+            }
+            private String getPosName(List<Expr> params) {
+                VariableExpr e = (VariableExpr)params.get(0);
+                return "src" + e.getVariable().getReg();
+            }
+        };
+        declareFunction(fimpl, "sample", type, FLOAT2);
+    }
+
+    /**
+     * Used to declare intcast function:
+     *   int intcast(float x)
+     */
+    private static void declareFunctionIntCast() {
+        FuncImpl fimpl = new FuncImpl() {
+            public String toString(int i, List<Expr> params) {
+                return "((int)x_tmp)";
+            }
+        };
+        declareFunction(fimpl, "intcast", FLOAT);
+    }
+    
+    /**
+     * Used to declare simple functions of the following form: 
+     *   <ftype> name(<ftype> x)
+     */
+    private static void declareOverloadsSimple(String name, final String pattern) {
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type);
+        }
+    }
+
+    /**
+     * Used to declare simple two parameter functions of the following form:
+     *   <ftype> name(<ftype> x, <ftype> y)
+     */
+    private static void declareOverloadsSimple2(String name, final String pattern) {
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            // declare (vectype,vectype) variants
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type);
+        }
+    }
+
+    /**
+     * Used to declare normalize functions of the following form: 
+     *   <ftype> normalize(<ftype> x)
+     */
+    private static void declareOverloadsNormalize() {
+        final String name = "normalize";
+        final String pattern = "x_tmp$1 / denom";
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            int n = type.getNumFields();
+            final String preamble;
+            if (n == 1) {
+                preamble = "float denom = x_tmp;\n";
+            } else {
+                String     s  =    "(x_tmp_x * x_tmp_x)";
+                           s += "+\n(x_tmp_y * x_tmp_y)";
+                if (n > 2) s += "+\n(x_tmp_z * x_tmp_z)";
+                if (n > 3) s += "+\n(x_tmp_w * x_tmp_w)";
+                preamble = "float denom = sqrt(" + s + ");\n";
+            }
+            
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                @Override
+                public String getPreamble(List<Expr> params) {
+                    return preamble;
+                }
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type);
+        }
+    }
+
+    /**
+     * Used to declare dot functions of the following form: 
+     *   float dot(<ftype> x, <ftype> y)
+     */
+    private static void declareOverloadsDot() {
+        final String name = "dot";
+        for (final Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            int n = type.getNumFields();
+            String s;
+            if (n == 1) {
+                s = "(x_tmp * y_tmp)";
+            } else {
+                           s  =    "(x_tmp_x * y_tmp_x)";
+                           s += "+\n(x_tmp_y * y_tmp_y)";
+                if (n > 2) s += "+\n(x_tmp_z * y_tmp_z)";
+                if (n > 3) s += "+\n(x_tmp_w * y_tmp_w)";
+            }
+            final String str = s;
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    return str;
+                }
+            };
+            declareFunction(fimpl, name, type, type);
+        }
+    }
+    
+    /**
+     * Used to declare distance functions of the following form: 
+     *   float distance(<ftype> x, <ftype> y)
+     */
+    private static void declareOverloadsDistance() {
+        final String name = "distance";
+        for (final Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            int n = type.getNumFields();
+            String s;
+            if (n == 1) {
+                s = "(x_tmp - y_tmp) * (x_tmp - y_tmp)";
+            } else {
+                           s  =    "((x_tmp_x - y_tmp_x) * (x_tmp_x - y_tmp_x))";
+                           s += "+\n((x_tmp_y - y_tmp_y) * (x_tmp_y - y_tmp_y))";
+                if (n > 2) s += "+\n((x_tmp_z - y_tmp_z) * (x_tmp_z - y_tmp_z))";
+                if (n > 3) s += "+\n((x_tmp_w - y_tmp_w) * (x_tmp_w - y_tmp_w))";
+            }
+            final String str = "sqrt(" + s + ")";
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    return str;
+                }
+            };
+            declareFunction(fimpl, name, type, type);
+        }
+    }
+    
+    /**
+     * Used to declare min/max functions of the following form:
+     *   <ftype> name(<ftype> x, <ftype> y)
+     *   <ftype> name(<ftype> x, float y)
+     * 
+     * TODO: this is currently geared to simple functions like
+     * min and max; we should make this more general...
+     */
+    private static void declareOverloadsMinMax(String name, final String pattern) {
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            // declare (vectype,vectype) variants
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type);
+            
+            if (type == FLOAT) {
+                continue;
+            }
+            
+            // declare (vectype,float) variants
+            fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = getSuffix(i);
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", "");
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, FLOAT);
+        }
+    }
+
+    /**
+     * Used to declare clamp functions of the following form:
+     *   <ftype> clamp(<ftype> val, <ftype> min, <ftype> max)
+     *   <ftype> clamp(<ftype> val, float min, float max)
+     */
+    private static void declareOverloadsClamp() {
+        final String name = "clamp";
+        final String pattern =
+            "(val_tmp$1 < min_tmp$2) ? min_tmp$2 : \n" +
+            "(val_tmp$1 > max_tmp$2) ? max_tmp$2 : val_tmp$1";
+        
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            // declare (vectype,vectype,vectype) variants
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type, type);
+            
+            if (type == FLOAT) {
+                continue;
+            }
+            
+            // declare (vectype,float,float) variants
+            fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = getSuffix(i);
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", "");
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, FLOAT, FLOAT);
+        }
+    }
+
+    /**
+     * Used to declare smoothstep functions of the following form:
+     *   <ftype> smoothstep(<ftype> min, <ftype> max, <ftype> val)
+     *   <ftype> smoothstep(float min, float max, <ftype> val)
+     */
+    private static void declareOverloadsSmoothstep() {
+        final String name = "smoothstep";
+        // TODO - the smoothstep function is defined to use Hermite interpolation
+        final String pattern =
+            "(val_tmp$1 < min_tmp$2) ? 0.0f : \n" +
+            "(val_tmp$1 > max_tmp$2) ? 1.0f : \n" +
+            "(val_tmp$1 / (max_tmp$2 - min_tmp$2))";
+        
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            // declare (vectype,vectype,vectype) variants
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type, type);
+            
+            if (type == FLOAT) {
+                continue;
+            }
+            
+            // declare (float,float,vectype) variants
+            fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = getSuffix(i);
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", "");
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, FLOAT, FLOAT, type);
+        }
+    }
+    
+    /**
+     * Used to declare mix functions of the following form:
+     *   <ftype> mix(<ftype> x, <ftype> y, <ftype> a)
+     *   <ftype> mix(<ftype> x, <ftype> y, float a)
+     */
+    private static void declareOverloadsMix() {
+        final String name = "mix";
+        final String pattern =
+            "(x_tmp$1 * (1.0f - a_tmp$2) + y_tmp$1 * a_tmp$2)";
+        
+        for (Type type : new Type[] {FLOAT, FLOAT2, FLOAT3, FLOAT4}) {
+            // declare (vectype,vectype,vectype) variants
+            final boolean useSuffix = (type != FLOAT);
+            FuncImpl fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = useSuffix ? getSuffix(i) : "";
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", sfx);
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type, type);
+            
+            if (type == FLOAT) {
+                continue;
+            }
+            
+            // declare (vectype,vectype,float) variants
+            fimpl = new FuncImpl() {
+                public String toString(int i, List<Expr> params) {
+                    String sfx = getSuffix(i);
+                    String s = pattern;
+                    s = s.replace("$1", sfx);
+                    s = s.replace("$2", "");
+                    return s;
+                }
+            };
+            declareFunction(fimpl, name, type, type, FLOAT);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/sse/SSEJavaGlue.stg	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,101 @@
+group SSEJavaGlue;
+
+glue(effectName,peerName,interfaceDecl,
+     usercode,samplers,cleanup,srcRects,constants,params,paramDecls) ::= <<
+/*
+ * Copyright (c) 2008, 2011, Oracle  and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * This file was generated by JSLC -- DO NOT EDIT MANUALLY!
+ */
+
+package com.sun.scenario.effect.impl.sw.sse;
+
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import com.sun.scenario.effect.Effect;
+import com.sun.scenario.effect.FilterContext;
+import com.sun.scenario.effect.FloatMap;
+import com.sun.scenario.effect.ImageData;
+import com.sun.scenario.effect.$effectName$;
+import com.sun.scenario.effect.impl.BufferUtil;
+import com.sun.scenario.effect.impl.HeapImage;
+import com.sun.scenario.effect.impl.Renderer;
+import com.sun.scenario.effect.impl.state.*;
+import com.sun.javafx.geom.Rectangle;
+import com.sun.javafx.geom.transform.BaseTransform;
+
+public class SSE$peerName$Peer extends SSEEffectPeer $interfaceDecl$ {
+
+    public SSE$peerName$Peer(FilterContext fctx, Renderer r, String uniqueName) {
+        super(fctx, r, uniqueName);
+    }
+
+    @Override
+    protected final $effectName$ getEffect() {
+        return ($effectName$)super.getEffect();
+    }
+
+    $usercode$
+
+    @Override
+    public ImageData filter(Effect effect,
+                            BaseTransform transform,
+                            Rectangle outputClip,
+                            ImageData... inputs)
+    {
+        setEffect(effect);
+        Rectangle dstBounds = getResultBounds(transform, outputClip, inputs);
+        setDestBounds(dstBounds);
+
+        // TODO: for now, all input images must be TYPE_INT_ARGB_PRE
+        $samplers$
+
+        $srcRects$
+
+        final int dstx = 0;
+        final int dsty = 0;
+        final int dstw = dstBounds.width;
+        final int dsth = dstBounds.height;
+
+        HeapImage dst = (HeapImage)getRenderer().getCompatibleImage(dstw, dsth);
+        setDestNativeBounds(dst.getPhysicalWidth(), dst.getPhysicalHeight());
+        int dstscan = dst.getScanlineStride();
+        int[] dstPixels = dst.getPixelArray();
+        
+        $constants$
+
+        filter(dstPixels, dstx, dsty, dstw, dsth, dstscan$params$);
+
+        $cleanup$
+
+        return new ImageData(getFilterContext(), dst, dstBounds);
+    }
+
+    private static native void filter(int[] dstPixels,
+                                      int dstx, int dsty,
+                                      int dstw, int dsth,
+                                      int dstscan$paramDecls$);
+}
+
+>>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/sse/SSENativeGlue.stg	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,81 @@
+group SSENativeGlue;
+
+glue(peerName,jniName,paramDecls,arrayGet,arrayRelease,
+     pixInitY,pixInitX,posDecls,posInitY,posIncrY,posInitX,posIncrX,
+     body) ::= <<
+/*
+ * Copyright (c) 2008, 2011, Oracle  and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * This file was generated by JSLC -- DO NOT EDIT MANUALLY!
+ */
+
+#include <jni.h>
+#include <math.h>
+#include "SSEUtils.h"
+#include "com_sun_scenario_effect_impl_sw_sse_SSE$peerName$Peer.h"
+
+JNIEXPORT void JNICALL
+Java_com_sun_scenario_effect_impl_sw_sse_SSE$jniName$Peer_filter
+  (JNIEnv *env, jclass klass,
+   jintArray dst_arr,
+   jint dstx, jint dsty, jint dstw, jint dsth, jint dstscan$paramDecls$)
+{
+    int dyi;
+    float color_x, color_y, color_z, color_w;
+
+    $arrayGet$
+
+    $posDecls$
+
+    $posInitY$
+    for (int dy = dsty; dy < dsty+dsth; dy++) {
+        $pixInitY$
+        dyi = dy*dstscan;
+
+        $posInitX$
+        for (int dx = dstx; dx < dstx+dstw; dx++) {
+            $pixInitX$
+
+            $body$
+
+            if (color_w < 0.f) color_w = 0.f; else if (color_w > 1.f) color_w = 1.f;
+            if (color_x < 0.f) color_x = 0.f; else if (color_x > color_w) color_x = color_w;
+            if (color_y < 0.f) color_y = 0.f; else if (color_y > color_w) color_y = color_w;
+            if (color_z < 0.f) color_z = 0.f; else if (color_z > color_w) color_z = color_w;
+            dst[dyi+dx] =
+                ((int)(color_x * 0xff) << 16) |
+                ((int)(color_y * 0xff) <<  8) |
+                ((int)(color_z * 0xff) <<  0) |
+                ((int)(color_w * 0xff) << 24);
+
+            $posIncrX$
+        }
+
+        $posIncrY$
+    }
+
+    $arrayRelease$
+}
+
+>>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/backend/sw/sse/SSETreeScanner.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,342 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.backend.sw.sse;
+
+import com.sun.scenario.effect.compiler.model.Function;
+import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.model.Variable;
+import com.sun.scenario.effect.compiler.tree.*;
+import static com.sun.scenario.effect.compiler.backend.sw.sse.SSEBackend.getFieldIndex;
+import static com.sun.scenario.effect.compiler.backend.sw.sse.SSEBackend.getSuffix;
+
+/**
+ */
+class SSETreeScanner extends TreeScanner {
+
+    private final String funcName;
+    private final StringBuilder sb = new StringBuilder();
+
+    private boolean inVectorOp = false;
+    private int vectorIndex = 0;
+    private boolean inFieldSelect = false;
+    private char selectedField = 'x';
+    
+    SSETreeScanner() {
+        this(null);
+    }
+    
+    SSETreeScanner(String funcName) {
+        this.funcName = funcName;
+    }
+    
+    private void output(String s) {
+        sb.append(s);
+    }
+    
+    String getResult() {
+        return (sb != null) ? sb.toString() : null;
+    }
+    
+    @Override
+    public void visitArrayAccessExpr(ArrayAccessExpr e) {
+        if (e.getExpr() instanceof VariableExpr &&
+            e.getIndex() instanceof VariableExpr)
+        {
+            VariableExpr ve = (VariableExpr)e.getExpr();
+            VariableExpr ie = (VariableExpr)e.getIndex();
+            output(ve.getVariable().getName());
+            output("_arr[" + ie.getVariable().getName());
+            output(" * " + ve.getVariable().getType().getNumFields());
+            output(" + " + getFieldIndex(selectedField) + "]");
+        } else {
+            throw new InternalError("Array access only supports variable expr/index (for now)");
+        }
+    }
+
+    @Override
+    public void visitBinaryExpr(BinaryExpr e) {
+        scan(e.getLeft());
+        output(" " + e.getOp() + " ");
+        scan(e.getRight());
+    }
+
+    @Override
+    public void visitBreakStmt(BreakStmt s) {
+        output("break;");
+    }
+
+    @Override
+    public void visitCallExpr(CallExpr e) {
+        Function func = e.getFunction();
+        output(func.getName() + "_res");
+        if (func.getReturnType().isVector()) {
+            // TODO: this needs more thought
+            if (inFieldSelect) {
+                output(getSuffix(getFieldIndex(selectedField)));
+            } else if (inVectorOp) {
+                output(getSuffix(vectorIndex));
+            } else {
+                throw new InternalError("TBD");
+            }
+        }
+    }
+
+    @Override
+    public void visitCompoundStmt(CompoundStmt s) {
+        output("{\n");
+        super.visitCompoundStmt(s);
+        output("}\n");
+    }
+
+    @Override
+    public void visitContinueStmt(ContinueStmt s) {
+        output("continue;");
+    }
+
+    @Override
+    public void visitDeclStmt(DeclStmt s) {
+        super.visitDeclStmt(s);
+    }
+
+    @Override
+    public void visitDiscardStmt(DiscardStmt s) {
+        // TODO: not yet implemented
+    }
+
+    @Override
+    public void visitDoWhileStmt(DoWhileStmt s) {
+        output("do ");
+        scan(s.getStmt());
+        output(" while (");
+        scan(s.getExpr());
+        output(");");
+    }
+
+    @Override
+    public void visitExprStmt(ExprStmt s) {
+        Expr expr = s.getExpr();
+        
+        outputPreambles(expr);
+
+        Type t = expr.getResultType();
+        if (t.isVector()) {
+            inVectorOp = true;
+            for (int i = 0; i < t.getNumFields(); i++) {
+                vectorIndex = i;
+                scan(s.getExpr());
+                output(";\n");
+            }
+            inVectorOp = false;
+        } else {
+            scan(s.getExpr());
+            output(";\n");
+        }
+    }
+
+    @Override
+    public void visitFieldSelectExpr(FieldSelectExpr e) {
+        if (e.getFields().length() == 1) {
+            selectedField = e.getFields().charAt(0);
+        } else {
+            int index = inVectorOp ? vectorIndex : 0;
+            selectedField = e.getFields().charAt(index);
+        }
+        inFieldSelect = true;
+        scan(e.getExpr());
+        inFieldSelect = false;
+    }
+    
+    @Override
+    public void visitForStmt(ForStmt s) {
+        output("for (");
+        scan(s.getInit());
+        scan(s.getCondition());
+        output(";");
+        scan(s.getExpr());
+        output(")");
+        scan(s.getStmt());
+    }
+
+    @Override
+    public void visitFuncDef(FuncDef d) {
+        if (d.getFunction().getName().equals("main")) {
+            scan(d.getStmt());
+        } else {
+            // TODO: this is a hacky approach to saving func defs, which
+            // will be inlined later at point of use)...
+            SSEBackend.putFuncDef(d);
+        }
+    }
+    
+    @Override
+    public void visitGlueBlock(GlueBlock b) {
+        SSEBackend.addGlueBlock(b.getText());
+    }
+
+    @Override
+    public void visitLiteralExpr(LiteralExpr e) {
+        output(e.getValue().toString());
+        if (e.getValue() instanceof Float) {
+            output("f");
+        }
+    }
+    
+    @Override
+    public void visitParenExpr(ParenExpr e) {
+        output("(");
+        scan(e.getExpr());
+        output(")");
+    }
+
+    @Override
+    public void visitProgramUnit(ProgramUnit p) {
+        super.visitProgramUnit(p);
+    }
+
+    @Override
+    public void visitReturnStmt(ReturnStmt s) {
+        Expr expr = s.getExpr();
+        if (expr == null) {
+            throw new InternalError("Empty return not yet implemented");
+        }
+        if (funcName == null) {
+            throw new RuntimeException("Return statement not expected");
+        }
+        
+        Type t = expr.getResultType();
+        if (t.isVector()) {
+            inVectorOp = true;
+            for (int i = 0; i < t.getNumFields(); i++) {
+                vectorIndex = i;
+                output(funcName + "_res" + getSuffix(i) + " = ");
+                scan(s.getExpr());
+                output(";\n");
+            }
+            inVectorOp = false;
+        } else {
+            output(funcName + "_res = ");
+            scan(s.getExpr());
+            output(";\n");
+        }
+    }
+
+    @Override
+    public void visitSelectStmt(SelectStmt s) {
+        output("if (");
+        scan(s.getIfExpr());
+        output(")");
+        scan(s.getThenStmt());
+        Stmt e = s.getElseStmt();
+        if (e != null) {
+            output(" else ");
+            scan(e);
+        }
+    }
+
+    @Override
+    public void visitUnaryExpr(UnaryExpr e) {
+        output(e.getOp().toString());
+        scan(e.getExpr());
+    }
+    
+    @Override
+    public void visitVarDecl(VarDecl d) {
+        Variable var = d.getVariable();
+        if (var.getQualifier() != null) {
+            // these will be declared separately outside the loop body
+            return;
+        }
+
+        outputPreambles(d);
+        
+        Type t = var.getType();
+        if (t.isVector()) {
+            inVectorOp = true;
+            for (int i = 0; i < t.getNumFields(); i++) {
+                output(t.getBaseType().toString() + " ");
+                output(var.getName() + getSuffix(i));
+                Expr init = d.getInit();
+                if (init != null) {
+                    output(" = ");
+                    vectorIndex = i;
+                    scan(init);
+                }
+                output(";\n");
+            }
+            inVectorOp = false;
+        } else {
+            output(t.toString() + " " + var.getName());
+            Expr init = d.getInit();
+            if (init != null) {
+                output(" = ");
+                scan(init);
+            }
+            output(";\n");
+        }
+    }
+
+    @Override
+    public void visitVariableExpr(VariableExpr e) {
+        Variable var = e.getVariable();
+        output(var.getName());
+        if (var.isParam()) {
+            output("_tmp");
+        }
+        if (var.getType().isVector()) {
+            if (inFieldSelect) {
+                output(getSuffix(getFieldIndex(selectedField)));
+            } else if (inVectorOp) {
+                output(getSuffix(vectorIndex));
+            } else {
+                throw new InternalError("TBD");
+            }
+        }
+    }
+
+    @Override
+    public void visitVectorCtorExpr(VectorCtorExpr e) {
+        // TODO: this will likely work for simple variables and literals,
+        // but we need something more for embedded function calls, etc...
+        scan(e.getParams().get(vectorIndex));
+    }
+
+    @Override
+    public void visitWhileStmt(WhileStmt s) {
+        output("while (");
+        scan(s.getCondition());
+        output(")");
+        scan(s.getStmt());
+    }
+    
+    private void outputPreambles(Tree tree) {
+        SSECallScanner scanner = new SSECallScanner();
+        scanner.scan(tree);
+        String res = scanner.getResult();
+        if (res != null) {
+            output(scanner.getResult());
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/model/BaseType.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.model;
+
+import java.util.Locale;
+
+/**
+ */
+public enum BaseType {
+    VOID,
+    FLOAT, 
+    INT,
+    BOOL,
+    SAMPLER;
+    
+    @Override
+    public String toString() {
+        return name().toLowerCase(Locale.ENGLISH);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/model/BinaryOpType.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.model;
+
+/**
+ */
+public enum BinaryOpType {
+
+    ADD  ("+",  Op.MATH),
+    SUB  ("-",  Op.MATH),
+    MUL  ("*",  Op.MATH),
+    DIV  ("/",  Op.MATH),
+    EQ   ("=",  Op.ASSIGN),
+    ADDEQ("+=", Op.ASSIGN),
+    SUBEQ("-=", Op.ASSIGN),
+    MULEQ("*=", Op.ASSIGN),
+    DIVEQ("/=", Op.ASSIGN),
+    OR   ("||", Op.REL),
+    XOR  ("^^", Op.REL),
+    AND  ("&&", Op.REL),
+    EQEQ ("==", Op.REL),
+    NEQ  ("!=", Op.REL),
+    LTEQ ("<=", Op.REL),
+    GTEQ (">=", Op.REL),
+    LT   ("<",  Op.REL),
+    GT   (">",  Op.REL);
+    
+    private enum Op { MATH, ASSIGN, REL }
+    private String symbol;
+    private Op op;
+
+    private BinaryOpType(String symbol, Op op) {
+        this.symbol = symbol;
+        this.op = op;
+    }
+    
+    public static BinaryOpType forSymbol(String symbol) {
+        for (BinaryOpType ot : BinaryOpType.values()) {
+            if (ot.getSymbol().equals(symbol)) {
+                return ot;
+            }
+        }
+        return null;
+    }
+
+    public String getSymbol() {
+        return symbol;
+    }
+    
+    public boolean isRelational() {
+        return (op == Op.REL);
+    }
+    
+    public boolean isAssignment() {
+        return (op == Op.ASSIGN);
+    }
+
+    @Override
+    public String toString() {
+        return symbol;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/model/CoreSymbols.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.model;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import static com.sun.scenario.effect.compiler.model.Precision.*;
+import static com.sun.scenario.effect.compiler.model.Type.*;
+
+/**
+ * Maintains the sets of core (built-in) functions and variables.
+ */
+public class CoreSymbols {
+
+    private static Set<Variable> vars = new HashSet<Variable>();
+    private static Set<Function> funcs = new HashSet<Function>();
+
+    static Set<Variable> getAllVariables() {
+        return vars;
+    }
+    
+    static Set<Function> getAllFunctions() {
+        return funcs;
+    }
+    
+    public static Function getFunction(String name, List<Type> ptypes) {
+        return SymbolTable.getFunctionForSignature(funcs, name, ptypes);
+    }
+    
+    static {
+        // pos0/1, pixcoord, and jsl_vertexColor are declared "const"
+        // (read-only) to prevent accidental assignment
+        // TODO: should probably add "jsl_" prefix to all of these to make
+        // it clear that they are special variables...
+        declareVariable("pos0",            FLOAT2, null, true);
+        declareVariable("pos1",            FLOAT2, null, true);
+        declareVariable("pixcoord",        FLOAT2, null, true);
+        declareVariable("jsl_vertexColor", FLOAT4, LOWP, true);
+        declareVariable("color",           FLOAT4, LOWP, false);
+        
+        // float4 sample(sampler s, float2 loc)
+        declareFunction(FLOAT4, "sample", SAMPLER, "s", FLOAT2, "loc");
+
+        // float4 sample(lsampler s, float2 loc)
+        declareFunction(FLOAT4, "sample", LSAMPLER, "s", FLOAT2, "loc");
+
+        // float4 sample(fsampler s, float2 loc)
+        declareFunction(FLOAT4, "sample", FSAMPLER, "s", FLOAT2, "loc");
+
+        // int intcast(float x)
+        declareFunction(INT, "intcast", FLOAT, "x");
+
+        // bool any(<btype> x)
+        // GLSL only supports: bool any(<btype N> x); where N := 2, 3, 4
+        // HLSL supports: bool any(<type> x)
+        declareOverloadsBool("any");
+
+        // <ftype> min(<ftype> x, <ftype> y)
+        // <ftype> min(<ftype> x, float y)
+        declareOverloadsMinMax("min");
+
+        // <ftype> max(<ftype> x, <ftype> y)
+        // <ftype> max(<ftype> x, float y)
+        declareOverloadsMinMax("max");
+
+        // <ftype> clamp(<ftype> val, <ftype> min, <ftype> max)
+        // <ftype> clamp(<ftype> val, float min, float max)
+        declareOverloadsClamp();
+
+        // <ftype> smoothstep(<ftype> min, <ftype> max, <ftype> val)
+        // <ftype> smoothstep(float min, float max, <ftype> val)
+        declareOverloadsSmoothstep();
+
+        // <ftype> abs(<ftype> x)
+        declareOverloadsSimple("abs");
+
+        // <ftype> floor(<ftype> x)
+        declareOverloadsSimple("floor");
+
+        // <ftype> ceil(<ftype> x)
+        declareOverloadsSimple("ceil");
+
+        // <ftype> fract(<ftype> x)
+        declareOverloadsSimple("fract");
+
+        // <ftype> sign(<ftype> x)
+        declareOverloadsSimple("sign");
+
+        // <ftype> sqrt(<ftype> x)
+        declareOverloadsSimple("sqrt");
+
+        // <ftype> sin(<ftype> x)
+        declareOverloadsSimple("sin");
+
+        // <ftype> cos(<ftype> x)
+        declareOverloadsSimple("cos");
+
+        // <ftype> tan(<ftype> x)
+        declareOverloadsSimple("tan");
+
+        // <ftype> pow(<ftype> x, <ftype> y)
+        declareOverloadsSimple2("pow");
+
+        // <ftype> mod(<ftype> x, <ftype> y)
+        // <ftype> mod(<ftype> x, float y)
+        declareOverloadsMinMax("mod");
+
+        // float dot(<ftype> x, <ftype> y)
+        declareOverloadsFloat2("dot");
+
+        // float distance(<ftype> x, <ftype> y)
+        declareOverloadsFloat2("distance");
+
+        // float length(<ftype> x)
+        declareOverloadsFloat("length");
+
+        // <ftype> mix(<ftype> x, <ftype> y, <ftype> a)
+        // <ftype> mix(<ftype> x, <ftype> y, float a)
+        declareOverloadsMix();
+        
+        // <ftype> normalize(<ftype> x)
+        declareOverloadsSimple("normalize");
+
+        // <ftype> ddx(<ftype> p)
+        declareOverloadsSimple("ddx");
+
+        // <ftype> ddy(<ftype> p)
+        declareOverloadsSimple("ddy");
+    }
+
+    private static void declareVariable(String name, Type type,
+                                        Precision precision,
+                                        boolean readonly)
+    {
+        Qualifier qual = readonly ? Qualifier.CONST : null;
+        vars.add(new Variable(name, type, qual, precision, -1, -1, null, false));
+    }
+    
+    private static void declareFunction(Type returnType,
+                                        String name,
+                                        Object... params)
+    {
+        List<Param> paramList = new ArrayList<Param>();
+        if (params.length % 2 != 0) {
+            throw new InternalError("Params array length must be even");
+        }
+        for (int i = 0; i < params.length; i+=2) {
+            if (!(params[i+0] instanceof Type) ||
+                !(params[i+1] instanceof String))
+            {
+                throw new InternalError("Params must be specified as (Type,String) pairs");
+            }
+            paramList.add(new Param((String)params[i+1], (Type)params[i]));
+        }
+        funcs.add(new Function(name, returnType, paramList));
+    }
+
+    private static void declareOverloadsSimple(String name) {
+        declareFunction(FLOAT,  name, FLOAT,  "x");
+        declareFunction(FLOAT2, name, FLOAT2, "x");
+        declareFunction(FLOAT3, name, FLOAT3, "x");
+        declareFunction(FLOAT4, name, FLOAT4, "x");
+    }
+
+    private static void declareOverloadsSimple2(String name) {
+        declareFunction(FLOAT,  name, FLOAT,  "x", FLOAT,  "y");
+        declareFunction(FLOAT2, name, FLOAT2, "x", FLOAT2, "y");
+        declareFunction(FLOAT3, name, FLOAT3, "x", FLOAT3, "y");
+        declareFunction(FLOAT4, name, FLOAT4, "x", FLOAT4, "y");
+    }
+
+    private static void declareOverloadsMinMax(String name) {
+        declareFunction(FLOAT,  name, FLOAT,  "x", FLOAT,  "y");
+        declareFunction(FLOAT2, name, FLOAT2, "x", FLOAT2, "y");
+        declareFunction(FLOAT3, name, FLOAT3, "x", FLOAT3, "y");
+        declareFunction(FLOAT4, name, FLOAT4, "x", FLOAT4, "y");
+        declareFunction(FLOAT2, name, FLOAT2, "x", FLOAT,  "y");
+        declareFunction(FLOAT3, name, FLOAT3, "x", FLOAT,  "y");
+        declareFunction(FLOAT4, name, FLOAT4, "x", FLOAT,  "y");
+    }
+
+    private static void declareOverloadsClamp() {
+        final String name = "clamp";
+        declareFunction(FLOAT,  name, FLOAT,  "val", FLOAT,  "min", FLOAT,  "max");
+        declareFunction(FLOAT2, name, FLOAT2, "val", FLOAT2, "min", FLOAT2, "max");
+        declareFunction(FLOAT3, name, FLOAT3, "val", FLOAT3, "min", FLOAT3, "max");
+        declareFunction(FLOAT4, name, FLOAT4, "val", FLOAT4, "min", FLOAT4, "max");
+        declareFunction(FLOAT2, name, FLOAT2, "val", FLOAT,  "min", FLOAT,  "max");
+        declareFunction(FLOAT3, name, FLOAT3, "val", FLOAT,  "min", FLOAT,  "max");
+        declareFunction(FLOAT4, name, FLOAT4, "val", FLOAT,  "min", FLOAT,  "max");
+    }
+
+    private static void declareOverloadsSmoothstep() {
+        final String name = "smoothstep";
+        declareFunction(FLOAT,  name, FLOAT,  "min", FLOAT,  "max", FLOAT,   "val");
+        declareFunction(FLOAT2, name, FLOAT2, "min", FLOAT2, "max", FLOAT2,  "val");
+        declareFunction(FLOAT3, name, FLOAT3, "min", FLOAT3, "max", FLOAT3,  "val");
+        declareFunction(FLOAT4, name, FLOAT4, "min", FLOAT4, "max", FLOAT4,  "val");
+        declareFunction(FLOAT2, name, FLOAT,  "min", FLOAT,  "max", FLOAT2,  "val");
+        declareFunction(FLOAT3, name, FLOAT,  "min", FLOAT,  "max", FLOAT3,  "val");
+        declareFunction(FLOAT4, name, FLOAT,  "min", FLOAT,  "max", FLOAT4,  "val");
+    }
+
+    private static void declareOverloadsMix() {
+        final String name = "mix";
+        declareFunction(FLOAT,  name, FLOAT,  "x", FLOAT,  "y", FLOAT,  "a");
+        declareFunction(FLOAT2, name, FLOAT2, "x", FLOAT2, "y", FLOAT2, "a");
+        declareFunction(FLOAT3, name, FLOAT3, "x", FLOAT3, "y", FLOAT3, "a");
+        declareFunction(FLOAT4, name, FLOAT4, "x", FLOAT4, "y", FLOAT4, "a");
+        declareFunction(FLOAT2, name, FLOAT2, "x", FLOAT2, "y", FLOAT,  "a");
+        declareFunction(FLOAT3, name, FLOAT3, "x", FLOAT3, "y", FLOAT,  "a");
+        declareFunction(FLOAT4, name, FLOAT4, "x", FLOAT4, "y", FLOAT,  "a");
+    }
+
+    private static void declareOverloadsBool(String name) {
+        declareFunction(BOOL, name, BOOL2, "x");
+        declareFunction(BOOL, name, BOOL3, "x");
+        declareFunction(BOOL, name, BOOL4, "x");
+    }
+
+    private static void declareOverloadsFloat(String name) {
+        declareFunction(FLOAT, name, FLOAT,  "x");
+        declareFunction(FLOAT, name, FLOAT2, "x");
+        declareFunction(FLOAT, name, FLOAT3, "x");
+        declareFunction(FLOAT, name, FLOAT4, "x");
+    }
+
+    private static void declareOverloadsFloat2(String name) {
+        declareFunction(FLOAT, name, FLOAT,  "x", FLOAT,  "y");
+        declareFunction(FLOAT, name, FLOAT2, "x", FLOAT2, "y");
+        declareFunction(FLOAT, name, FLOAT3, "x", FLOAT3, "y");
+        declareFunction(FLOAT, name, FLOAT4, "x", FLOAT4, "y");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/model/FuncImpl.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.model;
+
+import java.util.List;
+import com.sun.scenario.effect.compiler.tree.Expr;
+
+/**
+ */
+public abstract class FuncImpl {
+    public String getPreamble(List<Expr> params) {
+        return null;
+    }
+    
+    public abstract String toString(int i, List<Expr> params);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/model/Function.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.model;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ */
+public class Function {
+
+    private final String name;
+    private final Type returnType;
+    private final List<Param> params;
+
+    Function(String name, Type returnType, List<Param> params) {
+        this.name = name;
+        this.returnType = returnType;
+        if (params != null) {
+            this.params = params;
+        } else {
+            this.params = Collections.emptyList();
+        }
+    }
+
+    public String getName() {
+        return name;
+    }
+    
+    public Type getReturnType() {
+        return returnType;
+    }
+    
+    public List<Param> getParams() {
+        return params;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        final Function other = (Function) obj;
+        if (this.name != other.name && (this.name == null || !this.name.equals(other.name))) {
+            return false;
+        }
+        if (this.returnType != other.returnType) {
+            return false;
+        }
+        if (this.params != other.params && (this.params == null || !this.params.equals(other.params))) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 71 * hash + (this.name != null ? this.name.hashCode() : 0);
+        hash = 71 * hash + (this.returnType != null ? this.returnType.hashCode() : 0);
+        hash = 71 * hash + (this.params != null ? this.params.hashCode() : 0);
+        return hash;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/model/Param.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.model;
+
+/**
+ */
+public class Param {
+
+    private final String name;
+    private final Type type;
+
+    public Param(String name, Type type) {
+        if (name == null) {
+            throw new IllegalArgumentException("Name must be non-null");
+        }
+        if (type == null) {
+            throw new IllegalArgumentException("Type must be non-null");
+        }
+        this.name = name;
+        this.type = type;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public Type getType() {
+        return type;
+    }
+    
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if ((obj == null) || (obj.getClass() != this.getClass())) {
+            return false;
+        }
+        Param that = (Param)obj;
+        return this.name.equals(that.name) && this.type.equals(that.type);
+    }
+
+    @Override
+    public int hashCode() {
+        int hash = 7;
+        hash = 31 * hash + name.hashCode();
+        hash = 31 * hash + type.hashCode();
+        return hash;
+    }    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/model/Precision.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.model;
+
+import java.util.Locale;
+
+/**
+ */
+public enum Precision {
+    LOWP,
+    MEDIUMP,
+    HIGHP;
+
+    /**
+     * Returns a {@code Precision} instance given a lowercase token string.
+     * For example, given "lowp", this method will return
+     * {@code Precision.LOWP}.
+     */
+    public static Precision fromToken(String s) {
+        return valueOf(s.toUpperCase(Locale.ENGLISH));
+    }
+
+    @Override
+    public String toString() {
+        return name().toLowerCase(Locale.ENGLISH);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/model/Qualifier.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.model;
+
+import java.util.Locale;
+
+/**
+ */
+public enum Qualifier {
+    CONST,
+    PARAM;
+    
+    /**
+     * Returns a {@code Qualifier} instance given a lowercase token string.
+     * For example, given "param", this method will return
+     * {@code Qualifier.PARAM}.
+     */
+    public static Qualifier fromToken(String s) {
+        return valueOf(s.toUpperCase(Locale.ENGLISH));
+    }
+    
+    @Override
+    public String toString() {
+        return name().toLowerCase(Locale.ENGLISH);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/model/SymbolTable.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package com.sun.scenario.effect.compiler.model;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ */
+public class SymbolTable {
+
+    private final Map<String, Variable> globalVariableMap = new HashMap<String, Variable>();
+    private final Map<String, Variable> localVariableMap = new HashMap<String, Variable>();
+    private final Set<Function> globalFunctionSet = new HashSet<Function>();
+    private int numSamplers;
+    private int numParams;
+    private boolean global = true;
+
+    public SymbolTable() {
+        declareCoreFunctions();
+    }
+    
+    private Variable declareParamVariable(String name, Type type) {
+        return declareVariable(name, type, null, null, -1, null, true);
+    }
+
+    public Variable declareVariable(String name, Type type,
+                                    Qualifier qual)
+    {
+        return declareVariable(name, type, qual, null);
+    }
+
+    public Variable declareVariable(String name, Type type,
+                                    Qualifier qual, Precision precision)
+    {
+        return declareVariable(name, type, qual, precision, -1, null, false);
+    }
+
+    public Variable declareVariable(String name, Type type,
+                                    Qualifier qual, Precision precision,
+                                    int arraySize, Object constValue)
+    {
+        return declareVariable(name, type, qual, precision,
+                               arraySize, constValue, false);
+    }
+
+    public Variable declareVariable(String name, Type type,
+                                    Qualifier qual, Precision precision,
+                                    int arraySize, Object constValue,
+                                    boolean isParam)
+    {
+        Map<String, Variable> vars = getVariablesForScope();
+        Variable v = vars.get(name);
+        if (v != null) {
+            throw new RuntimeException("Variable '" + name + "' already declared");
+        }
+        
+        if (arraySize == 0) {
+            throw new RuntimeException("Array size cannot be zero");
+        }
+        
+        int reg = -1;
+        if (qual == Qualifier.PARAM) {
+            if (!global) {
+                throw new RuntimeException("Param variable can only be declared in global scope");
+            }
+            if (type.getBaseType() == BaseType.SAMPLER) {
+                reg = numSamplers;
+                numSamplers++;
+            } else {
+                reg = numParams;
+                if (arraySize > 0) {
+                    numParams += arraySize;
+                } else {
+                    numParams++;
+                }
+            }
+        }
+
+        v = new Variable(name, type, qual, precision,
+                         reg, arraySize, constValue, isParam);
+        vars.put(name, v);
+        return v;
+    }
+
+    public Function declareFunction(String name, Type returnType, List<Param> params) {
+        Function f = new Function(name, returnType, params);
+        if (isFunctionDeclared(f)) {
+            throw new RuntimeException("Function '" + name + "' already declared");
+        }
+        if (name.equals("main") && (params == null || params.isEmpty())) {
+            if (localVariableMap.isEmpty()) {
+                // core variables are implicitly declared for main() only
+                for (Variable v : CoreSymbols.getAllVariables()) {
+                    localVariableMap.put(v.getName(), v);
+                }
+            }
+        }
+        if (params != null) {
+            // only declare parameters for non-core functions so that they
+            // are visible in the function's scope (we skip this step for
+            // core functions because the way the code is currently set up,
+            // we'd end up declaring core function parameters in global scope;
+            // we should clean this up later)
+            for (Param param : params) {
+                declareParamVariable(param.getName(), param.getType());
+            }
+        }
+        declareUserFunction(f);
+        return f;
+    }
+    
+    public void enterFrame() {
+        global = false;
+        localVariableMap.clear();
+    }
+    
+    public void exitFrame() {
+        global = true;
+    }
+    
+    private void declareCoreFunctions() {
+        globalFunctionSet.addAll(CoreSymbols.getAllFunctions());
+    }
+
+    public Map<String, Variable> getGlobalVariables() {
+        return globalVariableMap;
+    }
+    
+    private boolean isFunctionDeclared(Function func) {
+       return globalFunctionSet.contains(func);
+    }
+    
+    private void declareUserFunction(Function func) {
+        globalFunctionSet.add(func);
+    }
+    
+    public Function getFunctionForSignature(String name, List<Type> ptypes) {
+        return getFunctionForSignature(globalFunctionSet, name, ptypes);
+    }
+    
+    static Function getFunctionForSignature(Set<Function> funcs,
+                                            String name,
+                                            List<Type> ptypes)
+    {
+        for (Function f : funcs) {
+            List<Param> params = f.getParams();
+            if (name.equals(f.getName()) && params.size() == ptypes.size()) {
+                boolean match = true;
+                for (int i = 0; i < params.size(); i++) {
+                    if (params.get(i).getType() != ptypes.get(i)) {
+                        match = false;
+                        break;
+                    }
+                }
+                if (match) {
+                    return f;
+                }
+            }
+        }
+        return null;
+    }
+    
+    public Map<String, Variable> getVariablesForScope() {
+        if (global) {
+            return globalVariableMap;
+        } else {
+            return localVariableMap;
+        }
+    }
+    
+    public int getNumSamplers() {
+        return numSamplers;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/decora-compiler/src/com/sun/scenario/effect/compiler/model/Type.java	Tue Nov 13 09:56:06 2012 -0800
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2008, 2012 Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it