github.com/4000d/go-ethereum@v1.8.2-0.20180223170251-423c8bb1d821/core/vm/vm_jit.go (about)

     1  // Copyright 2015 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  // +build evmjit
    18  
    19  package vm
    20  
    21  /*
    22  
    23  void* evmjit_create();
    24  int   evmjit_run(void* _jit, void* _data, void* _env);
    25  void  evmjit_destroy(void* _jit);
    26  
    27  // Shared library evmjit (e.g. libevmjit.so) is expected to be installed in /usr/local/lib
    28  // More: https://github.com/ethereum/evmjit
    29  #cgo LDFLAGS: -levmjit
    30  */
    31  import "C"
    32  
    33  /*
    34  import (
    35  	"bytes"
    36  	"errors"
    37  	"fmt"
    38  	"math/big"
    39  	"unsafe"
    40  
    41  	"github.com/ethereum/go-ethereum/core/state"
    42  	"github.com/ethereum/go-ethereum/crypto"
    43  	"github.com/ethereum/go-ethereum/params"
    44  )
    45  
    46  type JitVm struct {
    47  	env        EVM
    48  	me         ContextRef
    49  	callerAddr []byte
    50  	price      *big.Int
    51  	data       RuntimeData
    52  }
    53  
    54  type i256 [32]byte
    55  
    56  type RuntimeData struct {
    57  	gas          int64
    58  	gasPrice     int64
    59  	callData     *byte
    60  	callDataSize uint64
    61  	address      i256
    62  	caller       i256
    63  	origin       i256
    64  	callValue    i256
    65  	coinBase     i256
    66  	difficulty   i256
    67  	gasLimit     i256
    68  	number       uint64
    69  	timestamp    int64
    70  	code         *byte
    71  	codeSize     uint64
    72  	codeHash     i256
    73  }
    74  
    75  func hash2llvm(h []byte) i256 {
    76  	var m i256
    77  	copy(m[len(m)-len(h):], h) // right aligned copy
    78  	return m
    79  }
    80  
    81  func llvm2hash(m *i256) []byte {
    82  	return C.GoBytes(unsafe.Pointer(m), C.int(len(m)))
    83  }
    84  
    85  func llvm2hashRef(m *i256) []byte {
    86  	return (*[1 << 30]byte)(unsafe.Pointer(m))[:len(m):len(m)]
    87  }
    88  
    89  func address2llvm(addr []byte) i256 {
    90  	n := hash2llvm(addr)
    91  	bswap(&n)
    92  	return n
    93  }
    94  
    95  // bswap swap bytes of the 256-bit integer on LLVM side
    96  // TODO: Do not change memory on LLVM side, that can conflict with memory access optimizations
    97  func bswap(m *i256) *i256 {
    98  	for i, l := 0, len(m); i < l/2; i++ {
    99  		m[i], m[l-i-1] = m[l-i-1], m[i]
   100  	}
   101  	return m
   102  }
   103  
   104  func trim(m []byte) []byte {
   105  	skip := 0
   106  	for i := 0; i < len(m); i++ {
   107  		if m[i] == 0 {
   108  			skip++
   109  		} else {
   110  			break
   111  		}
   112  	}
   113  	return m[skip:]
   114  }
   115  
   116  func getDataPtr(m []byte) *byte {
   117  	var p *byte
   118  	if len(m) > 0 {
   119  		p = &m[0]
   120  	}
   121  	return p
   122  }
   123  
   124  func big2llvm(n *big.Int) i256 {
   125  	m := hash2llvm(n.Bytes())
   126  	bswap(&m)
   127  	return m
   128  }
   129  
   130  func llvm2big(m *i256) *big.Int {
   131  	n := big.NewInt(0)
   132  	for i := 0; i < len(m); i++ {
   133  		b := big.NewInt(int64(m[i]))
   134  		b.Lsh(b, uint(i)*8)
   135  		n.Add(n, b)
   136  	}
   137  	return n
   138  }
   139  
   140  // llvm2bytesRef creates a []byte slice that references byte buffer on LLVM side (as of that not controller by GC)
   141  // User must ensure that referenced memory is available to Go until the data is copied or not needed any more
   142  func llvm2bytesRef(data *byte, length uint64) []byte {
   143  	if length == 0 {
   144  		return nil
   145  	}
   146  	if data == nil {
   147  		panic("Unexpected nil data pointer")
   148  	}
   149  	return (*[1 << 30]byte)(unsafe.Pointer(data))[:length:length]
   150  }
   151  
   152  func untested(condition bool, message string) {
   153  	if condition {
   154  		panic("Condition `" + message + "` tested. Remove assert.")
   155  	}
   156  }
   157  
   158  func assert(condition bool, message string) {
   159  	if !condition {
   160  		panic("Assert `" + message + "` failed!")
   161  	}
   162  }
   163  
   164  func NewJitVm(env EVM) *JitVm {
   165  	return &JitVm{env: env}
   166  }
   167  
   168  func (self *JitVm) Run(me, caller ContextRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) {
   169  	// TODO: depth is increased but never checked by VM. VM should not know about it at all.
   170  	self.env.SetDepth(self.env.Depth() + 1)
   171  
   172  	// TODO: Move it to Env.Call() or sth
   173  	if Precompiled[string(me.Address())] != nil {
   174  		// if it's address of precompiled contract
   175  		// fallback to standard VM
   176  		stdVm := New(self.env)
   177  		return stdVm.Run(me, caller, code, value, gas, price, callData)
   178  	}
   179  
   180  	if self.me != nil {
   181  		panic("JitVm.Run() can be called only once per JitVm instance")
   182  	}
   183  
   184  	self.me = me
   185  	self.callerAddr = caller.Address()
   186  	self.price = price
   187  
   188  	self.data.gas = gas.Int64()
   189  	self.data.gasPrice = price.Int64()
   190  	self.data.callData = getDataPtr(callData)
   191  	self.data.callDataSize = uint64(len(callData))
   192  	self.data.address = address2llvm(self.me.Address())
   193  	self.data.caller = address2llvm(caller.Address())
   194  	self.data.origin = address2llvm(self.env.Origin())
   195  	self.data.callValue = big2llvm(value)
   196  	self.data.coinBase = address2llvm(self.env.Coinbase())
   197  	self.data.difficulty = big2llvm(self.env.Difficulty())
   198  	self.data.gasLimit = big2llvm(self.env.GasLimit())
   199  	self.data.number = self.env.BlockNumber().Uint64()
   200  	self.data.timestamp = self.env.Time()
   201  	self.data.code = getDataPtr(code)
   202  	self.data.codeSize = uint64(len(code))
   203  	self.data.codeHash = hash2llvm(crypto.Keccak256(code)) // TODO: Get already computed hash?
   204  
   205  	jit := C.evmjit_create()
   206  	retCode := C.evmjit_run(jit, unsafe.Pointer(&self.data), unsafe.Pointer(self))
   207  
   208  	if retCode < 0 {
   209  		err = errors.New("OOG from JIT")
   210  		gas.SetInt64(0) // Set gas to 0, JIT does not bother
   211  	} else {
   212  		gas.SetInt64(self.data.gas)
   213  		if retCode == 1 { // RETURN
   214  			ret = C.GoBytes(unsafe.Pointer(self.data.callData), C.int(self.data.callDataSize))
   215  		} else if retCode == 2 { // SUICIDE
   216  			// TODO: Suicide support logic should be moved to Env to be shared by VM implementations
   217  			state := self.Env().State()
   218  			receiverAddr := llvm2hashRef(bswap(&self.data.address))
   219  			receiver := state.GetOrNewStateObject(receiverAddr)
   220  			balance := state.GetBalance(me.Address())
   221  			receiver.AddBalance(balance)
   222  			state.Delete(me.Address())
   223  		}
   224  	}
   225  
   226  	C.evmjit_destroy(jit)
   227  	return
   228  }
   229  
   230  func (self *JitVm) Printf(format string, v ...interface{}) VirtualMachine {
   231  	return self
   232  }
   233  
   234  func (self *JitVm) Endl() VirtualMachine {
   235  	return self
   236  }
   237  
   238  func (self *JitVm) Env() EVM {
   239  	return self.env
   240  }
   241  
   242  //export env_sha3
   243  func env_sha3(dataPtr *byte, length uint64, resultPtr unsafe.Pointer) {
   244  	data := llvm2bytesRef(dataPtr, length)
   245  	hash := crypto.Keccak256(data)
   246  	result := (*i256)(resultPtr)
   247  	*result = hash2llvm(hash)
   248  }
   249  
   250  //export env_sstore
   251  func env_sstore(vmPtr unsafe.Pointer, indexPtr unsafe.Pointer, valuePtr unsafe.Pointer) {
   252  	vm := (*JitVm)(vmPtr)
   253  	index := llvm2hash(bswap((*i256)(indexPtr)))
   254  	value := llvm2hash(bswap((*i256)(valuePtr)))
   255  	value = trim(value)
   256  	if len(value) == 0 {
   257  		prevValue := vm.env.State().GetState(vm.me.Address(), index)
   258  		if len(prevValue) != 0 {
   259  			vm.Env().State().Refund(vm.callerAddr, GasSStoreRefund)
   260  		}
   261  	}
   262  
   263  	vm.env.State().SetState(vm.me.Address(), index, value)
   264  }
   265  
   266  //export env_sload
   267  func env_sload(vmPtr unsafe.Pointer, indexPtr unsafe.Pointer, resultPtr unsafe.Pointer) {
   268  	vm := (*JitVm)(vmPtr)
   269  	index := llvm2hash(bswap((*i256)(indexPtr)))
   270  	value := vm.env.State().GetState(vm.me.Address(), index)
   271  	result := (*i256)(resultPtr)
   272  	*result = hash2llvm(value)
   273  	bswap(result)
   274  }
   275  
   276  //export env_balance
   277  func env_balance(_vm unsafe.Pointer, _addr unsafe.Pointer, _result unsafe.Pointer) {
   278  	vm := (*JitVm)(_vm)
   279  	addr := llvm2hash((*i256)(_addr))
   280  	balance := vm.Env().State().GetBalance(addr)
   281  	result := (*i256)(_result)
   282  	*result = big2llvm(balance)
   283  }
   284  
   285  //export env_blockhash
   286  func env_blockhash(_vm unsafe.Pointer, _number unsafe.Pointer, _result unsafe.Pointer) {
   287  	vm := (*JitVm)(_vm)
   288  	number := llvm2big((*i256)(_number))
   289  	result := (*i256)(_result)
   290  
   291  	currNumber := vm.Env().BlockNumber()
   292  	limit := big.NewInt(0).Sub(currNumber, big.NewInt(256))
   293  	if number.Cmp(limit) >= 0 && number.Cmp(currNumber) < 0 {
   294  		hash := vm.Env().GetHash(uint64(number.Int64()))
   295  		*result = hash2llvm(hash)
   296  	} else {
   297  		*result = i256{}
   298  	}
   299  }
   300  
   301  //export env_call
   302  func env_call(_vm unsafe.Pointer, _gas *int64, _receiveAddr unsafe.Pointer, _value unsafe.Pointer, inDataPtr unsafe.Pointer, inDataLen uint64, outDataPtr *byte, outDataLen uint64, _codeAddr unsafe.Pointer) bool {
   303  	vm := (*JitVm)(_vm)
   304  
   305  	//fmt.Printf("env_call (depth %d)\n", vm.Env().Depth())
   306  
   307  	defer func() {
   308  		if r := recover(); r != nil {
   309  			fmt.Printf("Recovered in env_call (depth %d, out %p %d): %s\n", vm.Env().Depth(), outDataPtr, outDataLen, r)
   310  		}
   311  	}()
   312  
   313  	balance := vm.Env().State().GetBalance(vm.me.Address())
   314  	value := llvm2big((*i256)(_value))
   315  
   316  	if balance.Cmp(value) >= 0 {
   317  		receiveAddr := llvm2hash((*i256)(_receiveAddr))
   318  		inData := C.GoBytes(inDataPtr, C.int(inDataLen))
   319  		outData := llvm2bytesRef(outDataPtr, outDataLen)
   320  		codeAddr := llvm2hash((*i256)(_codeAddr))
   321  		gas := big.NewInt(*_gas)
   322  		var out []byte
   323  		var err error
   324  		if bytes.Equal(codeAddr, receiveAddr) {
   325  			out, err = vm.env.Call(vm.me, codeAddr, inData, gas, vm.price, value)
   326  		} else {
   327  			out, err = vm.env.CallCode(vm.me, codeAddr, inData, gas, vm.price, value)
   328  		}
   329  		*_gas = gas.Int64()
   330  		if err == nil {
   331  			copy(outData, out)
   332  			return true
   333  		}
   334  	}
   335  
   336  	return false
   337  }
   338  
   339  //export env_create
   340  func env_create(_vm unsafe.Pointer, _gas *int64, _value unsafe.Pointer, initDataPtr unsafe.Pointer, initDataLen uint64, _result unsafe.Pointer) {
   341  	vm := (*JitVm)(_vm)
   342  
   343  	value := llvm2big((*i256)(_value))
   344  	initData := C.GoBytes(initDataPtr, C.int(initDataLen)) // TODO: Unnecessary if low balance
   345  	result := (*i256)(_result)
   346  	*result = i256{}
   347  
   348  	gas := big.NewInt(*_gas)
   349  	ret, suberr, ref := vm.env.Create(vm.me, nil, initData, gas, vm.price, value)
   350  	if suberr == nil {
   351  		dataGas := big.NewInt(int64(len(ret))) // TODO: Not the best design. env.Create can do it, it has the reference to gas counter
   352  		dataGas.Mul(dataGas, params.CreateDataGas)
   353  		gas.Sub(gas, dataGas)
   354  		*result = hash2llvm(ref.Address())
   355  	}
   356  	*_gas = gas.Int64()
   357  }
   358  
   359  //export env_log
   360  func env_log(_vm unsafe.Pointer, dataPtr unsafe.Pointer, dataLen uint64, _topic1 unsafe.Pointer, _topic2 unsafe.Pointer, _topic3 unsafe.Pointer, _topic4 unsafe.Pointer) {
   361  	vm := (*JitVm)(_vm)
   362  
   363  	data := C.GoBytes(dataPtr, C.int(dataLen))
   364  
   365  	topics := make([][]byte, 0, 4)
   366  	if _topic1 != nil {
   367  		topics = append(topics, llvm2hash((*i256)(_topic1)))
   368  	}
   369  	if _topic2 != nil {
   370  		topics = append(topics, llvm2hash((*i256)(_topic2)))
   371  	}
   372  	if _topic3 != nil {
   373  		topics = append(topics, llvm2hash((*i256)(_topic3)))
   374  	}
   375  	if _topic4 != nil {
   376  		topics = append(topics, llvm2hash((*i256)(_topic4)))
   377  	}
   378  
   379  	vm.Env().AddLog(state.NewLog(vm.me.Address(), topics, data, vm.env.BlockNumber().Uint64()))
   380  }
   381  
   382  //export env_extcode
   383  func env_extcode(_vm unsafe.Pointer, _addr unsafe.Pointer, o_size *uint64) *byte {
   384  	vm := (*JitVm)(_vm)
   385  	addr := llvm2hash((*i256)(_addr))
   386  	code := vm.Env().State().GetCode(addr)
   387  	*o_size = uint64(len(code))
   388  	return getDataPtr(code)
   389  }*/