changeset 11243:f9d0dcb8f3bd

Merge
author kcr
date Fri, 22 Mar 2019 08:11:38 -0700
parents 2c6a0304266d dd580ab38ad7
children 66b5bcf8564d
files modules/javafx.graphics/src/jslc/antlr/com/sun/scenario/effect/compiler/JSL.g
diffstat 45 files changed, 1495 insertions(+), 1002 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Wed Mar 13 09:30:47 2019 +0530
+++ b/.hgtags	Fri Mar 22 08:11:38 2019 -0700
@@ -527,3 +527,5 @@
 653d5bdbfa2a7f21e81bb3c5ce6eb4b2087ce91b 12+13
 5bc59c85d44c7f88937915c2df88c496648241d4 12+14
 4d10485201c7dd803ada7c257d0452b8e13c7c82 13+1
+bf9eac8eebef0f469e62e08f394084bfa08ebffb 13+2
+fe567d56155a1b2e339b92a53511ac9353709e59 13+3
--- a/build.gradle	Wed Mar 13 09:30:47 2019 +0530
+++ b/build.gradle	Fri Mar 22 08:11:38 2019 -0700
@@ -1918,7 +1918,7 @@
     dependencies {
         stubCompile group: "junit", name: "junit", version: "4.8.2"
 
-        antlr group: "org.antlr", name: "antlr-complete", version: "3.5.2"
+        antlr group: "org.antlr", name: "antlr4", version: "4.7.2", classifier: "complete"
     }
 
     project.ext.moduleSourcePath = defaultModuleSourcePath_GraphicsOne
@@ -1969,14 +1969,14 @@
         executable = JAVA
         classpath = project.configurations.antlr
         workingDir = wd
-        main = "org.antlr.Tool"
+        main = "org.antlr.v4.Tool"
 
         args = [
-            "-Xconversiontimeout",
-            "30000",
             "-o",
             "$buildDir/gensrc/antlr",
-            "com/sun/scenario/effect/compiler/JSL.g" ]
+            "-package",
+            "com.sun.scenario.effect.compiler",
+            "com/sun/scenario/effect/compiler/JSL.g4" ]
 
         inputs.dir wd
         outputs.dir file("$buildDir/gensrc/antlr")
@@ -2297,7 +2297,7 @@
             libsDir.mkdirs();
 
             def allLibsPresent = true
-            def libNames = [ "antlr-complete-3.5.2.jar" ]
+            def libNames = [ "antlr4-4.7.2-complete.jar" ]
             libNames.each { name ->
                 File f = new File(libsDir, name)
                 if (!f.exists()) allLibsPresent = false
@@ -2308,7 +2308,7 @@
                 copy {
                     into libsDir
                     from f.getParentFile()
-                    include "**/antlr-complete-3.5.2.jar"
+                    include "**/antlr4-4.7.2-complete.jar"
                     includeEmptyDirs = false
                 }
             }
--- a/modules/javafx.graphics/src/jslc/antlr/com/sun/scenario/effect/compiler/JSL.g	Wed Mar 13 09:30:47 2019 +0530
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,664 +0,0 @@
-/*
- * Copyright (c) 2008, 2014, 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.
- */
-
-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/modules/javafx.graphics/src/jslc/antlr/com/sun/scenario/effect/compiler/JSL.g4	Fri Mar 22 08:11:38 2019 -0700
@@ -0,0 +1,615 @@
+/*
+ * Copyright (c) 2008, 2019, 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.
+ */
+
+grammar JSL;
+
+@header {
+    import com.sun.scenario.effect.compiler.model.*;
+    import com.sun.scenario.effect.compiler.tree.*;
+}
+
+@members {
+    private SymbolTable symbols = new SymbolTable();
+    private TreeMaker tm = new TreeMaker(symbols);
+
+    public SymbolTable getSymbolTable() {
+        return symbols;
+    }
+}
+
+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.ctx != 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.ctx != 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.ctx != 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.ctx != 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.ctx != null) $expr = $e.expr; }
+        | SEMICOLON e=expression? { if ($e.ctx != 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)); }
+        ;
+
+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';
+
+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
+    :   '/*' (.)*? '*/' -> channel(HIDDEN)
+    ;
+
+LINE_COMMENT
+    : '//' ~('\n'|'\r')* '\r'? '\n' -> channel(HIDDEN)
+    ;
+
+GLUE_BLOCK
+    : LEFT_FRENCH .* RIGHT_FRENCH
+    ;
--- a/modules/javafx.graphics/src/jslc/java/com/sun/scenario/effect/compiler/JSLC.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/jslc/java/com/sun/scenario/effect/compiler/JSLC.java	Fri Mar 22 08:11:38 2019 -0700
@@ -32,10 +32,11 @@
 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;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.STGroupDir;
 
 import java.io.*;
 import java.util.ArrayList;
@@ -67,10 +68,11 @@
     public static final int OUT_ALL        = OUT_SW_PEERS | OUT_HW_PEERS | OUT_HW_SHADERS;
 
     private static final String rootPkg = "com/sun/scenario/effect";
+    public static final STGroup group;
 
     static {
-        CommonGroupLoader loader = new CommonGroupLoader(rootPkg + "/compiler/backend", null);
-        StringTemplateGroup.registerGroupLoader(loader);
+        group = new STGroupDir(rootPkg + "/compiler/backend", null);
+        group.load();
     }
 
     public static class OutInfo {
@@ -95,7 +97,7 @@
 
     public static ParserInfo getParserInfo(InputStream stream) throws Exception {
         JSLParser parser = parse(stream);
-        ProgramUnit program = parser.translation_unit();
+        ProgramUnit program = parser.translation_unit().prog;
         return new ParserInfo(parser, program);
     }
 
@@ -156,14 +158,19 @@
         throws Exception
     {
         // Read input
-        ANTLRInputStream input = new ANTLRInputStream(stream);
+        CharStream input = CharStreams.fromStream(stream);
 
         // Lexer
         JSLLexer lexer = new JSLLexer(input);
+        lexer.removeErrorListeners();
+        lexer.addErrorListener(ThrowingErrorListener.INSTANCE);
         CommonTokenStream tokens = new CommonTokenStream(lexer);
 
         // Parser and AST construction
-        return new JSLParser(tokens);
+        JSLParser parser = new JSLParser(tokens);
+        parser.removeErrorListeners();
+        parser.addErrorListener(ThrowingErrorListener.INSTANCE);
+        return parser;
     }
 
     private static ParserInfo compile(JSLCInfo jslcinfo,
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/javafx.graphics/src/jslc/java/com/sun/scenario/effect/compiler/ThrowingErrorListener.java	Fri Mar 22 08:11:38 2019 -0700
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2019, 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 org.antlr.v4.runtime.BaseErrorListener;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+
+public class ThrowingErrorListener extends BaseErrorListener {
+
+    public static final ThrowingErrorListener INSTANCE = new ThrowingErrorListener();
+
+    @Override
+    public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e)
+            throws ParseCancellationException {
+        // We cannot throw a RecognitionException here because it would be swallowed by DefaultErrorStrategy.
+        throw new ParseCancellationException("line " + line + ":" + charPositionInLine + " " + msg);
+    }
+}
--- a/modules/javafx.graphics/src/jslc/java/com/sun/scenario/effect/compiler/backend/prism/PrismBackend.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/jslc/java/com/sun/scenario/effect/compiler/backend/prism/PrismBackend.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -37,9 +37,11 @@
 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;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.STGroupFile;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
 
 /**
  */
@@ -54,9 +56,8 @@
         scan(program);
     }
 
-    private StringTemplate getTemplate(String type) {
-        Reader template = new InputStreamReader(getClass().getResourceAsStream(type + "Glue.stg"));
-        StringTemplateGroup group = new StringTemplateGroup(template, DefaultTemplateLexer.class);
+    private ST getTemplate(String type) {
+        STGroup group = new STGroupFile(getClass().getResource(type + "Glue.stg"), UTF_8.displayName(), '$', '$');
         return group.getInstanceOf("glue");
     }
 
@@ -126,19 +127,19 @@
             interfaceDecl.append("implements "+interfaceName);
         }
 
-        StringTemplate glue = getTemplate("Prism");
-        glue.setAttribute("effectName", effectName);
-        glue.setAttribute("peerName", peerName);
-        glue.setAttribute("superClass", superClass);
-        glue.setAttribute("genericsDecl", genericsDecl.toString());
-        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();
+        ST glue = getTemplate("Prism");
+        glue.add("effectName", effectName);
+        glue.add("peerName", peerName);
+        glue.add("superClass", superClass);
+        glue.add("genericsDecl", genericsDecl.toString());
+        glue.add("interfaceDecl", interfaceDecl.toString());
+        glue.add("usercode", usercode.toString());
+        glue.add("samplerLinear", samplerLinear.toString());
+        glue.add("samplerInit", samplerInit.toString());
+        glue.add("paramInit", paramInit.toString());
+        glue.add("paramUpdate", paramUpdate.toString());
+        glue.add("isPixcoordUsed", isPixcoordReferenced);
+        return glue.render();
     }
 
     @Override
--- a/modules/javafx.graphics/src/jslc/java/com/sun/scenario/effect/compiler/backend/sw/java/JSWBackend.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/jslc/java/com/sun/scenario/effect/compiler/backend/sw/java/JSWBackend.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -39,9 +39,11 @@
 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;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.STGroupFile;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
 
 /**
  */
@@ -219,27 +221,26 @@
             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("genericsDecl", genericsDecl.toString());
-        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();
+        STGroup group = new STGroupFile(getClass().getResource("JSWGlue.stg"), UTF_8.displayName(), '$', '$');
+        ST glue = group.getInstanceOf("glue");
+        glue.add("effectName", effectName);
+        glue.add("peerName", peerName);
+        glue.add("genericsDecl", genericsDecl.toString());
+        glue.add("interfaceDecl", interfaceDecl.toString());
+        glue.add("usercode", usercode.toString());
+        glue.add("samplers", samplers.toString());
+        glue.add("cleanup", cleanup.toString());
+        glue.add("srcRects", srcRects.toString());
+        glue.add("constants", constants.toString());
+        glue.add("posDecls", posDecls.toString());
+        glue.add("pixInitY", pixInitY.toString());
+        glue.add("pixInitX", pixInitX.toString());
+        glue.add("posIncrY", posIncrY.toString());
+        glue.add("posInitY", posInitY.toString());
+        glue.add("posIncrX", posIncrX.toString());
+        glue.add("posInitX", posInitX.toString());
+        glue.add("body", body);
+        return glue.render();
     }
 
     // TODO: need better mechanism for querying fields
--- a/modules/javafx.graphics/src/jslc/java/com/sun/scenario/effect/compiler/backend/sw/me/MEBackend.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/jslc/java/com/sun/scenario/effect/compiler/backend/sw/me/MEBackend.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -39,9 +39,11 @@
 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;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.STGroupFile;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
 
 /**
  */
@@ -274,40 +276,38 @@
             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("genericsDecl", genericsDecl.toString());
-        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());
+        STGroup group = new STGroupFile(getClass().getResource("MEJavaGlue.stg"), UTF_8.displayName(), '$', '$');
+        ST jglue = group.getInstanceOf("glue");
+        jglue.add("effectName", effectName);
+        jglue.add("peerName", peerName);
+        jglue.add("genericsDecl", genericsDecl.toString());
+        jglue.add("interfaceDecl", interfaceDecl.toString());
+        jglue.add("usercode", usercode.toString());
+        jglue.add("samplers", samplers.toString());
+        jglue.add("srcRects", srcRects.toString());
+        jglue.add("constants", constants.toString());
+        jglue.add("params", jparams.toString());
+        jglue.add("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);
+        group = new STGroupFile(getClass().getResource("MENativeGlue.stg"), UTF_8.displayName(), '$', '$');
+        ST cglue = group.getInstanceOf("glue");
+        cglue.add("peerName", peerName);
+        cglue.add("jniName", peerName.replace("_", "_1"));
+        cglue.add("paramDecls", cparamDecls.toString());
+        cglue.add("arrayGet", arrayGet.toString());
+        cglue.add("arrayRelease", arrayRelease.toString());
+        cglue.add("posDecls", posDecls.toString());
+        cglue.add("pixInitY", pixInitY.toString());
+        cglue.add("pixInitX", pixInitX.toString());
+        cglue.add("posIncrY", posIncrY.toString());
+        cglue.add("posInitY", posInitY.toString());
+        cglue.add("posIncrX", posIncrX.toString());
+        cglue.add("posInitX", posInitX.toString());
+        cglue.add("body", body);
 
         GenCode gen = new GenCode();
-        gen.javaCode = jglue.toString();
-        gen.nativeCode = cglue.toString();
+        gen.javaCode = jglue.render();
+        gen.nativeCode = cglue.render();
         return gen;
     }
 
--- a/modules/javafx.graphics/src/jslc/java/com/sun/scenario/effect/compiler/backend/sw/sse/SSEBackend.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/jslc/java/com/sun/scenario/effect/compiler/backend/sw/sse/SSEBackend.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -43,9 +43,11 @@
 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;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.STGroupFile;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
 
 /**
  */
@@ -315,41 +317,39 @@
             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("genericsDecl", genericsDecl.toString());
-        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());
+        STGroup group = new STGroupFile(getClass().getResource("SSEJavaGlue.stg"), UTF_8.displayName(), '$', '$');
+        ST jglue = group.getInstanceOf("glue");
+        jglue.add("effectName", effectName);
+        jglue.add("peerName", peerName);
+        jglue.add("genericsDecl", genericsDecl.toString());
+        jglue.add("interfaceDecl", interfaceDecl.toString());
+        jglue.add("usercode", usercode.toString());
+        jglue.add("samplers", samplers.toString());
+        jglue.add("cleanup", cleanup.toString());
+        jglue.add("srcRects", srcRects.toString());
+        jglue.add("constants", constants.toString());
+        jglue.add("params", jparams.toString());
+        jglue.add("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);
+        group = new STGroupFile(getClass().getResource("SSENativeGlue.stg"), UTF_8.displayName(), '$', '$');
+        ST cglue = group.getInstanceOf("glue");
+        cglue.add("peerName", peerName);
+        cglue.add("jniName", peerName.replace("_", "_1"));
+        cglue.add("paramDecls", cparamDecls.toString());
+        cglue.add("arrayGet", arrayGet.toString());
+        cglue.add("arrayRelease", arrayRelease.toString());
+        cglue.add("posDecls", posDecls.toString());
+        cglue.add("pixInitY", pixInitY.toString());
+        cglue.add("pixInitX", pixInitX.toString());
+        cglue.add("posIncrY", posIncrY.toString());
+        cglue.add("posInitY", posInitY.toString());
+        cglue.add("posIncrX", posIncrX.toString());
+        cglue.add("posInitX", posInitX.toString());
+        cglue.add("body", body);
 
         GenCode gen = new GenCode();
-        gen.javaCode = jglue.toString();
-        gen.nativeCode = cglue.toString();
+        gen.javaCode = jglue.render();
+        gen.nativeCode = cglue.render();
         return gen;
     }
 
--- a/modules/javafx.graphics/src/main/java/com/sun/javafx/text/ScriptMapper.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/main/java/com/sun/javafx/text/ScriptMapper.java	Fri Mar 22 08:11:38 2019 -0700
@@ -145,7 +145,7 @@
         else if (code < 0x1100) {
             return false;
         }
-        else if (code < 0x11ff) { // U+1100 - U+11FF Old Hangul
+        else if (code <= 0x11ff) { // U+1100 - U+11FF Old Hangul
             return true;
         }
         else if (code < 0x1780) {
--- a/modules/javafx.graphics/src/main/java/com/sun/prism/sw/SWGraphics.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/main/java/com/sun/prism/sw/SWGraphics.java	Fri Mar 22 08:11:38 2019 -0700
@@ -62,6 +62,7 @@
 import com.sun.prism.paint.Color;
 import com.sun.prism.paint.ImagePattern;
 import com.sun.prism.paint.Paint;
+import com.sun.javafx.font.CharToGlyphMapper;
 
 final class SWGraphics implements ReadbackGraphics {
 
@@ -632,8 +633,10 @@
     private void drawGlyph(FontStrike strike, GlyphList gl, int idx, BaseTransform glyphTx,
                            boolean drawAsMasks, float x, float y)
     {
-
         final Glyph g = strike.getGlyph(gl.getGlyphCode(idx));
+        if (g.getGlyphCode() == CharToGlyphMapper.INVISIBLE_GLYPH_ID) {
+            return;
+        }
         if (drawAsMasks) {
             final Point2D pt = new Point2D((float)(x + tx.getMxt() + gl.getPosX(idx)),
                                            (float)(y + tx.getMyt() + gl.getPosY(idx)));
--- a/modules/javafx.graphics/src/main/jsl-prism/CompileJSL.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/main/jsl-prism/CompileJSL.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2019, 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
@@ -40,9 +40,11 @@
 import java.io.InputStreamReader;
 import java.io.Reader;
 import java.util.Map;
-import org.antlr.stringtemplate.StringTemplate;
-import org.antlr.stringtemplate.StringTemplateGroup;
-import org.antlr.stringtemplate.language.DefaultTemplateLexer;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.STGroupFile;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
 
 /**
  * This class is only used at build time to generate EffectPeer
@@ -514,9 +516,8 @@
         scan(program);
     }
 
-    private StringTemplate getTemplate(String type) {
-        Reader template = new InputStreamReader(getClass().getResourceAsStream(type + "Glue.stg"));
-        StringTemplateGroup group = new StringTemplateGroup(template, DefaultTemplateLexer.class);
+    private ST getTemplate(String type) {
+        STGroup group = new STGroupFile(getClass().getResource(type + "Glue.stg"), UTF_8.displayName(), '$', '$');
         return group.getInstanceOf("glue");
     }
 
@@ -536,13 +537,13 @@
             }
         }
 
-        StringTemplate glue = getTemplate("PrismLoader");
-        glue.setAttribute("shaderName", shaderName);
-        glue.setAttribute("samplerInit", samplerInit.toString());
-        glue.setAttribute("paramInit", paramInit.toString());
-        glue.setAttribute("maxTexCoordIndex", maxTexCoordIndex);
-        glue.setAttribute("isPixcoordUsed", isPixcoordReferenced);
-        return glue.toString();
+        ST glue = getTemplate("PrismLoader");
+        glue.add("shaderName", shaderName);
+        glue.add("samplerInit", samplerInit.toString());
+        glue.add("paramInit", paramInit.toString());
+        glue.add("maxTexCoordIndex", maxTexCoordIndex);
+        glue.add("isPixcoordUsed", isPixcoordReferenced);
+        return glue.render();
     }
 
     @Override
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/BoolTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/BoolTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -26,7 +26,6 @@
 package com.sun.scenario.effect.compiler.lexer;
 
 import com.sun.scenario.effect.compiler.JSLLexer;
-import org.antlr.runtime.RecognitionException;
 import org.junit.Test;
 
 public class BoolTest extends LexerBase {
@@ -41,14 +40,8 @@
         assertRecognized("false");
     }
 
-    @Test(expected = RecognitionException.class)
     public void notABool() throws Exception {
-        assertRecognized("629");
-    }
-
-    @Override
-    protected void fireLexerRule(JSLLexer lexer) throws Exception {
-        lexer.mBOOLCONSTANT();
+        assertNotRecognized("629");
     }
 
     @Override
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/CommentTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/CommentTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -26,7 +26,6 @@
 package com.sun.scenario.effect.compiler.lexer;
 
 import com.sun.scenario.effect.compiler.JSLLexer;
-import org.antlr.runtime.RecognitionException;
 import org.junit.Test;
 
 public class CommentTest extends LexerBase {
@@ -41,14 +40,9 @@
         assertRecognized("/* ignored \n * line 2 */");
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test
     public void notAComment() throws Exception {
-        assertRecognized("ignored");
-    }
-
-    @Override
-    protected void fireLexerRule(JSLLexer lexer) throws Exception {
-        lexer.mCOMMENT();
+        assertNotRecognized("ignored");
     }
 
     @Override
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/FloatTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/FloatTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -26,7 +26,6 @@
 package com.sun.scenario.effect.compiler.lexer;
 
 import com.sun.scenario.effect.compiler.JSLLexer;
-import org.antlr.runtime.RecognitionException;
 import org.junit.Test;
 
 public class FloatTest extends LexerBase {
@@ -43,14 +42,9 @@
         assertRecognized(".1234567890");
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test
     public void badDigits() throws Exception {
-        assertRecognized("0110");
-    }
-
-    @Override
-    protected void fireLexerRule(JSLLexer lexer) throws Exception {
-        lexer.mFLOATCONSTANT();
+        assertNotRecognized("0110", "0");
     }
 
     @Override
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/IdentifierTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/IdentifierTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -26,7 +26,7 @@
 package com.sun.scenario.effect.compiler.lexer;
 
 import com.sun.scenario.effect.compiler.JSLLexer;
-import org.antlr.runtime.RecognitionException;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
 import org.junit.Test;
 
 public class IdentifierTest extends LexerBase {
@@ -51,19 +51,14 @@
         assertRecognized("$aA___29");
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test
     public void notAnId1() throws Exception {
-        assertRecognized("6foo");
+        assertNotRecognized("6foo", "6");
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test(expected = ParseCancellationException.class)
     public void notAnId2() throws Exception {
-        assertRecognized("%###");
-    }
-
-    @Override
-    protected void fireLexerRule(JSLLexer lexer) throws Exception {
-        lexer.mIDENTIFIER();
+        assertRecognized("###");
     }
 
     @Override
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/IntegerTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/IntegerTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -26,7 +26,6 @@
 package com.sun.scenario.effect.compiler.lexer;
 
 import com.sun.scenario.effect.compiler.JSLLexer;
-import org.antlr.runtime.RecognitionException;
 import org.junit.Test;
 
 public class IntegerTest extends LexerBase {
@@ -38,14 +37,9 @@
         }
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test
     public void badDigits() throws Exception {
-        assertRecognized("H128376");
-    }
-
-    @Override
-    protected void fireLexerRule(JSLLexer lexer) throws Exception {
-        lexer.mINTCONSTANT();
+        recognize("H128376");
     }
 
     @Override
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/LexerBase.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/LexerBase.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -26,35 +26,26 @@
 package com.sun.scenario.effect.compiler.lexer;
 
 import com.sun.scenario.effect.compiler.JSLLexer;
-import org.antlr.runtime.ANTLRStringStream;
-import org.antlr.runtime.Token;
+import com.sun.scenario.effect.compiler.JSLParser;
+import com.sun.scenario.effect.compiler.ThrowingErrorListener;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.Token;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 
 import static org.junit.Assert.*;
 
 public abstract class LexerBase {
 
-    protected void assertRangeOfCharactersRecognized(char low, char high)
-        throws Exception {
-
-        for (char ch = low; ch <= high; ++ch) {
-            assertRecognized(ch);
-        }
-    }
-
-    protected void recognizeRange(char low, char high) throws Exception {
-        for (char ch = low; ch <= high; ++ch) {
-            recognize(ch);
-        }
-    }
-
     protected void assertRecognized(char ch) throws Exception {
         assertRecognized(String.valueOf(ch));
     }
 
-    protected Token recognize(char ch) throws Exception {
-        return recognize(String.valueOf(ch));
-    }
-
     protected void assertRecognized(String text) throws Exception {
         Token token = recognize(text);
         assertEquals(text, token.getText());
@@ -64,21 +55,37 @@
         }
     }
 
+    protected void assertNotRecognized(char ch) throws Exception {
+        assertNotRecognized(String.valueOf(ch));
+    }
+
+    protected void assertNotRecognized(String text) throws Exception {
+        assertNotRecognized(text, text);
+    }
+
+    protected void assertNotRecognized(String text, String shouldLex) throws Exception {
+        Token token = recognize(text);
+        assertEquals(shouldLex, token.getText());
+
+        if (expectedTokenType() != Integer.MIN_VALUE) {
+            assertFalse(expectedTokenType() == token.getType());
+        }
+    }
+
     protected Token recognize(String text) throws Exception {
         JSLLexer lexer = lexerOver(text);
-        fireLexerRule(lexer);
-        lexer = lexerOver(text);
         return lexer.nextToken();
     }
 
-    private JSLLexer lexerOver(String text) {
-        JSLLexer lexer = new JSLLexer();
-        lexer.setCharStream(new ANTLRStringStream(text));
+    private JSLLexer lexerOver(String text) throws IOException {
+        InputStream stream = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8));
+        CharStream charStream = CharStreams.fromStream(stream, StandardCharsets.UTF_8);
+        JSLLexer lexer = new JSLLexer(charStream);
+        lexer.removeErrorListeners();
+        lexer.addErrorListener(ThrowingErrorListener.INSTANCE);
         return lexer;
     }
 
-    protected abstract void fireLexerRule(JSLLexer lexer) throws Exception;
-
     protected int expectedTokenType() {
         return Integer.MIN_VALUE;
     }
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/LineCommentTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/LineCommentTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -26,7 +26,6 @@
 package com.sun.scenario.effect.compiler.lexer;
 
 import com.sun.scenario.effect.compiler.JSLLexer;
-import org.antlr.runtime.RecognitionException;
 import org.junit.Test;
 
 public class LineCommentTest extends LexerBase {
@@ -36,14 +35,9 @@
         assertRecognized("// ignored\n");
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test
     public void notAComment() throws Exception {
-        assertRecognized("ignored");
-    }
-
-    @Override
-    protected void fireLexerRule(JSLLexer lexer) throws Exception {
-        lexer.mLINE_COMMENT();
+        assertNotRecognized("ignored");
     }
 
     @Override
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/TypeTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/TypeTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -26,7 +26,6 @@
 package com.sun.scenario.effect.compiler.lexer;
 
 import com.sun.scenario.effect.compiler.JSLLexer;
-import org.antlr.runtime.RecognitionException;
 import org.junit.Test;
 
 public class TypeTest extends LexerBase {
@@ -96,14 +95,9 @@
         assertRecognized("sampler");
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test
     public void notAType() throws Exception {
-        assertRecognized("double");
-    }
-
-    @Override
-    protected void fireLexerRule(JSLLexer lexer) throws Exception {
-        lexer.mTYPE();
+        assertNotRecognized("double");
     }
 
     @Override
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/WhitespaceTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/lexer/WhitespaceTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -26,7 +26,6 @@
 package com.sun.scenario.effect.compiler.lexer;
 
 import com.sun.scenario.effect.compiler.JSLLexer;
-import org.antlr.runtime.RecognitionException;
 import org.junit.Test;
 
 public class WhitespaceTest extends LexerBase {
@@ -51,14 +50,9 @@
         assertRecognized('\r');
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test
     public void nonSpace() throws Exception {
-        recognize('4');
-    }
-
-    @Override
-    protected void fireLexerRule(JSLLexer lexer) throws Exception {
-        lexer.mWS();
+        assertNotRecognized('4');
     }
 
     @Override
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/AddExprTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/AddExprTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -28,7 +28,7 @@
 import com.sun.scenario.effect.compiler.JSLParser;
 import com.sun.scenario.effect.compiler.model.BinaryOpType;
 import com.sun.scenario.effect.compiler.tree.BinaryExpr;
-import org.antlr.runtime.RecognitionException;
+import com.sun.scenario.effect.compiler.tree.JSLCVisitor;
 import org.junit.Before;
 import org.junit.Test;
 import static org.junit.Assert.assertEquals;
@@ -47,19 +47,19 @@
     @Test
     public void oneAddition() throws Exception {
         BinaryExpr tree = parseTreeFor(mult + " + " + mult);
-        assertEquals(tree.getOp(), BinaryOpType.ADD);
+        assertEquals(BinaryOpType.ADD, tree.getOp());
     }
 
     @Test
     public void oneSubtraction() throws Exception {
         BinaryExpr tree = parseTreeFor(mult + "   - " + mult);
-        assertEquals(tree.getOp(), BinaryOpType.SUB);
+        assertEquals(BinaryOpType.SUB, tree.getOp());
     }
 
     @Test
     public void additiveCombination() throws Exception {
         BinaryExpr tree = parseTreeFor(mult + " + " + mult + '-' + mult + '-' + mult + "   +" + mult);
-        assertEquals(tree.getOp(), BinaryOpType.ADD);
+        assertEquals(BinaryOpType.ADD, tree.getOp());
     }
 
     @Test(expected = ClassCastException.class)
@@ -67,9 +67,10 @@
         parseTreeFor(mult + "!" + mult);
     }
 
-    private BinaryExpr parseTreeFor(String text) throws RecognitionException {
+    private BinaryExpr parseTreeFor(String text) throws Exception {
         JSLParser parser = parserOver(text);
-        return (BinaryExpr)parser.additive_expression();
+        JSLCVisitor visitor = new JSLCVisitor();
+        return (BinaryExpr) visitor.visit(parser.additive_expression());
     }
 
     protected String additive() {
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/AssignmentExprTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/AssignmentExprTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -26,18 +26,34 @@
 package com.sun.scenario.effect.compiler.parser;
 
 import com.sun.scenario.effect.compiler.JSLParser;
-import com.sun.scenario.effect.compiler.model.Qualifier;
 import com.sun.scenario.effect.compiler.model.SymbolTable;
 import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.model.Variable;
 import com.sun.scenario.effect.compiler.tree.BinaryExpr;
-import org.antlr.runtime.RecognitionException;
+import com.sun.scenario.effect.compiler.tree.LiteralExpr;
+import com.sun.scenario.effect.compiler.tree.VariableExpr;
+import com.sun.scenario.effect.compiler.tree.VectorCtorExpr;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
 import org.junit.Test;
 
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
 public class AssignmentExprTest extends ParserBase {
 
     @Test
     public void userVar() throws Exception {
         BinaryExpr tree = parseTreeFor("foo = 32.0");
+        assertEquals(Type.FLOAT, tree.getResultType());
+        assertEquals(BinaryOpType.EQ, tree.getOp());
+        assertEquals(VariableExpr.class, tree.getLeft().getClass());
+        Variable var = ((VariableExpr) tree.getLeft()).getVariable();
+        assertEquals("foo", var.getName());
+        assertEquals(Type.FLOAT, tree.getRight().getResultType());
+        assertEquals(LiteralExpr.class, tree.getRight().getClass());
+        Object val = ((LiteralExpr) tree.getRight()).getValue();
+        assertEquals(32.0f, val);
     }
 
     @Test(expected = RuntimeException.class)
@@ -48,29 +64,56 @@
     @Test
     public void coreVar() throws Exception {
         BinaryExpr tree = parseTreeFor("color = float4(1.0)");
+        assertEquals(Type.FLOAT4, tree.getResultType());
+        assertEquals(BinaryOpType.EQ, tree.getOp());
+        assertEquals(VariableExpr.class, tree.getLeft().getClass());
+        Variable var = ((VariableExpr) tree.getLeft()).getVariable();
+        assertEquals("color", var.getName());
+        assertEquals(Type.FLOAT4, tree.getRight().getResultType());
+        assertEquals(VectorCtorExpr.class, tree.getRight().getClass());
+        List<Expr> params = ((VectorCtorExpr) tree.getRight()).getParams();
+
+        assertEquals(4, params.size());
+
+        for (int i = 0; i < 4; i++) {
+            Object val = ((LiteralExpr) params.get(i)).getValue();
+            assertEquals(Type.FLOAT, params.get(i).getResultType());
+            assertEquals(1.0f, val);
+        }
     }
 
     @Test
     public void coreVarField() throws Exception {
         BinaryExpr tree = parseTreeFor("color.r = 3.0");
+        assertEquals(Type.FLOAT, tree.getResultType());
+        assertEquals(BinaryOpType.EQ, tree.getOp());
+        assertEquals(FieldSelectExpr.class, tree.getLeft().getClass());
+        FieldSelectExpr fsExpr = (FieldSelectExpr) tree.getLeft();
+        VariableExpr expr = (VariableExpr) fsExpr.getExpr();
+        assertEquals(Type.FLOAT4, expr.getResultType());
+        assertEquals("r", fsExpr.getFields());
+        assertEquals("color", expr.getVariable().getName());
+        assertEquals(LiteralExpr.class, tree.getRight().getClass());
+        Object val = ((LiteralExpr) tree.getRight()).getValue();
+        assertEquals(3.0f, val);
     }
 
     @Test(expected = RuntimeException.class)
     public void coreROVar() throws Exception {
-        BinaryExpr tree = parseTreeFor("pos0 = float2(1.0)");
+        parseTreeFor("pos0 = float2(1.0)");
     }
 
     @Test(expected = RuntimeException.class)
     public void coreROVarField() throws Exception {
-        BinaryExpr tree = parseTreeFor("pos0.x = 1.0");
+        parseTreeFor("pos0.x = 1.0");
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test(expected = ParseCancellationException.class)
     public void notAnAssignment() throws Exception {
         parseTreeFor("const foo");
     }
 
-    private BinaryExpr parseTreeFor(String text) throws RecognitionException {
+    private BinaryExpr parseTreeFor(String text) throws Exception {
         JSLParser parser = parserOver(text);
         SymbolTable st = parser.getSymbolTable();
         st.declareVariable("foo", Type.FLOAT, null);
@@ -79,6 +122,6 @@
         // scope so that we can test core variables such as color and pos0
         st.enterFrame();
         st.declareFunction("main", Type.VOID, null);
-        return (BinaryExpr)parser.assignment_expression();
+        return (BinaryExpr) parser.assignment_expression();
     }
 }
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/EqualityExprTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/EqualityExprTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -28,8 +28,11 @@
 import com.sun.scenario.effect.compiler.JSLParser;
 import com.sun.scenario.effect.compiler.model.BinaryOpType;
 import com.sun.scenario.effect.compiler.model.Type;
+import com.sun.scenario.effect.compiler.model.Variable;
 import com.sun.scenario.effect.compiler.tree.BinaryExpr;
-import org.antlr.runtime.RecognitionException;
+import com.sun.scenario.effect.compiler.tree.LiteralExpr;
+import com.sun.scenario.effect.compiler.tree.VariableExpr;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
 import org.junit.Test;
 
 import static org.junit.Assert.*;
@@ -40,22 +43,38 @@
     public void oneEq() throws Exception {
         BinaryExpr tree = parseTreeFor("foo == 3");
         assertEquals(tree.getOp(), BinaryOpType.EQEQ);
+        assertEquals(Type.INT, tree.getLeft().getResultType());
+        assertEquals(VariableExpr.class, tree.getLeft().getClass());
+        Variable var = ((VariableExpr) tree.getLeft()).getVariable();
+        assertEquals("foo", var.getName());
+        assertEquals(Type.INT, var.getType());
+        assertEquals(LiteralExpr.class, tree.getRight().getClass());
+        Object val = ((LiteralExpr) tree.getRight()).getValue();
+        assertEquals(3, val);
     }
 
     @Test
     public void oneNotEq() throws Exception {
         BinaryExpr tree = parseTreeFor("foo != 3");
         assertEquals(tree.getOp(), BinaryOpType.NEQ);
+        assertEquals(Type.INT, tree.getLeft().getResultType());
+        assertEquals(VariableExpr.class, tree.getLeft().getClass());
+        Variable var = ((VariableExpr) tree.getLeft()).getVariable();
+        assertEquals("foo", var.getName());
+        assertEquals(Type.INT, var.getType());
+        assertEquals(LiteralExpr.class, tree.getRight().getClass());
+        Object val = ((LiteralExpr) tree.getRight()).getValue();
+        assertEquals(3, val);
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test(expected = ParseCancellationException.class)
     public void notAnEqualityExpression() throws Exception {
         parseTreeFor("foo @ 3");
     }
 
-    private BinaryExpr parseTreeFor(String text) throws RecognitionException {
+    private BinaryExpr parseTreeFor(String text) throws Exception {
         JSLParser parser = parserOver(text);
         parser.getSymbolTable().declareVariable("foo", Type.INT, null);
-        return (BinaryExpr)parser.equality_expression();
+        return (BinaryExpr) parser.equality_expression();
     }
 }
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/ExternalDeclarationTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/ExternalDeclarationTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -35,7 +35,7 @@
 import com.sun.scenario.effect.compiler.tree.ExtDecl;
 import com.sun.scenario.effect.compiler.tree.FuncDef;
 import com.sun.scenario.effect.compiler.tree.VarDecl;
-import org.antlr.runtime.RecognitionException;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
 import org.junit.Test;
 
 import static org.junit.Assert.*;
@@ -125,12 +125,12 @@
         assertNotNull(d.getStmt());
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test(expected = ParseCancellationException.class)
     public void notAnExtDecl() throws Exception {
         parseTreeFor("foo = 4");
     }
 
-    private List<ExtDecl> parseTreeFor(String text) throws RecognitionException {
+    private List<ExtDecl> parseTreeFor(String text) throws Exception {
         JSLParser parser = parserOver(text);
         return parser.external_declaration();
     }
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/FieldSelectTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/FieldSelectTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -28,7 +28,7 @@
 import com.sun.scenario.effect.compiler.JSLParser;
 import junit.framework.Assert;
 import junit.framework.AssertionFailedError;
-import org.antlr.runtime.RecognitionException;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
 import org.junit.Test;
 
 import static org.junit.Assert.*;
@@ -107,7 +107,7 @@
         assertEquals(tree, ".wzyx");
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test(expected = ParseCancellationException.class)
     public void notAFieldSelection1() throws Exception {
         parseTreeFor("qpz");
     }
@@ -127,11 +127,11 @@
         parseTreeFor(".xyba", true);
     }
 
-    private String parseTreeFor(String text) throws RecognitionException {
+    private String parseTreeFor(String text) throws Exception {
         return parseTreeFor(text, false);
     }
 
-    private String parseTreeFor(String text, boolean expectEx) throws RecognitionException {
+    private String parseTreeFor(String text, boolean expectEx) throws Exception {
         JSLParser parser = parserOver(text);
         String ret = parser.field_selection();
         // TODO: there's probably a better way to check for trailing (invalid) characters
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/FullySpecifiedTypeTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/FullySpecifiedTypeTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -29,7 +29,7 @@
 import com.sun.scenario.effect.compiler.JSLParser.fully_specified_type_return;
 import com.sun.scenario.effect.compiler.model.Qualifier;
 import com.sun.scenario.effect.compiler.model.Type;
-import org.antlr.runtime.RecognitionException;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
 import org.junit.Test;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
@@ -50,12 +50,12 @@
         assertEquals(ret.type, Type.BOOL3);
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test(expected = ParseCancellationException.class)
     public void notAFullySpecifiedType() throws Exception {
         parseTreeFor("double");
     }
 
-    private fully_specified_type_return parseTreeFor(String text) throws RecognitionException {
+    private fully_specified_type_return parseTreeFor(String text) throws Exception {
         JSLParser parser = parserOver(text);
         return parser.fully_specified_type();
     }
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/IterationStatementTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/IterationStatementTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -33,7 +33,7 @@
 import com.sun.scenario.effect.compiler.tree.ForStmt;
 import com.sun.scenario.effect.compiler.tree.Stmt;
 import com.sun.scenario.effect.compiler.tree.WhileStmt;
-import org.antlr.runtime.RecognitionException;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
 import org.junit.Test;
 
 import static org.junit.Assert.*;
@@ -102,12 +102,12 @@
         assertTrue(s.getStmt() instanceof ExprStmt);
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test(expected = ParseCancellationException.class)
     public void notAnIterationStmt() throws Exception {
         parseTreeFor("return;");
     }
 
-    private Stmt parseTreeFor(String text) throws RecognitionException {
+    private Stmt parseTreeFor(String text) throws Exception {
         JSLParser parser = parserOver(text);
         parser.getSymbolTable().declareVariable("i", Type.INT, null);
         parser.getSymbolTable().declareVariable("j", Type.INT, null);
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/JumpStatementTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/JumpStatementTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -32,7 +32,7 @@
 import com.sun.scenario.effect.compiler.tree.LiteralExpr;
 import com.sun.scenario.effect.compiler.tree.ReturnStmt;
 import com.sun.scenario.effect.compiler.tree.Stmt;
-import org.antlr.runtime.RecognitionException;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
 import org.junit.Test;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
@@ -75,12 +75,12 @@
         assertEquals(lit.getValue(), new Integer(3));
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test(expected = ParseCancellationException.class)
     public void notAJump() throws Exception {
         parseTreeFor("float;");
     }
 
-    private Stmt parseTreeFor(String text) throws RecognitionException {
+    private Stmt parseTreeFor(String text) throws Exception {
         JSLParser parser = parserOver(text);
         return parser.jump_statement();
     }
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/MultExprTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/MultExprTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -67,7 +67,7 @@
         parseTreeFor("3 + 3");
     }
 
-    private BinaryExpr parseTreeFor(String text) throws RecognitionException {
+    private BinaryExpr parseTreeFor(String text) throws Exception {
         JSLParser parser = parserOver(text);
         return (BinaryExpr)parser.multiplicative_expression();
     }
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/ParserBase.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/ParserBase.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -27,16 +27,28 @@
 
 import com.sun.scenario.effect.compiler.JSLLexer;
 import com.sun.scenario.effect.compiler.JSLParser;
-import org.antlr.runtime.ANTLRStringStream;
-import org.antlr.runtime.CommonTokenStream;
-import org.antlr.runtime.TokenStream;
+import com.sun.scenario.effect.compiler.ThrowingErrorListener;
+import com.sun.scenario.effect.compiler.tree.JSLCVisitor;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.CommonTokenStream;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
 
 public abstract class ParserBase {
 
-    protected JSLParser parserOver(String text) {
-        JSLLexer.quiet = true; // suppress error messages generated by lexer
-        JSLLexer lexer = new JSLLexer(new ANTLRStringStream(text));
-        TokenStream tokenStream = new CommonTokenStream(lexer);
-        return new JSLParser(tokenStream);
+    protected JSLParser parserOver(String text) throws IOException {
+        InputStream stream = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8));
+        CharStream charStream = CharStreams.fromStream(stream, StandardCharsets.UTF_8);
+        JSLLexer lexer = new JSLLexer(charStream);
+        lexer.removeErrorListeners();
+        lexer.addErrorListener(ThrowingErrorListener.INSTANCE);
+        CommonTokenStream tokenStream = new CommonTokenStream(lexer);
+        JSLParser parser = new JSLParser(tokenStream);
+        parser.removeErrorListeners();
+        parser.addErrorListener(ThrowingErrorListener.INSTANCE);
+        return parser;
     }
 }
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/PrimaryExprTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/PrimaryExprTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -30,10 +30,10 @@
 import com.sun.scenario.effect.compiler.tree.Expr;
 import com.sun.scenario.effect.compiler.tree.LiteralExpr;
 import com.sun.scenario.effect.compiler.tree.VariableExpr;
-import static com.sun.scenario.effect.compiler.parser.Expressions.SIMPLE_EXPRESSION;
-import org.antlr.runtime.RecognitionException;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
 import org.junit.Before;
 import org.junit.Test;
+import static com.sun.scenario.effect.compiler.parser.Expressions.SIMPLE_EXPRESSION;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
@@ -86,12 +86,12 @@
         Expr tree = parseTreeFor("(" + primary + ")");
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test(expected = ParseCancellationException.class)
     public void notAPrimaryExpression() throws Exception {
         parseTreeFor("!(@&#");
     }
 
-    private Expr parseTreeFor(String text) throws RecognitionException {
+    private Expr parseTreeFor(String text) throws Exception {
         JSLParser parser = parserOver(text);
         parser.getSymbolTable().declareVariable("foo", Type.INT, null);
         return parser.primary_expression();
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/RelationalExprTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/RelationalExprTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -29,7 +29,7 @@
 import com.sun.scenario.effect.compiler.model.BinaryOpType;
 import com.sun.scenario.effect.compiler.model.Type;
 import com.sun.scenario.effect.compiler.tree.BinaryExpr;
-import org.antlr.runtime.RecognitionException;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
 import org.junit.Test;
 
 import static org.junit.Assert.*;
@@ -60,12 +60,12 @@
         assertEquals(tree.getOp(), BinaryOpType.GT);
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test(expected = ParseCancellationException.class)
     public void notARelationalExpression() throws Exception {
         parseTreeFor("foo @ 3");
     }
 
-    private BinaryExpr parseTreeFor(String text) throws RecognitionException {
+    private BinaryExpr parseTreeFor(String text) throws Exception {
         JSLParser parser = parserOver(text);
         parser.getSymbolTable().declareVariable("foo", Type.INT, null);
         return (BinaryExpr)parser.relational_expression();
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/SelectionStatementTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/SelectionStatementTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -32,7 +32,7 @@
 import com.sun.scenario.effect.compiler.tree.LiteralExpr;
 import com.sun.scenario.effect.compiler.tree.SelectStmt;
 import com.sun.scenario.effect.compiler.tree.Stmt;
-import org.antlr.runtime.RecognitionException;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
 import org.junit.Test;
 
 import static org.junit.Assert.*;
@@ -59,12 +59,12 @@
         assertTrue(s.getElseStmt() instanceof ExprStmt);
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test(expected = ParseCancellationException.class)
     public void notASelect() throws Exception {
         parseTreeFor("then (so) { bobs yer uncle }");
     }
 
-    private Stmt parseTreeFor(String text) throws RecognitionException {
+    private Stmt parseTreeFor(String text) throws Exception {
         JSLParser parser = parserOver(text);
         parser.getSymbolTable().declareVariable("foo", Type.INT, null);
         return parser.selection_statement();
--- a/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/UnaryExprTest.java	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.graphics/src/test/jslc/com/sun/scenario/effect/compiler/parser/UnaryExprTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2019, 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
@@ -31,7 +31,7 @@
 import com.sun.scenario.effect.compiler.tree.LiteralExpr;
 import com.sun.scenario.effect.compiler.tree.UnaryExpr;
 import com.sun.scenario.effect.compiler.tree.VariableExpr;
-import org.antlr.runtime.RecognitionException;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
 import org.junit.Before;
 import org.junit.Test;
 import static org.junit.Assert.assertEquals;
@@ -96,12 +96,12 @@
         assertEquals(((VariableExpr)tree.getExpr()).getVariable().getName(), "foo");
     }
 
-    @Test(expected = RecognitionException.class)
+    @Test(expected = ParseCancellationException.class)
     public void notAUnaryExpression() throws Exception {
         parseTreeFor("^" + primary);
     }
 
-    private UnaryExpr parseTreeFor(String text) throws RecognitionException {
+    private UnaryExpr parseTreeFor(String text) throws Exception {
         JSLParser parser = parserOver(text);
         parser.getSymbolTable().declareVariable("foo", Type.INT, null);
         parser.getSymbolTable().declareVariable("vec", Type.INT3, null);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/javafx.web/src/main/java/com/sun/javafx/webkit/WCMessageDigestImpl.java	Fri Mar 22 08:11:38 2019 -0700
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2019, 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.javafx.webkit;
+
+import com.sun.webkit.security.WCMessageDigest;
+import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class WCMessageDigestImpl extends WCMessageDigest {
+    private final MessageDigest digest;
+
+    public WCMessageDigestImpl(String algorithm) throws NoSuchAlgorithmException {
+        digest = MessageDigest.getInstance(algorithm);
+    }
+
+    @Override
+    public void addBytes(ByteBuffer input) {
+        digest.update(input);
+    }
+
+    @Override
+    public byte[] computeHash() {
+        return digest.digest();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/javafx.web/src/main/java/com/sun/webkit/perf/WCMessageDigestPerfLogger.java	Fri Mar 22 08:11:38 2019 -0700
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2019, 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.webkit.perf;
+
+import com.sun.javafx.logging.PlatformLogger;
+import com.sun.webkit.security.WCMessageDigest;
+import java.nio.ByteBuffer;
+
+public class WCMessageDigestPerfLogger extends WCMessageDigest {
+    private static final PlatformLogger log =
+            PlatformLogger.getLogger(WCMessageDigestPerfLogger.class.getName());
+
+    private static final PerfLogger logger = PerfLogger.getLogger(log);
+
+    final private WCMessageDigest digest;
+
+    public WCMessageDigestPerfLogger(WCMessageDigest digest) {
+        this.digest = digest;
+    }
+
+    public synchronized static boolean isEnabled() {
+        return logger.isEnabled();
+    }
+
+    @Override
+    public void addBytes(ByteBuffer input) {
+        logger.resumeCount("ADDBYTES");
+        digest.addBytes(input);
+        logger.suspendCount("ADDBYTES");
+    }
+
+    @Override
+    public byte[] computeHash() {
+        logger.resumeCount("COMPUTEHASH");
+        byte[] result = digest.computeHash();
+        logger.suspendCount("COMPUTEHASH");
+        return result;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/javafx.web/src/main/java/com/sun/webkit/security/WCMessageDigest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019, 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.webkit.security;
+
+import com.sun.javafx.webkit.WCMessageDigestImpl;
+import com.sun.webkit.perf.WCMessageDigestPerfLogger;
+import java.nio.ByteBuffer;
+
+public abstract class WCMessageDigest {
+    /**
+     * Creates the instance of WCMessageDigest for the given algorithm.
+     * @param algorithm the name of the algorithm like SHA-1, SHA-256.
+     */
+    protected static WCMessageDigest getInstance(String algorithm) {
+        try {
+            WCMessageDigest digest = new WCMessageDigestImpl(algorithm);
+            return WCMessageDigestPerfLogger.isEnabled() ? new WCMessageDigestPerfLogger(digest) : digest;
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
+    /**
+     * Update the digest using the specified ByteBuffer.
+     */
+    public abstract void addBytes(ByteBuffer input);
+
+    /**
+     * Returns the computed hash value.
+     */
+    public abstract byte[] computeHash();
+}
--- a/modules/javafx.web/src/main/native/Source/WebCore/PAL/pal/PlatformJava.cmake	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.web/src/main/native/Source/WebCore/PAL/pal/PlatformJava.cmake	Fri Mar 22 08:11:38 2019 -0700
@@ -9,15 +9,9 @@
     "${ICU_INCLUDE_DIRS}"
 )
 
-if (APPLE)
-    list(APPEND PAL_SOURCES
-        crypto/commoncrypto/CryptoDigestCommonCrypto.cpp
-    )
-else ()
-    list(APPEND PAL_SOURCES
-        crypto/java/CryptoDigestJava.cpp
-    )
-endif ()
+list(APPEND PAL_SOURCES
+    crypto/java/CryptoDigestJava.cpp
+)
 
 add_definitions(-DSTATICALLY_LINKED_WITH_JavaScriptCore)
 add_definitions(-DSTATICALLY_LINKED_WITH_WTF)
--- a/modules/javafx.web/src/main/native/Source/WebCore/PAL/pal/crypto/java/CryptoDigestJava.cpp	Wed Mar 13 09:30:47 2019 +0530
+++ b/modules/javafx.web/src/main/native/Source/WebCore/PAL/pal/crypto/java/CryptoDigestJava.cpp	Fri Mar 22 08:11:38 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2019, 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
@@ -26,39 +26,131 @@
 #include "config.h"
 
 #include "CryptoDigest.h"
-#include "Logging.h"
-
-#define notImplemented()
+#include <jni.h>
+#include <wtf/java/JavaEnv.h>
+#include <wtf/java/JavaRef.h>
 
 namespace PAL {
 
-struct CryptoDigestContext { };
+namespace CryptoDigestInternal {
+
+inline jclass GetMessageDigestClass(JNIEnv* env)
+{
+    static JGClass messageDigestCls(
+        env->FindClass("com/sun/webkit/security/WCMessageDigest"));
+    ASSERT(messageDigestCls);
+    return messageDigestCls;
+}
+
+inline JLObject GetMessageDigestInstance(jstring algorithm)
+{
+    JNIEnv* env = WebCore_GetJavaEnv();
+    if (!env) {
+        return { };
+    }
+
+    static jmethodID midGetInstance = env->GetStaticMethodID(
+        GetMessageDigestClass(env),
+        "getInstance",
+        "(Ljava/lang/String;)Lcom/sun/webkit/security/WCMessageDigest;");
+    ASSERT(midGetInstance);
+    JLObject jDigest = env->CallStaticObjectMethod(GetMessageDigestClass(env), midGetInstance, algorithm);
+    if (CheckAndClearException(env)) {
+        return { };
+    }
+    return jDigest;
+}
+
+jstring toJavaMessageDigestAlgorithm(CryptoDigest::Algorithm algorithm)
+{
+    JNIEnv* env = WebCore_GetJavaEnv();
+
+    const char* algorithmStr = "";
+    switch (algorithm) {
+        case CryptoDigest::Algorithm::SHA_1:
+            algorithmStr = "SHA-1";
+            break;
+        case CryptoDigest::Algorithm::SHA_224:
+            algorithmStr = "SHA-224";
+            break;
+        case CryptoDigest::Algorithm::SHA_256:
+            algorithmStr = "SHA-256";
+            break;
+        case CryptoDigest::Algorithm::SHA_384:
+            algorithmStr = "SHA-384";
+            break;
+        case CryptoDigest::Algorithm::SHA_512:
+            algorithmStr = "SHA-512";
+            break;
+    }
+    return env->NewStringUTF(algorithmStr);
+}
+
+} // namespace CryptoDigestInternal
+
+struct CryptoDigestContext {
+    JGObject jDigest { };
+};
 
 CryptoDigest::CryptoDigest()
+    : m_context(new CryptoDigestContext)
 {
-    notImplemented();
 }
 
 CryptoDigest::~CryptoDigest()
 {
-    notImplemented();
 }
 
-std::unique_ptr<CryptoDigest> CryptoDigest::create(CryptoDigest::Algorithm)
+std::unique_ptr<CryptoDigest> CryptoDigest::create(CryptoDigest::Algorithm algorithm)
 {
-    notImplemented();
-    return std::unique_ptr<CryptoDigest>(new CryptoDigest);
+    using namespace CryptoDigestInternal;
+    auto digest = std::unique_ptr<CryptoDigest>(new CryptoDigest);
+    digest->m_context->jDigest = GetMessageDigestInstance(toJavaMessageDigestAlgorithm(algorithm));
+    return digest;
 }
 
-void CryptoDigest::addBytes(const void*, size_t)
+void CryptoDigest::addBytes(const void* input, size_t length)
 {
-    notImplemented();
+    using namespace CryptoDigestInternal;
+
+    JNIEnv* env = WebCore_GetJavaEnv();
+    if (!m_context->jDigest || !env) {
+        return;
+    }
+
+    static jmethodID midUpdate = env->GetMethodID(
+        GetMessageDigestClass(env),
+        "addBytes",
+        "(Ljava/nio/ByteBuffer;)V");
+    ASSERT(midUpdate);
+    env->CallVoidMethod(jobject(m_context->jDigest), midUpdate, env->NewDirectByteBuffer(const_cast<void*>(input), length));
 }
 
 Vector<uint8_t> CryptoDigest::computeHash()
 {
-    notImplemented();
-    return {};
+    using namespace CryptoDigestInternal;
+
+    JNIEnv* env = WebCore_GetJavaEnv();
+    if (!m_context->jDigest || !env) {
+        return { };
+    }
+
+    static jmethodID midDigest = env->GetMethodID(
+        GetMessageDigestClass(env),
+        "computeHash",
+        "()[B");
+    ASSERT(midUpdate);
+
+    JLocalRef<jbyteArray> jDigestBytes = static_cast<jbyteArray>(env->CallObjectMethod(jobject(m_context->jDigest), midDigest));
+    void* digest = env->GetPrimitiveArrayCritical(static_cast<jbyteArray>(jDigestBytes), 0);
+    if (!digest) {
+        return { };
+    }
+
+    Vector<uint8_t> result;
+    result.append(static_cast<uint8_t*>(digest), env->GetArrayLength(jDigestBytes));
+    env->ReleasePrimitiveArrayCritical(jDigestBytes, digest, 0);
+    return result;
 }
 
 } // namespace PAL
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/javafx.web/src/test/java/test/javafx/scene/web/SubresourceIntegrityTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2019, 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 test.javafx.scene.web;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized.Parameters;
+import org.junit.runners.Parameterized;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+@RunWith(Parameterized.class)
+public final class SubresourceIntegrityTest extends TestBase {
+
+    // To arguments from junit data provider.
+    private final String hashValue;
+    private final String expected;
+    private File htmlFile;
+    // Expectations
+    private final static String LOADED = "hello";
+    private final static String NOT_LOADED = "not loaded";
+    // TODO: junit 4.11 provides an option to label arguments.
+    @Parameters
+    public static Collection<String[]> data() {
+        return Arrays.asList(new String[][] {
+            // shasum -b -a 1 subresource-integrity-test.js | awk '{ print $1 }' | xxd -r -p | base64
+            {"sha1-/kpzvnGzRkcE9OFn5j8qRE61nZY=", LOADED},
+            // shasum -b -a 224 subresource-integrity-test.js | awk '{ print $1 }' | xxd -r -p | base64
+            {"sha224-zgiBbbuKJixMVEkaOXnvpSYZGsx7SbSZ0QOckg==", LOADED},
+            // shasum -b -a 256 subresource-integrity-test.js | awk '{ print $1 }' | xxd -r -p | base64
+            {"sha256-vcl3cFaIDAtcQBkUZFdY+tW/bjrg6vX1R+hQ8uB5tHc=", LOADED},
+            // shasum -b -a 384 subresource-integrity-test.js | awk '{ print $1 }' | xxd -r -p | base64
+            {"sha384-+GrI+cacF05VlQitRghQhs1by9CSIyc8XgZTbymUg2oA0EYdLiPMtilnFP3LDbkY", LOADED},
+            // shasum -b -a 512 subresource-integrity-test.js | awk '{ print $1 }' | xxd -r -p | base64
+            {"sha512-V8m3j61x5soaVcO83NuHavY7Yn4MQYoUgrqJe38f6QYG9QzzgWbVDB1SrZsZ2CVR1IsOnV2MLhnDaZhWOwHDsw==", LOADED},
+            // Only sha256, sha384, sha512 are validated, rest will be ignored and loaded
+            // Ref. https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity#Using_Subresource_Integrity
+            {"sha1-0000000000000000000000000000", LOADED},
+            {"sha224-0000000000000000000000000000000000000000", LOADED},
+            // negative tests, change the hash value and ensure it fails
+            {"sha256-Vcl3cFaIDAtcQBkUZFdY+tW/bjrg6vX1R+hQ8uB5tHc=", NOT_LOADED},
+            {"sha384-+grI+cacF05VlQitRghQhs1by9CSIyc8XgZTbymUg2oA0EYdLiPMtilnFP3LDbkY", NOT_LOADED},
+            {"sha512-v8m3j61x5soaVcO83NuHavY7Yn4MQYoUgrqJe38f6QYG9QzzgWbVDB1SrZsZ2CVR1IsOnV2MLhnDaZhWOwHDsw==", NOT_LOADED},
+            // should load for invalid hash algorithm
+            {"unknown-0000", LOADED},
+            {"", LOADED},
+        });
+    }
+
+    public SubresourceIntegrityTest(final String hashValue, final String expected) {
+        this.hashValue = hashValue;
+        this.expected = expected;
+    }
+
+    @Before
+    public void setup() throws Exception {
+        // loadContent won't work with CORS, use file:// for main resource.
+        htmlFile = new File("subresource-integrity-test.html");
+        final FileOutputStream out = new FileOutputStream(htmlFile);
+        final String scriptUrl =
+                new File("src/test/resources/test/html/subresource-integrity-test.js").toURI().toASCIIString();
+        final String html =
+                String.format("<html>\n" +
+                "<head><script src='%s' integrity='%s' crossorigin='anonymous'></script></head>\n" +
+                "<body>%s</body>\n" +
+                "</html>", scriptUrl, hashValue, NOT_LOADED);
+        out.write(html.getBytes());
+        out.close();
+    }
+
+    @Test
+    public void testScriptTagWithCorrectHashValue() {
+        load(htmlFile);
+        final String bodyText = (String) executeScript("document.body.innerText");
+        assertNotNull("document.body.innerText must be non null for " + hashValue, bodyText);
+        assertEquals(hashValue, expected, bodyText);
+    }
+
+    @After
+    public void tearDown() {
+        if (!htmlFile.delete()) {
+            htmlFile.deleteOnExit();
+        }
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/javafx.web/src/test/resources/test/html/subresource-integrity-test.js	Fri Mar 22 08:11:38 2019 -0700
@@ -0,0 +1,3 @@
+window.onload = () => {
+    document.body.innerText = "hello";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/manual/text/INVISIBLE_GLYPH_IDTest.java	Fri Mar 22 08:11:38 2019 -0700
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2019, 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.
+ */
+
+import javafx.application.Application;
+import static javafx.application.Application.launch;
+import javafx.scene.Group;
+import javafx.scene.Scene;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.Font;
+import javafx.scene.text.Text;
+import javafx.stage.Stage;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+
+public class INVISIBLE_GLYPH_IDTest extends Application {
+
+    private static String OS = System.getProperty("os.name").toLowerCase();
+
+    public void start(Stage stage) {
+        if (OS.indexOf("win") < 0) {
+            System.err.println("# You need to run on Windows");
+            System.exit(0);
+        }
+
+        final String fontName = "ipaexm.ttf";
+        // download from https://ipafont.ipa.go.jp/node26#en
+        // and place in {user.home}/fonts/
+
+        String userHome = System.getProperty("user.home");
+        userHome = userHome.replace("\\", "/");
+        final String base = userHome+"/fonts/";
+        Font font = Font.loadFont("file:"+base+fontName, 48);
+        if (font == null || !"IPAexMincho".equals(font.getName())) {
+            System.err.println("# You need to place "+fontName+" in "+base);
+            System.exit(0);
+        }
+
+        stage.setWidth(140);
+        stage.setHeight(260);
+        Group g = new Group();
+        final Scene scene = new Scene(new Group());
+        VBox box = new VBox();
+        ((Group)scene.getRoot()).getChildren().add(box);
+        stage.setScene(scene);
+
+        Text txt = new Text("\ud869\ude1a"); // U+2A61A (surrogate pair)
+        txt.setFont(font);
+        box.getChildren().add(txt);
+
+        Image img = new Image("INVISIBLE_GLYPH_IDTest_Expected.png");
+        ImageView iv = new ImageView();
+        iv.setImage(img);
+        box.getChildren().add(iv);
+
+        stage.show();
+    }
+}
Binary file tests/manual/text/INVISIBLE_GLYPH_IDTest_Expected.png has changed