Do not copy variables for target specific variables

167.22user 131.10system 5:27.42elapsed 91%CPU (1355792maxresident)k =>
91.34user 122.72system 3:52.62elapsed 92%CPU (1180900maxresident)k
repo/android.sh time kati --kati_cpuprofile=kati.prof -n
diff --git a/exec.go b/exec.go
index 977cbaa..25c1559 100644
--- a/exec.go
+++ b/exec.go
@@ -245,9 +245,18 @@
 		}
 		return outputTs, fmt.Errorf("no rule to make target %q", output)
 	}
+
+	var olds []oldVar
 	if rule.vars != nil {
-		vars = NewVars(vars)
-		vars.Merge(rule.vars)
+		for k, v := range rule.vars {
+			olds = append(olds, newOldVar(vars, k))
+			vars[k] = v
+		}
+		defer func() {
+			for _, old := range olds {
+				old.restore(vars)
+			}
+		}()
 	}
 
 	latest := int64(-1)
diff --git a/func.go b/func.go
index 44dfa13..333ac92 100644
--- a/func.go
+++ b/func.go
@@ -12,27 +12,6 @@
 	"strings"
 )
 
-// TODO(ukai): move in var.go?
-type oldVar struct {
-	name  string
-	value Var
-}
-
-func newOldVar(ev *Evaluator, name string) oldVar {
-	return oldVar{
-		name:  name,
-		value: ev.outVars.Lookup(name),
-	}
-}
-
-func (old oldVar) restore(ev *Evaluator) {
-	if old.value.IsDefined() {
-		ev.outVars.Assign(old.name, old.value)
-		return
-	}
-	delete(ev.outVars, old.name)
-}
-
 // Func is a make function.
 // http://www.gnu.org/software/make/manual/make.html#Functions
 
@@ -585,7 +564,7 @@
 	var olds []oldVar
 	for i, arg := range args {
 		name := fmt.Sprintf("%d", i+1)
-		olds = append(olds, newOldVar(ev, name))
+		olds = append(olds, newOldVar(ev.outVars, name))
 		ev.outVars.Assign(name,
 			SimpleVar{
 				value:  arg,
@@ -596,7 +575,7 @@
 	var buf bytes.Buffer
 	v.Eval(&buf, ev)
 	for _, old := range olds {
-		old.restore(ev)
+		old.restore(ev.outVars)
 	}
 	Log("call %q return %q", f.args[0], buf.Bytes())
 	w.Write(buf.Bytes())
@@ -690,7 +669,7 @@
 	varname := string(ev.Value(f.args[0]))
 	list := ev.Values(f.args[1])
 	text := f.args[2]
-	old := newOldVar(ev, varname)
+	old := newOldVar(ev.outVars, varname)
 	space := false
 	for _, word := range list {
 		ev.outVars.Assign(varname,
@@ -704,5 +683,5 @@
 		w.Write(ev.Value(text))
 		space = true
 	}
-	old.restore(ev)
+	old.restore(ev.outVars)
 }
diff --git a/var.go b/var.go
index 72bb86a..d246b58 100644
--- a/var.go
+++ b/var.go
@@ -112,3 +112,23 @@
 		vt[k] = v
 	}
 }
+
+type oldVar struct {
+	name  string
+	value Var
+}
+
+func newOldVar(vars Vars, name string) oldVar {
+	return oldVar{
+		name:  name,
+		value: vars.Lookup(name),
+	}
+}
+
+func (old oldVar) restore(vars Vars) {
+	if old.value.IsDefined() {
+		vars[old.name] = old.value
+		return
+	}
+	delete(vars, old.name)
+}