github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/core/vm/jit.go (about)

     1  // Copyright 2014 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package vm
    18  
    19  import (
    20  	"fmt"
    21  	"math/big"
    22  	"sync/atomic"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  	"github.com/ethereum/go-ethereum/core/state"
    26  	"github.com/ethereum/go-ethereum/crypto"
    27  	"github.com/ethereum/go-ethereum/params"
    28  	"github.com/hashicorp/golang-lru"
    29  )
    30  
    31  type progStatus int32
    32  
    33  const (
    34  	progUnknown progStatus = iota
    35  	progCompile
    36  	progReady
    37  	progError
    38  )
    39  
    40  var programs *lru.Cache
    41  
    42  func init() {
    43  	programs, _ = lru.New(defaultJitMaxCache)
    44  }
    45  
    46  // SetJITCacheSize recreates the program cache with the max given size. Setting
    47  // a new cache is **not** thread safe. Use with caution.
    48  func SetJITCacheSize(size int) {
    49  	programs, _ = lru.New(size)
    50  }
    51  
    52  // GetProgram returns the program by id or nil when non-existent
    53  func GetProgram(id common.Hash) *Program {
    54  	if p, ok := programs.Get(id); ok {
    55  		return p.(*Program)
    56  	}
    57  
    58  	return nil
    59  }
    60  
    61  // GenProgramStatus returns the status of the given program id
    62  func GetProgramStatus(id common.Hash) progStatus {
    63  	program := GetProgram(id)
    64  	if program != nil {
    65  		return progStatus(atomic.LoadInt32(&program.status))
    66  	}
    67  
    68  	return progUnknown
    69  }
    70  
    71  // Program is a compiled program for the JIT VM and holds all required for
    72  // running a compiled JIT program.
    73  type Program struct {
    74  	Id     common.Hash // Id of the program
    75  	status int32       // status should be accessed atomically
    76  
    77  	context *Context
    78  
    79  	instructions []instruction       // instruction set
    80  	mapping      map[uint64]int      // real PC mapping to array indices
    81  	destinations map[uint64]struct{} // cached jump destinations
    82  
    83  	code []byte
    84  }
    85  
    86  // NewProgram returns a new JIT program
    87  func NewProgram(code []byte) *Program {
    88  	program := &Program{
    89  		Id:           crypto.Sha3Hash(code),
    90  		mapping:      make(map[uint64]int),
    91  		destinations: make(map[uint64]struct{}),
    92  		code:         code,
    93  	}
    94  
    95  	programs.Add(program.Id, program)
    96  	return program
    97  }
    98  
    99  func (p *Program) addInstr(op OpCode, pc uint64, fn instrFn, data *big.Int) {
   100  	// PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit
   101  	// PUSH is also allowed to calculate the same price for all PUSHes
   102  	// DUP requirements are handled elsewhere (except for the stack limit check)
   103  	baseOp := op
   104  	if op >= PUSH1 && op <= PUSH32 {
   105  		baseOp = PUSH1
   106  	}
   107  	if op >= DUP1 && op <= DUP16 {
   108  		baseOp = DUP1
   109  	}
   110  	base := _baseCheck[baseOp]
   111  	instr := instruction{op, pc, fn, nil, data, base.gas, base.stackPop, base.stackPush}
   112  
   113  	p.instructions = append(p.instructions, instr)
   114  	p.mapping[pc] = len(p.instructions) - 1
   115  }
   116  
   117  // CompileProgram compiles the given program and return an error when it fails
   118  func CompileProgram(program *Program) (err error) {
   119  	if progStatus(atomic.LoadInt32(&program.status)) == progCompile {
   120  		return nil
   121  	}
   122  	atomic.StoreInt32(&program.status, int32(progCompile))
   123  	defer func() {
   124  		if err != nil {
   125  			atomic.StoreInt32(&program.status, int32(progError))
   126  		} else {
   127  			atomic.StoreInt32(&program.status, int32(progReady))
   128  		}
   129  	}()
   130  
   131  	// loop thru the opcodes and "compile" in to instructions
   132  	for pc := uint64(0); pc < uint64(len(program.code)); pc++ {
   133  		switch op := OpCode(program.code[pc]); op {
   134  		case ADD:
   135  			program.addInstr(op, pc, opAdd, nil)
   136  		case SUB:
   137  			program.addInstr(op, pc, opSub, nil)
   138  		case MUL:
   139  			program.addInstr(op, pc, opMul, nil)
   140  		case DIV:
   141  			program.addInstr(op, pc, opDiv, nil)
   142  		case SDIV:
   143  			program.addInstr(op, pc, opSdiv, nil)
   144  		case MOD:
   145  			program.addInstr(op, pc, opMod, nil)
   146  		case SMOD:
   147  			program.addInstr(op, pc, opSmod, nil)
   148  		case EXP:
   149  			program.addInstr(op, pc, opExp, nil)
   150  		case SIGNEXTEND:
   151  			program.addInstr(op, pc, opSignExtend, nil)
   152  		case NOT:
   153  			program.addInstr(op, pc, opNot, nil)
   154  		case LT:
   155  			program.addInstr(op, pc, opLt, nil)
   156  		case GT:
   157  			program.addInstr(op, pc, opGt, nil)
   158  		case SLT:
   159  			program.addInstr(op, pc, opSlt, nil)
   160  		case SGT:
   161  			program.addInstr(op, pc, opSgt, nil)
   162  		case EQ:
   163  			program.addInstr(op, pc, opEq, nil)
   164  		case ISZERO:
   165  			program.addInstr(op, pc, opIszero, nil)
   166  		case AND:
   167  			program.addInstr(op, pc, opAnd, nil)
   168  		case OR:
   169  			program.addInstr(op, pc, opOr, nil)
   170  		case XOR:
   171  			program.addInstr(op, pc, opXor, nil)
   172  		case BYTE:
   173  			program.addInstr(op, pc, opByte, nil)
   174  		case ADDMOD:
   175  			program.addInstr(op, pc, opAddmod, nil)
   176  		case MULMOD:
   177  			program.addInstr(op, pc, opMulmod, nil)
   178  		case SHA3:
   179  			program.addInstr(op, pc, opSha3, nil)
   180  		case ADDRESS:
   181  			program.addInstr(op, pc, opAddress, nil)
   182  		case BALANCE:
   183  			program.addInstr(op, pc, opBalance, nil)
   184  		case ORIGIN:
   185  			program.addInstr(op, pc, opOrigin, nil)
   186  		case CALLER:
   187  			program.addInstr(op, pc, opCaller, nil)
   188  		case CALLVALUE:
   189  			program.addInstr(op, pc, opCallValue, nil)
   190  		case CALLDATALOAD:
   191  			program.addInstr(op, pc, opCalldataLoad, nil)
   192  		case CALLDATASIZE:
   193  			program.addInstr(op, pc, opCalldataSize, nil)
   194  		case CALLDATACOPY:
   195  			program.addInstr(op, pc, opCalldataCopy, nil)
   196  		case CODESIZE:
   197  			program.addInstr(op, pc, opCodeSize, nil)
   198  		case EXTCODESIZE:
   199  			program.addInstr(op, pc, opExtCodeSize, nil)
   200  		case CODECOPY:
   201  			program.addInstr(op, pc, opCodeCopy, nil)
   202  		case EXTCODECOPY:
   203  			program.addInstr(op, pc, opExtCodeCopy, nil)
   204  		case GASPRICE:
   205  			program.addInstr(op, pc, opGasprice, nil)
   206  		case BLOCKHASH:
   207  			program.addInstr(op, pc, opBlockhash, nil)
   208  		case COINBASE:
   209  			program.addInstr(op, pc, opCoinbase, nil)
   210  		case TIMESTAMP:
   211  			program.addInstr(op, pc, opTimestamp, nil)
   212  		case NUMBER:
   213  			program.addInstr(op, pc, opNumber, nil)
   214  		case DIFFICULTY:
   215  			program.addInstr(op, pc, opDifficulty, nil)
   216  		case GASLIMIT:
   217  			program.addInstr(op, pc, opGasLimit, nil)
   218  		case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
   219  			size := uint64(op - PUSH1 + 1)
   220  			bytes := getData([]byte(program.code), new(big.Int).SetUint64(pc+1), new(big.Int).SetUint64(size))
   221  
   222  			program.addInstr(op, pc, opPush, common.Bytes2Big(bytes))
   223  
   224  			pc += size
   225  
   226  		case POP:
   227  			program.addInstr(op, pc, opPop, nil)
   228  		case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
   229  			program.addInstr(op, pc, opDup, big.NewInt(int64(op-DUP1+1)))
   230  		case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
   231  			program.addInstr(op, pc, opSwap, big.NewInt(int64(op-SWAP1+2)))
   232  		case LOG0, LOG1, LOG2, LOG3, LOG4:
   233  			program.addInstr(op, pc, opLog, big.NewInt(int64(op-LOG0)))
   234  		case MLOAD:
   235  			program.addInstr(op, pc, opMload, nil)
   236  		case MSTORE:
   237  			program.addInstr(op, pc, opMstore, nil)
   238  		case MSTORE8:
   239  			program.addInstr(op, pc, opMstore8, nil)
   240  		case SLOAD:
   241  			program.addInstr(op, pc, opSload, nil)
   242  		case SSTORE:
   243  			program.addInstr(op, pc, opSstore, nil)
   244  		case JUMP:
   245  			program.addInstr(op, pc, opJump, nil)
   246  		case JUMPI:
   247  			program.addInstr(op, pc, opJumpi, nil)
   248  		case JUMPDEST:
   249  			program.addInstr(op, pc, opJumpdest, nil)
   250  			program.destinations[pc] = struct{}{}
   251  		case PC:
   252  			program.addInstr(op, pc, opPc, big.NewInt(int64(pc)))
   253  		case MSIZE:
   254  			program.addInstr(op, pc, opMsize, nil)
   255  		case GAS:
   256  			program.addInstr(op, pc, opGas, nil)
   257  		case CREATE:
   258  			program.addInstr(op, pc, opCreate, nil)
   259  		case CALL:
   260  			program.addInstr(op, pc, opCall, nil)
   261  		case CALLCODE:
   262  			program.addInstr(op, pc, opCallCode, nil)
   263  		case RETURN:
   264  			program.addInstr(op, pc, opReturn, nil)
   265  		case SUICIDE:
   266  			program.addInstr(op, pc, opSuicide, nil)
   267  		case STOP: // Stop the context
   268  			program.addInstr(op, pc, opStop, nil)
   269  		default:
   270  			program.addInstr(op, pc, nil, nil)
   271  		}
   272  	}
   273  
   274  	return nil
   275  }
   276  
   277  // RunProgram runs the program given the enviroment and context and returns an
   278  // error if the execution failed (non-consensus)
   279  func RunProgram(program *Program, env Environment, context *Context, input []byte) ([]byte, error) {
   280  	return runProgram(program, 0, NewMemory(), newstack(), env, context, input)
   281  }
   282  
   283  func runProgram(program *Program, pcstart uint64, mem *Memory, stack *stack, env Environment, context *Context, input []byte) ([]byte, error) {
   284  	context.Input = input
   285  
   286  	var (
   287  		caller      = context.caller
   288  		statedb     = env.State()
   289  		pc      int = program.mapping[pcstart]
   290  
   291  		jump = func(to *big.Int) error {
   292  			if !validDest(program.destinations, to) {
   293  				nop := context.GetOp(to.Uint64())
   294  				return fmt.Errorf("invalid jump destination (%v) %v", nop, to)
   295  			}
   296  
   297  			pc = program.mapping[to.Uint64()]
   298  
   299  			return nil
   300  		}
   301  	)
   302  
   303  	for pc < len(program.instructions) {
   304  		instr := program.instructions[pc]
   305  
   306  		// calculate the new memory size and gas price for the current executing opcode
   307  		newMemSize, cost, err := jitCalculateGasAndSize(env, context, caller, instr, statedb, mem, stack)
   308  		if err != nil {
   309  			return nil, err
   310  		}
   311  
   312  		// Use the calculated gas. When insufficient gas is present, use all gas and return an
   313  		// Out Of Gas error
   314  		if !context.UseGas(cost) {
   315  			return nil, OutOfGasError
   316  		}
   317  		// Resize the memory calculated previously
   318  		mem.Resize(newMemSize.Uint64())
   319  
   320  		// These opcodes return an argument and are thefor handled
   321  		// differently from the rest of the opcodes
   322  		switch instr.op {
   323  		case JUMP:
   324  			if err := jump(stack.pop()); err != nil {
   325  				return nil, err
   326  			}
   327  			continue
   328  		case JUMPI:
   329  			pos, cond := stack.pop(), stack.pop()
   330  
   331  			if cond.Cmp(common.BigTrue) >= 0 {
   332  				if err := jump(pos); err != nil {
   333  					return nil, err
   334  				}
   335  				continue
   336  			}
   337  		case RETURN:
   338  			offset, size := stack.pop(), stack.pop()
   339  			ret := mem.GetPtr(offset.Int64(), size.Int64())
   340  
   341  			return context.Return(ret), nil
   342  		case SUICIDE:
   343  			instr.fn(instr, env, context, mem, stack)
   344  
   345  			return context.Return(nil), nil
   346  		case STOP:
   347  			return context.Return(nil), nil
   348  		default:
   349  			if instr.fn == nil {
   350  				return nil, fmt.Errorf("Invalid opcode %x", instr.op)
   351  			}
   352  
   353  			instr.fn(instr, env, context, mem, stack)
   354  		}
   355  
   356  		pc++
   357  	}
   358  
   359  	context.Input = nil
   360  
   361  	return context.Return(nil), nil
   362  }
   363  
   364  // validDest checks if the given distination is a valid one given the
   365  // destination table of the program
   366  func validDest(dests map[uint64]struct{}, dest *big.Int) bool {
   367  	// PC cannot go beyond len(code) and certainly can't be bigger than 64bits.
   368  	// Don't bother checking for JUMPDEST in that case.
   369  	if dest.Cmp(bigMaxUint64) > 0 {
   370  		return false
   371  	}
   372  	_, ok := dests[dest.Uint64()]
   373  	return ok
   374  }
   375  
   376  // jitCalculateGasAndSize calculates the required given the opcode and stack items calculates the new memorysize for
   377  // the operation. This does not reduce gas or resizes the memory.
   378  func jitCalculateGasAndSize(env Environment, context *Context, caller ContextRef, instr instruction, statedb *state.StateDB, mem *Memory, stack *stack) (*big.Int, *big.Int, error) {
   379  	var (
   380  		gas                 = new(big.Int)
   381  		newMemSize *big.Int = new(big.Int)
   382  	)
   383  	err := jitBaseCheck(instr, stack, gas)
   384  	if err != nil {
   385  		return nil, nil, err
   386  	}
   387  
   388  	// stack Check, memory resize & gas phase
   389  	switch op := instr.op; op {
   390  	case SWAP1, SWAP2, SWAP3, SWAP4, SWAP5, SWAP6, SWAP7, SWAP8, SWAP9, SWAP10, SWAP11, SWAP12, SWAP13, SWAP14, SWAP15, SWAP16:
   391  		n := int(op - SWAP1 + 2)
   392  		err := stack.require(n)
   393  		if err != nil {
   394  			return nil, nil, err
   395  		}
   396  		gas.Set(GasFastestStep)
   397  	case DUP1, DUP2, DUP3, DUP4, DUP5, DUP6, DUP7, DUP8, DUP9, DUP10, DUP11, DUP12, DUP13, DUP14, DUP15, DUP16:
   398  		n := int(op - DUP1 + 1)
   399  		err := stack.require(n)
   400  		if err != nil {
   401  			return nil, nil, err
   402  		}
   403  		gas.Set(GasFastestStep)
   404  	case LOG0, LOG1, LOG2, LOG3, LOG4:
   405  		n := int(op - LOG0)
   406  		err := stack.require(n + 2)
   407  		if err != nil {
   408  			return nil, nil, err
   409  		}
   410  
   411  		mSize, mStart := stack.data[stack.len()-2], stack.data[stack.len()-1]
   412  
   413  		add := new(big.Int)
   414  		gas.Add(gas, params.LogGas)
   415  		gas.Add(gas, add.Mul(big.NewInt(int64(n)), params.LogTopicGas))
   416  		gas.Add(gas, add.Mul(mSize, params.LogDataGas))
   417  
   418  		newMemSize = calcMemSize(mStart, mSize)
   419  	case EXP:
   420  		gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas))
   421  	case SSTORE:
   422  		err := stack.require(2)
   423  		if err != nil {
   424  			return nil, nil, err
   425  		}
   426  
   427  		var g *big.Int
   428  		y, x := stack.data[stack.len()-2], stack.data[stack.len()-1]
   429  		val := statedb.GetState(context.Address(), common.BigToHash(x))
   430  
   431  		// This checks for 3 scenario's and calculates gas accordingly
   432  		// 1. From a zero-value address to a non-zero value         (NEW VALUE)
   433  		// 2. From a non-zero value address to a zero-value address (DELETE)
   434  		// 3. From a nen-zero to a non-zero                         (CHANGE)
   435  		if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) {
   436  			// 0 => non 0
   437  			g = params.SstoreSetGas
   438  		} else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) {
   439  			statedb.Refund(params.SstoreRefundGas)
   440  
   441  			g = params.SstoreClearGas
   442  		} else {
   443  			// non 0 => non 0 (or 0 => 0)
   444  			g = params.SstoreClearGas
   445  		}
   446  		gas.Set(g)
   447  	case SUICIDE:
   448  		if !statedb.IsDeleted(context.Address()) {
   449  			statedb.Refund(params.SuicideRefundGas)
   450  		}
   451  	case MLOAD:
   452  		newMemSize = calcMemSize(stack.peek(), u256(32))
   453  	case MSTORE8:
   454  		newMemSize = calcMemSize(stack.peek(), u256(1))
   455  	case MSTORE:
   456  		newMemSize = calcMemSize(stack.peek(), u256(32))
   457  	case RETURN:
   458  		newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
   459  	case SHA3:
   460  		newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-2])
   461  
   462  		words := toWordSize(stack.data[stack.len()-2])
   463  		gas.Add(gas, words.Mul(words, params.Sha3WordGas))
   464  	case CALLDATACOPY:
   465  		newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
   466  
   467  		words := toWordSize(stack.data[stack.len()-3])
   468  		gas.Add(gas, words.Mul(words, params.CopyGas))
   469  	case CODECOPY:
   470  		newMemSize = calcMemSize(stack.peek(), stack.data[stack.len()-3])
   471  
   472  		words := toWordSize(stack.data[stack.len()-3])
   473  		gas.Add(gas, words.Mul(words, params.CopyGas))
   474  	case EXTCODECOPY:
   475  		newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-4])
   476  
   477  		words := toWordSize(stack.data[stack.len()-4])
   478  		gas.Add(gas, words.Mul(words, params.CopyGas))
   479  
   480  	case CREATE:
   481  		newMemSize = calcMemSize(stack.data[stack.len()-2], stack.data[stack.len()-3])
   482  	case CALL, CALLCODE:
   483  		gas.Add(gas, stack.data[stack.len()-1])
   484  
   485  		if op == CALL {
   486  			if env.State().GetStateObject(common.BigToAddress(stack.data[stack.len()-2])) == nil {
   487  				gas.Add(gas, params.CallNewAccountGas)
   488  			}
   489  		}
   490  
   491  		if len(stack.data[stack.len()-3].Bytes()) > 0 {
   492  			gas.Add(gas, params.CallValueTransferGas)
   493  		}
   494  
   495  		x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])
   496  		y := calcMemSize(stack.data[stack.len()-4], stack.data[stack.len()-5])
   497  
   498  		newMemSize = common.BigMax(x, y)
   499  	}
   500  
   501  	if newMemSize.Cmp(common.Big0) > 0 {
   502  		newMemSizeWords := toWordSize(newMemSize)
   503  		newMemSize.Mul(newMemSizeWords, u256(32))
   504  
   505  		if newMemSize.Cmp(u256(int64(mem.Len()))) > 0 {
   506  			// be careful reusing variables here when changing.
   507  			// The order has been optimised to reduce allocation
   508  			oldSize := toWordSize(big.NewInt(int64(mem.Len())))
   509  			pow := new(big.Int).Exp(oldSize, common.Big2, Zero)
   510  			linCoef := oldSize.Mul(oldSize, params.MemoryGas)
   511  			quadCoef := new(big.Int).Div(pow, params.QuadCoeffDiv)
   512  			oldTotalFee := new(big.Int).Add(linCoef, quadCoef)
   513  
   514  			pow.Exp(newMemSizeWords, common.Big2, Zero)
   515  			linCoef = linCoef.Mul(newMemSizeWords, params.MemoryGas)
   516  			quadCoef = quadCoef.Div(pow, params.QuadCoeffDiv)
   517  			newTotalFee := linCoef.Add(linCoef, quadCoef)
   518  
   519  			fee := newTotalFee.Sub(newTotalFee, oldTotalFee)
   520  			gas.Add(gas, fee)
   521  		}
   522  	}
   523  
   524  	return newMemSize, gas, nil
   525  }
   526  
   527  // jitBaseCheck is the same as baseCheck except it doesn't do the look up in the
   528  // gas table. This is done during compilation instead.
   529  func jitBaseCheck(instr instruction, stack *stack, gas *big.Int) error {
   530  	err := stack.require(instr.spop)
   531  	if err != nil {
   532  		return err
   533  	}
   534  
   535  	if instr.spush > 0 && stack.len()-instr.spop+instr.spush > int(params.StackLimit.Int64()) {
   536  		return fmt.Errorf("stack limit reached %d (%d)", stack.len(), params.StackLimit.Int64())
   537  	}
   538  
   539  	// nil on gas means no base calculation
   540  	if instr.gas == nil {
   541  		return nil
   542  	}
   543  
   544  	gas.Add(gas, instr.gas)
   545  
   546  	return nil
   547  }