heap.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  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 "explorer/ast/value.h"
  6. #include "explorer/common/error_builders.h"
  7. #include "llvm/ADT/StringExtras.h"
  8. #include "llvm/Support/Error.h"
  9. namespace Carbon {
  10. auto Heap::AllocateValue(Nonnull<const Value*> v) -> AllocationId {
  11. // Putting the following two side effects together in this function
  12. // ensures that we don't do anything else in between, which would be really
  13. // bad! Consider whether to include a copy of the input v in this function or
  14. // to leave it up to the caller.
  15. AllocationId a(values_.size());
  16. values_.push_back(v);
  17. if (v->kind() == Carbon::Value::Kind::UninitializedValue) {
  18. states_.push_back(ValueState::Uninitialized);
  19. } else {
  20. states_.push_back(ValueState::Alive);
  21. }
  22. return a;
  23. }
  24. auto Heap::Read(const Address& a, SourceLocation source_loc) const
  25. -> ErrorOr<Nonnull<const Value*>> {
  26. CARBON_RETURN_IF_ERROR(this->CheckInit(a.allocation_, source_loc));
  27. CARBON_RETURN_IF_ERROR(this->CheckAlive(a.allocation_, source_loc));
  28. Nonnull<const Value*> value = values_[a.allocation_.index_];
  29. return value->GetElement(arena_, a.element_path_, source_loc, value);
  30. }
  31. auto Heap::Write(const Address& a, Nonnull<const Value*> v,
  32. SourceLocation source_loc) -> ErrorOr<Success> {
  33. CARBON_RETURN_IF_ERROR(this->CheckAlive(a.allocation_, source_loc));
  34. if (states_[a.allocation_.index_] == ValueState::Uninitialized) {
  35. if (!a.element_path_.IsEmpty()) {
  36. return ProgramError(source_loc)
  37. << "undefined behavior: store to subobject of uninitialized value "
  38. << *values_[a.allocation_.index_];
  39. }
  40. states_[a.allocation_.index_] = ValueState::Alive;
  41. }
  42. CARBON_ASSIGN_OR_RETURN(values_[a.allocation_.index_],
  43. values_[a.allocation_.index_]->SetField(
  44. arena_, a.element_path_, v, source_loc));
  45. return Success();
  46. }
  47. auto Heap::GetAllocationId(Nonnull<const Value*> v) const
  48. -> std::optional<AllocationId> {
  49. auto iter = std::find(values_.begin(), values_.end(), v);
  50. if (iter != values_.end()) {
  51. auto index = iter - values_.begin();
  52. if (states_[index] == ValueState::Alive) {
  53. return AllocationId(index);
  54. }
  55. }
  56. return std::nullopt;
  57. }
  58. auto Heap::CheckAlive(AllocationId allocation, SourceLocation source_loc) const
  59. -> ErrorOr<Success> {
  60. if (states_[allocation.index_] == ValueState::Dead) {
  61. return ProgramError(source_loc)
  62. << "undefined behavior: access to dead value "
  63. << *values_[allocation.index_];
  64. }
  65. return Success();
  66. }
  67. auto Heap::CheckInit(AllocationId allocation, SourceLocation source_loc) const
  68. -> ErrorOr<Success> {
  69. if (states_[allocation.index_] == ValueState::Uninitialized) {
  70. return ProgramError(source_loc)
  71. << "undefined behavior: access to uninitialized value "
  72. << *values_[allocation.index_];
  73. }
  74. return Success();
  75. }
  76. void Heap::Deallocate(AllocationId allocation) {
  77. if (states_[allocation.index_] != ValueState::Dead) {
  78. states_[allocation.index_] = ValueState::Dead;
  79. } else {
  80. CARBON_FATAL() << "deallocating an already dead value: "
  81. << *values_[allocation.index_];
  82. }
  83. }
  84. void Heap::Deallocate(const Address& a) { Deallocate(a.allocation_); }
  85. void Heap::Print(llvm::raw_ostream& out) const {
  86. llvm::ListSeparator sep;
  87. for (size_t i = 0; i < values_.size(); ++i) {
  88. out << sep;
  89. out << i << ": ";
  90. if (states_[i] == ValueState::Uninitialized) {
  91. out << "!";
  92. } else if (states_[i] == ValueState::Dead) {
  93. out << "!!";
  94. }
  95. out << *values_[i];
  96. }
  97. }
  98. } // namespace Carbon