diff options
Diffstat (limited to 'vendor/github.com/d5/tengo/compiler/bytecode_optimize.go')
-rw-r--r-- | vendor/github.com/d5/tengo/compiler/bytecode_optimize.go | 129 |
1 files changed, 129 insertions, 0 deletions
diff --git a/vendor/github.com/d5/tengo/compiler/bytecode_optimize.go b/vendor/github.com/d5/tengo/compiler/bytecode_optimize.go new file mode 100644 index 00000000..9526de2e --- /dev/null +++ b/vendor/github.com/d5/tengo/compiler/bytecode_optimize.go @@ -0,0 +1,129 @@ +package compiler + +import ( + "fmt" + + "github.com/d5/tengo/objects" +) + +// RemoveDuplicates finds and remove the duplicate values in Constants. +// Note this function mutates Bytecode. +func (b *Bytecode) RemoveDuplicates() { + var deduped []objects.Object + + indexMap := make(map[int]int) // mapping from old constant index to new index + ints := make(map[int64]int) + strings := make(map[string]int) + floats := make(map[float64]int) + chars := make(map[rune]int) + immutableMaps := make(map[string]int) // for modules + + for curIdx, c := range b.Constants { + switch c := c.(type) { + case *objects.CompiledFunction: + // add to deduped list + indexMap[curIdx] = len(deduped) + deduped = append(deduped, c) + case *objects.ImmutableMap: + modName := moduleName(c) + newIdx, ok := immutableMaps[modName] + if modName != "" && ok { + indexMap[curIdx] = newIdx + } else { + newIdx = len(deduped) + immutableMaps[modName] = newIdx + indexMap[curIdx] = newIdx + deduped = append(deduped, c) + } + case *objects.Int: + if newIdx, ok := ints[c.Value]; ok { + indexMap[curIdx] = newIdx + } else { + newIdx = len(deduped) + ints[c.Value] = newIdx + indexMap[curIdx] = newIdx + deduped = append(deduped, c) + } + case *objects.String: + if newIdx, ok := strings[c.Value]; ok { + indexMap[curIdx] = newIdx + } else { + newIdx = len(deduped) + strings[c.Value] = newIdx + indexMap[curIdx] = newIdx + deduped = append(deduped, c) + } + case *objects.Float: + if newIdx, ok := floats[c.Value]; ok { + indexMap[curIdx] = newIdx + } else { + newIdx = len(deduped) + floats[c.Value] = newIdx + indexMap[curIdx] = newIdx + deduped = append(deduped, c) + } + case *objects.Char: + if newIdx, ok := chars[c.Value]; ok { + indexMap[curIdx] = newIdx + } else { + newIdx = len(deduped) + chars[c.Value] = newIdx + indexMap[curIdx] = newIdx + deduped = append(deduped, c) + } + default: + panic(fmt.Errorf("unsupported top-level constant type: %s", c.TypeName())) + } + } + + // replace with de-duplicated constants + b.Constants = deduped + + // update CONST instructions with new indexes + // main function + updateConstIndexes(b.MainFunction.Instructions, indexMap) + // other compiled functions in constants + for _, c := range b.Constants { + switch c := c.(type) { + case *objects.CompiledFunction: + updateConstIndexes(c.Instructions, indexMap) + } + } +} + +func updateConstIndexes(insts []byte, indexMap map[int]int) { + i := 0 + for i < len(insts) { + op := insts[i] + numOperands := OpcodeOperands[op] + _, read := ReadOperands(numOperands, insts[i+1:]) + + switch op { + case OpConstant: + curIdx := int(insts[i+2]) | int(insts[i+1])<<8 + newIdx, ok := indexMap[curIdx] + if !ok { + panic(fmt.Errorf("constant index not found: %d", curIdx)) + } + copy(insts[i:], MakeInstruction(op, newIdx)) + case OpClosure: + curIdx := int(insts[i+2]) | int(insts[i+1])<<8 + numFree := int(insts[i+3]) + newIdx, ok := indexMap[curIdx] + if !ok { + panic(fmt.Errorf("constant index not found: %d", curIdx)) + } + copy(insts[i:], MakeInstruction(op, newIdx, numFree)) + } + + i += 1 + read + } +} + +func moduleName(mod *objects.ImmutableMap) string { + if modName, ok := mod.Value["__module_name__"].(*objects.String); ok { + return modName.Value + } + + return "" +} |