diff --git a/core/evm.go b/core/evm.go
index 55db53927b606c1e1de990b62008944897ce9e0b..596ea95fb7ff115451cf9cbbf8e0e577684d29c3 100644
--- a/core/evm.go
+++ b/core/evm.go
@@ -60,13 +60,26 @@ func NewEVMContext(msg Message, header *types.Header, chain ChainContext, author
 
 // GetHashFn returns a GetHashFunc which retrieves header hashes by number
 func GetHashFn(ref *types.Header, chain ChainContext) func(n uint64) common.Hash {
+	var cache map[uint64]common.Hash
+
 	return func(n uint64) common.Hash {
+		// If there's no hash cache yet, make one
+		if cache == nil {
+			cache = map[uint64]common.Hash{
+				ref.Number.Uint64() - 1: ref.ParentHash,
+			}
+		}
+		// Try to fulfill the request from the cache
+		if hash, ok := cache[n]; ok {
+			return hash
+		}
+		// Not cached, iterate the blocks and cache the hashes
 		for header := chain.GetHeader(ref.ParentHash, ref.Number.Uint64()-1); header != nil; header = chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) {
-			if header.Number.Uint64() == n {
-				return header.Hash()
+			cache[header.Number.Uint64()-1] = header.ParentHash
+			if n == header.Number.Uint64()-1 {
+				return header.ParentHash
 			}
 		}
-
 		return common.Hash{}
 	}
 }
diff --git a/core/headerchain.go b/core/headerchain.go
index 73cd5d2c41cbed83ccaf5b8f1486cf72725e0f00..2d1b0a2a185f8fcc29bb02695da8dcd3686cbf91 100644
--- a/core/headerchain.go
+++ b/core/headerchain.go
@@ -23,6 +23,7 @@ import (
 	"math"
 	"math/big"
 	mrand "math/rand"
+	"sync/atomic"
 	"time"
 
 	"github.com/ethereum/go-ethereum/common"
@@ -32,7 +33,6 @@ import (
 	"github.com/ethereum/go-ethereum/log"
 	"github.com/ethereum/go-ethereum/params"
 	"github.com/hashicorp/golang-lru"
-	"sync/atomic"
 )
 
 const (
diff --git a/core/vm/instructions.go b/core/vm/instructions.go
index 66e804fb7e46a7ac8e7226c4077c7d2fdea64e30..1e494a0eb89ed18e12918662410f0de3767f4da6 100644
--- a/core/vm/instructions.go
+++ b/core/vm/instructions.go
@@ -39,20 +39,18 @@ var (
 )
 
 func opAdd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	x, y := stack.pop(), stack.pop()
-	stack.push(math.U256(x.Add(x, y)))
-
-	evm.interpreter.intPool.put(y)
+	x, y := stack.pop(), stack.peek()
+	math.U256(y.Add(x, y))
 
+	evm.interpreter.intPool.put(x)
 	return nil, nil
 }
 
 func opSub(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	x, y := stack.pop(), stack.pop()
-	stack.push(math.U256(x.Sub(x, y)))
-
-	evm.interpreter.intPool.put(y)
+	x, y := stack.pop(), stack.peek()
+	math.U256(y.Sub(x, y))
 
+	evm.interpreter.intPool.put(x)
 	return nil, nil
 }
 
@@ -66,44 +64,39 @@ func opMul(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
 }
 
 func opDiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	x, y := stack.pop(), stack.pop()
+	x, y := stack.pop(), stack.peek()
 	if y.Sign() != 0 {
-		stack.push(math.U256(x.Div(x, y)))
+		math.U256(y.Div(x, y))
 	} else {
-		stack.push(new(big.Int))
+		y.SetUint64(0)
 	}
-
-	evm.interpreter.intPool.put(y)
-
+	evm.interpreter.intPool.put(x)
 	return nil, nil
 }
 
 func opSdiv(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := math.S256(stack.pop()), math.S256(stack.pop())
-	if y.Sign() == 0 {
-		stack.push(new(big.Int))
-		return nil, nil
+	res := evm.interpreter.intPool.getZero()
+
+	if y.Sign() == 0 || x.Sign() == 0 {
+		stack.push(res)
 	} else {
-		n := new(big.Int)
-		if evm.interpreter.intPool.get().Mul(x, y).Sign() < 0 {
-			n.SetInt64(-1)
+		if x.Sign() != y.Sign() {
+			res.Div(x.Abs(x), y.Abs(y))
+			res.Neg(res)
 		} else {
-			n.SetInt64(1)
+			res.Div(x.Abs(x), y.Abs(y))
 		}
-
-		res := x.Div(x.Abs(x), y.Abs(y))
-		res.Mul(res, n)
-
 		stack.push(math.U256(res))
 	}
-	evm.interpreter.intPool.put(y)
+	evm.interpreter.intPool.put(x, y)
 	return nil, nil
 }
 
 func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := stack.pop(), stack.pop()
 	if y.Sign() == 0 {
-		stack.push(new(big.Int))
+		stack.push(x.SetUint64(0))
 	} else {
 		stack.push(math.U256(x.Mod(x, y)))
 	}
@@ -113,23 +106,20 @@ func opMod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
 
 func opSmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y := math.S256(stack.pop()), math.S256(stack.pop())
+	res := evm.interpreter.intPool.getZero()
 
 	if y.Sign() == 0 {
-		stack.push(new(big.Int))
+		stack.push(res)
 	} else {
-		n := new(big.Int)
 		if x.Sign() < 0 {
-			n.SetInt64(-1)
+			res.Mod(x.Abs(x), y.Abs(y))
+			res.Neg(res)
 		} else {
-			n.SetInt64(1)
+			res.Mod(x.Abs(x), y.Abs(y))
 		}
-
-		res := x.Mod(x.Abs(x), y.Abs(y))
-		res.Mul(res, n)
-
 		stack.push(math.U256(res))
 	}
-	evm.interpreter.intPool.put(y)
+	evm.interpreter.intPool.put(x, y)
 	return nil, nil
 }
 
@@ -163,32 +153,30 @@ func opSignExtend(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac
 }
 
 func opNot(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	x := stack.pop()
-	stack.push(math.U256(x.Not(x)))
+	x := stack.peek()
+	math.U256(x.Not(x))
 	return nil, nil
 }
 
 func opLt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	x, y := stack.pop(), stack.pop()
+	x, y := stack.pop(), stack.peek()
 	if x.Cmp(y) < 0 {
-		stack.push(evm.interpreter.intPool.get().SetUint64(1))
+		y.SetUint64(1)
 	} else {
-		stack.push(new(big.Int))
+		y.SetUint64(0)
 	}
-
-	evm.interpreter.intPool.put(x, y)
+	evm.interpreter.intPool.put(x)
 	return nil, nil
 }
 
 func opGt(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	x, y := stack.pop(), stack.pop()
+	x, y := stack.pop(), stack.peek()
 	if x.Cmp(y) > 0 {
-		stack.push(evm.interpreter.intPool.get().SetUint64(1))
+		y.SetUint64(1)
 	} else {
-		stack.push(new(big.Int))
+		y.SetUint64(0)
 	}
-
-	evm.interpreter.intPool.put(x, y)
+	evm.interpreter.intPool.put(x)
 	return nil, nil
 }
 
@@ -270,18 +258,18 @@ func opAnd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
 }
 
 func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	x, y := stack.pop(), stack.pop()
-	stack.push(x.Or(x, y))
+	x, y := stack.pop(), stack.peek()
+	y.Or(x, y)
 
-	evm.interpreter.intPool.put(y)
+	evm.interpreter.intPool.put(x)
 	return nil, nil
 }
 
 func opXor(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	x, y := stack.pop(), stack.pop()
-	stack.push(x.Xor(x, y))
+	x, y := stack.pop(), stack.peek()
+	y.Xor(x, y)
 
-	evm.interpreter.intPool.put(y)
+	evm.interpreter.intPool.put(x)
 	return nil, nil
 }
 
@@ -300,13 +288,12 @@ func opByte(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
 func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y, z := stack.pop(), stack.pop(), stack.pop()
 	if z.Cmp(bigZero) > 0 {
-		add := x.Add(x, y)
-		add.Mod(add, z)
-		stack.push(math.U256(add))
+		x.Add(x, y)
+		x.Mod(x, z)
+		stack.push(math.U256(x))
 	} else {
-		stack.push(new(big.Int))
+		stack.push(x.SetUint64(0))
 	}
-
 	evm.interpreter.intPool.put(y, z)
 	return nil, nil
 }
@@ -314,13 +301,12 @@ func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
 func opMulmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	x, y, z := stack.pop(), stack.pop(), stack.pop()
 	if z.Cmp(bigZero) > 0 {
-		mul := x.Mul(x, y)
-		mul.Mod(mul, z)
-		stack.push(math.U256(mul))
+		x.Mul(x, y)
+		x.Mod(x, z)
+		stack.push(math.U256(x))
 	} else {
-		stack.push(new(big.Int))
+		stack.push(x.SetUint64(0))
 	}
-
 	evm.interpreter.intPool.put(y, z)
 	return nil, nil
 }
@@ -393,8 +379,7 @@ func opSha3(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
 	if evm.vmConfig.EnablePreimageRecording {
 		evm.StateDB.AddPreimage(common.BytesToHash(hash), data)
 	}
-
-	stack.push(new(big.Int).SetBytes(hash))
+	stack.push(evm.interpreter.intPool.get().SetBytes(hash))
 
 	evm.interpreter.intPool.put(offset, size)
 	return nil, nil
@@ -406,10 +391,8 @@ func opAddress(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *
 }
 
 func opBalance(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	addr := common.BigToAddress(stack.pop())
-	balance := evm.StateDB.GetBalance(addr)
-
-	stack.push(new(big.Int).Set(balance))
+	slot := stack.peek()
+	slot.Set(evm.StateDB.GetBalance(common.BigToAddress(slot)))
 	return nil, nil
 }
 
@@ -429,7 +412,7 @@ func opCallValue(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
 }
 
 func opCallDataLoad(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(new(big.Int).SetBytes(getDataBig(contract.Input, stack.pop(), big32)))
+	stack.push(evm.interpreter.intPool.get().SetBytes(getDataBig(contract.Input, stack.pop(), big32)))
 	return nil, nil
 }
 
@@ -460,10 +443,11 @@ func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory,
 		memOffset  = stack.pop()
 		dataOffset = stack.pop()
 		length     = stack.pop()
+
+		end = evm.interpreter.intPool.get().Add(dataOffset, length)
 	)
-	defer evm.interpreter.intPool.put(memOffset, dataOffset, length)
+	defer evm.interpreter.intPool.put(memOffset, dataOffset, length, end)
 
-	end := new(big.Int).Add(dataOffset, length)
 	if end.BitLen() > 64 || uint64(len(evm.interpreter.returnData)) < end.Uint64() {
 		return nil, errReturnDataOutOfBounds
 	}
@@ -473,11 +457,8 @@ func opReturnDataCopy(pc *uint64, evm *EVM, contract *Contract, memory *Memory,
 }
 
 func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	a := stack.pop()
-
-	addr := common.BigToAddress(a)
-	a.SetInt64(int64(evm.StateDB.GetCodeSize(addr)))
-	stack.push(a)
+	slot := stack.peek()
+	slot.SetUint64(uint64(evm.StateDB.GetCodeSize(common.BigToAddress(slot))))
 
 	return nil, nil
 }
@@ -485,6 +466,7 @@ func opExtCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, sta
 func opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	l := evm.interpreter.intPool.get().SetInt64(int64(len(contract.Code)))
 	stack.push(l)
+
 	return nil, nil
 }
 
@@ -527,9 +509,8 @@ func opBlockhash(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
 	if num.Cmp(n) > 0 && num.Cmp(evm.BlockNumber) < 0 {
 		stack.push(evm.GetHash(num.Uint64()).Big())
 	} else {
-		stack.push(new(big.Int))
+		stack.push(evm.interpreter.intPool.getZero())
 	}
-
 	evm.interpreter.intPool.put(num, n)
 	return nil, nil
 }
@@ -540,22 +521,22 @@ func opCoinbase(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
 }
 
 func opTimestamp(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(math.U256(new(big.Int).Set(evm.Time)))
+	stack.push(math.U256(evm.interpreter.intPool.get().Set(evm.Time)))
 	return nil, nil
 }
 
 func opNumber(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(math.U256(new(big.Int).Set(evm.BlockNumber)))
+	stack.push(math.U256(evm.interpreter.intPool.get().Set(evm.BlockNumber)))
 	return nil, nil
 }
 
 func opDifficulty(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(math.U256(new(big.Int).Set(evm.Difficulty)))
+	stack.push(math.U256(evm.interpreter.intPool.get().Set(evm.Difficulty)))
 	return nil, nil
 }
 
 func opGasLimit(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
-	stack.push(math.U256(new(big.Int).SetUint64(evm.GasLimit)))
+	stack.push(math.U256(evm.interpreter.intPool.get().SetUint64(evm.GasLimit)))
 	return nil, nil
 }
 
@@ -566,7 +547,7 @@ func opPop(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
 
 func opMload(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) {
 	offset := stack.pop()
-	val := new(big.Int).SetBytes(memory.Get(offset.Int64(), 32))
+	val := evm.interpreter.intPool.get().SetBytes(memory.Get(offset.Int64(), 32))
 	stack.push(val)
 
 	evm.interpreter.intPool.put(offset)
@@ -670,9 +651,9 @@ func opCreate(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
 	// rule) and treat as an error, if the ruleset is frontier we must
 	// ignore this error and pretend the operation was successful.
 	if evm.ChainConfig().IsHomestead(evm.BlockNumber) && suberr == ErrCodeStoreOutOfGas {
-		stack.push(new(big.Int))
+		stack.push(evm.interpreter.intPool.getZero())
 	} else if suberr != nil && suberr != ErrCodeStoreOutOfGas {
-		stack.push(new(big.Int))
+		stack.push(evm.interpreter.intPool.getZero())
 	} else {
 		stack.push(addr.Big())
 	}
@@ -701,9 +682,9 @@ func opCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
 	}
 	ret, returnGas, err := evm.Call(contract, toAddr, args, gas, value)
 	if err != nil {
-		stack.push(new(big.Int))
+		stack.push(evm.interpreter.intPool.getZero())
 	} else {
-		stack.push(big.NewInt(1))
+		stack.push(evm.interpreter.intPool.get().SetUint64(1))
 	}
 	if err == nil || err == errExecutionReverted {
 		memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
@@ -730,9 +711,9 @@ func opCallCode(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
 	}
 	ret, returnGas, err := evm.CallCode(contract, toAddr, args, gas, value)
 	if err != nil {
-		stack.push(new(big.Int))
+		stack.push(evm.interpreter.intPool.getZero())
 	} else {
-		stack.push(big.NewInt(1))
+		stack.push(evm.interpreter.intPool.get().SetUint64(1))
 	}
 	if err == nil || err == errExecutionReverted {
 		memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
@@ -755,9 +736,9 @@ func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, st
 
 	ret, returnGas, err := evm.DelegateCall(contract, toAddr, args, gas)
 	if err != nil {
-		stack.push(new(big.Int))
+		stack.push(evm.interpreter.intPool.getZero())
 	} else {
-		stack.push(big.NewInt(1))
+		stack.push(evm.interpreter.intPool.get().SetUint64(1))
 	}
 	if err == nil || err == errExecutionReverted {
 		memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
@@ -780,9 +761,9 @@ func opStaticCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stac
 
 	ret, returnGas, err := evm.StaticCall(contract, toAddr, args, gas)
 	if err != nil {
-		stack.push(new(big.Int))
+		stack.push(evm.interpreter.intPool.getZero())
 	} else {
-		stack.push(big.NewInt(1))
+		stack.push(evm.interpreter.intPool.get().SetUint64(1))
 	}
 	if err == nil || err == errExecutionReverted {
 		memory.Set(retOffset.Uint64(), retSize.Uint64(), ret)
diff --git a/core/vm/intpool.go b/core/vm/intpool.go
index 384f5df59bd6c5c9a0c65ce55ff2d5415cc9f4d2..5dbda18eeefa0b1e624a837f8085f08880a35272 100644
--- a/core/vm/intpool.go
+++ b/core/vm/intpool.go
@@ -32,24 +32,36 @@ func newIntPool() *intPool {
 	return &intPool{pool: newstack()}
 }
 
+// get retrieves a big int from the pool, allocating one if the pool is empty.
+// Note, the returned int's value is arbitrary and will not be zeroed!
 func (p *intPool) get() *big.Int {
 	if p.pool.len() > 0 {
 		return p.pool.pop()
 	}
 	return new(big.Int)
 }
+
+// getZero retrieves a big int from the pool, setting it to zero or allocating
+// a new one if the pool is empty.
+func (p *intPool) getZero() *big.Int {
+	if p.pool.len() > 0 {
+		return p.pool.pop().SetUint64(0)
+	}
+	return new(big.Int)
+}
+
+// put returns an allocated big int to the pool to be later reused by get calls.
+// Note, the values as saved as is; neither put nor get zeroes the ints out!
 func (p *intPool) put(is ...*big.Int) {
 	if len(p.pool.data) > poolLimit {
 		return
 	}
-
 	for _, i := range is {
 		// verifyPool is a build flag. Pool verification makes sure the integrity
 		// of the integer pool by comparing values to a default value.
 		if verifyPool {
 			i.Set(checkVal)
 		}
-
 		p.pool.push(i)
 	}
 }