ExtVM.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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. /** @file ExtVM.cpp
  15. * @author Gav Wood <i@gavwood.com>
  16. * @date 2014
  17. */
  18. #include "ExtVM.h"
  19. #include <exception>
  20. #include <boost/thread.hpp>
  21. #include "Executive.h"
  22. using namespace dev;
  23. using namespace dev::eth;
  24. namespace // anonymous
  25. {
  26. static unsigned const c_depthLimit = 1024;
  27. /// Upper bound of stack space needed by single CALL/CREATE execution. Set experimentally.
  28. static size_t const c_singleExecutionStackSize = 14 * 1024;
  29. /// Standard thread stack size.
  30. static size_t const c_defaultStackSize =
  31. #if defined(__linux)
  32. 8 * 1024 * 1024;
  33. #elif defined(_WIN32)
  34. 16 * 1024 * 1024;
  35. #else
  36. 512 * 1024; // OSX and other OSs
  37. #endif
  38. /// Stack overhead prior to allocation.
  39. static size_t const c_entryOverhead = 128 * 1024;
  40. /// On what depth execution should be offloaded to additional separated stack space.
  41. static unsigned const c_offloadPoint = (c_defaultStackSize - c_entryOverhead) / c_singleExecutionStackSize;
  42. void goOnOffloadedStack(Executive& _e, OnOpFunc const& _onOp)
  43. {
  44. // Set new stack size enouth to handle the rest of the calls up to the limit.
  45. boost::thread::attributes attrs;
  46. attrs.set_stack_size((c_depthLimit - c_offloadPoint) * c_singleExecutionStackSize);
  47. // Create new thread with big stack and join immediately.
  48. // TODO: It is possible to switch the implementation to Boost.Context or similar when the API is stable.
  49. boost::exception_ptr exception;
  50. boost::thread{attrs, [&]{
  51. try
  52. {
  53. _e.go(_onOp);
  54. }
  55. catch (...)
  56. {
  57. exception = boost::current_exception(); // Catch all exceptions to be rethrown in parent thread.
  58. }
  59. }}.join();
  60. if (exception)
  61. boost::rethrow_exception(exception);
  62. }
  63. void go(unsigned _depth, Executive& _e, OnOpFunc const& _onOp)
  64. {
  65. // If in the offloading point we need to switch to additional separated stack space.
  66. // Current stack is too small to handle more CALL/CREATE executions.
  67. // It needs to be done only once as newly allocated stack space it enough to handle
  68. // the rest of the calls up to the depth limit (c_depthLimit).
  69. if (_depth == c_offloadPoint)
  70. {
  71. cnote << "Stack offloading (depth: " << c_offloadPoint << ")";
  72. goOnOffloadedStack(_e, _onOp);
  73. }
  74. else
  75. _e.go(_onOp);
  76. }
  77. } // anonymous namespace
  78. bool ExtVM::call(CallParameters& _p)
  79. {
  80. Executive e(m_s, envInfo(), m_sealEngine, depth + 1);
  81. if (!e.call(_p, gasPrice, origin))
  82. {
  83. go(depth, e, _p.onOp);
  84. e.accrueSubState(sub);
  85. }
  86. _p.gas = e.gas();
  87. return !e.excepted();
  88. }
  89. size_t ExtVM::codeSizeAt(dev::Address _a)
  90. {
  91. return m_s.codeSize(_a);
  92. }
  93. h160 ExtVM::create(u256 _endowment, u256& io_gas, bytesConstRef _code, OnOpFunc const& _onOp)
  94. {
  95. Executive e(m_s, envInfo(), m_sealEngine, depth + 1);
  96. if (!e.create(myAddress, _endowment, gasPrice, io_gas, _code, origin))
  97. {
  98. go(depth, e, _onOp);
  99. e.accrueSubState(sub);
  100. }
  101. io_gas = e.gas();
  102. return e.newAddress();
  103. }