VMOpt.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. /*
  2. This file is part of cpp-ethereum.
  3. cpp-ethereum is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. cpp-ethereum is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #include <libethereum/ExtVM.h>
  15. #include "VMConfig.h"
  16. #include "VM.h"
  17. using namespace std;
  18. using namespace dev;
  19. using namespace dev::eth;
  20. void VM::reportStackUse()
  21. {
  22. static intptr_t p = 0;
  23. intptr_t q = intptr_t(&q);
  24. if (p)
  25. cerr << "STACK: " << p << " - " << q << " = " << (p - q) << endl;
  26. p = q;
  27. }
  28. std::array<InstructionMetric, 256> VM::c_metrics;
  29. void VM::initMetrics()
  30. {
  31. static bool done=false;
  32. if (!done)
  33. {
  34. for (unsigned i = 0; i < 256; ++i)
  35. {
  36. InstructionInfo op = instructionInfo((Instruction)i);
  37. c_metrics[i].gasPriceTier = op.gasPriceTier;
  38. c_metrics[i].args = op.args;
  39. c_metrics[i].ret = op.ret;
  40. }
  41. }
  42. done = true;
  43. }
  44. void VM::copyCode()
  45. {
  46. // Copy code so that it can be safely modified and extend code by
  47. // 33 zero bytes to allow reading virtual data at the end of the
  48. // code without bounds checks.
  49. auto extendedSize = m_ext->code.size() + 33;
  50. m_codeSpace.reserve(extendedSize);
  51. m_codeSpace = m_ext->code;
  52. m_codeSpace.resize(extendedSize);
  53. m_code = m_codeSpace.data();
  54. }
  55. // Implementation of EXP.
  56. //
  57. // This implements exponentiation by squaring algorithm.
  58. // Is is faster than boost::multiprecision::powm() because avoids explicit
  59. // mod operation.
  60. // Do not inline it.
  61. u256 VM::exp256(u256 _base, u256 _exponent)
  62. {
  63. using boost::multiprecision::limb_type;
  64. u256 result = 1;
  65. while (_exponent)
  66. {
  67. if (static_cast<limb_type>(_exponent) & 1) // If exponent is odd.
  68. result *= _base;
  69. _base *= _base;
  70. _exponent >>= 1;
  71. }
  72. return result;
  73. }
  74. //
  75. // Init interpreter on entry.
  76. //
  77. void VM::initEntry()
  78. {
  79. m_bounce = &VM::interpretCases;
  80. interpretCases(); // first call initializes jump table
  81. initMetrics();
  82. copyCode();
  83. optimize();
  84. }
  85. int VM::poolConstant(const u256& _con)
  86. {
  87. TRACE_VAL(2, "pool constant", _con);
  88. int i = 0, n = m_pool.size();
  89. for (; i < n; ++i)
  90. {
  91. const u256& pooled = m_pool[i];
  92. TRACE_VAL(2, "pooled constant", pooled);
  93. if (_con == pooled)
  94. return i;
  95. }
  96. if (i <= 255 )
  97. {
  98. TRACE_VAL(1, "constant pooled", _con);
  99. m_pool.push_back(_con);
  100. return i;
  101. }
  102. return -1;
  103. }
  104. void VM::optimize()
  105. {
  106. size_t nBytes = m_codeSpace.size();
  107. // build a table of jump destinations for use in verifyJumpDest
  108. TRACE_STR(1, "Build JUMPDEST table")
  109. for (size_t i = 0; i < nBytes; ++i)
  110. {
  111. Instruction op = Instruction(m_code[i]);
  112. TRACE_OP(2, i, op);
  113. // make synthetic ops in user code trigger invalid instruction if run
  114. if (op == Instruction::PUSHC ||
  115. op == Instruction::JUMPV ||
  116. op == Instruction::JUMPVI)
  117. {
  118. TRACE_OP(1, i, op);
  119. m_code[i] = (byte)Instruction::BAD;
  120. }
  121. if (op == Instruction::JUMPDEST)
  122. {
  123. m_jumpDests.push_back(i);
  124. }
  125. else if ((byte)Instruction::PUSH1 <= (byte)op &&
  126. (byte)op <= (byte)Instruction::PUSH32)
  127. {
  128. i += (byte)op - (byte)Instruction::PUSH1 + 1;
  129. }
  130. }
  131. #ifdef EVM_DO_FIRST_PASS_OPTIMIZATION
  132. TRACE_STR(1, "Do first pass optimizations")
  133. for (size_t i = 0; i < nBytes; ++i)
  134. {
  135. Instruction op = Instruction(m_code[i]);
  136. if ((byte)Instruction::PUSH1 <= (byte)op && (byte)op <= (byte)Instruction::PUSH32)
  137. {
  138. byte nPush = (byte)op - (byte)Instruction::PUSH1 + 1;
  139. // decode pushed bytes to integral value
  140. u256 val = m_code[i+1];
  141. for (uint64_t j = i+2, n = nPush; --n; ++j)
  142. val = (val << 8) | m_code[j];
  143. #ifdef EVM_USE_CONSTANT_POOL
  144. // add value to constant pool and replace PUSHn with PUSHC if room
  145. if (1 < nPush)
  146. {
  147. TRACE_PRE_OPT(1, i, op);
  148. int pool_off = poolConstant(val);
  149. if (0 <= pool_off && pool_off < 256)
  150. {
  151. m_code[i] = byte(op = Instruction::PUSHC);
  152. m_code[i+1] = pool_off;
  153. m_code[i+2] = nPush - 1;
  154. }
  155. TRACE_POST_OPT(1, i, op);
  156. }
  157. #endif
  158. #ifdef EVM_REPLACE_CONST_JUMP
  159. // replace JUMP or JUMPI to constant location with JUMPV or JUMPVI
  160. // verifyJumpDest is M = log(number of jump destinations)
  161. // outer loop is N = number of bytes in code array
  162. // so complexity is N log M, worst case is N log N
  163. size_t ii = i + nPush + 1;
  164. op = Instruction(m_code[ii]);
  165. if (op == Instruction::JUMP)
  166. {
  167. TRACE_STR(1, "Replace const JUMPV")
  168. TRACE_PRE_OPT(1, ii, op);
  169. if (0 <= verifyJumpDest(val, false))
  170. m_code[ii] = byte(op = Instruction::JUMPV);
  171. TRACE_POST_OPT(1, ii, op);
  172. }
  173. else if (op == Instruction::JUMPI)
  174. {
  175. TRACE_STR(1, "Replace const JUMPVI")
  176. TRACE_PRE_OPT(1, ii, op);
  177. if (0 <= verifyJumpDest(val, false))
  178. m_code[ii] = byte(op = Instruction::JUMPVI);
  179. TRACE_POST_OPT(1, ii, op);
  180. }
  181. #endif
  182. i += nPush;
  183. }
  184. }
  185. TRACE_STR(1, "Finished optimizations")
  186. #endif
  187. }