diff --git a/bytecode.go b/bytecode.go index cfd0d0b..f3049ce 100644 --- a/bytecode.go +++ b/bytecode.go @@ -97,6 +97,7 @@ func (b *Bytecode) RemoveDuplicates() { var deduped []Object indexMap := make(map[int]int) // mapping from old constant index to new index + fns := make(map[*CompiledFunction]int) ints := make(map[int64]int) strings := make(map[string]int) floats := make(map[float64]int) @@ -106,9 +107,14 @@ func (b *Bytecode) RemoveDuplicates() { for curIdx, c := range b.Constants { switch c := c.(type) { case *CompiledFunction: - // add to deduped list - indexMap[curIdx] = len(deduped) - deduped = append(deduped, c) + if newIdx, ok := fns[c]; ok { + indexMap[curIdx] = newIdx + } else { + newIdx = len(deduped) + fns[c] = newIdx + indexMap[curIdx] = newIdx + deduped = append(deduped, c) + } case *ImmutableMap: modName := inferModuleName(c) newIdx, ok := immutableMaps[modName] diff --git a/vm_test.go b/vm_test.go index d451726..0adefe7 100644 --- a/vm_test.go +++ b/vm_test.go @@ -2654,6 +2654,25 @@ export func(a) { expectRun(t, `out = import("mod0")`, Opts().Module("mod0", `for v:=0;;v++ { if v == 3 { break } } }`), 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) {