StatementReader.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "RuntimeByteCodePch.h"
  6. namespace Js
  7. {
  8. template <typename TStatementMapList>
  9. void StatementReader<TStatementMapList>::Create(FunctionBody * functionRead, uint startOffset /* = 0 */)
  10. {
  11. Assert(functionRead);
  12. StatementReader::Create(functionRead, startOffset, false);
  13. }
  14. template <typename TStatementMapList>
  15. void StatementReader<TStatementMapList>::Create(
  16. _In_ const byte * byteCodeStart,
  17. uint startOffset,
  18. Js::SmallSpanSequence * statementMap,
  19. TStatementMapList* fullstatementMap)
  20. {
  21. m_startLocation = byteCodeStart;
  22. const byte * currentLocation = m_startLocation + startOffset;
  23. m_statementMap = statementMap;
  24. m_fullstatementMap = fullstatementMap;
  25. if (m_statementMap && m_statementMap->Count())
  26. {
  27. m_statementMap->Reset(m_statementMapIter);
  28. m_statementIndex = 0;
  29. m_startOfStatement = true;
  30. StatementData data;
  31. if (!m_statementMap->Seek(m_statementIndex, data))
  32. {
  33. Assert(FALSE);
  34. }
  35. m_nextStatementBoundary = m_startLocation + data.bytecodeBegin;
  36. // If we starting in the middle of the function (e.g., loop body), find out where the next statement is.
  37. while (m_nextStatementBoundary < currentLocation)
  38. {
  39. this->MoveNextStatementBoundary();
  40. }
  41. }
  42. else if (m_fullstatementMap && m_fullstatementMap->Count())
  43. {
  44. m_statementIndex = 0;
  45. m_startOfStatement = true;
  46. FunctionBody::StatementMap *nextMap = Js::FunctionBody::GetNextNonSubexpressionStatementMap(m_fullstatementMap, m_statementIndex);
  47. if (!nextMap)
  48. {
  49. // set to a location that will never match
  50. m_nextStatementBoundary = currentLocation - 1;
  51. }
  52. else
  53. {
  54. m_nextStatementBoundary = m_startLocation + m_fullstatementMap->Item(m_statementIndex)->byteCodeSpan.begin;
  55. // If we starting in the middle of the function (e.g., loop body), find out where the next statement is.
  56. while (m_nextStatementBoundary < currentLocation)
  57. {
  58. this->MoveNextStatementBoundary();
  59. }
  60. }
  61. }
  62. else
  63. {
  64. // set to a location that will never match
  65. m_nextStatementBoundary = currentLocation - 1;
  66. }
  67. }
  68. template <>
  69. void StatementReader<FunctionBody::ArenaStatementMapList>::Create(FunctionBody* functionRead, uint startOffset, bool useOriginalByteCode)
  70. {
  71. Assert(UNREACHED);
  72. }
  73. template <>
  74. void StatementReader<FunctionBody::StatementMapList>::Create(FunctionBody* functionRead, uint startOffset, bool useOriginalByteCode)
  75. {
  76. AssertMsg(functionRead != nullptr, "Must provide valid function to execute");
  77. ByteBlock * pblkByteCode = useOriginalByteCode ?
  78. functionRead->GetOriginalByteCode() :
  79. functionRead->GetByteCode();
  80. AssertMsg(pblkByteCode != nullptr, "Must have valid byte-code to read");
  81. SmallSpanSequence* statementMap = functionRead->GetStatementMapSpanSequence();
  82. FunctionBody::StatementMapList* fullMap = nullptr;
  83. if (statementMap == nullptr && functionRead->IsInDebugMode())
  84. {
  85. fullMap = functionRead->GetStatementMaps();
  86. }
  87. Create(pblkByteCode->GetBuffer(), startOffset, statementMap, fullMap);
  88. }
  89. template <typename TStatementMapList>
  90. uint32 StatementReader<TStatementMapList>::MoveNextStatementBoundary()
  91. {
  92. StatementData data;
  93. uint32 retStatement = Js::Constants::NoStatementIndex;
  94. if (m_startOfStatement)
  95. {
  96. m_statementIndex++;
  97. if (m_statementMap && (uint32)m_statementIndex < m_statementMap->Count() && m_statementMap->Item(m_statementIndex, m_statementMapIter, data))
  98. {
  99. // The end boundary is the last byte of the last instruction in the previous range.
  100. // We want to track the beginning of the next instruction for AtStatementBoundary.
  101. m_nextStatementBoundary = m_startLocation + data.bytecodeBegin;
  102. // The next user statement is adjacent in the bytecode
  103. retStatement = m_statementIndex;
  104. }
  105. else if (m_fullstatementMap && m_statementIndex < m_fullstatementMap->Count())
  106. {
  107. int nextInstrStart = m_fullstatementMap->Item(m_statementIndex - 1)->byteCodeSpan.end + 1;
  108. m_nextStatementBoundary = m_startLocation + nextInstrStart;
  109. Js::FunctionBody::GetNextNonSubexpressionStatementMap(m_fullstatementMap, m_statementIndex);
  110. if (nextInstrStart == m_fullstatementMap->Item(m_statementIndex)->byteCodeSpan.begin)
  111. {
  112. retStatement = m_statementIndex;
  113. }
  114. else
  115. {
  116. m_startOfStatement = false;
  117. }
  118. }
  119. else
  120. {
  121. m_startOfStatement = false;
  122. }
  123. }
  124. else
  125. {
  126. m_startOfStatement = true;
  127. if (m_statementMap && (uint32)m_statementIndex < m_statementMap->Count() && m_statementMap->Item(m_statementIndex, m_statementMapIter, data))
  128. {
  129. // Start a range of bytecode that maps to a user statement
  130. m_nextStatementBoundary = m_startLocation + data.bytecodeBegin;
  131. retStatement = m_statementIndex;
  132. }
  133. else if (m_fullstatementMap && m_statementIndex < m_fullstatementMap->Count())
  134. {
  135. FunctionBody::StatementMap *nextMap = Js::FunctionBody::GetNextNonSubexpressionStatementMap(m_fullstatementMap, m_statementIndex);
  136. if (!nextMap)
  137. {
  138. // set to a location that will never match
  139. m_nextStatementBoundary = m_startLocation - 1;
  140. }
  141. else
  142. {
  143. // Start a range of bytecode that maps to a user statement
  144. m_nextStatementBoundary = m_startLocation + m_fullstatementMap->Item(m_statementIndex)->byteCodeSpan.begin;
  145. retStatement = m_statementIndex;
  146. }
  147. }
  148. else
  149. {
  150. // The remaining bytecode instructions do not map to a user statement, set a statementBoundary that cannot match
  151. m_nextStatementBoundary = m_startLocation - 1;
  152. }
  153. }
  154. return retStatement;
  155. }
  156. // explicit instantiations
  157. template class StatementReader<FunctionBody::ArenaStatementMapList>;
  158. template class StatementReader<FunctionBody::StatementMapList>;
  159. } // namespace Js