boot-truffle/src/main/java/net/java/html/boot/truffle/TrufflePresenter.java
author Jaroslav Tulach <jtulach@netbeans.org>
Thu, 21 Jul 2016 10:23:46 +0200
branchTruffle
changeset 1102 86f56d464357
parent 1098 20246cbd02c3
permissions -rw-r--r--
Addressing lints and warnings
jtulach@1094
     1
/**
jtulach@1094
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
jtulach@1094
     3
 *
jtulach@1094
     4
 * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
jtulach@1094
     5
 *
jtulach@1094
     6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
jtulach@1094
     7
 * Other names may be trademarks of their respective owners.
jtulach@1094
     8
 *
jtulach@1094
     9
 * The contents of this file are subject to the terms of either the GNU
jtulach@1094
    10
 * General Public License Version 2 only ("GPL") or the Common
jtulach@1094
    11
 * Development and Distribution License("CDDL") (collectively, the
jtulach@1094
    12
 * "License"). You may not use this file except in compliance with the
jtulach@1094
    13
 * License. You can obtain a copy of the License at
jtulach@1094
    14
 * http://www.netbeans.org/cddl-gplv2.html
jtulach@1094
    15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
jtulach@1094
    16
 * specific language governing permissions and limitations under the
jtulach@1094
    17
 * License.  When distributing the software, include this License Header
jtulach@1094
    18
 * Notice in each file and include the License file at
jtulach@1094
    19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
jtulach@1094
    20
 * particular file as subject to the "Classpath" exception as provided
jtulach@1094
    21
 * by Oracle in the GPL Version 2 section of the License file that
jtulach@1094
    22
 * accompanied this code. If applicable, add the following below the
jtulach@1094
    23
 * License Header, with the fields enclosed by brackets [] replaced by
jtulach@1094
    24
 * your own identifying information:
jtulach@1094
    25
 * "Portions Copyrighted [year] [name of copyright owner]"
jtulach@1094
    26
 *
jtulach@1094
    27
 * Contributor(s):
jtulach@1094
    28
 *
jtulach@1094
    29
 * The Original Software is NetBeans. The Initial Developer of the Original
jtulach@1094
    30
 * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
jtulach@1094
    31
 *
jtulach@1094
    32
 * If you wish your version of this file to be governed by only the CDDL
jtulach@1094
    33
 * or only the GPL Version 2, indicate your decision by adding
jtulach@1094
    34
 * "[Contributor] elects to include this software in this distribution
jtulach@1094
    35
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
jtulach@1094
    36
 * single choice of license, a recipient has the option to distribute
jtulach@1094
    37
 * your version of this file under either the CDDL, the GPL Version 2 or
jtulach@1094
    38
 * to extend the choice of license to its licensees as provided above.
jtulach@1094
    39
 * However, if you add GPL Version 2 code and therefore, elected the GPL
jtulach@1094
    40
 * Version 2 license, then the option applies only if the new code is
jtulach@1094
    41
 * made subject to such option by the copyright holder.
jtulach@1094
    42
 */
jtulach@1094
    43
package net.java.html.boot.truffle;
jtulach@1094
    44
jtulach@1094
    45
import com.oracle.truffle.api.CallTarget;
jtulach@1096
    46
import com.oracle.truffle.api.Truffle;
jtulach@1094
    47
import com.oracle.truffle.api.TruffleLanguage;
jtulach@1094
    48
import com.oracle.truffle.api.interop.TruffleObject;
jtulach@1094
    49
import com.oracle.truffle.api.interop.java.JavaInterop;
jtulach@1094
    50
import com.oracle.truffle.api.source.Source;
jtulach@1094
    51
import com.oracle.truffle.api.vm.PolyglotEngine;
jtulach@1094
    52
import java.io.Closeable;
jtulach@1094
    53
import java.io.IOException;
jtulach@1094
    54
import java.io.Reader;
jtulach@1094
    55
import java.net.URL;
jtulach@1094
    56
import java.util.ArrayList;
jtulach@1094
    57
import java.util.List;
jtulach@1094
    58
import java.util.concurrent.Executor;
jtulach@1094
    59
import org.netbeans.html.boot.spi.Fn;
jtulach@1094
    60
import org.netbeans.html.boot.spi.Fn.Presenter;
jtulach@1094
    61
jtulach@1094
    62
/**
jtulach@1094
    63
 * Implementation of {@link Presenter} that delegates to Truffle.
jtulach@1094
    64
 *
jtulach@1094
    65
 * @author Jaroslav Tulach
jtulach@1094
    66
 */
jtulach@1094
    67
final class TrufflePresenter implements Fn.KeepAlive,
jtulach@1094
    68
    Presenter, Fn.FromJavaScript, Fn.ToJavaScript, Executor {
jtulach@1094
    69
jtulach@1094
    70
    private Eval eval;
jtulach@1094
    71
    private WrapArray copy;
jtulach@1094
    72
    private final Executor exc;
jtulach@1098
    73
    private final CallTarget isNull;
jtulach@1098
    74
    private final CallTarget isArray;
jtulach@1094
    75
jtulach@1094
    76
    TrufflePresenter(Executor exc, TruffleObject eval) {
jtulach@1094
    77
        this.exc = exc;
jtulach@1094
    78
        this.eval = eval == null ? null : JavaInterop.asJavaFunction(Eval.class, eval);
jtulach@1098
    79
        this.isNull = Truffle.getRuntime().createCallTarget(new IsNullNode());
jtulach@1098
    80
        this.isArray = Truffle.getRuntime().createCallTarget(new IsArrayNode());
jtulach@1094
    81
    }
jtulach@1094
    82
jtulach@1094
    83
    @Override
jtulach@1094
    84
    public Fn defineFn(String code, String... names) {
jtulach@1094
    85
        return defineImpl(code, names, null);
jtulach@1094
    86
    }
jtulach@1094
    87
jtulach@1094
    88
    @Override
jtulach@1094
    89
    public Fn defineFn(String code, String[] names, boolean[] keepAlive) {
jtulach@1094
    90
        return defineImpl(code, names, keepAlive);
jtulach@1094
    91
    }
jtulach@1094
    92
jtulach@1094
    93
    private FnImpl defineImpl(String code, String[] names, boolean[] keepAlive) {
jtulach@1094
    94
        StringBuilder sb = new StringBuilder();
jtulach@1094
    95
        sb.append("(function() {\n");
jtulach@1094
    96
        sb.append("  return function(");
jtulach@1094
    97
        String sep = "";
jtulach@1102
    98
        for (String n : names) {
jtulach@1102
    99
            sb.append(sep).append(n);
jtulach@1102
   100
            sep = ",";
jtulach@1094
   101
        }
jtulach@1094
   102
        sb.append(") {\n");
jtulach@1094
   103
        sb.append(code);
jtulach@1094
   104
        sb.append("\n  };\n");
jtulach@1094
   105
        sb.append("})()\n");
jtulach@1094
   106
jtulach@1094
   107
        TruffleObject fn = (TruffleObject) getEval().eval(sb.toString());
jtulach@1096
   108
        return new FnImpl(this, fn, names.length);
jtulach@1094
   109
    }
jtulach@1094
   110
jtulach@1094
   111
    @Override
jtulach@1094
   112
    public void displayPage(URL page, Runnable onPageLoad) {
jtulach@1094
   113
        if (onPageLoad != null) {
jtulach@1094
   114
            onPageLoad.run();
jtulach@1094
   115
        }
jtulach@1094
   116
    }
jtulach@1094
   117
jtulach@1094
   118
    @Override
jtulach@1094
   119
    public void loadScript(Reader code) throws Exception {
jtulach@1102
   120
        Source src = Source.newBuilder(code).
jtulach@1102
   121
            name("unknown.js").
jtulach@1102
   122
            mimeType("text/javascript").
jtulach@1102
   123
            build();
jtulach@1094
   124
        getEval().eval(src.getCode());
jtulach@1094
   125
    }
jtulach@1094
   126
jtulach@1094
   127
    interface WrapArray {
jtulach@1094
   128
        public Object copy(Object arr);
jtulach@1094
   129
    }
jtulach@1094
   130
jtulach@1094
   131
    interface Eval {
jtulach@1094
   132
        public Object eval(String code);
jtulach@1094
   133
    }
jtulach@1094
   134
jtulach@1094
   135
    final Object checkArray(Object val) throws Exception {
jtulach@1094
   136
        if (val instanceof TruffleObject) {
jtulach@1094
   137
            final TruffleObject truffleObj = (TruffleObject)val;
jtulach@1098
   138
            boolean hasSize = (boolean) isArray.call(truffleObj);
jtulach@1098
   139
            if (hasSize) {
jtulach@1098
   140
                List<?> list = JavaInterop.asJavaObject(List.class, truffleObj);
jtulach@1098
   141
                Object[] arr = list.toArray();
jtulach@1098
   142
                for (int i = 0; i < arr.length; i++) {
jtulach@1098
   143
                    arr[i] = toJava(arr[i]);
jtulach@1094
   144
                }
jtulach@1098
   145
                return arr;
jtulach@1094
   146
            }
jtulach@1094
   147
        }
jtulach@1094
   148
        return val;
jtulach@1094
   149
    }
jtulach@1094
   150
jtulach@1094
   151
    @Override
jtulach@1094
   152
    public Object toJava(Object jsArray) {
jtulach@1094
   153
        if (jsArray instanceof JavaValue) {
jtulach@1094
   154
            jsArray = ((JavaValue) jsArray).get();
jtulach@1094
   155
        }
jtulach@1094
   156
        if (jsArray instanceof TruffleObject) {
jtulach@1098
   157
            boolean checkNull = (boolean) isNull.call(jsArray);
jtulach@1098
   158
            if (checkNull) {
jtulach@1098
   159
                return null;
jtulach@1094
   160
            }
jtulach@1094
   161
        }
jtulach@1094
   162
        try {
jtulach@1094
   163
            return checkArray(jsArray);
jtulach@1094
   164
        } catch (Exception ex) {
jtulach@1094
   165
            throw new IllegalStateException(ex);
jtulach@1094
   166
        }
jtulach@1094
   167
    }
jtulach@1094
   168
jtulach@1094
   169
    @Override
jtulach@1094
   170
    public Object toJavaScript(Object conv) {
jtulach@1094
   171
        return JavaValue.toJavaScript(conv, getWrap());
jtulach@1094
   172
    }
jtulach@1094
   173
jtulach@1094
   174
    @Override
jtulach@1094
   175
    public void execute(final Runnable command) {
jtulach@1094
   176
        if (Fn.activePresenter() == this) {
jtulach@1094
   177
            command.run();
jtulach@1094
   178
            return;
jtulach@1094
   179
        }
jtulach@1094
   180
jtulach@1094
   181
        class Wrap implements Runnable {
jtulach@1094
   182
jtulach@1102
   183
            @Override
jtulach@1094
   184
            public void run() {
jtulach@1094
   185
                try (Closeable c = Fn.activate(TrufflePresenter.this)) {
jtulach@1094
   186
                    command.run();
jtulach@1094
   187
                } catch (IOException ex) {
jtulach@1094
   188
                    throw new IllegalStateException(ex);
jtulach@1094
   189
                }
jtulach@1094
   190
            }
jtulach@1094
   191
        }
jtulach@1094
   192
        final Runnable wrap = new Wrap();
jtulach@1094
   193
        if (exc == null) {
jtulach@1094
   194
            wrap.run();
jtulach@1094
   195
        } else {
jtulach@1094
   196
            exc.execute(wrap);
jtulach@1094
   197
        }
jtulach@1094
   198
    }
jtulach@1094
   199
jtulach@1094
   200
    private Eval getEval() {
jtulach@1094
   201
        if (eval == null) {
jtulach@1094
   202
            try {
jtulach@1094
   203
                PolyglotEngine engine = PolyglotEngine.newBuilder().build();
jtulach@1094
   204
                TruffleObject fn = (TruffleObject) engine.eval(
jtulach@1102
   205
                    Source.newBuilder("eval.bind(this)").
jtulach@1102
   206
                        mimeType("text/javascript").
jtulach@1102
   207
                        name("eval.js").build()
jtulach@1094
   208
                ).get();
jtulach@1094
   209
                eval = JavaInterop.asJavaFunction(Eval.class, fn);
jtulach@1094
   210
            } catch (IOException ex) {
jtulach@1094
   211
                throw new IllegalStateException(ex);
jtulach@1094
   212
            }
jtulach@1094
   213
        }
jtulach@1094
   214
        return eval;
jtulach@1094
   215
    }
jtulach@1094
   216
jtulach@1094
   217
    private WrapArray getWrap() {
jtulach@1094
   218
        if (copy == null) {
jtulach@1094
   219
            TruffleObject fn = (TruffleObject) getEval().eval("(function(arr) {\n"
jtulach@1094
   220
                + "  var n = [];\n"
jtulach@1094
   221
                + "  for (var i = 0; i < arr.length; i++) {\n"
jtulach@1094
   222
                + "    n[i] = arr[i];\n"
jtulach@1094
   223
                + "  }\n"
jtulach@1094
   224
                + "  return n;\n"
jtulach@1094
   225
                + "}).bind(this)"
jtulach@1094
   226
            );
jtulach@1094
   227
            copy = JavaInterop.asJavaFunction(WrapArray.class, fn);
jtulach@1094
   228
        }
jtulach@1094
   229
        return copy;
jtulach@1094
   230
    }
jtulach@1094
   231
jtulach@1094
   232
    private class FnImpl extends Fn {
jtulach@1094
   233
jtulach@1094
   234
        private final CallTarget fn;
jtulach@1094
   235
jtulach@1096
   236
        public FnImpl(Presenter presenter, TruffleObject fn, int arity) {
jtulach@1094
   237
            super(presenter);
jtulach@1096
   238
            this.fn = Truffle.getRuntime().createCallTarget(new FnRootNode(fn, arity));
jtulach@1094
   239
        }
jtulach@1094
   240
jtulach@1094
   241
        @Override
jtulach@1094
   242
        public Object invoke(Object thiz, Object... args) throws Exception {
jtulach@1094
   243
            List<Object> all = new ArrayList<>(args.length + 1);
jtulach@1094
   244
            all.add(thiz == null ? fn : toJavaScript(thiz));
jtulach@1102
   245
            for (Object conv : args) {
jtulach@1094
   246
                conv = toJavaScript(conv);
jtulach@1094
   247
                all.add(conv);
jtulach@1094
   248
            }
jtulach@1094
   249
            Object ret = fn.call(all.toArray());
jtulach@1094
   250
            if (ret instanceof JavaValue) {
jtulach@1094
   251
                ret = ((JavaValue)ret).get();
jtulach@1094
   252
            }
jtulach@1094
   253
            if (ret == fn) {
jtulach@1094
   254
                return null;
jtulach@1094
   255
            }
jtulach@1094
   256
            return toJava(ret);
jtulach@1094
   257
        }
jtulach@1094
   258
    }
jtulach@1094
   259
jtulach@1094
   260
    static abstract class JavaLang extends TruffleLanguage<Object> {
jtulach@1094
   261
    }
jtulach@1094
   262
}