Giving the flow analyzer chance to generate the whole function body flow
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Fri, 11 Sep 2015 14:51:09 +0200
branchflow
changeset 1842dd4dabfead82
parent 1841 e38cdcd3c997
Giving the flow analyzer chance to generate the whole function body
rt/flow/src/main/java/org/apidesign/bck2brwsr/flow/GraalFlowAnalyzer.java
rt/flow/src/test/java/org/apidesign/bck2brwsr/flow/LoopControlTest.java
rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java
rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java
     1.1 --- a/rt/flow/src/main/java/org/apidesign/bck2brwsr/flow/GraalFlowAnalyzer.java	Fri Sep 11 14:23:06 2015 +0200
     1.2 +++ b/rt/flow/src/main/java/org/apidesign/bck2brwsr/flow/GraalFlowAnalyzer.java	Fri Sep 11 14:51:09 2015 +0200
     1.3 @@ -17,6 +17,7 @@
     1.4   */
     1.5  package org.apidesign.bck2brwsr.flow;
     1.6  
     1.7 +import java.io.IOException;
     1.8  import org.apidesign.vm4brwsr.Bck2Brwsr;
     1.9  
    1.10  /** Poweful flow analyzer. Based on internals used by Graal JVM
    1.11 @@ -39,10 +40,11 @@
    1.12          }
    1.13  
    1.14          @Override
    1.15 -        public boolean analyze(final Bck2Brwsr.Flow result) {
    1.16 -            // Delete the previous line and fix pom.xml, David.
    1.17 +        public boolean analyze(final Bck2Brwsr.Flow result) throws IOException {
    1.18 +            // Use Graal to generate optimal function, David.
    1.19              double x = com.oracle.graal.api.directives.GraalDirectives.FASTPATH_PROBABILITY;
    1.20 -            return false;
    1.21 +            result.emit("function() { return 922869; }");
    1.22 +            return true;
    1.23          }
    1.24      }
    1.25  }
     2.1 --- a/rt/flow/src/test/java/org/apidesign/bck2brwsr/flow/LoopControlTest.java	Fri Sep 11 14:23:06 2015 +0200
     2.2 +++ b/rt/flow/src/test/java/org/apidesign/bck2brwsr/flow/LoopControlTest.java	Fri Sep 11 14:51:09 2015 +0200
     2.3 @@ -17,6 +17,7 @@
     2.4   */
     2.5  package org.apidesign.bck2brwsr.flow;
     2.6  
     2.7 +import java.io.IOException;
     2.8  import javax.script.ScriptEngine;
     2.9  import javax.script.ScriptEngineManager;
    2.10  import javax.script.ScriptException;
    2.11 @@ -43,7 +44,7 @@
    2.12          class MyFlow implements Flow.Analyzer {
    2.13              boolean called;
    2.14              @Override
    2.15 -            public boolean analyze(Flow request) {
    2.16 +            public boolean analyze(Flow request) throws IOException {
    2.17                  if (
    2.18                      request.getMethodName().equals("simpleLoopTest") ||
    2.19                      request.getMethodName().equals("simpleLoopTestWithExit") ||
     3.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java	Fri Sep 11 14:23:06 2015 +0200
     3.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java	Fri Sep 11 14:51:09 2015 +0200
     3.3 @@ -422,10 +422,10 @@
     3.4       */
     3.5      public static final class Flow {
     3.6          private final MethodData m;
     3.7 -        private byte[] ops;
     3.8 -        Flow(MethodData m) {
     3.9 +        private final Appendable emit;
    3.10 +        Flow(MethodData m, Appendable emit) {
    3.11              this.m = m;
    3.12 -            ops = new byte[m.getCode().length];
    3.13 +            this.emit = emit;
    3.14          }
    3.15          
    3.16          /** Access to bytecode of the method to analyse.
    3.17 @@ -442,47 +442,12 @@
    3.18          public String getMethodName() {
    3.19              return m.getName();
    3.20          }
    3.21 -        
    3.22 -        public void beginLoopAt(int bci) {
    3.23 -            ops[bci] |= 0x10;
    3.24 -        }
    3.25 -        
    3.26 -        public void beginIfAt(int bci) {
    3.27 -            ops[bci] |= 0x20;
    3.28 -        }
    3.29  
    3.30 -
    3.31 -        public void breakAt(int bci) {
    3.32 -            ops[bci] |= 0x40;
    3.33 -        }
    3.34 -
    3.35 -        public void beginElseAt(int bci) {
    3.36 -            ops[bci] |= 0x80;
    3.37 -        }
    3.38 -
    3.39 -        public void endAt(int bci) {
    3.40 -            int cnt = (ops[bci] & 0x0f) + 1;
    3.41 -            int rest = ops[bci] & 0xf0;
    3.42 -            ops[bci] = (byte)(rest | cnt);
    3.43 -        }
    3.44 -        
    3.45 -        boolean isFlow(int at) {
    3.46 -            return ops[at] != 0;
    3.47 -        }
    3.48 -        boolean isLoop(int at) {
    3.49 -            return (ops[at] & 0x10) != 0;
    3.50 -        }
    3.51 -        boolean isIf(int at) {
    3.52 -            return (ops[at] & 0x20) != 0;
    3.53 -        }
    3.54 -        boolean isBreak(int at) {
    3.55 -            return (ops[at] & 0x40) != 0;
    3.56 -        }
    3.57 -        boolean isElse(int at) {
    3.58 -            return (ops[at] & 0x80) != 0;
    3.59 -        }
    3.60 -        int isEnd(int at) {
    3.61 -            return (ops[at] & 0x0f);
    3.62 +        /** Emits JavaScript to the final JavaScript output.
    3.63 +         * @param seq text to emit
    3.64 +         */
    3.65 +        public void emit(CharSequence seq) throws IOException {
    3.66 +            this.emit.append(seq);
    3.67          }
    3.68          
    3.69          /** Provider of advanced analysis of the code flow inside of
    3.70 @@ -500,7 +465,7 @@
    3.71               * @return <code>true</code> if the analysis was successful,
    3.72               *   <code>false</code> otherwise
    3.73               */
    3.74 -            public boolean analyze(Flow request);
    3.75 +            public boolean analyze(Flow request) throws IOException;
    3.76          }
    3.77      }
    3.78      
     4.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Fri Sep 11 14:23:06 2015 +0200
     4.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Fri Sep 11 14:51:09 2015 +0200
     4.3 @@ -22,6 +22,15 @@
     4.4  import org.apidesign.bck2brwsr.core.JavaScriptBody;
     4.5  import org.apidesign.vm4brwsr.Bck2Brwsr.Flow;
     4.6  import static org.apidesign.vm4brwsr.ByteCodeParser.*;
     4.7 +import org.apidesign.vm4brwsr.ByteCodeParser.AnnotationParser;
     4.8 +import org.apidesign.vm4brwsr.ByteCodeParser.BootMethodData;
     4.9 +import org.apidesign.vm4brwsr.ByteCodeParser.CPX2;
    4.10 +import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
    4.11 +import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
    4.12 +import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
    4.13 +import org.apidesign.vm4brwsr.ByteCodeParser.StackMapIterator;
    4.14 +import org.apidesign.vm4brwsr.ByteCodeParser.TrapData;
    4.15 +import org.apidesign.vm4brwsr.ByteCodeParser.TrapDataIterator;
    4.16  
    4.17  /** Translator of the code inside class files to JavaScript.
    4.18   *
    4.19 @@ -429,10 +438,21 @@
    4.20          
    4.21          if (defineProp) {
    4.22              append("Object.defineProperty(").append(destObject).
    4.23 -            append(", '").append(name).append("', { configurable: true, writable: true, value: m = function(");
    4.24 +            append(", '").append(name).append("', { configurable: true, writable: true, value: m = ");
    4.25          } else {
    4.26 -            append("m = ").append(destObject).append(".").append(name).append(" = function(");
    4.27 +            append("m = ").append(destObject).append(".").append(name).append(" = ");
    4.28          }
    4.29 +        Flow flow = checkFlow(m);
    4.30 +        if (flow != null) {
    4.31 +            // OK, assume generate
    4.32 +            if (defineProp) {
    4.33 +                append("\n});");
    4.34 +            } else {
    4.35 +                append("\n;");
    4.36 +            }
    4.37 +            return defineProp;
    4.38 +        }
    4.39 +        append("function(");
    4.40          lmapper.outputArguments(this, m.isStatic());
    4.41          append(") {").append("\n");
    4.42  
    4.43 @@ -450,7 +470,6 @@
    4.44              }
    4.45              return defineProp;
    4.46          }
    4.47 -        Flow flow = checkFlow(m);
    4.48  
    4.49          final StackMapper smapper = new StackMapper();
    4.50  
    4.51 @@ -504,16 +523,8 @@
    4.52                  lastStackFrame = stackMapIterator.getFrameIndex();
    4.53                  lmapper.syncWithFrameLocals(stackMapIterator.getFrameLocals());
    4.54                  smapper.syncWithFrameStack(stackMapIterator.getFrameStack());
    4.55 -                if (flow == null) {
    4.56 -                    append("    X_" + i).append(": for (;;) { IF: if (gt <= " + i + ") {\n");
    4.57 -                    openBraces++;
    4.58 -                } else {
    4.59 -                    if (!flow.isFlow(i)) {
    4.60 -                        if (i != 0) {
    4.61 -                            throw new IOException("Expecting flow suggestion at " + i);
    4.62 -                        }
    4.63 -                    }
    4.64 -                }
    4.65 +                append("    X_" + i).append(": for (;;) { IF: if (gt <= " + i + ") {\n");
    4.66 +                openBraces++;
    4.67                  changeInCatch = true;
    4.68              } else {
    4.69                  debug("    /* " + i + " */ ");
    4.70 @@ -522,20 +533,6 @@
    4.71                  append("try {");
    4.72                  previousTrap = trap.current();
    4.73              }
    4.74 -            if (flow != null) {
    4.75 -                if (flow.isLoop(i)) {
    4.76 -                    append("    for (;;) {\n");
    4.77 -                } 
    4.78 -                if (flow.isBreak(i)) {
    4.79 -                    append("\n    break;");
    4.80 -                }
    4.81 -                for (int j = 0; j < flow.isEnd(i); j++) {
    4.82 -                    append("\n    }");
    4.83 -                }
    4.84 -                if (flow.isElse(i)) {
    4.85 -                    append("    else {\n");
    4.86 -                }
    4.87 -            }
    4.88              final int c = readUByte(byteCodes, i);
    4.89              switch (c) {
    4.90                  case opc_aload_0:
    4.91 @@ -2303,13 +2300,6 @@
    4.92      }
    4.93  
    4.94      private static void goTo(Appendable out, Flow flow, int current, int to, int canBack) throws IOException {
    4.95 -        if (flow != null) {
    4.96 -            if (flow.isIf(current)) {
    4.97 -                out.append("{");
    4.98 -                return;
    4.99 -            }
   4.100 -            throw new IllegalStateException("Opn: ");
   4.101 -        }
   4.102          if (to < current) {
   4.103              if (canBack < to) {
   4.104                  out.append("{ gt = 0; continue X_" + to + "; }");
   4.105 @@ -2498,7 +2488,7 @@
   4.106          System.err.println(msg);
   4.107      }
   4.108  
   4.109 -    protected Flow checkFlow(MethodData byteCodes) {
   4.110 +    protected Flow checkFlow(MethodData byteCodes) throws IOException {
   4.111          return null;
   4.112      }
   4.113  }
     5.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java	Fri Sep 11 14:23:06 2015 +0200
     5.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java	Fri Sep 11 14:51:09 2015 +0200
     5.3 @@ -425,11 +425,11 @@
     5.4      }
     5.5  
     5.6      @Override
     5.7 -    protected Flow checkFlow(MethodData byteCodes) {
     5.8 +    protected Flow checkFlow(MethodData byteCodes) throws IOException {
     5.9          if (flow == null) {
    5.10              return null;
    5.11          }
    5.12 -        Flow f = new Flow(byteCodes);
    5.13 +        Flow f = new Flow(byteCodes, this);
    5.14          return flow.analyze(f) ? f : null;
    5.15      }
    5.16