vm_jit.go 11 KB

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