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 }*/