github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/core/vm/analysis.go (about)

     1  package vm
     2  
     3  import (
     4  	"math/big"
     5  
     6  	"github.com/quickchainproject/quickchain/common"
     7  )
     8  
     9  // destinations stores one map per contract (keyed by hash of code).
    10  // The maps contain an entry for each location of a JUMPDEST
    11  // instruction.
    12  type destinations map[common.Hash]bitvec
    13  
    14  // has checks whether code has a JUMPDEST at dest.
    15  func (d destinations) has(codehash common.Hash, code []byte, dest *big.Int) bool {
    16  	// PC cannot go beyond len(code) and certainly can't be bigger than 63bits.
    17  	// Don't bother checking for JUMPDEST in that case.
    18  	udest := dest.Uint64()
    19  	if dest.BitLen() >= 63 || udest >= uint64(len(code)) {
    20  		return false
    21  	}
    22  
    23  	m, analysed := d[codehash]
    24  	if !analysed {
    25  		m = codeBitmap(code)
    26  		d[codehash] = m
    27  	}
    28  	return OpCode(code[udest]) == JUMPDEST && m.codeSegment(udest)
    29  }
    30  
    31  // bitvec is a bit vector which maps bytes in a program.
    32  // An unset bit means the byte is an opcode, a set bit means
    33  // it's data (i.e. argument of PUSHxx).
    34  type bitvec []byte
    35  
    36  func (bits *bitvec) set(pos uint64) {
    37  	(*bits)[pos/8] |= 0x80 >> (pos % 8)
    38  }
    39  func (bits *bitvec) set8(pos uint64) {
    40  	(*bits)[pos/8] |= 0xFF >> (pos % 8)
    41  	(*bits)[pos/8+1] |= ^(0xFF >> (pos % 8))
    42  }
    43  
    44  // codeSegment checks if the position is in a code segment.
    45  func (bits *bitvec) codeSegment(pos uint64) bool {
    46  	return ((*bits)[pos/8] & (0x80 >> (pos % 8))) == 0
    47  }
    48  
    49  // codeBitmap collects data locations in code.
    50  func codeBitmap(code []byte) bitvec {
    51  	// The bitmap is 4 bytes longer than necessary, in case the code
    52  	// ends with a PUSH32, the algorithm will push zeroes onto the
    53  	// bitvector outside the bounds of the actual code.
    54  	bits := make(bitvec, len(code)/8+1+4)
    55  	for pc := uint64(0); pc < uint64(len(code)); {
    56  		op := OpCode(code[pc])
    57  
    58  		if op >= PUSH1 && op <= PUSH32 {
    59  			numbits := op - PUSH1 + 1
    60  			pc++
    61  			for ; numbits >= 8; numbits -= 8 {
    62  				bits.set8(pc) // 8
    63  				pc += 8
    64  			}
    65  			for ; numbits > 0; numbits-- {
    66  				bits.set(pc)
    67  				pc++
    68  			}
    69  		} else {
    70  			pc++
    71  		}
    72  	}
    73  	return bits
    74  }