heap.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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/base/error_builders.h"
  9. #include "explorer/base/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_->Allocate()
  30. << "memory-alloc: #" << a.index_ << " `" << *v << "`"
  31. << (is_uninitialized ? " uninitialized" : "") << "\n";
  32. }
  33. return a;
  34. }
  35. auto Heap::Read(const Address& a, SourceLocation source_loc) const
  36. -> ErrorOr<Nonnull<const Value*>> {
  37. CARBON_RETURN_IF_ERROR(this->CheckInit(a.allocation_, source_loc));
  38. CARBON_RETURN_IF_ERROR(this->CheckAlive(a.allocation_, source_loc));
  39. Nonnull<const Value*> value = values_[a.allocation_.index_];
  40. ErrorOr<Nonnull<const Value*>> read_value =
  41. value->GetElement(arena_, a.element_path_, source_loc, value);
  42. if (trace_stream_->is_enabled()) {
  43. trace_stream_->Read() << "memory-read: #" << a.allocation_.index_ << " `"
  44. << **read_value << "`\n";
  45. }
  46. return read_value;
  47. }
  48. auto Heap::Write(const Address& a, Nonnull<const Value*> v,
  49. SourceLocation source_loc) -> ErrorOr<Success> {
  50. CARBON_RETURN_IF_ERROR(this->CheckAlive(a.allocation_, source_loc));
  51. if (states_[a.allocation_.index_] == ValueState::Uninitialized) {
  52. if (!a.element_path_.IsEmpty()) {
  53. return ProgramError(source_loc)
  54. << "undefined behavior: store to subobject of uninitialized value "
  55. << *values_[a.allocation_.index_];
  56. }
  57. states_[a.allocation_.index_] = ValueState::Alive;
  58. }
  59. CARBON_ASSIGN_OR_RETURN(values_[a.allocation_.index_],
  60. values_[a.allocation_.index_]->SetField(
  61. arena_, a.element_path_, v, source_loc));
  62. auto& bound_values_map = bound_values_[a.allocation_.index_];
  63. // End lifetime of all values bound to this address and its subobjects.
  64. if (a.element_path_.IsEmpty()) {
  65. bound_values_map.clear();
  66. } else {
  67. for (auto value_it = bound_values_map.begin();
  68. value_it != bound_values_map.end(); ++value_it) {
  69. if (AddressesAreStrictlyNested(a, value_it->second)) {
  70. bound_values_map.erase(value_it);
  71. }
  72. }
  73. }
  74. if (trace_stream_->is_enabled()) {
  75. trace_stream_->Write() << "memory-write: #" << a.allocation_.index_ << " `"
  76. << *values_[a.allocation_.index_] << "`\n";
  77. }
  78. return Success();
  79. }
  80. auto Heap::CheckAlive(AllocationId allocation, SourceLocation source_loc) const
  81. -> ErrorOr<Success> {
  82. const auto state = states_[allocation.index_];
  83. if (state == ValueState::Dead || state == ValueState::Discarded) {
  84. return ProgramError(source_loc)
  85. << "undefined behavior: access to dead or discarded value "
  86. << *values_[allocation.index_];
  87. }
  88. return Success();
  89. }
  90. auto Heap::CheckInit(AllocationId allocation, SourceLocation source_loc) const
  91. -> ErrorOr<Success> {
  92. if (states_[allocation.index_] == ValueState::Uninitialized) {
  93. return ProgramError(source_loc)
  94. << "undefined behavior: access to uninitialized value "
  95. << *values_[allocation.index_];
  96. }
  97. return Success();
  98. }
  99. auto Heap::Deallocate(AllocationId allocation) -> ErrorOr<Success> {
  100. if (states_[allocation.index_] != ValueState::Dead) {
  101. states_[allocation.index_] = ValueState::Dead;
  102. } else {
  103. CARBON_FATAL() << "deallocating an already dead value: "
  104. << *values_[allocation.index_];
  105. }
  106. if (trace_stream_->is_enabled()) {
  107. trace_stream_->Deallocate() << "memory-dealloc: #" << allocation.index_
  108. << " `" << *values_[allocation.index_] << "`\n";
  109. }
  110. return Success();
  111. }
  112. auto Heap::Deallocate(const Address& a) -> ErrorOr<Success> {
  113. return Deallocate(a.allocation_);
  114. }
  115. auto Heap::is_initialized(AllocationId allocation) const -> bool {
  116. return states_[allocation.index_] != ValueState::Uninitialized;
  117. }
  118. auto Heap::is_discarded(AllocationId allocation) const -> bool {
  119. return states_[allocation.index_] == ValueState::Discarded;
  120. }
  121. void Heap::Discard(AllocationId allocation) {
  122. CARBON_CHECK(states_[allocation.index_] == ValueState::Uninitialized);
  123. states_[allocation.index_] = ValueState::Discarded;
  124. }
  125. void Heap::BindValueToReference(const ValueNodeView& node, const Address& a) {
  126. // Update mapped node ignoring any previous mapping.
  127. bound_values_[a.allocation_.index_].insert({&node.base(), a});
  128. }
  129. auto Heap::is_bound_value_alive(const ValueNodeView& node,
  130. const Address& a) const -> bool {
  131. return bound_values_[a.allocation_.index_].contains(&node.base());
  132. }
  133. void Heap::Print(llvm::raw_ostream& out) const {
  134. llvm::ListSeparator sep;
  135. for (size_t i = 0; i < values_.size(); ++i) {
  136. out << sep;
  137. out << i << ": ";
  138. if (states_[i] == ValueState::Uninitialized) {
  139. out << "!";
  140. } else if (states_[i] == ValueState::Dead) {
  141. out << "!!";
  142. }
  143. out << *values_[i];
  144. }
  145. }
  146. auto Heap::AddressesAreStrictlyNested(const Address& first,
  147. const Address& second) -> bool {
  148. if (first.allocation_.index_ != second.allocation_.index_) {
  149. return false;
  150. }
  151. return PathsAreStrictlyNested(first.element_path_, second.element_path_);
  152. }
  153. auto Heap::PathsAreStrictlyNested(const ElementPath& first,
  154. const ElementPath& second) -> bool {
  155. for (size_t i = 0;
  156. i < std::min(first.components_.size(), second.components_.size()); ++i) {
  157. Nonnull<const Element*> element = first.components_[i].element();
  158. Nonnull<const Element*> other_element = second.components_[i].element();
  159. if (element->kind() != other_element->kind()) {
  160. return false;
  161. }
  162. switch (element->kind()) {
  163. case Carbon::ElementKind::NamedElement:
  164. if (!element->IsNamed(
  165. llvm::cast<NamedElement>(other_element)->name())) {
  166. return false;
  167. }
  168. break;
  169. case Carbon::ElementKind::PositionalElement:
  170. if (llvm::cast<PositionalElement>(element)->index() !=
  171. llvm::cast<PositionalElement>(other_element)->index()) {
  172. return false;
  173. }
  174. break;
  175. case Carbon::ElementKind::BaseElement:
  176. // Nothing to test.
  177. break;
  178. }
  179. }
  180. return true;
  181. }
  182. } // namespace Carbon