vm_jit.go 10 KB

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