diff --git a/teavm-samples/teavm-samples-async/pom.xml b/teavm-samples/teavm-samples-async/pom.xml index b04494c1b..23133d3ec 100644 --- a/teavm-samples/teavm-samples-async/pom.xml +++ b/teavm-samples/teavm-samples-async/pom.xml @@ -64,7 +64,7 @@ ${project.build.directory}/generated/js/teavm org.teavm.samples.async.AsyncProgram SEPARATE - false + true true true true diff --git a/teavm-samples/teavm-samples-async/src/main/webapp/highlight.pack.js b/teavm-samples/teavm-samples-async/src/main/webapp/highlight.pack.js new file mode 100644 index 000000000..1225a13e2 --- /dev/null +++ b/teavm-samples/teavm-samples-async/src/main/webapp/highlight.pack.js @@ -0,0 +1 @@ +!function(e){"undefined"!=typeof exports?e(exports):(window.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return window.hljs}))}(function(e){function n(e){return e.replace(/&/gm,"&").replace(//gm,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0==t.index}function a(e){var n=(e.className+" "+(e.parentNode?e.parentNode.className:"")).split(/\s+/);return n=n.map(function(e){return e.replace(/^lang(uage)?-/,"")}),n.filter(function(e){return N(e)||/no(-?)highlight/.test(e)})[0]}function o(e,n){var t={};for(var r in e)t[r]=e[r];if(n)for(var r in n)t[r]=n[r];return t}function i(e){var n=[];return function r(e,a){for(var o=e.firstChild;o;o=o.nextSibling)3==o.nodeType?a+=o.nodeValue.length:1==o.nodeType&&(n.push({event:"start",offset:a,node:o}),a=r(o,a),t(o).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:o}));return a}(e,0),n}function c(e,r,a){function o(){return e.length&&r.length?e[0].offset!=r[0].offset?e[0].offset"}function c(e){l+=""}function u(e){("start"==e.event?i:c)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=o();if(l+=n(a.substr(s,g[0].offset-s)),s=g[0].offset,g==e){f.reverse().forEach(c);do u(g.splice(0,1)[0]),g=o();while(g==e&&g.length&&g[0].offset==s);f.reverse().forEach(i)}else"start"==g[0].event?f.push(g[0].node):f.pop(),u(g.splice(0,1)[0])}return l+n(a.substr(s))}function u(e){function n(e){return e&&e.source||e}function t(t,r){return RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var c={},u=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");c[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?u("keyword",a.k):Object.keys(a.k).forEach(function(e){u(e,a.k[e])}),a.k=c}a.lR=t(a.l||/\b[A-Za-z0-9_]+\b/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),void 0===a.r&&(a.r=1),a.c||(a.c=[]);var s=[];a.c.forEach(function(e){e.v?e.v.forEach(function(n){s.push(o(e,n))}):s.push("self"==e?a:e)}),a.c=s,a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var l=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=l.length?t(l.join("|"),!0):{exec:function(){return null}}}}r(e)}function s(e,t,a,o){function i(e,n){for(var t=0;t";return o+=e+'">',o+n+i}function d(){if(!w.k)return n(y);var e="",t=0;w.lR.lastIndex=0;for(var r=w.lR.exec(y);r;){e+=n(y.substr(t,r.index-t));var a=g(w,r);a?(B+=a[1],e+=p(a[0],n(r[0]))):e+=n(r[0]),t=w.lR.lastIndex,r=w.lR.exec(y)}return e+n(y.substr(t))}function h(){if(w.sL&&!R[w.sL])return n(y);var e=w.sL?s(w.sL,y,!0,L[w.sL]):l(y);return w.r>0&&(B+=e.r),"continuous"==w.subLanguageMode&&(L[w.sL]=e.top),p(e.language,e.value,!1,!0)}function v(){return void 0!==w.sL?h():d()}function b(e,t){var r=e.cN?p(e.cN,"",!0):"";e.rB?(M+=r,y=""):e.eB?(M+=n(t)+r,y=""):(M+=r,y=t),w=Object.create(e,{parent:{value:w}})}function m(e,t){if(y+=e,void 0===t)return M+=v(),0;var r=i(t,w);if(r)return M+=v(),b(r,t),r.rB?0:t.length;var a=c(w,t);if(a){var o=w;o.rE||o.eE||(y+=t),M+=v();do w.cN&&(M+=""),B+=w.r,w=w.parent;while(w!=a.parent);return o.eE&&(M+=n(t)),y="",a.starts&&b(a.starts,""),o.rE?0:t.length}if(f(t,w))throw new Error('Illegal lexeme "'+t+'" for mode "'+(w.cN||"")+'"');return y+=t,t.length||1}var x=N(e);if(!x)throw new Error('Unknown language: "'+e+'"');u(x);for(var w=o||x,L={},M="",k=w;k!=x;k=k.parent)k.cN&&(M=p(k.cN,"",!0)+M);var y="",B=0;try{for(var C,j,I=0;;){if(w.t.lastIndex=I,C=w.t.exec(t),!C)break;j=m(t.substr(I,C.index-I),C[0]),I=C.index+j}m(t.substr(I));for(var k=w;k.parent;k=k.parent)k.cN&&(M+="");return{r:B,value:M,language:e,top:w}}catch(A){if(-1!=A.message.indexOf("Illegal"))return{r:0,value:n(t)};throw A}}function l(e,t){t=t||E.languages||Object.keys(R);var r={r:0,value:n(e)},a=r;return t.forEach(function(n){if(N(n)){var t=s(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}}),a.language&&(r.second_best=a),r}function f(e){return E.tabReplace&&(e=e.replace(/^((<[^>]+>|\t)+)/gm,function(e,n){return n.replace(/\t/g,E.tabReplace)})),E.useBR&&(e=e.replace(/\n/g,"
")),e}function g(e,n,t){var r=n?x[n]:t,a=[e.trim()];return e.match(/(\s|^)hljs(\s|$)/)||a.push("hljs"),r&&a.push(r),a.join(" ").trim()}function p(e){var n=a(e);if(!/no(-?)highlight/.test(n)){var t;E.useBR?(t=document.createElementNS("http://www.w3.org/1999/xhtml","div"),t.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):t=e;var r=t.textContent,o=n?s(n,r,!0):l(r),u=i(t);if(u.length){var p=document.createElementNS("http://www.w3.org/1999/xhtml","div");p.innerHTML=o.value,o.value=c(u,i(p),r)}o.value=f(o.value),e.innerHTML=o.value,e.className=g(e.className,n,o.language),e.result={language:o.language,re:o.r},o.second_best&&(e.second_best={language:o.second_best.language,re:o.second_best.r})}}function d(e){E=o(E,e)}function h(){if(!h.called){h.called=!0;var e=document.querySelectorAll("pre code");Array.prototype.forEach.call(e,p)}}function v(){addEventListener("DOMContentLoaded",h,!1),addEventListener("load",h,!1)}function b(n,t){var r=R[n]=t(e);r.aliases&&r.aliases.forEach(function(e){x[e]=n})}function m(){return Object.keys(R)}function N(e){return R[e]||R[x[e]]}var E={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},R={},x={};return e.highlight=s,e.highlightAuto=l,e.fixMarkup=f,e.highlightBlock=p,e.configure=d,e.initHighlighting=h,e.initHighlightingOnLoad=v,e.registerLanguage=b,e.listLanguages=m,e.getLanguage=N,e.inherit=o,e.IR="[a-zA-Z][a-zA-Z0-9_]*",e.UIR="[a-zA-Z_][a-zA-Z0-9_]*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such)\b/},e.CLCM={cN:"comment",b:"//",e:"$",c:[e.PWM]},e.CBCM={cN:"comment",b:"/\\*",e:"\\*/",c:[e.PWM]},e.HCM={cN:"comment",b:"#",e:"$",c:[e.PWM]},e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e});hljs.registerLanguage("java",function(e){var a=e.UIR+"(<"+e.UIR+">)?",t="false synchronized int abstract float private char boolean static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private",c="(\\b(0b[01_]+)|\\b0[xX][a-fA-F0-9_]+|(\\b[\\d_]+(\\.[\\d_]*)?|\\.[\\d_]+)([eE][-+]?\\d+)?)[lLfF]?",r={cN:"number",b:c,r:0};return{aliases:["jsp"],k:t,i:/<\//,c:[{cN:"javadoc",b:"/\\*\\*",e:"\\*/",r:0,c:[{cN:"javadoctag",b:"(^|\\s)@[A-Za-z]+"}]},e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"new throw return",r:0},{cN:"function",b:"("+a+"\\s+)+"+e.UIR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:t,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,k:t,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},r,{cN:"annotation",b:"@[A-Za-z]+"}]}}); \ No newline at end of file diff --git a/teavm-samples/teavm-samples-async/src/main/webapp/index.html b/teavm-samples/teavm-samples-async/src/main/webapp/index.html index 96817c4a0..71f93b7a7 100644 --- a/teavm-samples/teavm-samples-async/src/main/webapp/index.html +++ b/teavm-samples/teavm-samples-async/src/main/webapp/index.html @@ -20,8 +20,177 @@ + + + + + - -

Please, open developer's console to view program's output

+ +
This application shows how TeaVM can handle multiple threads and synchronization primitives + (see source code on GitHub).
+ +
+
+
stdout
+
+
+ +
+
Source code
+
+public final class AsyncProgram {
+    private static long start = System.currentTimeMillis();
+
+    private AsyncProgram() {
+    }
+
+    public static void main(String[] args) throws InterruptedException {
+        report(Arrays.toString(args));
+        findPrimes();
+        withoutAsync();
+        report("");
+        withAsync();
+
+        report("");
+        final Object lock = new Object();
+        Thread t = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    doRun(lock);
+                } catch (InterruptedException ex) {
+                    report("Exception caught: " + ex.getMessage());
+                }
+            }
+
+        }, "Test Thread");
+        t.start();
+
+        Thread t2 = new Thread(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    doRun(lock);
+                } catch (InterruptedException ex) {
+                    report("Exception caught: " + ex.getMessage());
+                }
+            }
+        }, "Test Thread 2");
+        t2.start();
+
+        report("Should be main");
+        report("Now trying wait...");
+
+        synchronized (lock) {
+            report("Lock acquired");
+            lock.wait(20000);
+        }
+        report("Finished main thread");
+    }
+
+    private static void findPrimes() {
+        report("Finding primes");
+        boolean[] prime = new boolean[1000];
+        prime[2] = true;
+        prime[3] = true;
+        nextPrime: for (int i = 5; i < prime.length; i += 2) {
+            int maxPrime = (int)Math.sqrt(i);
+            for (int j = 3; j <= maxPrime; j += 2) {
+                Thread.yield();
+                if (prime[j] && i % j == 0) {
+                    continue nextPrime;
+                }
+            }
+            prime[i] = true;
+        }
+        StringBuilder sb = new StringBuilder();
+        for (int i = 0; i < 1000; ++i) {
+            if (prime[i]) {
+                sb.append(i).append(' ');
+            }
+        }
+        report(sb.toString());
+    }
+
+    private static void report(String message) {
+        long current = System.currentTimeMillis() - start;
+        System.out.println("[" + Thread.currentThread().getName() + "]/" + current + ": " + message);
+    }
+
+    private static void doRun(Object lock) throws InterruptedException {
+        report("Executing timer task");
+        Thread.sleep(2000);
+        report("Calling lock.notify()");
+        synchronized (lock) {
+            lock.notify();
+        }
+        report("Finished calling lock.notify()");
+        report("Waiting 5 seconds");
+        Thread.sleep(5000);
+        report("Finished another 5 second sleep");
+
+        synchronized (lock) {
+            report("Sleep inside locked section");
+            Thread.sleep(2000);
+            report("Finished locked section");
+        }
+    }
+
+    private static void withoutAsync() {
+        report("Start sync");
+        for (int i = 0; i < 20; ++i) {
+            StringBuilder sb = new StringBuilder();
+            for (int j = 0; j <= i; ++j) {
+                sb.append(j);
+                sb.append(' ');
+            }
+            report(sb.toString());
+        }
+        report("Complete sync");
+    }
+
+    private static void withAsync() throws InterruptedException {
+        report("Start async");
+        for (int i = 0; i < 20; ++i) {
+            StringBuilder sb = new StringBuilder();
+            for (int j = 0; j <= i; ++j) {
+                sb.append(j);
+                sb.append(' ');
+            }
+            report(sb.toString());
+            if (i % 3 == 0) {
+                report("Suspend for a second");
+                Thread.sleep(1000);
+            }
+        }
+        report("2nd Thread.sleep in same method");
+        Thread.sleep(1000);
+
+        report("Throwing exception");
+        try {
+            throwException();
+        } catch (IllegalStateException e) {
+            report("Exception caught");
+        }
+        report("Complete async");
+    }
+
+    private static void throwException() {
+        Thread.yield();
+        report("Thread.yield called");
+        throw new IllegalStateException();
+    }
+}
+
+ +
+
+ \ No newline at end of file diff --git a/teavm-samples/teavm-samples-async/src/main/webapp/style.css b/teavm-samples/teavm-samples-async/src/main/webapp/style.css new file mode 100644 index 000000000..ca3f74b5f --- /dev/null +++ b/teavm-samples/teavm-samples-async/src/main/webapp/style.css @@ -0,0 +1,62 @@ +html, body { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + margin: 0; + padding: 0; +} + +.block { + position: absolute; + left: 0px; + right: 0px; +} +.block-title { + position: absolute; + top: 10px; + height: 20px; + left: 10px; + right: 10px; + font-weight: bold; +} +.block-content { + position: absolute; + top: 30px; + bottom: 5px; + left: 10px; + right: 10px; + background-color: rgb(240,240,240); + border-width: 1px; + border-style: solid; + border-color: rgb(210,210,210); + overflow: auto; + padding: 3px; + margin: 0; + border-radius: 3px; +} + +#description { + position: absolute; + top: 10px; + height: 40px; + left: 10px; + right: 10px; +} +#blocks { + position: absolute; + top: 50px; + bottom: 0; + left: 0; + right: 0; +} +#stdout-wrapper { + top: 0; + height: 50%; +} +#source-wrapper { + top: 50%; + bottom: 0; +} + diff --git a/teavm-samples/teavm-samples-async/src/main/webapp/syntax.css b/teavm-samples/teavm-samples-async/src/main/webapp/syntax.css new file mode 100644 index 000000000..e4d47b0a7 --- /dev/null +++ b/teavm-samples/teavm-samples-async/src/main/webapp/syntax.css @@ -0,0 +1,12 @@ +.hljs-keyword { + font-weight: bold; +} +.hljs-class .hljs-title { + color: #9BB01D; +} +.hljs-annotation { + color: #FFA500; +} +.hljs-string, .hljs-number { + color: red; +} \ No newline at end of file diff --git a/teavm-samples/teavm-samples-async/src/main/webapp/teavm/stdout.js b/teavm-samples/teavm-samples-async/src/main/webapp/teavm/stdout.js new file mode 100644 index 000000000..cb279b2b8 --- /dev/null +++ b/teavm-samples/teavm-samples-async/src/main/webapp/teavm/stdout.js @@ -0,0 +1,12 @@ +function $rt_putStdout(ch) { + if (ch == 0xA) { + var lineElem = document.createElement("div"); + var stdoutElem = document.getElementById("stdout"); + lineElem.appendChild(document.createTextNode($rt_stdoutBuffer)); + stdoutElem.appendChild(lineElem); + $rt_stdoutBuffer = ""; + stdoutElem.scrollTop = stdoutElem.scrollHeight; + } else { + $rt_stdoutBuffer += String.fromCharCode(ch); + } +}