heap.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include "explorer/interpreter/heap.h"
  5. #include "common/check.h"
  6. #include "common/error.h"
  7. #include "explorer/ast/value.h"
  8. #include "explorer/common/error_builders.h"
  9. #include "explorer/common/source_location.h"
  10. #include "llvm/ADT/StringExtras.h"
  11. #include "llvm/Support/Error.h"
  12. namespace Carbon {
  13. auto Heap::AllocateValue(Nonnull<const Value*> v) -> AllocationId {
  14. // Putting the following two side effects together in this function
  15. // ensures that we don't do anything else in between, which would be really
  16. // bad! Consider whether to include a copy of the input v in this function or
  17. // to leave it up to the caller.
  18. AllocationId a(values_.size());
  19. values_.push_back(v);
  20. bool is_uninitialized = false;
  21. if (v->kind() == Carbon::Value::Kind::UninitializedValue) {
  22. states_.push_back(ValueState::Uninitialized);
  23. is_uninitialized = true;
  24. } else {
  25. states_.push_back(ValueState::Alive);
  26. }
  27. bound_values_.push_back(llvm::DenseMap<const AstNode*, Address>{});
  28. if (trace_stream_->is_enabled()) {
  29. *trace_stream_ << "(+) memory-alloc: #" << a.index_ << " `" << *v << "`"
  30. << (is_uninitialized ? " uninitialized" : "") << "\n";
  31. }
  32. return a;
  33. }
  34. auto Heap::Read(const Address& a, SourceLocation source_loc) const
  35. -> ErrorOr<Nonnull<const Value*>> {
  36. CARBON_RETURN_IF_ERROR(this->CheckInit(a.allocation_, source_loc));
  37. CARBON_RETURN_IF_ERROR(this->CheckAlive(a.allocation_, source_loc));
  38. Nonnull<const Value*> value = values_[a.allocation_.index_];
  39. ErrorOr<Nonnull<const Value*>> read_value =
  40. value->GetElement(arena_, a.element_path_, source_loc, value);
  41. if (trace_stream_->is_enabled()) {
  42. *trace_stream_ << "+++ memory-read: #" << a.allocation_.index_ << " `"
  43. << **read_value << "`\n";
  44. }
  45. return read_value;
  46. }
  47. auto Heap::Write(const Address& a, Nonnull<const Value*> v,
  48. SourceLocation source_loc) -> ErrorOr<Success> {
  49. CARBON_RETURN_IF_ERROR(this->CheckAlive(a.allocation_, source_loc));
  50. if (states_[a.allocation_.index_] == ValueState::Uninitialized) {
  51. if (!a.element_path_.IsEmpty()) {
  52. return ProgramError(source_loc)
  53. << "undefined behavior: store to subobject of uninitialized value "
  54. << *values_[a.allocation_.index_];
  55. }
  56. states_[a.allocation_.index_] = ValueState::Alive;
  57. }
  58. CARBON_ASSIGN_OR_RETURN(values_[a.allocation_.index_],
  59. values_[a.allocation_.index_]->SetField(
  60. arena_, a.element_path_, v, source_loc));
  61. auto& bound_values_map = bound_values_[a.allocation_.index_];
  62. // End lifetime of all values bound to this address and its subobjects.
  63. if (a.element_path_.IsEmpty()) {
  64. bound_values_map.clear();
  65. } else {
  66. for (auto value_it = bound_values_map.begin();
  67. value_it != bound_values_map.end(); ++value_it) {
  68. if (AddressesAreStrictlyNested(a, value_it->second)) {
  69. bound_values_map.erase(value_it);
  70. }
  71. }
  72. }
  73. if (trace_stream_->is_enabled()) {
  74. *trace_stream_ << "+++ memory-write: #" << a.allocation_.index_ << " `"
  75. << *values_[a.allocation_.index_] << "`\n";
  76. }
  77. return Success();
  78. }
  79. auto Heap::CheckAlive(AllocationId allocation, SourceLocation source_loc) const
  80. -> ErrorOr<Success> {
  81. const auto state = states_[allocation.index_];
  82. if (state == ValueState::Dead || state == ValueState::Discarded) {
  83. return ProgramError(source_loc)
  84. << "undefined behavior: access to dead or discarded value "
  85. << *values_[allocation.index_];
  86. }
  87. return Success();
  88. }
  89. auto Heap::CheckInit(AllocationId allocation, SourceLocation source_loc) const
  90. -> ErrorOr<Success> {
  91. if (states_[allocation.index_] == ValueState::Uninitialized) {
  92. return ProgramError(source_loc)
  93. << "undefined behavior: access to uninitialized value "
  94. << *values_[allocation.index_];
  95. }
  96. return Success();
  97. }
  98. auto Heap::Deallocate(AllocationId allocation) -> ErrorOr<Success> {
  99. if (states_[allocation.index_] != ValueState::Dead) {
  100. states_[allocation.index_] = ValueState::Dead;
  101. } else {
  102. CARBON_FATAL() << "deallocating an already dead value: "
  103. << *values_[allocation.index_];
  104. }
  105. if (trace_stream_->is_enabled()) {
  106. *trace_stream_ << "(-) memory-dealloc: #" << allocation.index_ << " `"
  107. << *values_[allocation.index_] << "`\n";
  108. }
  109. return Success();
  110. }
  111. auto Heap::Deallocate(const Address& a) -> ErrorOr<Success> {
  112. return Deallocate(a.allocation_);
  113. }
  114. auto Heap::is_initialized(AllocationId allocation) const -> bool {
  115. return states_[allocation.index_] != ValueState::Uninitialized;
  116. }
  117. auto Heap::is_discarded(AllocationId allocation) const -> bool {
  118. return states_[allocation.index_] == ValueState::Discarded;
  119. }
  120. void Heap::Discard(AllocationId allocation) {
  121. CARBON_CHECK(states_[allocation.index_] == ValueState::Uninitialized);
  122. states_[allocation.index_] = ValueState::Discarded;
  123. }
  124. void Heap::BindValueToReference(const ValueNodeView& node, const Address& a) {
  125. // Update mapped node ignoring any previous mapping.
  126. bound_values_[a.allocation_.index_].insert({&node.base(), a});
  127. }
  128. auto Heap::is_bound_value_alive(const ValueNodeView& node,
  129. const Address& a) const -> bool {
  130. return bound_values_[a.allocation_.index_].contains(&node.base());
  131. }
  132. void Heap::Print(llvm::raw_ostream& out) const {
  133. llvm::ListSeparator sep;
  134. for (size_t i = 0; i < values_.size(); ++i) {
  135. out << sep;
  136. out << i << ": ";
  137. if (states_[i] == ValueState::Uninitialized) {
  138. out << "!";
  139. } else if (states_[i] == ValueState::Dead) {
  140. out << "!!";
  141. }
  142. out << *values_[i];
  143. }
  144. }
  145. auto Heap::AddressesAreStrictlyNested(const Address& first,
  146. const Address& second) -> bool {
  147. if (first.allocation_.index_ != second.allocation_.index_) {
  148. return false;
  149. }
  150. return PathsAreStrictlyNested(first.element_path_, second.element_path_);
  151. }
  152. auto Heap::PathsAreStrictlyNested(const ElementPath& first,
  153. const ElementPath& second) -> bool {
  154. for (size_t i = 0;
  155. i < std::min(first.components_.size(), second.components_.size()); ++i) {
  156. Nonnull<const Element*> element = first.components_[i].element();
  157. Nonnull<const Element*> other_element = second.components_[i].element();
  158. if (element->kind() != other_element->kind()) {
  159. return false;
  160. }
  161. switch (element->kind()) {
  162. case Carbon::ElementKind::NamedElement:
  163. if (!element->IsNamed(
  164. llvm::cast<NamedElement>(other_element)->name())) {
  165. return false;
  166. }
  167. break;
  168. case Carbon::ElementKind::PositionalElement:
  169. if (llvm::cast<PositionalElement>(element)->index() !=
  170. llvm::cast<PositionalElement>(other_element)->index()) {
  171. return false;
  172. }
  173. break;
  174. case Carbon::ElementKind::BaseElement:
  175. // Nothing to test.
  176. break;
  177. }
  178. }
  179. return true;
  180. }
  181. } // namespace Carbon