optimize the ast (eliminate (function(_) e)(null) calls)

treat function literals as synchronized by default
This commit is contained in:
ncannasse
2018-09-19 18:45:07 +02:00
parent 1ac194ed1d
commit e407b2a307
+28 -18
View File
@@ -79,8 +79,10 @@ class Async {
function buildSync( e : Expr, exit : Expr ) : Expr {
switch( expr(e) ) {
case EFunction(_):
return toCps(e, null, null);
case EFunction(_,_,name,_):
if( name != null )
return toCps(e, null, null);
return e;
case EBlock(el):
var v = saveVars();
for( e in el )
@@ -96,7 +98,7 @@ class Async {
case EBreak if( currentBreak != null ):
return currentBreak(e);
case EContinue if( currentLoop != null ):
return block([call(currentLoop, [nullId], e), mk(EReturn(),e)],e);
return block([retNull(currentLoop, e), mk(EReturn(),e)],e);
case EFor(_), EWhile(_):
var oldLoop = currentLoop, oldBreak = currentBreak;
currentLoop = null;
@@ -106,7 +108,7 @@ class Async {
currentBreak = oldBreak;
return e;
case EReturn(eret) if( exit != null ):
return block([call(exit,[eret == null ? nullId : eret], e), mk(EReturn(),e)], e);
return block([eret == null ? retNull(exit, e) : call(exit,[eret], e), mk(EReturn(),e)], e);
default:
return Tools.map(e, buildSync.bind(_, exit));
}
@@ -133,7 +135,9 @@ class Async {
return mk(EFunction([for( a in arg ) { name : a, t : null }], e, name), e);
}
inline function block(arr, e) {
inline function block(arr:Array<Expr>, e) {
if( arr.length == 1 && expr(arr[0]).match(EBlock(_)) )
return arr[0];
return mk(EBlock(arr), e);
}
@@ -149,8 +153,12 @@ class Async {
return mk(ECall(e, args), inf);
}
function retNull(e) : Expr {
return call(e, [nullId],e);
function retNull(e:Expr,?pos) : Expr {
switch( expr(e) ) {
case EFunction([{name:"_"}], e, _, _): return e;
default:
}
return call(e, [nullId], pos == null ? e : pos);
}
function makeCall( ecall, args : Array<Expr>, rest : Expr, exit, sync = false ) {
@@ -179,7 +187,9 @@ class Async {
if( !syncFlag )
return;
switch( expr(e) ) {
case ECall(_), EFunction(_):
case ECall(_):
syncFlag = false;
case EFunction(_,_,name,_) if( name != null ):
syncFlag = false;
case EMeta("sync" | "async", _, _):
// isolated from the sync part
@@ -206,7 +216,7 @@ class Async {
// local recursion
for( e in el )
switch( expr(e) ) {
case EFunction(_, _, name, null): varNames.push(name);
case EFunction(_, _, name, null): if( name != null ) varNames.push(name);
default:
}
while( el.length > 0 ) {
@@ -250,7 +260,7 @@ class Async {
var oldLoop = currentLoop, oldBreak = currentBreak;
var loop = ident("_loop" + id,e);
currentLoop = loop;
currentBreak = function(inf) return block([call(rest, [nullId], inf), mk(EReturn(),inf)], inf);
currentBreak = function(inf) return block([retNull(rest, inf), mk(EReturn(),inf)], inf);
var efor = block([
mk(EVar("_i" + id, call(ident("makeIterator",eit),[eit],eit)),eit),
fun("_", block([
@@ -258,7 +268,7 @@ class Async {
mk(EVar(v, call(field(it, "next",it), [], it)), it),
toCps(eloop, loop, exit),
], it),"_loop" + id),
call(loop, [nullId], e),
retNull(loop, e),
], e);
currentLoop = oldLoop;
currentBreak = oldBreak;
@@ -306,18 +316,18 @@ class Async {
var loop = ident("_loop" + id, cond);
var oldLoop = currentLoop, oldBreak = currentBreak;
currentLoop = loop;
currentBreak = function(e) return block([call(rest, [nullId], e), mk(EReturn(),e)],e);
currentBreak = function(e) return block([retNull(rest,e), mk(EReturn(),e)],e);
var ewhile = block([
fun("_r",
toCps(cond, fun("_c", mk(EIf(ident("_c", cond), toCps(ewh, loop, exit), call(rest, [nullId], cond)),cond)), exit)
toCps(cond, fun("_c", mk(EIf(ident("_c", cond), toCps(ewh, loop, exit), retNull(rest,cond)),cond)), exit)
, "_loop"+id),
call(loop, [nullId], cond),
retNull(loop, cond),
],e);
currentLoop = oldLoop;
currentBreak = oldBreak;
return ewhile;
case EReturn(eret):
return eret == null ? call(exit, [nullId], e) : toCps(eret, exit, exit);
return eret == null ? retNull(exit, e) : toCps(eret, exit, exit);
case EObject(fields):
var id = "_o" + uid++;
var rest = call(rest, [ident(id,e)], e);
@@ -353,10 +363,10 @@ class Async {
return toCps(earr, fun(id1, toCps(eindex, fun(id2, call(rest, [mk(EArray(ident(id1,e), ident(id2,e)),e)], e)), exit)), exit);
case EVar(v, t, ev):
if( ev == null )
return block([e, call(rest, [nullId],e)], e);
return block([e, retNull(rest, e)], e);
return block([
mk(EVar(v, t),e),
toCps(ev, fun("_r", block([binop("=", ident(v,e), ident("_r",e), e), call(rest,[nullId],e)], e)), exit),
toCps(ev, fun("_r", block([binop("=", ident(v,e), ident("_r",e), e), retNull(rest,e)], e)), exit),
],e);
case EConst(_), EIdent(_), EUnop(_), EField(_):
return call(rest, [e], e);
@@ -375,7 +385,7 @@ class Async {
return currentBreak(e);
case EContinue:
if( currentLoop == null ) throw "Continue outside loop";
return block([call(currentLoop, [nullId], e), mk(EReturn(),e)], e);
return block([retNull(currentLoop, e), mk(EReturn(),e)], e);
case ESwitch(v, cases, def):
var cases = [for( c in cases ) { values : c.values, expr : toCps(c.expr, rest, exit) } ];
return toCps(v, mk(EFunction([ { name : "_c", t : null } ], mk(ESwitch(ident("_c",v), cases, def == null ? retNull(rest) : toCps(def, rest, exit)),e)),e), exit );