summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/d5/tengo/compiler/bytecode_optimize.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/d5/tengo/compiler/bytecode_optimize.go')
-rw-r--r--vendor/github.com/d5/tengo/compiler/bytecode_optimize.go129
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 ""
+}