Skip to content

Commit fa93314

Browse files
committed
Reorder Eval tag dispatch for optimized code
1 parent fd0e3c9 commit fa93314

1 file changed

Lines changed: 50 additions & 50 deletions

File tree

scm/scm.go

Lines changed: 50 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -101,25 +101,8 @@ func evalWithSourceInfo(si SourceInfo, en *Env) (value Scmer) {
101101
func Eval(expression Scmer, en *Env) (value Scmer) {
102102
restart:
103103
switch expression.GetTag() {
104-
case tagSourceInfo:
105-
return evalWithSourceInfo(*expression.SourceInfo(), en)
106-
case tagNil, tagBool, tagInt, tagFloat, tagDate, tagString, tagVector, tagFastDict, tagParser, tagAny, tagFunc, tagFuncEnv, tagProc, tagJIT, tagClosure, tagPromise:
107-
// literals
108-
return expression
109-
case tagSymbol:
110-
// get named variable
111-
return en.FindRead(mustSymbol(expression)).Vars[mustSymbol(expression)]
112-
case tagNthLocalVar:
113-
// get numbered variable
114-
idx := int(expression.NthLocalVar())
115-
if idx >= len(en.VarsNumbered) {
116-
buf := make([]byte, 8192)
117-
n := runtime.Stack(buf, false)
118-
panic(fmt.Sprintf("NthLocalVar(%d) out of range (len=%d)\n%s", idx, len(en.VarsNumbered), buf[:n]))
119-
}
120-
return en.VarsNumbered[idx]
121104
case tagSlice:
122-
// slice -> function call
105+
// Hot path: optimized queryplan/runtime code is dominated by call forms.
123106
list := expression.Slice()
124107
if len(list) == 0 {
125108
return expression
@@ -416,6 +399,10 @@ restart:
416399
args[i] = Eval(x, en)
417400
}
418401
return fn(args...)
402+
case tagProc:
403+
// Lambdas (procs)
404+
en, expression = prepareProcCall(procedure.Proc(), operands, en)
405+
goto restart
419406
case tagFuncEnv:
420407
// Native funcs with env
421408
fn := procedure.FuncEnv()
@@ -431,10 +418,34 @@ restart:
431418
args[i] = Eval(x, en)
432419
}
433420
return fn(en, args...)
434-
case tagProc:
435-
// Lambdas (procs)
436-
en, expression = prepareProcCall(procedure.Proc(), operands, en)
437-
goto restart
421+
case tagClosure:
422+
fn := *(*func(uint32, ...Scmer) Scmer)(unsafe.Pointer(procedure.ptr))
423+
id := uint32(auxVal(procedure.aux))
424+
if n := len(operands); n <= 4 {
425+
var buf [4]Scmer
426+
for i := 0; i < n; i++ {
427+
buf[i] = Eval(operands[i], en)
428+
}
429+
return fn(id, buf[:n]...)
430+
}
431+
args := make([]Scmer, len(operands))
432+
for i, x := range operands {
433+
args[i] = Eval(x, en)
434+
}
435+
return fn(id, args...)
436+
case tagPromise:
437+
if n := len(operands); n <= 4 {
438+
var buf [4]Scmer
439+
for i := 0; i < n; i++ {
440+
buf[i] = Eval(operands[i], en)
441+
}
442+
return ApplyPromise(procedure, buf[:n])
443+
}
444+
args := make([]Scmer, len(operands))
445+
for i, x := range operands {
446+
args[i] = Eval(x, en)
447+
}
448+
return ApplyPromise(procedure, args)
438449
case tagSlice:
439450
// Associative list
440451
p := procedure.Slice()
@@ -482,37 +493,26 @@ restart:
482493
args[i] = Eval(x, en)
483494
}
484495
return jep.Native(args...)
485-
case tagClosure:
486-
fn := *(*func(uint32, ...Scmer) Scmer)(unsafe.Pointer(procedure.ptr))
487-
id := uint32(auxVal(procedure.aux))
488-
if n := len(operands); n <= 4 {
489-
var buf [4]Scmer
490-
for i := 0; i < n; i++ {
491-
buf[i] = Eval(operands[i], en)
492-
}
493-
return fn(id, buf[:n]...)
494-
}
495-
args := make([]Scmer, len(operands))
496-
for i, x := range operands {
497-
args[i] = Eval(x, en)
498-
}
499-
return fn(id, args...)
500-
case tagPromise:
501-
if n := len(operands); n <= 4 {
502-
var buf [4]Scmer
503-
for i := 0; i < n; i++ {
504-
buf[i] = Eval(operands[i], en)
505-
}
506-
return ApplyPromise(procedure, buf[:n])
507-
}
508-
args := make([]Scmer, len(operands))
509-
for i, x := range operands {
510-
args[i] = Eval(x, en)
511-
}
512-
return ApplyPromise(procedure, args)
513496
default:
514497
panic("Unknown function: " + list[0].String())
515498
}
499+
case tagNthLocalVar:
500+
// Optimized lambda bodies resolve locals directly through numbered slots.
501+
idx := int(expression.NthLocalVar())
502+
if idx >= len(en.VarsNumbered) {
503+
buf := make([]byte, 8192)
504+
n := runtime.Stack(buf, false)
505+
panic(fmt.Sprintf("NthLocalVar(%d) out of range (len=%d)\n%s", idx, len(en.VarsNumbered), buf[:n]))
506+
}
507+
return en.VarsNumbered[idx]
508+
case tagFunc, tagFuncEnv, tagProc, tagNil, tagBool, tagInt, tagFloat, tagDate, tagString, tagVector, tagFastDict, tagParser, tagJIT, tagClosure, tagPromise, tagAny:
509+
// Self-evaluating literals and optimizer-resolved native callables.
510+
return expression
511+
case tagSymbol:
512+
// Fallback for names not folded to numbered vars/native funcs by the optimizer.
513+
return en.FindRead(mustSymbol(expression)).Vars[mustSymbol(expression)]
514+
case tagSourceInfo:
515+
return evalWithSourceInfo(*expression.SourceInfo(), en)
516516
default:
517517
if expression.GetTag() >= 100 {
518518
// custom tags (e.g. TagTable) are opaque literals

0 commit comments

Comments
 (0)