source/MemoryLocation.cpp (123 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #include <fmt/format.h> #include <Show.h> #include <mariana-trench/Assert.h> #include <mariana-trench/MemoryLocation.h> namespace marianatrench { FieldMemoryLocation* MemoryLocation::make_field(const DexString* field) { mt_assert(field != nullptr); auto found = fields_.find(field); if (found != fields_.end()) { return found->second.get(); } // To avoid non-convergence, we need to break infinite chains. // If any parent of `this` is already a `FieldMemoryLocation` for the given // field, return it in order to collapse the memory locations into a single // location. MemoryLocation* memory_location = this; while (auto* field_memory_location = memory_location->dyn_cast<FieldMemoryLocation>()) { if (field_memory_location->field() == field) { return field_memory_location; } else { memory_location = field_memory_location->parent(); } } auto result = fields_.emplace( field, std::make_unique<FieldMemoryLocation>(this, field)); mt_assert(result.second); return result.first->second.get(); } MemoryLocation* MemoryLocation::root() { // By defaut, this is a root memory location. return this; } const Path& MemoryLocation::path() { // By default, this is a root memory location. static const Path empty_path; return empty_path; } std::optional<AccessPath> MemoryLocation::access_path() { auto* parameter = root()->dyn_cast<ParameterMemoryLocation>(); if (!parameter) { return std::nullopt; } return AccessPath(Root(Root::Kind::Argument, parameter->position()), path()); } std::ostream& operator<<( std::ostream& out, const MemoryLocation& memory_location) { return out << memory_location.str(); } ParameterMemoryLocation::ParameterMemoryLocation(ParameterPosition position) : position_(position) {} std::string ParameterMemoryLocation::str() const { return fmt::format("ParameterMemoryLocation({})", position_); } ThisParameterMemoryLocation::ThisParameterMemoryLocation() : ParameterMemoryLocation(0) {} std::string ThisParameterMemoryLocation::str() const { return "ThisParameterMemoryLocation"; } FieldMemoryLocation::FieldMemoryLocation( MemoryLocation* parent, const DexString* field) : parent_(parent), field_(field), root_(parent->root()), path_(parent->path()) { mt_assert(parent != nullptr); mt_assert(field != nullptr); path_.append(field); } std::string FieldMemoryLocation::str() const { return fmt::format( "FieldMemoryLocation({}, `{}`)", parent_->str(), show(field_)); } MemoryLocation* FieldMemoryLocation::root() { return root_; } const Path& FieldMemoryLocation::path() { return path_; } InstructionMemoryLocation::InstructionMemoryLocation( const IRInstruction* instruction) : instruction_(instruction) { mt_assert(instruction != nullptr); } std::string InstructionMemoryLocation::str() const { return fmt::format("InstructionMemoryLocation(`{}`)", show(instruction_)); } std::optional<std::string> InstructionMemoryLocation::get_constant() const { if (instruction_->has_literal()) { return std::to_string(instruction_->get_literal()); } else if (instruction_->has_string()) { return instruction_->get_string()->str(); } return std::nullopt; } MemoryFactory::MemoryFactory(const Method* method) { mt_assert(method != nullptr); // Create parameter locations for (ParameterPosition i = 0; i < method->number_of_parameters(); i++) { if (i == 0 && !method->is_static()) { parameters_.push_back(std::make_unique<ThisParameterMemoryLocation>()); } else { parameters_.push_back(std::make_unique<ParameterMemoryLocation>(i)); } } } ParameterMemoryLocation* MemoryFactory::make_parameter( ParameterPosition parameter_position) { static_assert(std::is_unsigned_v<ParameterPosition>); if (parameter_position >= parameters_.size()) { throw std::out_of_range( "Accessing out of bounds parameter in memory factory."); } return parameters_[parameter_position].get(); } InstructionMemoryLocation* MemoryFactory::make_location( const IRInstruction* instruction) { mt_assert(instruction != nullptr); auto found = instructions_.find(instruction); if (found != instructions_.end()) { return found->second.get(); } auto result = instructions_.emplace( instruction, std::make_unique<InstructionMemoryLocation>(instruction)); mt_assert(result.second); return result.first->second.get(); } } // namespace marianatrench