jit_optimiser.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  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. package vm
  17. import (
  18. "math/big"
  19. "time"
  20. "github.com/ethereum/go-ethereum/logger"
  21. "github.com/ethereum/go-ethereum/logger/glog"
  22. )
  23. // optimeProgram optimises a JIT program creating segments out of program
  24. // instructions. Currently covered are multi-pushes and static jumps
  25. func optimiseProgram(program *Program) {
  26. var load []instruction
  27. var (
  28. statsJump = 0
  29. statsPush = 0
  30. )
  31. if glog.V(logger.Debug) {
  32. glog.Infof("optimising %x\n", program.Id[:4])
  33. tstart := time.Now()
  34. defer func() {
  35. glog.Infof("optimised %x done in %v with JMP: %d PSH: %d\n", program.Id[:4], time.Since(tstart), statsJump, statsPush)
  36. }()
  37. }
  38. /*
  39. code := Parse(program.code)
  40. for _, test := range [][]OpCode{
  41. []OpCode{PUSH, PUSH, ADD},
  42. []OpCode{PUSH, PUSH, SUB},
  43. []OpCode{PUSH, PUSH, MUL},
  44. []OpCode{PUSH, PUSH, DIV},
  45. } {
  46. matchCount := 0
  47. MatchFn(code, test, func(i int) bool {
  48. matchCount++
  49. return true
  50. })
  51. fmt.Printf("found %d match count on: %v\n", matchCount, test)
  52. }
  53. */
  54. for i := 0; i < len(program.instructions); i++ {
  55. instr := program.instructions[i].(instruction)
  56. switch {
  57. case instr.op.IsPush():
  58. load = append(load, instr)
  59. case instr.op.IsStaticJump():
  60. if len(load) == 0 {
  61. continue
  62. }
  63. // if the push load is greater than 1, finalise that
  64. // segment first
  65. if len(load) > 2 {
  66. seg, size := makePushSeg(load[:len(load)-1])
  67. program.instructions[i-size-1] = seg
  68. statsPush++
  69. }
  70. // create a segment consisting of a pre determined
  71. // jump, destination and validity.
  72. seg := makeStaticJumpSeg(load[len(load)-1].data, program)
  73. program.instructions[i-1] = seg
  74. statsJump++
  75. load = nil
  76. default:
  77. // create a new N pushes segment
  78. if len(load) > 1 {
  79. seg, size := makePushSeg(load)
  80. program.instructions[i-size] = seg
  81. statsPush++
  82. }
  83. load = nil
  84. }
  85. }
  86. }
  87. // makePushSeg creates a new push segment from N amount of push instructions
  88. func makePushSeg(instrs []instruction) (pushSeg, int) {
  89. var (
  90. data []*big.Int
  91. gas = new(big.Int)
  92. )
  93. for _, instr := range instrs {
  94. data = append(data, instr.data)
  95. gas.Add(gas, instr.gas)
  96. }
  97. return pushSeg{data, gas}, len(instrs)
  98. }
  99. // makeStaticJumpSeg creates a new static jump segment from a predefined
  100. // destination (PUSH, JUMP).
  101. func makeStaticJumpSeg(to *big.Int, program *Program) jumpSeg {
  102. gas := new(big.Int)
  103. gas.Add(gas, _baseCheck[PUSH1].gas)
  104. gas.Add(gas, _baseCheck[JUMP].gas)
  105. contract := &Contract{Code: program.code}
  106. pos, err := jump(program.mapping, program.destinations, contract, to)
  107. return jumpSeg{pos, err, gas}
  108. }