Commit de02b4c5 authored by Darius M's avatar Darius M Committed by V8 LUCI CQ

Reland "Move some string allocation functions from Factory to FactoryBase"

The original CL triggered a fail in a test that was actually broken.
This broken test has now been disabled.

Original CL description:

> In a subsequent CL, I'll need to do String allocations in Turbofan (in
> the background), where only a LocalFactory is available. By moving
> those string allocation functions to FactoryBase, they will also be
> available in the LocalFactory.
>
> Change-Id: I066bbd4b5016645de183633ef237986e0ae50f5d
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3811581
> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
> Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
> Commit-Queue: Darius Mercadier <dmercadier@chromium.org>
> Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> Cr-Commit-Position: refs/heads/main@{#82262}

Change-Id: I89108038bd7b3d1e99ad16837fd730b7703d3c9b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3816669Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Darius Mercadier <dmercadier@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82335}
parent 6cad3a0b
......@@ -16,6 +16,14 @@
namespace v8 {
namespace internal {
#define ROOT_ACCESSOR(Type, name, CamelName) \
template <typename Impl> \
Handle<Type> FactoryBase<Impl>::name() { \
return read_only_roots().name##_handle(); \
}
READ_ONLY_ROOT_LIST(ROOT_ACCESSOR)
#undef ROOT_ACCESSOR
template <typename Impl>
Handle<Oddball> FactoryBase<Impl>::ToBoolean(bool value) {
return value ? impl()->true_value() : impl()->false_value();
......
......@@ -27,6 +27,7 @@
#include "src/objects/string.h"
#include "src/objects/swiss-name-dictionary-inl.h"
#include "src/objects/template-objects-inl.h"
#include "src/roots/roots.h"
namespace v8 {
namespace internal {
......@@ -818,6 +819,144 @@ Handle<String> FactoryBase<Impl>::NewConsString(Handle<String> left,
return handle(result, isolate());
}
template <typename Impl>
Handle<String> FactoryBase<Impl>::LookupSingleCharacterStringFromCode(
uint16_t code) {
if (code <= unibrow::Latin1::kMaxChar) {
DisallowGarbageCollection no_gc;
Object value = single_character_string_table()->get(code);
DCHECK_NE(value, *undefined_value());
return handle(String::cast(value), isolate());
}
uint16_t buffer[] = {code};
return InternalizeString(base::Vector<const uint16_t>(buffer, 1));
}
template <typename Impl>
MaybeHandle<String> FactoryBase<Impl>::NewStringFromOneByte(
const base::Vector<const uint8_t>& string, AllocationType allocation) {
DCHECK_NE(allocation, AllocationType::kReadOnly);
int length = string.length();
if (length == 0) return empty_string();
if (length == 1) return LookupSingleCharacterStringFromCode(string[0]);
Handle<SeqOneByteString> result;
ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
NewRawOneByteString(string.length(), allocation),
String);
DisallowGarbageCollection no_gc;
// Copy the characters into the new object.
// SharedStringAccessGuardIfNeeded is NotNeeded because {result} is freshly
// allocated and hasn't escaped the factory yet, so it can't be concurrently
// accessed.
CopyChars(SeqOneByteString::cast(*result).GetChars(
no_gc, SharedStringAccessGuardIfNeeded::NotNeeded()),
string.begin(), length);
return result;
}
namespace {
template <typename Impl>
V8_INLINE Handle<String> CharToString(FactoryBase<Impl>* factory,
const char* string,
NumberCacheMode mode) {
// We tenure the allocated string since it is referenced from the
// number-string cache which lives in the old space.
AllocationType type = mode == NumberCacheMode::kIgnore
? AllocationType::kYoung
: AllocationType::kOld;
return factory->NewStringFromAsciiChecked(string, type);
}
} // namespace
template <typename Impl>
Handle<String> FactoryBase<Impl>::NumberToString(Handle<Object> number,
NumberCacheMode mode) {
SLOW_DCHECK(number->IsNumber());
if (number->IsSmi()) return SmiToString(Smi::cast(*number), mode);
double double_value = Handle<HeapNumber>::cast(number)->value();
// Try to canonicalize doubles.
int smi_value;
if (DoubleToSmiInteger(double_value, &smi_value)) {
return SmiToString(Smi::FromInt(smi_value), mode);
}
return HeapNumberToString(Handle<HeapNumber>::cast(number), double_value,
mode);
}
template <typename Impl>
Handle<String> FactoryBase<Impl>::HeapNumberToString(Handle<HeapNumber> number,
double value,
NumberCacheMode mode) {
int hash = mode == NumberCacheMode::kIgnore
? 0
: impl()->NumberToStringCacheHash(value);
if (mode == NumberCacheMode::kBoth) {
Handle<Object> cached = impl()->NumberToStringCacheGet(*number, hash);
if (!cached->IsUndefined(isolate())) return Handle<String>::cast(cached);
}
Handle<String> result;
if (value == 0) {
result = zero_string();
} else if (std::isnan(value)) {
result = NaN_string();
} else {
char arr[kNumberToStringBufferSize];
base::Vector<char> buffer(arr, arraysize(arr));
const char* string = DoubleToCString(value, buffer);
result = CharToString(this, string, mode);
}
if (mode != NumberCacheMode::kIgnore) {
impl()->NumberToStringCacheSet(number, hash, result);
}
return result;
}
template <typename Impl>
inline Handle<String> FactoryBase<Impl>::SmiToString(Smi number,
NumberCacheMode mode) {
int hash = mode == NumberCacheMode::kIgnore
? 0
: impl()->NumberToStringCacheHash(number);
if (mode == NumberCacheMode::kBoth) {
Handle<Object> cached = impl()->NumberToStringCacheGet(number, hash);
if (!cached->IsUndefined(isolate())) return Handle<String>::cast(cached);
}
Handle<String> result;
if (number == Smi::zero()) {
result = zero_string();
} else {
char arr[kNumberToStringBufferSize];
base::Vector<char> buffer(arr, arraysize(arr));
const char* string = IntToCString(number.value(), buffer);
result = CharToString(this, string, mode);
}
if (mode != NumberCacheMode::kIgnore) {
impl()->NumberToStringCacheSet(handle(number, isolate()), hash, result);
}
// Compute the hash here (rather than letting the caller take care of it) so
// that the "cache hit" case above doesn't have to bother with it.
static_assert(Smi::kMaxValue <= std::numeric_limits<uint32_t>::max());
{
DisallowGarbageCollection no_gc;
String raw = *result;
if (raw.raw_hash_field() == String::kEmptyHashField &&
number.value() >= 0) {
uint32_t raw_hash_field = StringHasher::MakeArrayIndexHash(
static_cast<uint32_t>(number.value()), raw.length());
raw.set_raw_hash_field(raw_hash_field);
}
}
return result;
}
template <typename Impl>
Handle<FreshlyAllocatedBigInt> FactoryBase<Impl>::NewBigInt(
int length, AllocationType allocation) {
......
......@@ -47,6 +47,8 @@ class ValueType;
template <typename Impl>
class FactoryBase;
enum class NumberCacheMode { kIgnore, kSetOnly, kBoth };
// Putting Torque-generated definitions in a superclass allows to shadow them
// easily when they shouldn't be used and to reference them when they happen to
// have the same signature.
......@@ -60,12 +62,15 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) TorqueGeneratedFactory {
};
template <typename Impl>
class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase
: public TorqueGeneratedFactory<Impl> {
class FactoryBase : public TorqueGeneratedFactory<Impl> {
public:
// Converts the given boolean condition to JavaScript boolean value.
inline Handle<Oddball> ToBoolean(bool value);
#define ROOT_ACCESSOR(Type, name, CamelName) inline Handle<Type> name();
READ_ONLY_ROOT_LIST(ROOT_ACCESSOR)
#undef ROOT_ACCESSOR
// Numbers (e.g. literals) are pretenured by the parser.
// The return value may be a smi or a heap number.
template <AllocationType allocation = AllocationType::kYoung>
......@@ -221,6 +226,20 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase
Handle<SeqTwoByteString> AllocateRawTwoByteInternalizedString(
int length, uint32_t raw_hash_field);
// Creates a single character string where the character has given code.
// A cache is used for Latin1 codes.
Handle<String> LookupSingleCharacterStringFromCode(uint16_t code);
MaybeHandle<String> NewStringFromOneByte(
const base::Vector<const uint8_t>& string,
AllocationType allocation = AllocationType::kYoung);
inline Handle<String> NewStringFromAsciiChecked(
const char* str, AllocationType allocation = AllocationType::kYoung) {
return NewStringFromOneByte(base::OneByteVector(str), allocation)
.ToHandleChecked();
}
// Allocates and partially initializes an one-byte or two-byte String. The
// characters of the string are uninitialized. Currently used in regexp code
// only, where they are pretenured.
......@@ -237,6 +256,14 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase
Handle<String> left, Handle<String> right, int length, bool one_byte,
AllocationType allocation = AllocationType::kYoung);
V8_WARN_UNUSED_RESULT Handle<String> NumberToString(
Handle<Object> number, NumberCacheMode mode = NumberCacheMode::kBoth);
V8_WARN_UNUSED_RESULT Handle<String> HeapNumberToString(
Handle<HeapNumber> number, double value,
NumberCacheMode mode = NumberCacheMode::kBoth);
V8_WARN_UNUSED_RESULT Handle<String> SmiToString(
Smi number, NumberCacheMode mode = NumberCacheMode::kBoth);
V8_WARN_UNUSED_RESULT MaybeHandle<SeqOneByteString> NewRawSharedOneByteString(
int length);
V8_WARN_UNUSED_RESULT MaybeHandle<SeqTwoByteString> NewRawSharedTwoByteString(
......@@ -274,6 +301,9 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase
AllocationType allocation, Map string_map);
protected:
// Must be large enough to fit any double, int, or size_t.
static constexpr int kNumberToStringBufferSize = 32;
// Allocate memory for an uninitialized array (e.g., a FixedArray or similar).
HeapObject AllocateRawArray(int size, AllocationType allocation);
HeapObject AllocateRawFixedArray(int length, AllocationType allocation);
......@@ -318,6 +348,11 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase
friend TorqueGeneratedFactory<Impl>;
};
extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
FactoryBase<Factory>;
extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
FactoryBase<LocalFactory>;
} // namespace internal
} // namespace v8
......
......@@ -27,7 +27,7 @@ namespace internal {
Handle<Type> Factory::name() { \
return Handle<Type>(&isolate()->roots_table()[RootIndex::k##CamelName]); \
}
ROOT_LIST(ROOT_ACCESSOR)
MUTABLE_ROOT_LIST(ROOT_ACCESSOR)
#undef ROOT_ACCESSOR
bool Factory::CodeBuilder::CompiledWithConcurrentBaseline() const {
......@@ -89,6 +89,35 @@ Factory::CodeBuilder& Factory::CodeBuilder::set_interpreter_data(
return *this;
}
void Factory::NumberToStringCacheSet(Handle<Object> number, int hash,
Handle<String> js_string) {
if (!number_string_cache()->get(hash * 2).IsUndefined(isolate()) &&
!FLAG_optimize_for_size) {
int full_size = isolate()->heap()->MaxNumberToStringCacheSize();
if (number_string_cache()->length() != full_size) {
Handle<FixedArray> new_cache =
NewFixedArray(full_size, AllocationType::kOld);
isolate()->heap()->set_number_string_cache(*new_cache);
return;
}
}
DisallowGarbageCollection no_gc;
FixedArray cache = *number_string_cache();
cache.set(hash * 2, *number);
cache.set(hash * 2 + 1, *js_string);
}
Handle<Object> Factory::NumberToStringCacheGet(Object number, int hash) {
DisallowGarbageCollection no_gc;
FixedArray cache = *number_string_cache();
Object key = cache.get(hash * 2);
if (key == number || (key.IsHeapNumber() && number.IsHeapNumber() &&
key.Number() == number.Number())) {
return Handle<String>(String::cast(cache.get(hash * 2 + 1)), isolate());
}
return undefined_value();
}
} // namespace internal
} // namespace v8
......
......@@ -684,24 +684,6 @@ template Handle<String> Factory::InternalizeString(
Handle<SeqTwoByteString> string, int from, int length,
bool convert_encoding);
MaybeHandle<String> Factory::NewStringFromOneByte(
const base::Vector<const uint8_t>& string, AllocationType allocation) {
DCHECK_NE(allocation, AllocationType::kReadOnly);
int length = string.length();
if (length == 0) return empty_string();
if (length == 1) return LookupSingleCharacterStringFromCode(string[0]);
Handle<SeqOneByteString> result;
ASSIGN_RETURN_ON_EXCEPTION(isolate(), result,
NewRawOneByteString(string.length(), allocation),
String);
DisallowGarbageCollection no_gc;
// Copy the characters into the new object.
CopyChars(SeqOneByteString::cast(*result).GetChars(no_gc), string.begin(),
length);
return result;
}
namespace {
void ThrowInvalidEncodedStringBytes(Isolate* isolate, MessageTemplate message) {
#if V8_ENABLE_WEBASSEMBLY
......@@ -1059,17 +1041,6 @@ StringTransitionStrategy Factory::ComputeSharingStrategyForString(
}
}
Handle<String> Factory::LookupSingleCharacterStringFromCode(uint16_t code) {
if (code <= unibrow::Latin1::kMaxChar) {
DisallowGarbageCollection no_gc;
Object value = single_character_string_table()->get(code);
DCHECK_NE(value, *undefined_value());
return handle(String::cast(value), isolate());
}
uint16_t buffer[] = {code};
return InternalizeString(base::Vector<const uint16_t>(buffer, 1));
}
Handle<String> Factory::NewSurrogatePairString(uint16_t lead, uint16_t trail) {
DCHECK_GE(lead, 0xD800);
DCHECK_LE(lead, 0xDBFF);
......@@ -3340,141 +3311,17 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfoForWebSnapshot() {
FunctionKind::kNormalFunction);
}
namespace {
V8_INLINE int NumberToStringCacheHash(Handle<FixedArray> cache, Smi number) {
int mask = (cache->length() >> 1) - 1;
int Factory::NumberToStringCacheHash(Smi number) {
int mask = (number_string_cache()->length() >> 1) - 1;
return number.value() & mask;
}
V8_INLINE int NumberToStringCacheHash(Handle<FixedArray> cache, double number) {
int mask = (cache->length() >> 1) - 1;
int Factory::NumberToStringCacheHash(double number) {
int mask = (number_string_cache()->length() >> 1) - 1;
int64_t bits = base::bit_cast<int64_t>(number);
return (static_cast<int>(bits) ^ static_cast<int>(bits >> 32)) & mask;
}
V8_INLINE Handle<String> CharToString(Factory* factory, const char* string,
NumberCacheMode mode) {
// We tenure the allocated string since it is referenced from the
// number-string cache which lives in the old space.
AllocationType type = mode == NumberCacheMode::kIgnore
? AllocationType::kYoung
: AllocationType::kOld;
return factory->NewStringFromAsciiChecked(string, type);
}
} // namespace
void Factory::NumberToStringCacheSet(Handle<Object> number, int hash,
Handle<String> js_string) {
if (!number_string_cache()->get(hash * 2).IsUndefined(isolate()) &&
!FLAG_optimize_for_size) {
int full_size = isolate()->heap()->MaxNumberToStringCacheSize();
if (number_string_cache()->length() != full_size) {
Handle<FixedArray> new_cache =
NewFixedArray(full_size, AllocationType::kOld);
isolate()->heap()->set_number_string_cache(*new_cache);
return;
}
}
DisallowGarbageCollection no_gc;
FixedArray cache = *number_string_cache();
cache.set(hash * 2, *number);
cache.set(hash * 2 + 1, *js_string);
}
Handle<Object> Factory::NumberToStringCacheGet(Object number, int hash) {
DisallowGarbageCollection no_gc;
FixedArray cache = *number_string_cache();
Object key = cache.get(hash * 2);
if (key == number || (key.IsHeapNumber() && number.IsHeapNumber() &&
key.Number() == number.Number())) {
return Handle<String>(String::cast(cache.get(hash * 2 + 1)), isolate());
}
return undefined_value();
}
Handle<String> Factory::NumberToString(Handle<Object> number,
NumberCacheMode mode) {
SLOW_DCHECK(number->IsNumber());
if (number->IsSmi()) return SmiToString(Smi::cast(*number), mode);
double double_value = Handle<HeapNumber>::cast(number)->value();
// Try to canonicalize doubles.
int smi_value;
if (DoubleToSmiInteger(double_value, &smi_value)) {
return SmiToString(Smi::FromInt(smi_value), mode);
}
return HeapNumberToString(Handle<HeapNumber>::cast(number), double_value,
mode);
}
// Must be large enough to fit any double, int, or size_t.
static const int kNumberToStringBufferSize = 32;
Handle<String> Factory::HeapNumberToString(Handle<HeapNumber> number,
double value, NumberCacheMode mode) {
int hash = 0;
if (mode != NumberCacheMode::kIgnore) {
hash = NumberToStringCacheHash(number_string_cache(), value);
}
if (mode == NumberCacheMode::kBoth) {
Handle<Object> cached = NumberToStringCacheGet(*number, hash);
if (!cached->IsUndefined(isolate())) return Handle<String>::cast(cached);
}
Handle<String> result;
if (value == 0) {
result = zero_string();
} else if (std::isnan(value)) {
result = NaN_string();
} else {
char arr[kNumberToStringBufferSize];
base::Vector<char> buffer(arr, arraysize(arr));
const char* string = DoubleToCString(value, buffer);
result = CharToString(this, string, mode);
}
if (mode != NumberCacheMode::kIgnore) {
NumberToStringCacheSet(number, hash, result);
}
return result;
}
inline Handle<String> Factory::SmiToString(Smi number, NumberCacheMode mode) {
int hash = NumberToStringCacheHash(number_string_cache(), number);
if (mode == NumberCacheMode::kBoth) {
Handle<Object> cached = NumberToStringCacheGet(number, hash);
if (!cached->IsUndefined(isolate())) return Handle<String>::cast(cached);
}
Handle<String> result;
if (number == Smi::zero()) {
result = zero_string();
} else {
char arr[kNumberToStringBufferSize];
base::Vector<char> buffer(arr, arraysize(arr));
const char* string = IntToCString(number.value(), buffer);
result = CharToString(this, string, mode);
}
if (mode != NumberCacheMode::kIgnore) {
NumberToStringCacheSet(handle(number, isolate()), hash, result);
}
// Compute the hash here (rather than letting the caller take care of it) so
// that the "cache hit" case above doesn't have to bother with it.
static_assert(Smi::kMaxValue <= std::numeric_limits<uint32_t>::max());
{
DisallowGarbageCollection no_gc;
String raw = *result;
if (raw.raw_hash_field() == String::kEmptyHashField &&
number.value() >= 0) {
uint32_t raw_hash_field = StringHasher::MakeArrayIndexHash(
static_cast<uint32_t>(number.value()), raw.length());
raw.set_raw_hash_field(raw_hash_field);
}
}
return result;
}
Handle<String> Factory::SizeToString(size_t value, bool check_cache) {
Handle<String> result;
NumberCacheMode cache_mode =
......
......@@ -112,8 +112,6 @@ enum FunctionMode {
kWithReadonlyPrototypeBit | kWithNameBit,
};
enum class NumberCacheMode { kIgnore, kSetOnly, kBoth };
// Interface for handle based allocation.
class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
public:
......@@ -228,9 +226,9 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
// two-byte. One should choose between the three string factory functions
// based on the encoding of the string buffer that the string is
// initialized from.
// - ...FromOneByte initializes the string from a buffer that is Latin1
// encoded (it does not check that the buffer is Latin1 encoded) and
// the result will be Latin1 encoded.
// - ...FromOneByte (defined in FactoryBase) initializes the string from a
// buffer that is Latin1 encoded (it does not check that the buffer is
// Latin1 encoded) and the result will be Latin1 encoded.
// - ...FromUtf8 initializes the string from a buffer that is UTF-8
// encoded. If the characters are all ASCII characters, the result
// will be Latin1 encoded, otherwise it will converted to two-byte.
......@@ -239,10 +237,6 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
// will be converted to Latin1, otherwise it will be left as two-byte.
//
// One-byte strings are pretenured when used as keys in the SourceCodeCache.
V8_WARN_UNUSED_RESULT MaybeHandle<String> NewStringFromOneByte(
const base::Vector<const uint8_t>& str,
AllocationType allocation = AllocationType::kYoung);
template <size_t N>
inline Handle<String> NewStringFromStaticChars(
const char (&str)[N],
......@@ -341,10 +335,6 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
ComputeSharingStrategyForString(Handle<String> string,
MaybeHandle<Map>* shared_map);
// Creates a single character string where the character has given code.
// A cache is used for Latin1 codes.
Handle<String> LookupSingleCharacterStringFromCode(uint16_t code);
// Create or lookup a single character string made up of a utf16 surrogate
// pair.
Handle<String> NewSurrogatePairString(uint16_t lead, uint16_t trail);
......@@ -785,14 +775,6 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
DECLARE_ERROR(WasmExceptionError)
#undef DECLARE_ERROR
Handle<String> NumberToString(Handle<Object> number,
NumberCacheMode mode = NumberCacheMode::kBoth);
Handle<String> SmiToString(Smi number,
NumberCacheMode mode = NumberCacheMode::kBoth);
Handle<String> HeapNumberToString(
Handle<HeapNumber> number, double value,
NumberCacheMode mode = NumberCacheMode::kBoth);
Handle<String> SizeToString(size_t value, bool check_cache = true);
inline Handle<String> Uint32ToString(uint32_t value,
bool check_cache = true) {
......@@ -800,7 +782,7 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
}
#define ROOT_ACCESSOR(Type, name, CamelName) inline Handle<Type> name();
ROOT_LIST(ROOT_ACCESSOR)
MUTABLE_ROOT_LIST(ROOT_ACCESSOR)
#undef ROOT_ACCESSOR
// Allocates a new SharedFunctionInfo object.
......@@ -1131,6 +1113,10 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
MaybeHandle<String> NewStringFromTwoByte(const base::uc16* string, int length,
AllocationType allocation);
// Functions to get the hash of a number for the number_string_cache.
int NumberToStringCacheHash(Smi number);
int NumberToStringCacheHash(double number);
// Attempt to find the number in a small cache. If we finds it, return
// the string representation of the number. Otherwise return undefined.
V8_INLINE Handle<Object> NumberToStringCacheGet(Object number, int hash);
......
......@@ -133,6 +133,11 @@ RootsTable& Heap::roots_table() { return isolate()->roots_table(); }
MUTABLE_ROOT_LIST(ROOT_ACCESSOR)
#undef ROOT_ACCESSOR
FixedArray Heap::single_character_string_table() {
return FixedArray::cast(
Object(roots_table()[RootIndex::kSingleCharacterStringTable]));
}
#define ROOT_ACCESSOR(type, name, CamelName) \
void Heap::set_##name(type value) { \
/* The deserializer makes use of the fact that these common roots are */ \
......
......@@ -939,6 +939,8 @@ class Heap {
MUTABLE_ROOT_LIST(ROOT_ACCESSOR)
#undef ROOT_ACCESSOR
V8_INLINE FixedArray single_character_string_table();
V8_INLINE void SetRootMaterializedObjects(FixedArray objects);
V8_INLINE void SetRootScriptList(Object value);
V8_INLINE void SetRootNoScriptSharedFunctionInfos(Object value);
......
......@@ -12,13 +12,6 @@
namespace v8 {
namespace internal {
#define ROOT_ACCESSOR(Type, name, CamelName) \
Handle<Type> LocalFactory::name() { \
return read_only_roots().name##_handle(); \
}
READ_ONLY_ROOT_LIST(ROOT_ACCESSOR)
#undef ROOT_ACCESSOR
#define ACCESSOR_INFO_ACCESSOR(Type, name, CamelName) \
Handle<Type> LocalFactory::name() { \
/* Do a bit of handle location magic to cast the Handle without having */ \
......
......@@ -8,6 +8,7 @@
#include "src/execution/local-isolate.h"
#include "src/handles/handles.h"
#include "src/heap/concurrent-allocator-inl.h"
#include "src/heap/local-factory-inl.h"
#include "src/heap/local-heap-inl.h"
#include "src/numbers/hash-seed-inl.h"
#include "src/objects/fixed-array.h"
......@@ -51,5 +52,16 @@ HeapObject LocalFactory::AllocateRaw(int size, AllocationType allocation,
size, allocation, AllocationOrigin::kRuntime, alignment));
}
int LocalFactory::NumberToStringCacheHash(Smi) { return 0; }
int LocalFactory::NumberToStringCacheHash(double) { return 0; }
void LocalFactory::NumberToStringCacheSet(Handle<Object>, int, Handle<String>) {
}
Handle<Object> LocalFactory::NumberToStringCacheGet(Object, int) {
return undefined_value();
}
} // namespace internal
} // namespace v8
......@@ -33,7 +33,6 @@ class V8_EXPORT_PRIVATE LocalFactory : public FactoryBase<LocalFactory> {
ReadOnlyRoots read_only_roots() const { return roots_; }
#define ROOT_ACCESSOR(Type, name, CamelName) inline Handle<Type> name();
READ_ONLY_ROOT_LIST(ROOT_ACCESSOR)
// AccessorInfos appear mutable, but they're actually not mutated once they
// finish initializing. In particular, the root accessors are not mutated and
// are safe to access (as long as the off-thread job doesn't try to mutate
......@@ -48,6 +47,16 @@ class V8_EXPORT_PRIVATE LocalFactory : public FactoryBase<LocalFactory> {
UNREACHABLE();
}
// The LocalFactory does not have access to the number_string_cache (since
// it's a mutable root), but it still needs to define some cache-related
// method that are used by FactoryBase. Those method do basically nothing in
// the case of the LocalFactory.
int NumberToStringCacheHash(Smi number);
int NumberToStringCacheHash(double number);
void NumberToStringCacheSet(Handle<Object> number, int hash,
Handle<String> js_string);
Handle<Object> NumberToStringCacheGet(Object number, int hash);
private:
friend class FactoryBase<LocalFactory>;
......
......@@ -691,7 +691,7 @@ void Heap::CreateInitialObjects() {
// Allocate and initialize table for single character one byte strings.
int table_size = String::kMaxOneByteCharCode + 1;
set_single_character_string_table(
*factory->NewFixedArray(table_size, AllocationType::kOld));
*factory->NewFixedArray(table_size, AllocationType::kReadOnly));
for (int i = 0; i < table_size; ++i) {
uint8_t code = static_cast<uint8_t>(i);
Handle<String> str =
......
......@@ -23,6 +23,10 @@ template <typename T>
class Handle;
class Heap;
class Isolate;
class Factory;
template <typename Impl>
class FactoryBase;
class LocalFactory;
class Map;
class PropertyCell;
class ReadOnlyHeap;
......@@ -195,6 +199,8 @@ class Symbol;
V(HeapNumber, infinity_value, InfinityValue) \
V(HeapNumber, minus_zero_value, MinusZeroValue) \
V(HeapNumber, minus_infinity_value, MinusInfinityValue) \
/* Table of strings of one-byte single characters */ \
V(FixedArray, single_character_string_table, SingleCharacterStringTable) \
/* Marker for self-references during code-generation */ \
V(HeapObject, self_reference_marker, SelfReferenceMarker) \
/* Marker for basic-block usage counters array during code-generation */ \
......@@ -246,8 +252,6 @@ class Symbol;
/* Caches */ \
V(FixedArray, string_split_cache, StringSplitCache) \
V(FixedArray, regexp_multiple_cache, RegExpMultipleCache) \
/* Table of strings of one-byte single characters */ \
V(FixedArray, single_character_string_table, SingleCharacterStringTable) \
/* Indirection lists for isolate-independent builtins */ \
V(FixedArray, builtins_constants_table, BuiltinsConstantsTable) \
/* Internal SharedFunctionInfos */ \
......@@ -566,6 +570,8 @@ class RootsTable {
friend class Isolate;
friend class Heap;
friend class Factory;
friend class FactoryBase<Factory>;
friend class FactoryBase<LocalFactory>;
friend class PointerCompressedReadOnlyArtifacts;
friend class ReadOnlyHeap;
friend class ReadOnlyRoots;
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment