blob: 807cf73bc994805c0c3104f37405625175a8bb75 [file] [log] [blame]
// Copyright 2017 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_NAME_H_
#define V8_OBJECTS_NAME_H_
#include <atomic>
#include "src/base/bit-field.h"
#include "src/objects/objects.h"
#include "src/objects/primitive-heap-object.h"
#include "torque-generated/bit-fields.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
namespace compiler {
class WasmGraphBuilder;
}
class SharedStringAccessGuardIfNeeded;
// The Name abstract class captures anything that can be used as a property
// name, i.e., strings and symbols. All names store a hash value.
V8_OBJECT class Name : public PrimitiveHeapObject {
public:
// Tells whether the hash code has been computed.
// Note: Use TryGetHash() whenever you want to use the hash, instead of a
// combination of HashHashCode() and hash() for thread-safety.
inline bool HasHashCode() const;
// Tells whether the name contains a forwarding index pointing to a row
// in the string forwarding table.
inline bool HasForwardingIndex(AcquireLoadTag) const;
inline bool HasInternalizedForwardingIndex(AcquireLoadTag) const;
inline bool HasExternalForwardingIndex(AcquireLoadTag) const;
inline uint32_t raw_hash_field() const {
return raw_hash_field_.load(std::memory_order_relaxed);
}
inline uint32_t raw_hash_field(AcquireLoadTag) const {
return raw_hash_field_.load(std::memory_order_acquire);
}
inline void set_raw_hash_field(uint32_t hash) {
raw_hash_field_.store(hash, std::memory_order_relaxed);
}
inline void set_raw_hash_field(uint32_t hash, ReleaseStoreTag) {
raw_hash_field_.store(hash, std::memory_order_release);
}
// Sets the hash field only if it is empty. Otherwise does nothing.
inline void set_raw_hash_field_if_empty(uint32_t hash);
// Returns a hash value used for the property table (same as Hash()), assumes
// the hash is already computed.
inline uint32_t hash() const;
// Returns true if the hash has been computed, and sets the computed hash
// as out-parameter.
inline bool TryGetHash(uint32_t* hash) const;
// Equality operations.
inline bool Equals(Tagged<Name> other);
inline static bool Equals(Isolate* isolate, Handle<Name> one,
Handle<Name> two);
// Conversion.
inline bool AsArrayIndex(uint32_t* index);
inline bool AsIntegerIndex(size_t* index);
// An "interesting" is a well-known symbol or string, like @@toStringTag,
// @@toJSON, that's often looked up on random objects but is usually not
// present. We optimize this by setting a flag on the object's map when such
// symbol properties are added, so we can optimize lookups on objects
// that don't have the flag.
inline bool IsInteresting(Isolate* isolate);
// If the name is private, it can only name own properties.
inline bool IsPrivate();
// If the name is a private name, it should behave like a private
// symbol but also throw on property access miss.
inline bool IsPrivateName();
// If the name is a private brand, it should behave like a private name
// symbol but is filtered out when generating list of private fields.
inline bool IsPrivateBrand();
static inline bool ContainsCachedArrayIndex(uint32_t hash);
// Return a string version of this name that is converted according to the
// rules described in ES6 section 9.2.11.
V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToFunctionName(
Isolate* isolate, Handle<Name> name);
V8_WARN_UNUSED_RESULT static MaybeHandle<String> ToFunctionName(
Isolate* isolate, Handle<Name> name, Handle<String> prefix);
DECL_CAST(Name)
DECL_VERIFIER(Name)
DECL_PRINTER(Name)
void NameShortPrint();
int NameShortPrint(base::Vector<char> str);
// Mask constant for checking if a name has a computed hash code and the type
// of information stored in the hash field. The least significant bit
// indicates whether the value can be used as a hash (i.e. different values
// imply different strings).
enum class HashFieldType : uint32_t {
kHash = 0b10,
kIntegerIndex = 0b00,
kForwardingIndex = 0b01,
kEmpty = 0b11
};
using HashFieldTypeBits = base::BitField<HashFieldType, 0, 2>;
using HashBits =
HashFieldTypeBits::Next<uint32_t, kBitsPerInt - HashFieldTypeBits::kSize>;
static constexpr int kHashNotComputedMask = 1;
// Value of empty hash field indicating that the hash is not computed.
static constexpr int kEmptyHashField =
HashFieldTypeBits::encode(HashFieldType::kEmpty);
// Empty hash and forwarding indices can not be used as hash.
static_assert((kEmptyHashField & kHashNotComputedMask) != 0);
static_assert((HashFieldTypeBits::encode(HashFieldType::kForwardingIndex) &
kHashNotComputedMask) != 0);
using IsInternalizedForwardingIndexBit = HashFieldTypeBits::Next<bool, 1>;
using IsExternalForwardingIndexBit =
IsInternalizedForwardingIndexBit::Next<bool, 1>;
using ForwardingIndexValueBits = IsExternalForwardingIndexBit::Next<
unsigned int, kBitsPerInt - HashFieldTypeBits::kSize -
IsInternalizedForwardingIndexBit::kSize -
IsExternalForwardingIndexBit::kSize>;
// Array index strings this short can keep their index in the hash field.
static const int kMaxCachedArrayIndexLength = 7;
// Maximum number of characters to consider when trying to convert a string
// value into an array index.
static const int kMaxArrayIndexSize = 10;
// Maximum number of characters in a string that can possibly be an
// "integer index" in the spec sense, i.e. a canonical representation of a
// number in the range up to MAX_SAFE_INTEGER. We parse these into a size_t,
// so the size of that type also factors in as a limit: 10 characters per
// 32 bits of size_t width.
static const int kMaxIntegerIndexSize =
std::min(16, int{10 * (sizeof(size_t) / 4)});
// For strings which are array indexes the hash value has the string length
// mixed into the hash, mainly to avoid a hash value of zero which would be
// the case for the string '0'. 24 bits are used for the array index value.
static const int kArrayIndexValueBits = 24;
static const int kArrayIndexLengthBits =
kBitsPerInt - kArrayIndexValueBits - HashFieldTypeBits::kSize;
static_assert(kArrayIndexLengthBits > 0);
static_assert(kMaxArrayIndexSize < (1 << kArrayIndexLengthBits));
using ArrayIndexValueBits =
HashFieldTypeBits::Next<unsigned int, kArrayIndexValueBits>;
using ArrayIndexLengthBits =
ArrayIndexValueBits::Next<unsigned int, kArrayIndexLengthBits>;
// Check that kMaxCachedArrayIndexLength + 1 is a power of two so we
// could use a mask to test if the length of string is less than or equal to
// kMaxCachedArrayIndexLength.
static_assert(base::bits::IsPowerOfTwo(kMaxCachedArrayIndexLength + 1),
"(kMaxCachedArrayIndexLength + 1) must be power of two");
// When any of these bits is set then the hash field does not contain a cached
// array index.
static_assert(HashFieldTypeBits::encode(HashFieldType::kIntegerIndex) == 0);
static const unsigned int kDoesNotContainCachedArrayIndexMask =
(~static_cast<unsigned>(kMaxCachedArrayIndexLength)
<< ArrayIndexLengthBits::kShift) |
HashFieldTypeBits::kMask;
// When any of these bits is set then the hash field does not contain an
// integer or forwarding index.
static const unsigned int kDoesNotContainIntegerOrForwardingIndexMask = 0b10;
static_assert((HashFieldTypeBits::encode(HashFieldType::kIntegerIndex) &
kDoesNotContainIntegerOrForwardingIndexMask) == 0);
static_assert((HashFieldTypeBits::encode(HashFieldType::kForwardingIndex) &
kDoesNotContainIntegerOrForwardingIndexMask) == 0);
// Returns a hash value used for the property table. Ensures that the hash
// value is computed.
//
// The overload without SharedStringAccessGuardIfNeeded can only be called on
// the main thread.
inline uint32_t EnsureHash();
inline uint32_t EnsureHash(const SharedStringAccessGuardIfNeeded&);
// The value returned is always a computed hash, even if the value stored is
// a forwarding index.
inline uint32_t EnsureRawHash();
inline uint32_t EnsureRawHash(const SharedStringAccessGuardIfNeeded&);
inline uint32_t RawHash();
static inline bool IsHashFieldComputed(uint32_t raw_hash_field);
static inline bool IsHash(uint32_t raw_hash_field);
static inline bool IsIntegerIndex(uint32_t raw_hash_field);
static inline bool IsForwardingIndex(uint32_t raw_hash_field);
static inline bool IsInternalizedForwardingIndex(uint32_t raw_hash_field);
static inline bool IsExternalForwardingIndex(uint32_t raw_hash_field);
static inline uint32_t CreateHashFieldValue(uint32_t hash,
HashFieldType type);
static inline uint32_t CreateInternalizedForwardingIndex(uint32_t index);
static inline uint32_t CreateExternalForwardingIndex(uint32_t index);
private:
friend class V8HeapExplorer;
friend class CodeStubAssembler;
friend class StringBuiltinsAssembler;
friend class maglev::MaglevAssembler;
friend class compiler::AccessBuilder;
friend class compiler::WasmGraphBuilder;
friend class TorqueGeneratedNameAsserts;
inline uint32_t GetRawHashFromForwardingTable(uint32_t raw_hash) const;
std::atomic_uint32_t raw_hash_field_;
} V8_OBJECT_END;
inline bool IsUniqueName(Tagged<Name> obj);
inline bool IsUniqueName(Tagged<Name> obj, PtrComprCageBase cage_base);
// ES6 symbols.
V8_OBJECT class Symbol : public Name {
public:
using IsPrivateBit = base::BitField<bool, 0, 1>;
using IsWellKnownSymbolBit = IsPrivateBit::Next<bool, 1>;
using IsInPublicSymbolTableBit = IsWellKnownSymbolBit::Next<bool, 1>;
using IsInterestingSymbolBit = IsInPublicSymbolTableBit::Next<bool, 1>;
using IsPrivateNameBit = IsInterestingSymbolBit::Next<bool, 1>;
using IsPrivateBrandBit = IsPrivateNameBit::Next<bool, 1>;
inline Tagged<PrimitiveHeapObject> description() const;
inline void set_description(Tagged<PrimitiveHeapObject> value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
// [is_private]: Whether this is a private symbol. Private symbols can only
// be used to designate own properties of objects.
inline bool is_private() const;
inline void set_is_private(bool value);
// [is_well_known_symbol]: Whether this is a spec-defined well-known symbol,
// or not. Well-known symbols do not throw when an access check fails during
// a load.
inline bool is_well_known_symbol() const;
inline void set_is_well_known_symbol(bool value);
// [is_interesting_symbol]: Whether this is an "interesting symbol", which
// is a well-known symbol like @@toStringTag that's often looked up on
// random objects but is usually not present. See Name::IsInterestingSymbol()
// for a detailed description.
inline bool is_interesting_symbol() const;
inline void set_is_interesting_symbol(bool value);
// [is_in_public_symbol_table]: Whether this is a symbol created by
// Symbol.for. Calling Symbol.keyFor on such a symbol simply needs
// to return the attached name.
inline bool is_in_public_symbol_table() const;
inline void set_is_in_public_symbol_table(bool value);
// [is_private_name]: Whether this is a private name. Private names
// are the same as private symbols except they throw on missing
// property access.
//
// This also sets the is_private bit.
inline bool is_private_name() const;
inline void set_is_private_name();
// [is_private_name]: Whether this is a brand symbol. Brand symbols are
// private name symbols that are used for validating access to
// private methods and storing information about the private methods.
//
// This also sets the is_private bit.
inline bool is_private_brand() const;
inline void set_is_private_brand();
DECL_CAST(Symbol)
// Dispatched behavior.
DECL_PRINTER(Symbol)
DECL_VERIFIER(Symbol)
void SymbolShortPrint(std::ostream& os);
private:
friend class Factory;
friend struct ObjectTraits<Symbol>;
friend struct OffsetsForDebug;
friend class V8HeapExplorer;
friend class CodeStubAssembler;
friend class maglev::MaglevAssembler;
friend class TorqueGeneratedSymbolAsserts;
// TODO(cbruni): remove once the new maptracer is in place.
friend class Name; // For PrivateSymbolToName.
uint32_t flags() const { return flags_; }
void set_flags(uint32_t value) { flags_ = value; }
const char* PrivateSymbolToName() const;
uint32_t flags_;
// String|Undefined
// TODO(leszeks): Introduce a union type for this.
TaggedMember<PrimitiveHeapObject> description_;
} V8_OBJECT_END;
template <>
struct ObjectTraits<Symbol> {
using BodyDescriptor = FixedBodyDescriptor<offsetof(Symbol, description_),
sizeof(Symbol), sizeof(Symbol)>;
};
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_NAME_H_