fix a bug in bytecode optimization code (#292)

* fix a bug in bytecode optimization code

* add a test
This commit is contained in:
daniel 2020-05-23 08:23:33 -07:00 committed by GitHub
parent d08a636e7c
commit d1dd01499f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 3 deletions

View file

@ -97,6 +97,7 @@ func (b *Bytecode) RemoveDuplicates() {
var deduped []Object var deduped []Object
indexMap := make(map[int]int) // mapping from old constant index to new index indexMap := make(map[int]int) // mapping from old constant index to new index
fns := make(map[*CompiledFunction]int)
ints := make(map[int64]int) ints := make(map[int64]int)
strings := make(map[string]int) strings := make(map[string]int)
floats := make(map[float64]int) floats := make(map[float64]int)
@ -106,9 +107,14 @@ func (b *Bytecode) RemoveDuplicates() {
for curIdx, c := range b.Constants { for curIdx, c := range b.Constants {
switch c := c.(type) { switch c := c.(type) {
case *CompiledFunction: case *CompiledFunction:
// add to deduped list if newIdx, ok := fns[c]; ok {
indexMap[curIdx] = len(deduped) indexMap[curIdx] = newIdx
deduped = append(deduped, c) } else {
newIdx = len(deduped)
fns[c] = newIdx
indexMap[curIdx] = newIdx
deduped = append(deduped, c)
}
case *ImmutableMap: case *ImmutableMap:
modName := inferModuleName(c) modName := inferModuleName(c)
newIdx, ok := immutableMaps[modName] newIdx, ok := immutableMaps[modName]

View file

@ -2654,6 +2654,25 @@ export func(a) {
expectRun(t, `out = import("mod0")`, expectRun(t, `out = import("mod0")`,
Opts().Module("mod0", `for v:=0;;v++ { if v == 3 { break } } }`), Opts().Module("mod0", `for v:=0;;v++ { if v == 3 { break } } }`),
tengo.UndefinedValue) tengo.UndefinedValue)
// duplicate compiled functions
// NOTE: module "mod" has a function with some local variable, and it's
// imported twice by the main script. That causes the same CompiledFunction
// put in constants twice and the Bytecode optimization (removing duplicate
// constants) should still work correctly.
expectRun(t, `
m1 := import("mod")
m2 := import("mod")
out = m1.x
`,
Opts().Module("mod", `
f1 := func(a, b) {
c := a + b + 1
return a + b + 1
}
export { x: 1 }
`),
1)
} }
func TestModuleBlockScopes(t *testing.T) { func TestModuleBlockScopes(t *testing.T) {