vm_jit.go 9.7 KB

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