chromium/v8/src/objects/tagged-field.h

// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_OBJECTS_TAGGED_FIELD_H_
#define V8_OBJECTS_TAGGED_FIELD_H_

#include "src/base/atomicops.h"
#include "src/base/macros.h"
#include "src/base/template-meta-programming/functional.h"
#include "src/common/globals.h"
#include "src/common/ptr-compr.h"
#include "src/objects/tagged-value.h"

namespace v8::internal {

// TaggedMember<T> represents an potentially compressed V8 tagged pointer, which
// is intended to be used as a member of a V8 object class.
//
// TODO(leszeks): Merge with TaggedField.
template <typename T, typename CompressionScheme = V8HeapCompressionScheme>
class TaggedMember;

// Base class for all TaggedMember<T> classes.
// TODO(leszeks): Merge with TaggedImpl.
TaggedMemberBase;

template <typename T, typename CompressionScheme>
class TaggedMember : public TaggedMemberBase {};

static_assert(alignof(TaggedMember<Object>) == alignof(Tagged_t));
static_assert(sizeof(TaggedMember<Object>) == sizeof(Tagged_t));

template <typename T>
class UnalignedValueMember {};

class UnalignedDoubleMember : public UnalignedValueMember<double> {};
static_assert;
static_assert;

// FLEXIBLE_ARRAY_MEMBER(T, name) represents a marker for a variable-sized
// suffix of members for a type.
//
// It behaves as if it were the last member of a class, and creates an accessor
// for `T* name()`.
//
// This macro is used instead of the C99 flexible array member syntax, because
//
//   a) That syntax is only in C++ as an extension,
//   b) On all our major compilers, it doesn't allow the class to have
//      subclasses (which means it doesn't work for e.g. TaggedArrayBase or
//      BigIntBase),
//   c) The similar zero-length array extension _also_ doesn't allow subclasses
//      on some compilers (specifically, MSVC).
//
// On compilers that do support zero length arrays (i.e. not MSVC), we use one
// of these instead of `this` pointer fiddling. This gives LLVM better
// information for optimization, and gives us the warnings we'd want to have
// (e.g. only allowing one FAM in a class, ensuring that OFFSET_OF_DATA_START is
// only used on classes with a FAM) on clang -- the MSVC version then doesn't
// check the same constraints, and relies on the code being equivalent enough.
#if V8_CC_MSVC && !defined(__clang__)
// MSVC doesn't support zero length arrays in base classes. Cast the
// one-past-this value to a zero length array reference, so that the return
// values match that in GCC/clang.
#define FLEXIBLE_ARRAY_MEMBER
#else
// GCC and clang allow zero length arrays in base classes. Return the zero
// length array by reference, to avoid array-to-pointer decay which can lose
// aliasing information.
#define FLEXIBLE_ARRAY_MEMBER(Type, name)
#endif

// OFFSET_OF_DATA_START(T) returns the offset of the FLEXIBLE_ARRAY_MEMBER of
// the class T.
#if V8_CC_MSVC && !defined(__clang__)
#define OFFSET_OF_DATA_START
#else
#define OFFSET_OF_DATA_START(Type)
#endif

// This helper static class represents a tagged field of type T at offset
// kFieldOffset inside some host HeapObject.
// For full-pointer mode this type adds no overhead but when pointer
// compression is enabled such class allows us to use proper decompression
// function depending on the field type.
template <typename T, int kFieldOffset = 0,
          typename CompressionScheme = V8HeapCompressionScheme>
class TaggedField : public AllStatic {};

template <typename T>
class TaggedField<Tagged<T>> : public TaggedField<T> {};

template <typename T, int kFieldOffset>
class TaggedField<Tagged<T>, kFieldOffset>
    : public TaggedField<T, kFieldOffset> {};

TaggedField<Tagged<T>, kFieldOffset, CompressionScheme>;

}  // namespace v8::internal

#endif  // V8_OBJECTS_TAGGED_FIELD_H_