Merging the !keepAlive behavior into default branch. Seems to work consistently accross FX and script providers.
authorJaroslav Tulach <jtulach@netbeans.org>
Thu, 18 Dec 2014 03:29:48 +0100
changeset 9167e1929093f06
parent 906 e1291f7b7626
parent 915 15af7ebf1d0e
child 917 05eb1b3bef41
Merging the !keepAlive behavior into default branch. Seems to work consistently accross FX and script providers.
     1.1 --- a/boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java	Tue Dec 16 21:49:45 2014 +0100
     1.2 +++ b/boot-fx/src/main/java/org/netbeans/html/boot/fx/AbstractFXPresenter.java	Thu Dec 18 03:29:48 2014 +0100
     1.3 @@ -46,6 +46,7 @@
     1.4  import java.io.Closeable;
     1.5  import java.io.IOException;
     1.6  import java.io.Reader;
     1.7 +import java.lang.ref.WeakReference;
     1.8  import java.net.URL;
     1.9  import java.util.ArrayList;
    1.10  import java.util.Arrays;
    1.11 @@ -54,8 +55,6 @@
    1.12  import java.util.logging.Level;
    1.13  import java.util.logging.Logger;
    1.14  import javafx.application.Platform;
    1.15 -import javafx.collections.ObservableList;
    1.16 -import javafx.scene.Node;
    1.17  import javafx.scene.Parent;
    1.18  import javafx.scene.layout.BorderPane;
    1.19  import javafx.scene.web.WebEngine;
    1.20 @@ -67,8 +66,8 @@
    1.21   *
    1.22   * @author Jaroslav Tulach
    1.23   */
    1.24 -public abstract class AbstractFXPresenter 
    1.25 -implements Fn.Presenter, Fn.ToJavaScript, Fn.FromJavaScript, Executor, Cloneable {
    1.26 +public abstract class AbstractFXPresenter implements Fn.Presenter,
    1.27 +Fn.KeepAlive, Fn.ToJavaScript, Fn.FromJavaScript, Executor, Cloneable {
    1.28      static final Logger LOG = Logger.getLogger(FXPresenter.class.getName());
    1.29      protected static int cnt;
    1.30      protected Runnable onLoad;
    1.31 @@ -92,15 +91,22 @@
    1.32      
    1.33      @Override
    1.34      public Fn defineFn(String code, String... names) {
    1.35 -        return defineJSFn(code, names);
    1.36 +        return defineJSFn(code, names, null);
    1.37 +    }
    1.38 +
    1.39 +    @Override
    1.40 +    public Fn defineFn(String code, String[] names, boolean[] keepAlive) {
    1.41 +        return defineJSFn(code, names, keepAlive);
    1.42      }
    1.43      
    1.44 -    final JSFn defineJSFn(String code, String... names) {
    1.45 +    
    1.46 +    
    1.47 +    final JSFn defineJSFn(String code, String[] names, boolean[] keepAlive) {
    1.48          StringBuilder sb = new StringBuilder();
    1.49          sb.append("(function() {");
    1.50          sb.append("  return function(");
    1.51          String sep = "";
    1.52 -        for (String n : names) {
    1.53 +        if (names != null) for (String n : names) {
    1.54              sb.append(sep).append(n);
    1.55              sep = ",";
    1.56          }
    1.57 @@ -115,7 +121,7 @@
    1.58              );
    1.59          }
    1.60          JSObject x = (JSObject) engine.executeScript(sb.toString());
    1.61 -        return new JSFn(this, x, cnt);
    1.62 +        return new JSFn(this, x, cnt, keepAlive);
    1.63      }
    1.64  
    1.65      @Override
    1.66 @@ -208,7 +214,7 @@
    1.67                      + "  k.array= function() {"
    1.68                      + "    return Array.prototype.slice.call(arguments);"
    1.69                      + "  };"
    1.70 -                    + "  return k;"
    1.71 +                    + "  return k;", null, null
    1.72                  ).invokeImpl(null, false);
    1.73              } catch (Exception ex) {
    1.74                  throw new IllegalStateException(ex);
    1.75 @@ -218,6 +224,9 @@
    1.76      }
    1.77  
    1.78      final Object checkArray(Object val) {
    1.79 +        if (!(val instanceof JSObject)) {
    1.80 +            return val;
    1.81 +        }
    1.82          int length = ((Number) arraySizeFn().call("array", val, null)).intValue();
    1.83          if (length == -1) {
    1.84              return val;
    1.85 @@ -240,7 +249,7 @@
    1.86                      + "      return l;"
    1.87                      + "    }"
    1.88                      + "  };"
    1.89 -                    + "  return k;"
    1.90 +                    + "  return k;", null, null
    1.91                  ).invokeImpl(null, false);
    1.92              } catch (Exception ex) {
    1.93                  throw new IllegalStateException(ex);
    1.94 @@ -251,6 +260,9 @@
    1.95  
    1.96      @Override
    1.97      public Object toJava(Object jsArray) {
    1.98 +        if (jsArray instanceof Weak) {
    1.99 +            jsArray = ((Weak)jsArray).get();
   1.100 +        }
   1.101          return checkArray(jsArray);
   1.102      }
   1.103      
   1.104 @@ -300,11 +312,13 @@
   1.105          private final JSObject fn;
   1.106          private static int call;
   1.107          private final int id;
   1.108 +        private final boolean[] keepAlive;
   1.109  
   1.110 -        public JSFn(AbstractFXPresenter p, JSObject fn, int id) {
   1.111 +        public JSFn(AbstractFXPresenter p, JSObject fn, int id, boolean[] keepAlive) {
   1.112              super(p);
   1.113              this.fn = fn;
   1.114              this.id = id;
   1.115 +            this.keepAlive = keepAlive;
   1.116          }
   1.117  
   1.118          @Override
   1.119 @@ -322,14 +336,25 @@
   1.120                  List<Object> all = new ArrayList<Object>(args.length + 1);
   1.121                  all.add(thiz == null ? fn : thiz);
   1.122                  for (int i = 0; i < args.length; i++) {
   1.123 -                    if (arrayChecks && args[i] instanceof Object[]) {
   1.124 -                        Object[] arr = (Object[]) args[i];
   1.125 -                        Object conv = ((AbstractFXPresenter)presenter()).convertArrays(arr);
   1.126 -                        args[i] = conv;
   1.127 +                    Object conv = args[i];
   1.128 +                    if (arrayChecks) {
   1.129 +                        if (args[i] instanceof Object[]) {
   1.130 +                            Object[] arr = (Object[]) args[i];
   1.131 +                            conv = ((AbstractFXPresenter)presenter()).convertArrays(arr);
   1.132 +                        }
   1.133 +                        if (conv != null && keepAlive != null && 
   1.134 +                            !keepAlive[i] && !isJSReady(conv) &&
   1.135 +                            !conv.getClass().getSimpleName().equals("$JsCallbacks$") // NOI18N
   1.136 +                        ) {
   1.137 +                            conv = new Weak(conv);
   1.138 +                        }
   1.139                      }
   1.140 -                    all.add(args[i]);
   1.141 +                    all.add(conv);
   1.142                  }
   1.143                  Object ret = fn.call("call", all.toArray()); // NOI18N
   1.144 +                if (ret instanceof Weak) {
   1.145 +                    ret = ((Weak)ret).get();
   1.146 +                }
   1.147                  if (ret == fn) {
   1.148                      return null;
   1.149                  }
   1.150 @@ -347,4 +372,29 @@
   1.151          }
   1.152      }
   1.153      
   1.154 +    private static boolean isJSReady(Object obj) {
   1.155 +        if (obj == null) {
   1.156 +            return true;
   1.157 +        }
   1.158 +        if (obj instanceof String) {
   1.159 +            return true;
   1.160 +        }
   1.161 +        if (obj instanceof Number) {
   1.162 +            return true;
   1.163 +        }
   1.164 +        if (obj instanceof JSObject) {
   1.165 +            return true;
   1.166 +        }
   1.167 +        if (obj instanceof Character) {
   1.168 +            return true;
   1.169 +        }
   1.170 +        return false;
   1.171 +    }
   1.172 +    
   1.173 +    private static final class Weak extends WeakReference<Object> {
   1.174 +        public Weak(Object referent) {
   1.175 +            super(referent);
   1.176 +            assert !(referent instanceof Weak);
   1.177 +        }
   1.178 +    } // end of Weak
   1.179  }
     2.1 --- a/boot-script/src/main/java/net/java/html/boot/script/ScriptPresenter.java	Tue Dec 16 21:49:45 2014 +0100
     2.2 +++ b/boot-script/src/main/java/net/java/html/boot/script/ScriptPresenter.java	Thu Dec 18 03:29:48 2014 +0100
     2.3 @@ -45,6 +45,7 @@
     2.4  import java.io.Closeable;
     2.5  import java.io.IOException;
     2.6  import java.io.Reader;
     2.7 +import java.lang.ref.WeakReference;
     2.8  import java.net.URL;
     2.9  import java.util.ArrayList;
    2.10  import java.util.List;
    2.11 @@ -70,8 +71,8 @@
    2.12   *
    2.13   * @author Jaroslav Tulach
    2.14   */
    2.15 -final class ScriptPresenter 
    2.16 -implements Presenter, Fn.FromJavaScript, Fn.ToJavaScript, Executor {
    2.17 +final class ScriptPresenter implements Fn.KeepAlive,
    2.18 +Presenter, Fn.FromJavaScript, Fn.ToJavaScript, Executor {
    2.19      private static final Logger LOG = Logger.getLogger(ScriptPresenter.class.getName());
    2.20      private final ScriptEngine eng;
    2.21      private final Executor exc;
    2.22 @@ -90,9 +91,14 @@
    2.23  
    2.24      @Override
    2.25      public Fn defineFn(String code, String... names) {
    2.26 -        return defineImpl(code, names);
    2.27 +        return defineImpl(code, names, null);
    2.28      }
    2.29 -    private FnImpl defineImpl(String code, String... names) {
    2.30 +
    2.31 +    @Override
    2.32 +    public Fn defineFn(String code, String[] names, boolean[] keepAlive) {
    2.33 +        return defineImpl(code, names, keepAlive);
    2.34 +    }    
    2.35 +    private FnImpl defineImpl(String code, String[] names, boolean[] keepAlive) {
    2.36          StringBuilder sb = new StringBuilder();
    2.37          sb.append("(function() {");
    2.38          sb.append("  return function(");
    2.39 @@ -112,7 +118,7 @@
    2.40          } catch (ScriptException ex) {
    2.41              throw new IllegalStateException(ex);
    2.42          }
    2.43 -        return new FnImpl(this, fn);
    2.44 +        return new FnImpl(this, fn, keepAlive);
    2.45      }
    2.46  
    2.47      @Override
    2.48 @@ -150,7 +156,7 @@
    2.49      private FnImpl wrapArrFn() {
    2.50          if (wrapArrImpl == null) {
    2.51              try {
    2.52 -                wrapArrImpl = defineImpl("return Array.prototype.slice.call(arguments);");
    2.53 +                wrapArrImpl = defineImpl("return Array.prototype.slice.call(arguments);", null, null);
    2.54              } catch (Exception ex) {
    2.55                  throw new IllegalStateException(ex);
    2.56              }
    2.57 @@ -181,7 +187,7 @@
    2.58                      + "  var l = arr.length;\n"
    2.59                      + "  for (var i = 0; i < l; i++) to[i] = arr[i];\n"
    2.60                      + "  return l;\n"
    2.61 -                    + "}", "arr", "to"
    2.62 +                    + "}", new String[] { "arr", "to" }, null
    2.63                  );
    2.64              } catch (Exception ex) {
    2.65                  throw new IllegalStateException(ex);
    2.66 @@ -192,6 +198,9 @@
    2.67  
    2.68      @Override
    2.69      public Object toJava(Object jsArray) {
    2.70 +        if (jsArray instanceof Weak) {
    2.71 +            jsArray = ((Weak)jsArray).get();
    2.72 +        }
    2.73          try {
    2.74              return checkArray(jsArray);
    2.75          } catch (Exception ex) {
    2.76 @@ -239,10 +248,12 @@
    2.77      private class FnImpl extends Fn {
    2.78  
    2.79          private final Object fn;
    2.80 +        private final boolean[] keepAlive;
    2.81  
    2.82 -        public FnImpl(Presenter presenter, Object fn) {
    2.83 +        public FnImpl(Presenter presenter, Object fn, boolean[] keepAlive) {
    2.84              super(presenter);
    2.85              this.fn = fn;
    2.86 +            this.keepAlive = keepAlive;
    2.87          }
    2.88  
    2.89          @Override
    2.90 @@ -254,19 +265,28 @@
    2.91                  List<Object> all = new ArrayList<>(args.length + 1);
    2.92                  all.add(thiz == null ? fn : thiz);
    2.93                  for (int i = 0; i < args.length; i++) {
    2.94 +                    Object conv = args[i];
    2.95                      if (arrayChecks) {
    2.96                          if (args[i] instanceof Object[]) {
    2.97                              Object[] arr = (Object[]) args[i];
    2.98 -                            Object conv = ((ScriptPresenter)presenter()).convertArrays(arr);
    2.99 -                            args[i] = conv;
   2.100 +                            conv = ((ScriptPresenter) presenter()).convertArrays(arr);
   2.101                          }
   2.102 -                        if (args[i] instanceof Character) {
   2.103 -                            args[i] = (int)((Character)args[i]);
   2.104 +                        if (conv != null && keepAlive != null
   2.105 +                            && !keepAlive[i] && !isJSReady(conv)
   2.106 +                            && !conv.getClass().getSimpleName().equals("$JsCallbacks$") // NOI18N
   2.107 +                            ) {
   2.108 +                            conv = new Weak(conv);
   2.109 +                        }
   2.110 +                        if (conv instanceof Character) {
   2.111 +                            conv = (int)(Character)conv;
   2.112                          }
   2.113                      }
   2.114 -                    all.add(args[i]);
   2.115 +                    all.add(conv);
   2.116                  }
   2.117                  Object ret = ((Invocable)eng).invokeMethod(fn, "call", all.toArray()); // NOI18N
   2.118 +                if (ret instanceof Weak) {
   2.119 +                    ret = ((Weak)ret).get();
   2.120 +                }
   2.121                  if (ret == fn) {
   2.122                      return null;
   2.123                  }
   2.124 @@ -277,4 +297,31 @@
   2.125              }
   2.126      }
   2.127      
   2.128 +    private static boolean isJSReady(Object obj) {
   2.129 +        if (obj == null) {
   2.130 +            return true;
   2.131 +        }
   2.132 +        if (obj instanceof String) {
   2.133 +            return true;
   2.134 +        }
   2.135 +        if (obj instanceof Number) {
   2.136 +            return true;
   2.137 +        }
   2.138 +        final String cn = obj.getClass().getName();
   2.139 +        if (cn.startsWith("jdk.nashorn") || ( // NOI18N
   2.140 +            cn.contains(".mozilla.") && cn.contains(".Native") // NOI18N
   2.141 +        )) {
   2.142 +            return true;
   2.143 +        }
   2.144 +        if (obj instanceof Character) {
   2.145 +            return true;
   2.146 +        }
   2.147 +        return false;
   2.148 +    }    
   2.149 +    
   2.150 +    private static final class Weak extends WeakReference<Object> {
   2.151 +        public Weak(Object referent) {
   2.152 +            super(referent);
   2.153 +        }
   2.154 +    }
   2.155  }
     3.1 --- a/boot/src/main/java/org/netbeans/html/boot/impl/FnUtils.java	Tue Dec 16 21:49:45 2014 +0100
     3.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/FnUtils.java	Thu Dec 18 03:29:48 2014 +0100
     3.3 @@ -150,7 +150,12 @@
     3.4                  String ident, String fqn, String method, String params
     3.5              ) {
     3.6                  StringBuilder sb = new StringBuilder();
     3.7 -                sb.append("vm.").append(mangle(fqn, method, params));
     3.8 +                if (ident != null) {
     3.9 +                    sb.append("vm.raw$");
    3.10 +                } else {
    3.11 +                    sb.append("vm.");
    3.12 +                }
    3.13 +                sb.append(mangle(fqn, method, params));
    3.14                  sb.append("(");
    3.15                  if (ident != null) {
    3.16                      sb.append(ident);
     4.1 --- a/boot/src/main/java/org/netbeans/html/boot/impl/JavaScriptProcesor.java	Tue Dec 16 21:49:45 2014 +0100
     4.2 +++ b/boot/src/main/java/org/netbeans/html/boot/impl/JavaScriptProcesor.java	Thu Dec 18 03:29:48 2014 +0100
     4.3 @@ -367,83 +367,8 @@
     4.4              for (Map.Entry<String, ExecutableElement> entry : map.entrySet()) {
     4.5                  final String mangled = entry.getKey();
     4.6                  final ExecutableElement m = entry.getValue();
     4.7 -                final boolean isStatic = m.getModifiers().contains(Modifier.STATIC);
     4.8 -                
     4.9 -                source.append("\n  public java.lang.Object ")
    4.10 -                    .append(mangled)
    4.11 -                    .append("(");
    4.12 -                
    4.13 -                String sep = "";
    4.14 -                if (!isStatic) {
    4.15 -                    source.append(((TypeElement)m.getEnclosingElement()).getQualifiedName());
    4.16 -                    source.append(" self");
    4.17 -                    sep = ", ";
    4.18 -                }
    4.19 -                
    4.20 -                int cnt = 0;
    4.21 -                StringBuilder convert = new StringBuilder();
    4.22 -                for (VariableElement ve : m.getParameters()) {
    4.23 -                    source.append(sep);
    4.24 -                    ++cnt;
    4.25 -                    final TypeMirror t = ve.asType();
    4.26 -                    if (!t.getKind().isPrimitive()) {
    4.27 -                        source.append("Object");
    4.28 -                        convert.append("    if (p instanceof org.netbeans.html.boot.spi.Fn.FromJavaScript) {\n");
    4.29 -                        convert.append("      arg").append(cnt).
    4.30 -                            append(" = ((org.netbeans.html.boot.spi.Fn.FromJavaScript)p).toJava(arg").append(cnt).
    4.31 -                            append(");\n");
    4.32 -                        convert.append("    }\n");
    4.33 -                    } else {
    4.34 -                        source.append(t);
    4.35 -                    }
    4.36 -                    source.append(" arg").append(cnt);
    4.37 -                    sep = ", ";
    4.38 -                }
    4.39 -                source.append(") throws Throwable {\n");
    4.40 -                source.append(convert);
    4.41 -                if (useTryResources()) {
    4.42 -                    source.append("    try (java.io.Closeable a = org.netbeans.html.boot.spi.Fn.activate(p)) { \n");
    4.43 -                } else {
    4.44 -                    source.append("    java.io.Closeable a = org.netbeans.html.boot.spi.Fn.activate(p); try {\n");
    4.45 -                }
    4.46 -                source.append("    ");
    4.47 -                if (m.getReturnType().getKind() != TypeKind.VOID) {
    4.48 -                    source.append("Object $ret = ");
    4.49 -                }
    4.50 -                if (isStatic) {
    4.51 -                    source.append(((TypeElement)m.getEnclosingElement()).getQualifiedName());
    4.52 -                    source.append('.');
    4.53 -                } else {
    4.54 -                    source.append("self.");
    4.55 -                }
    4.56 -                source.append(m.getSimpleName());
    4.57 -                source.append("(");
    4.58 -                cnt = 0;
    4.59 -                sep = "";
    4.60 -                for (VariableElement ve : m.getParameters()) {
    4.61 -                    source.append(sep);
    4.62 -                    source.append("(").append(ve.asType());
    4.63 -                    source.append(")arg").append(++cnt);
    4.64 -                    sep = ", ";
    4.65 -                }
    4.66 -                source.append(");\n");
    4.67 -                if (m.getReturnType().getKind() == TypeKind.VOID) {
    4.68 -                    source.append("    return null;\n");
    4.69 -                } else {
    4.70 -                    source.append("    if (p instanceof org.netbeans.html.boot.spi.Fn.ToJavaScript) {\n");
    4.71 -                    source.append("      $ret = ((org.netbeans.html.boot.spi.Fn.ToJavaScript)p).toJavaScript($ret);\n");
    4.72 -                    source.append("    }\n");
    4.73 -                    source.append("    return $ret;\n");
    4.74 -                }
    4.75 -                if (useTryResources()) {
    4.76 -                    source.append("    }\n");
    4.77 -                } else {
    4.78 -                    
    4.79 -                    source.append("    } finally {\n");
    4.80 -                    source.append("      a.close();\n");
    4.81 -                    source.append("    }\n");
    4.82 -                }
    4.83 -                source.append("  }\n");
    4.84 +                generateMethod(false, m, source, mangled);
    4.85 +                generateMethod(true, m, source, "raw$" + mangled);
    4.86              }
    4.87              source.append("}\n");
    4.88              final String srcName = pkgName + ".$JsCallbacks$";
    4.89 @@ -461,6 +386,106 @@
    4.90          }
    4.91      }
    4.92  
    4.93 +    private void generateMethod(boolean selfObj, final ExecutableElement m, StringBuilder source, final String mangled) {
    4.94 +        final boolean isStatic = m.getModifiers().contains(Modifier.STATIC);
    4.95 +        if (isStatic && selfObj) {
    4.96 +            return;
    4.97 +        }
    4.98 +        final TypeElement selfType = (TypeElement)m.getEnclosingElement();
    4.99 +        
   4.100 +        
   4.101 +        source.append("\n  public java.lang.Object ")
   4.102 +                .append(mangled)
   4.103 +                .append("(");
   4.104 +        
   4.105 +        String sep = "";
   4.106 +        StringBuilder convert = new StringBuilder();
   4.107 +        if (!isStatic) {
   4.108 +            if (selfObj) {
   4.109 +                source.append("Object self");
   4.110 +                convert.append("    if (p instanceof org.netbeans.html.boot.spi.Fn.FromJavaScript) {\n");
   4.111 +                convert.append("      self").
   4.112 +                        append(" = ((org.netbeans.html.boot.spi.Fn.FromJavaScript)p).toJava(self").
   4.113 +                        append(");\n");
   4.114 +                convert.append("    }\n");
   4.115 +            } else {
   4.116 +                source.append(selfType.getQualifiedName());
   4.117 +                source.append(" self");
   4.118 +            }
   4.119 +            sep = ", ";
   4.120 +        }
   4.121 +        
   4.122 +        int cnt = 0;
   4.123 +        for (VariableElement ve : m.getParameters()) {
   4.124 +            source.append(sep);
   4.125 +            ++cnt;
   4.126 +            final TypeMirror t = ve.asType();
   4.127 +            if (!t.getKind().isPrimitive() && !"java.lang.String".equals(t.toString())) { // NOI18N
   4.128 +                source.append("Object");
   4.129 +                convert.append("    if (p instanceof org.netbeans.html.boot.spi.Fn.FromJavaScript) {\n");
   4.130 +                convert.append("      arg").append(cnt).
   4.131 +                        append(" = ((org.netbeans.html.boot.spi.Fn.FromJavaScript)p).toJava(arg").append(cnt).
   4.132 +                        append(");\n");
   4.133 +                convert.append("    }\n");
   4.134 +            } else {
   4.135 +                source.append(t);
   4.136 +            }
   4.137 +            source.append(" arg").append(cnt);
   4.138 +            sep = ", ";
   4.139 +        }
   4.140 +        source.append(") throws Throwable {\n");
   4.141 +        source.append(convert);
   4.142 +        if (useTryResources()) {
   4.143 +            source.append("    try (java.io.Closeable a = org.netbeans.html.boot.spi.Fn.activate(p)) { \n");
   4.144 +        } else {
   4.145 +            source.append("    java.io.Closeable a = org.netbeans.html.boot.spi.Fn.activate(p); try {\n");
   4.146 +        }
   4.147 +        source.append("    ");
   4.148 +        if (m.getReturnType().getKind() != TypeKind.VOID) {
   4.149 +            source.append("Object $ret = ");
   4.150 +        }
   4.151 +        if (isStatic) {
   4.152 +            source.append(((TypeElement)m.getEnclosingElement()).getQualifiedName());
   4.153 +            source.append('.');
   4.154 +        } else {
   4.155 +            if (selfObj) {
   4.156 +                source.append("((");
   4.157 +                source.append(selfType.getQualifiedName());
   4.158 +                source.append(")self).");
   4.159 +            } else {
   4.160 +                source.append("self.");
   4.161 +            }
   4.162 +        }
   4.163 +        source.append(m.getSimpleName());
   4.164 +        source.append("(");
   4.165 +        cnt = 0;
   4.166 +        sep = "";
   4.167 +        for (VariableElement ve : m.getParameters()) {
   4.168 +            source.append(sep);
   4.169 +            source.append("(").append(ve.asType());
   4.170 +            source.append(")arg").append(++cnt);
   4.171 +            sep = ", ";
   4.172 +        }
   4.173 +        source.append(");\n");
   4.174 +        if (m.getReturnType().getKind() == TypeKind.VOID) {
   4.175 +            source.append("    return null;\n");
   4.176 +        } else {
   4.177 +            source.append("    if (p instanceof org.netbeans.html.boot.spi.Fn.ToJavaScript) {\n");
   4.178 +            source.append("      $ret = ((org.netbeans.html.boot.spi.Fn.ToJavaScript)p).toJavaScript($ret);\n");
   4.179 +            source.append("    }\n");
   4.180 +            source.append("    return $ret;\n");
   4.181 +        }
   4.182 +        if (useTryResources()) {
   4.183 +            source.append("    }\n");
   4.184 +        } else {
   4.185 +            
   4.186 +            source.append("    } finally {\n");
   4.187 +            source.append("      a.close();\n");
   4.188 +            source.append("    }\n");
   4.189 +        }
   4.190 +        source.append("  }\n");
   4.191 +    }
   4.192 +
   4.193      private boolean useTryResources() {
   4.194          try {
   4.195              return processingEnv.getSourceVersion().compareTo(SourceVersion.RELEASE_7) >= 0;
     5.1 --- a/boot/src/main/java/org/netbeans/html/boot/spi/Fn.java	Tue Dec 16 21:49:45 2014 +0100
     5.2 +++ b/boot/src/main/java/org/netbeans/html/boot/spi/Fn.java	Thu Dec 18 03:29:48 2014 +0100
     5.3 @@ -137,7 +137,7 @@
     5.4          }
     5.5          if (p instanceof KeepAlive) {
     5.6              boolean[] arr;
     5.7 -            if (!keepParametersAlive) {
     5.8 +            if (!keepParametersAlive && names.length > 0) {
     5.9                  arr = new boolean[names.length];
    5.10                  for (int i = 0; i < arr.length; i++) {
    5.11                      arr[i] = false;
     6.1 --- a/json-tck/src/main/java/net/java/html/js/tests/Bodies.java	Tue Dec 16 21:49:45 2014 +0100
     6.2 +++ b/json-tck/src/main/java/net/java/html/js/tests/Bodies.java	Thu Dec 18 03:29:48 2014 +0100
     6.3 @@ -91,10 +91,10 @@
     6.4      @JavaScriptBody(args = { "o", "x" }, keepAlive = false, body = "o.x = x;")
     6.5      public static native Object setX(Object o, Object x);
     6.6  
     6.7 -    @JavaScriptBody(args = { "c" }, keepAlive = false, javacall = true, body = 
     6.8 -        "return c.@net.java.html.js.tests.Sum::sum(II)(40, 2);"
     6.9 +    @JavaScriptBody(args = { "c", "a", "b" }, keepAlive = false, javacall = true, body = 
    6.10 +        "return c.@net.java.html.js.tests.Sum::sum(II)(a, b);"
    6.11      )
    6.12 -    public static native int sumIndirect(Sum c);
    6.13 +    public static native int sumIndirect(Sum c, int a, int b);
    6.14      
    6.15      @JavaScriptBody(args = { "arr", "index" }, body = "return arr[index];")
    6.16      public static native Object select(Object[] arr, int index);
    6.17 @@ -191,6 +191,11 @@
    6.18          "return @net.java.html.js.tests.Bodies::problematicString()();"
    6.19      )
    6.20      public static native String problematicCallback();
    6.21 +
    6.22 +    @JavaScriptBody(args = { "sum" }, javacall = true, body = 
    6.23 +        "return sum.@net.java.html.js.tests.Sum::all(ZBSIJFDCLjava/lang/String;)(false, 1, 2, 3, 5, 6, 7, 32, 'TheEND');\n"
    6.24 +    )
    6.25 +    static native String primitiveTypes(Sum sum);
    6.26      
    6.27      static String problematicString() {
    6.28          return "{\n" +
     7.1 --- a/json-tck/src/main/java/net/java/html/js/tests/GCBodyTest.java	Tue Dec 16 21:49:45 2014 +0100
     7.2 +++ b/json-tck/src/main/java/net/java/html/js/tests/GCBodyTest.java	Thu Dec 18 03:29:48 2014 +0100
     7.3 @@ -60,7 +60,7 @@
     7.4              return;
     7.5          }
     7.6          Sum s = new Sum();
     7.7 -        int res = Bodies.sumIndirect(s);
     7.8 +        int res = Bodies.sumIndirect(s, 22, 20);
     7.9          assert res == 42 : "Expecting 42";
    7.10          Reference<?> ref = new WeakReference<Object>(s);
    7.11          s = null;
    7.12 @@ -85,10 +85,22 @@
    7.13          Object obj = assignInst();
    7.14          assert ref != null;
    7.15          
    7.16 -        Bodies.setX(obj, null);
    7.17 -        obj = null;
    7.18 -        
    7.19 -        assertGC(ref, "Can disappear!");
    7.20 +        assertGC(ref, "Can disappear as it is keepAlive false!");
    7.21 +        assert obj != null : "Object is still present";
    7.22 +    }
    7.23 +
    7.24 +    @KOTest public void strongReceiverBehavior() {
    7.25 +        Object v = new EmptyInstance();
    7.26 +        Receiver r = new Receiver(v);
    7.27 +        r.apply();
    7.28 +        assert v == r.value : "Value is as expected";
    7.29 +    }
    7.30 +    
    7.31 +    @KOTest public void gcReceiverBehavior() throws InterruptedException {
    7.32 +        Receiver r = new Receiver(new EmptyInstance());
    7.33 +        assertGC(r.ref, "The empty instance can be GCed even when referenced from JS");
    7.34 +        r.apply();
    7.35 +        assert r.value == null : "Setter called with null value";
    7.36      }
    7.37  
    7.38      private static Reference<?> sendRunnable(final int[] arr) {
     8.1 --- a/json-tck/src/main/java/net/java/html/js/tests/JavaScriptBodyTest.java	Tue Dec 16 21:49:45 2014 +0100
     8.2 +++ b/json-tck/src/main/java/net/java/html/js/tests/JavaScriptBodyTest.java	Thu Dec 18 03:29:48 2014 +0100
     8.3 @@ -213,7 +213,7 @@
     8.4      
     8.5      @KOTest public void callbackWithParameters() throws InterruptedException {
     8.6          Sum s = new Sum();
     8.7 -        int res = Bodies.sumIndirect(s);
     8.8 +        int res = Bodies.sumIndirect(s, 40, 2);
     8.9          assert res == 42 : "Expecting 42";
    8.10      }
    8.11      
    8.12 @@ -340,6 +340,11 @@
    8.13          assert ret[2].equals("Ciao") : "Expecting Ciao: " + ret[2];
    8.14      }
    8.15      
    8.16 +    @KOTest public void primitiveTypes() {
    8.17 +        String all = Bodies.primitiveTypes(new Sum());
    8.18 +        assert "Ahojfalse12356.07.0 TheEND".equals(all) : "Valid return type: " + all;
    8.19 +    }
    8.20 +    
    8.21      @KOTest public void problematicString() {
    8.22          String orig = Bodies.problematicString();
    8.23          String js = Bodies.problematicCallback();
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/json-tck/src/main/java/net/java/html/js/tests/Receiver.java	Thu Dec 18 03:29:48 2014 +0100
     9.3 @@ -0,0 +1,80 @@
     9.4 +/**
     9.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     9.6 + *
     9.7 + * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
     9.8 + *
     9.9 + * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
    9.10 + * Other names may be trademarks of their respective owners.
    9.11 + *
    9.12 + * The contents of this file are subject to the terms of either the GNU
    9.13 + * General Public License Version 2 only ("GPL") or the Common
    9.14 + * Development and Distribution License("CDDL") (collectively, the
    9.15 + * "License"). You may not use this file except in compliance with the
    9.16 + * License. You can obtain a copy of the License at
    9.17 + * http://www.netbeans.org/cddl-gplv2.html
    9.18 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    9.19 + * specific language governing permissions and limitations under the
    9.20 + * License.  When distributing the software, include this License Header
    9.21 + * Notice in each file and include the License file at
    9.22 + * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
    9.23 + * particular file as subject to the "Classpath" exception as provided
    9.24 + * by Oracle in the GPL Version 2 section of the License file that
    9.25 + * accompanied this code. If applicable, add the following below the
    9.26 + * License Header, with the fields enclosed by brackets [] replaced by
    9.27 + * your own identifying information:
    9.28 + * "Portions Copyrighted [year] [name of copyright owner]"
    9.29 + *
    9.30 + * Contributor(s):
    9.31 + *
    9.32 + * The Original Software is NetBeans. The Initial Developer of the Original
    9.33 + * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
    9.34 + *
    9.35 + * If you wish your version of this file to be governed by only the CDDL
    9.36 + * or only the GPL Version 2, indicate your decision by adding
    9.37 + * "[Contributor] elects to include this software in this distribution
    9.38 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
    9.39 + * single choice of license, a recipient has the option to distribute
    9.40 + * your version of this file under either the CDDL, the GPL Version 2 or
    9.41 + * to extend the choice of license to its licensees as provided above.
    9.42 + * However, if you add GPL Version 2 code and therefore, elected the GPL
    9.43 + * Version 2 license, then the option applies only if the new code is
    9.44 + * made subject to such option by the copyright holder.
    9.45 + */
    9.46 +package net.java.html.js.tests;
    9.47 +
    9.48 +import java.lang.ref.Reference;
    9.49 +import java.lang.ref.WeakReference;
    9.50 +import net.java.html.js.JavaScriptBody;
    9.51 +
    9.52 +/**
    9.53 + */
    9.54 +public final class Receiver {
    9.55 +    private final Object fn;
    9.56 +    Object value;
    9.57 +    final Reference<Object> ref;
    9.58 +
    9.59 +    public Receiver(Object v) {
    9.60 +        this.fn = initFn(v);
    9.61 +        this.ref = new WeakReference<Object>(v);
    9.62 +        this.value = this;
    9.63 +    }
    9.64 +    
    9.65 +    public void apply() {
    9.66 +        fnApply(fn, this);
    9.67 +    }
    9.68 +    
    9.69 +    void set(Object v) {
    9.70 +        value = v;
    9.71 +    }
    9.72 +    
    9.73 +    @JavaScriptBody(args = { "v" }, keepAlive = false, javacall = true, 
    9.74 +        body = "return function(rec) {\n"
    9.75 +        + "  rec.@net.java.html.js.tests.Receiver::set(Ljava/lang/Object;)(v);\n"
    9.76 +        + "};\n")
    9.77 +    private static native Object initFn(Object v);
    9.78 +    
    9.79 +    @JavaScriptBody(args = { "fn", "thiz" }, body =
    9.80 +        "fn(thiz);"
    9.81 +    )
    9.82 +    private static native void fnApply(Object fn, Receiver thiz);
    9.83 +}
    10.1 --- a/json-tck/src/main/java/net/java/html/js/tests/Sum.java	Tue Dec 16 21:49:45 2014 +0100
    10.2 +++ b/json-tck/src/main/java/net/java/html/js/tests/Sum.java	Thu Dec 18 03:29:48 2014 +0100
    10.3 @@ -60,4 +60,8 @@
    10.4          }
    10.5          return s;
    10.6      }
    10.7 +    
    10.8 +    public String all(boolean z, byte b, short s, int i, long l, float f, double d, char ch, String str) {
    10.9 +        return "Ahoj" + z + b + s + i + l + f + d + ch + str;
   10.10 +    }
   10.11  }
    11.1 --- a/pom.xml	Tue Dec 16 21:49:45 2014 +0100
    11.2 +++ b/pom.xml	Thu Dec 18 03:29:48 2014 +0100
    11.3 @@ -97,6 +97,7 @@
    11.4                    <excludes>
    11.5                         <exclude>*</exclude>
    11.6                         <exclude>.*/**</exclude>
    11.7 +                       <exclude>*/nb-configuration.xml</exclude>
    11.8                         <exclude>boot-script/src/test/resources/net/java/html/boot/script/ko4j/env.nashorn.1.2-debug.js</exclude>
    11.9                         <exclude>src/main/javadoc/resources/teavm.js</exclude>
   11.10                    </excludes>