blob: b847c2d907cec9c922512046f49c7874611d13ec [file] [log] [blame]
//===--- MemberAccessStrategy.h - Abstract member access --------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file defines an interface for summarizing how to access a
// particular physical member.
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_IRGEN_MEMBERACCESSSTRATEGY_H
#define SWIFT_IRGEN_MEMBERACCESSSTRATEGY_H
#include <string>
#include "IRGen.h"
namespace swift {
namespace irgen {
/// A class which describes how to access a particular physical member.
class MemberAccessStrategy {
public:
enum class OffsetKind : unsigned char {
/// A word-size offset that represents a number of bytes.
Bytes_Word,
};
enum class Kind : unsigned char {
/// The member has complex or overlapping storage. It cannot be
/// accessed simply by projecting out to a particular offset.
Complex,
/// The member is at an offset which is statically known.
DirectFixed,
/// The member is at an offset which must be loaded from global memory.
DirectGlobal,
/// The member is at an offset which must be loaded from a
/// statically-known offset within the type's metadata.
IndirectFixed,
/// The member is at an offset which must be loaded from an offset
/// within the type's metadata, which itself must be loaded from
/// a global symbol.
IndirectGlobal,
};
private:
union StorageType {
std::string GlobalSymbol;
Size FixedOffset;
StorageType() {}
~StorageType() {}
} Storage;
Kind TheKind;
OffsetKind DirectOffsetKind;
OffsetKind IndirectOffsetKind;
explicit MemberAccessStrategy(Kind kind) : TheKind(kind) {}
public:
// These are implementable, but there's no need.
MemberAccessStrategy(const MemberAccessStrategy &other) = delete;
MemberAccessStrategy &operator=(const MemberAccessStrategy &other) = delete;
MemberAccessStrategy(MemberAccessStrategy &&other)
: TheKind(other.TheKind) {
switch (TheKind) {
case Kind::Complex:
return;
case Kind::DirectFixed:
Storage.FixedOffset = other.Storage.FixedOffset;
return;
case Kind::DirectGlobal:
DirectOffsetKind = other.DirectOffsetKind;
::new (&Storage.GlobalSymbol)
std::string(std::move(other.Storage.GlobalSymbol));
return;
case Kind::IndirectFixed:
DirectOffsetKind = other.DirectOffsetKind;
Storage.FixedOffset = other.Storage.FixedOffset;
return;
case Kind::IndirectGlobal:
DirectOffsetKind = other.DirectOffsetKind;
IndirectOffsetKind = other.IndirectOffsetKind;
::new (&Storage.GlobalSymbol)
std::string(std::move(other.Storage.GlobalSymbol));
return;
}
llvm_unreachable("bad member access strategy kind");
}
MemberAccessStrategy &operator=(MemberAccessStrategy &&other) {
this->~MemberAccessStrategy();
::new (this) MemberAccessStrategy(std::move(other));
return *this;
}
~MemberAccessStrategy() {
switch (TheKind) {
case Kind::Complex:
case Kind::DirectFixed:
case Kind::IndirectFixed:
return;
case Kind::DirectGlobal:
case Kind::IndirectGlobal:
Storage.GlobalSymbol.~basic_string();
return;
}
llvm_unreachable("bad member access strategy kind");
}
static MemberAccessStrategy
getComplex() {
return MemberAccessStrategy(Kind::Complex);
}
static MemberAccessStrategy
getDirectFixed(Size directOffset) {
MemberAccessStrategy result(Kind::DirectFixed);
result.Storage.FixedOffset = directOffset;
return result;
}
static MemberAccessStrategy
getDirectGlobal(std::string &&directOffsetSymbol,
OffsetKind directOffsetKind) {
MemberAccessStrategy result(Kind::DirectGlobal);
::new(&result.Storage.GlobalSymbol)
std::string(std::move(directOffsetSymbol));
result.DirectOffsetKind = directOffsetKind;
return result;
}
static MemberAccessStrategy
getIndirectFixed(Size indirectOffset, OffsetKind directOffsetKind) {
MemberAccessStrategy result(Kind::IndirectFixed);
result.Storage.FixedOffset = indirectOffset;
result.DirectOffsetKind = directOffsetKind;
return result;
}
static MemberAccessStrategy
getIndirectGlobal(std::string &&indirectOffsetSymbol,
OffsetKind indirectOffsetKind,
OffsetKind directOffsetKind) {
MemberAccessStrategy result(Kind::DirectGlobal);
::new(&result.Storage.GlobalSymbol)
std::string(std::move(indirectOffsetSymbol));
result.IndirectOffsetKind = indirectOffsetKind;
result.DirectOffsetKind = directOffsetKind;
return result;
}
Kind getKind() const { return TheKind; }
OffsetKind getDirectOffsetKind() const {
assert(TheKind == Kind::DirectGlobal ||
TheKind == Kind::IndirectFixed ||
TheKind == Kind::IndirectGlobal);
return DirectOffsetKind;
}
OffsetKind getIndirectOffsetKind() const {
assert(TheKind == Kind::IndirectGlobal);
return IndirectOffsetKind;
}
Size getDirectOffset() const {
assert(TheKind == Kind::DirectFixed);
return Storage.FixedOffset;
}
Size getIndirectOffset() const {
assert(TheKind == Kind::IndirectFixed);
return Storage.FixedOffset;
}
const std::string &getDirectGlobalSymbol() const {
assert(TheKind == Kind::DirectGlobal);
return Storage.GlobalSymbol;
}
const std::string &getIndirectGlobalSymbol() const {
assert(TheKind == Kind::IndirectGlobal);
return Storage.GlobalSymbol;
}
};
} // end namespace irgen
} // end namespace swift
#endif