Skip to content

Commit 2d12e51

Browse files
authored
Merge pull request #1137 from nevkontakte/es6-loads
Use ES 2015 syntax to generate more compact code for blocking functions.
2 parents fa8544d + 3067214 commit 2d12e51

File tree

3 files changed

+29
-12
lines changed

3 files changed

+29
-12
lines changed

compiler/package.go

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ func translateFunction(typ *ast.FuncType, recv *ast.Ident, body *ast.BlockStmt,
805805

806806
if len(c.Flattened) != 0 {
807807
c.localVars = append(c.localVars, "$s")
808-
prefix = prefix + " $s = 0;"
808+
prefix = prefix + " $s = $s || 0;"
809809
}
810810

811811
if c.HasDefer {
@@ -816,19 +816,29 @@ func translateFunction(typ *ast.FuncType, recv *ast.Ident, body *ast.BlockStmt,
816816
}
817817
}
818818

819+
localVarDefs := "" // Function-local var declaration at the top.
820+
819821
if len(c.Blocking) != 0 {
820-
c.localVars = append(c.localVars, "$r")
821822
if funcRef == "" {
822823
funcRef = "$b"
823824
functionName = " $b"
824825
}
825-
var stores, loads string
826-
for _, v := range c.localVars {
827-
loads += fmt.Sprintf("%s = $f.%s; ", v, v)
828-
stores += fmt.Sprintf("$f.%s = %s; ", v, v)
829-
}
830-
prefix = prefix + " var $f, $c = false; if (this !== undefined && this.$blk !== undefined) { $f = this; $c = true; " + loads + "}"
831-
suffix = " if ($f === undefined) { $f = { $blk: " + funcRef + " }; } " + stores + "return $f;" + suffix
826+
827+
localVars := append([]string{}, c.localVars...)
828+
// There are several special variables involved in handling blocking functions:
829+
// $r is sometimes used as a temporary variable to store blocking call result.
830+
// $c indicates that a function is being resumed after a blocking call when set to true.
831+
// $f is an object used to save and restore function context for blocking calls.
832+
localVars = append(localVars, "$r")
833+
// If a blocking function is being resumed, initialize local variables from the saved context.
834+
localVarDefs = fmt.Sprintf("var {%s, $c} = $restore(this, {%s});\n", strings.Join(localVars, ", "), strings.Join(params, ", "))
835+
// If the function gets blocked, save local variables for future.
836+
saveContext := fmt.Sprintf("var $f = {$blk: "+funcRef+", $c: true, $r, %s};", strings.Join(c.localVars, ", "))
837+
838+
suffix = " " + saveContext + "return $f;" + suffix
839+
} else if len(c.localVars) > 0 {
840+
// Non-blocking functions simply declare local variables with no need for restore support.
841+
localVarDefs = fmt.Sprintf("var %s;\n", strings.Join(c.localVars, ", "))
832842
}
833843

834844
if c.HasDefer {
@@ -865,8 +875,8 @@ func translateFunction(typ *ast.FuncType, recv *ast.Ident, body *ast.BlockStmt,
865875
if suffix != "" {
866876
bodyOutput = bodyOutput + strings.Repeat("\t", c.pkgCtx.indentation+1) + "/* */" + suffix + "\n"
867877
}
868-
if len(c.localVars) != 0 {
869-
bodyOutput = fmt.Sprintf("%svar %s;\n", strings.Repeat("\t", c.pkgCtx.indentation+1), strings.Join(c.localVars, ", ")) + bodyOutput
878+
if localVarDefs != "" {
879+
bodyOutput = strings.Repeat("\t", c.pkgCtx.indentation+1) + localVarDefs + bodyOutput
870880
}
871881

872882
c.pkgCtx.escapingVars = prevEV

compiler/prelude/goroutines.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,13 @@ var $block = function() {
223223
$curGoroutine.asleep = true;
224224
};
225225
226+
var $restore = function(context, params) {
227+
if (context !== undefined && context.$blk !== undefined) {
228+
return context;
229+
}
230+
return params;
231+
}
232+
226233
var $send = function(chan, value) {
227234
if (chan.$closed) {
228235
$throwRuntimeError("send on closed channel");

0 commit comments

Comments
 (0)