Commit 012af69b authored by Leszek Swirski's avatar Leszek Swirski Committed by V8 LUCI CQ

[string] Add PtrCage for ExternalString::GetChars

Change-Id: I14400c0efea88b4bbb40aa2fbe9527dc9c67d3fb
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3160340
Auto-Submit: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/main@{#76837}
parent d345b25a
......@@ -7,9 +7,11 @@
#include "src/api/api.h"
#include "src/base/ieee754.h"
#include "src/codegen/cpu-features.h"
#include "src/common/globals.h"
#include "src/date/date.h"
#include "src/debug/debug.h"
#include "src/deoptimizer/deoptimizer.h"
#include "src/execution/isolate-utils.h"
#include "src/execution/isolate.h"
#include "src/execution/microtask-queue.h"
#include "src/execution/simulator-base.h"
......@@ -895,22 +897,24 @@ void StringWriteToFlatTwoByte(Address source, uint16_t* sink, int32_t start,
}
const uint8_t* ExternalOneByteStringGetChars(Address string) {
PtrComprCageBase cage_base = GetPtrComprCageBaseFromOnHeapAddress(string);
// The following CHECK is a workaround to prevent a CFI bug where
// ExternalOneByteStringGetChars() and ExternalTwoByteStringGetChars() are
// merged by the linker, resulting in one of the input type's vtable address
// failing the address range check.
// TODO(chromium:1160961): Consider removing the CHECK when CFI is fixed.
CHECK(Object(string).IsExternalOneByteString());
return ExternalOneByteString::cast(Object(string)).GetChars();
CHECK(Object(string).IsExternalOneByteString(cage_base));
return ExternalOneByteString::cast(Object(string)).GetChars(cage_base);
}
const uint16_t* ExternalTwoByteStringGetChars(Address string) {
PtrComprCageBase cage_base = GetPtrComprCageBaseFromOnHeapAddress(string);
// The following CHECK is a workaround to prevent a CFI bug where
// ExternalOneByteStringGetChars() and ExternalTwoByteStringGetChars() are
// merged by the linker, resulting in one of the input type's vtable address
// failing the address range check.
// TODO(chromium:1160961): Consider removing the CHECK when CFI is fixed.
CHECK(Object(string).IsExternalTwoByteString());
return ExternalTwoByteString::cast(Object(string)).GetChars();
CHECK(Object(string).IsExternalTwoByteString(cage_base));
return ExternalTwoByteString::cast(Object(string)).GetChars(cage_base);
}
} // namespace
......
......@@ -627,13 +627,13 @@ MaybeHandle<String> FactoryBase<Impl>::NewConsString(
// Copy left part.
{
const uint8_t* src =
left->template GetChars<uint8_t>(no_gc, access_guard);
left->template GetChars<uint8_t>(isolate(), no_gc, access_guard);
CopyChars(dest, src, left_length);
}
// Copy right part.
{
const uint8_t* src =
right->template GetChars<uint8_t>(no_gc, access_guard);
right->template GetChars<uint8_t>(isolate(), no_gc, access_guard);
CopyChars(dest + left_length, src, right_length);
}
return result;
......
......@@ -5,6 +5,7 @@
#include "src/json/json-parser.h"
#include "src/base/strings.h"
#include "src/common/globals.h"
#include "src/common/message-template.h"
#include "src/debug/debug.h"
#include "src/numbers/conversions.h"
......@@ -210,19 +211,21 @@ JsonParser<Char>::JsonParser(Isolate* isolate, Handle<String> source)
original_source_(source) {
size_t start = 0;
size_t length = source->length();
if (source->IsSlicedString()) {
PtrComprCageBase cage_base(isolate);
if (source->IsSlicedString(cage_base)) {
SlicedString string = SlicedString::cast(*source);
start = string.offset();
String parent = string.parent();
if (parent.IsThinString()) parent = ThinString::cast(parent).actual();
String parent = string.parent(cage_base);
if (parent.IsThinString(cage_base))
parent = ThinString::cast(parent).actual(cage_base);
source_ = handle(parent, isolate);
} else {
source_ = String::Flatten(isolate, source);
}
if (StringShape(*source_).IsExternal()) {
chars_ =
static_cast<const Char*>(SeqExternalString::cast(*source_).GetChars());
if (StringShape(*source_, cage_base).IsExternal()) {
chars_ = static_cast<const Char*>(
SeqExternalString::cast(*source_).GetChars(cage_base));
chars_may_relocate_ = false;
} else {
DisallowGarbageCollection no_gc;
......
......@@ -512,12 +512,14 @@ bool String::IsEqualToImpl(
data, len);
case kExternalStringTag | kOneByteStringTag:
return CompareCharsEqual(
ExternalOneByteString::cast(string).GetChars() + slice_offset, data,
len);
ExternalOneByteString::cast(string).GetChars(cage_base) +
slice_offset,
data, len);
case kExternalStringTag | kTwoByteStringTag:
return CompareCharsEqual(
ExternalTwoByteString::cast(string).GetChars() + slice_offset, data,
len);
ExternalTwoByteString::cast(string).GetChars(cage_base) +
slice_offset,
data, len);
case kSlicedStringTag | kOneByteStringTag:
case kSlicedStringTag | kTwoByteStringTag: {
......@@ -582,19 +584,20 @@ bool String::IsOneByteEqualTo(base::Vector<const char> str) {
}
template <typename Char>
const Char* String::GetChars(const DisallowGarbageCollection& no_gc) const {
const Char* String::GetChars(PtrComprCageBase cage_base,
const DisallowGarbageCollection& no_gc) const {
DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
return StringShape(*this).IsExternal()
? CharTraits<Char>::ExternalString::cast(*this).GetChars()
return StringShape(*this, cage_base).IsExternal()
? CharTraits<Char>::ExternalString::cast(*this).GetChars(cage_base)
: CharTraits<Char>::String::cast(*this).GetChars(no_gc);
}
template <typename Char>
const Char* String::GetChars(
const DisallowGarbageCollection& no_gc,
PtrComprCageBase cage_base, const DisallowGarbageCollection& no_gc,
const SharedStringAccessGuardIfNeeded& access_guard) const {
return StringShape(*this).IsExternal()
? CharTraits<Char>::ExternalString::cast(*this).GetChars()
return StringShape(*this, cage_base).IsExternal()
? CharTraits<Char>::ExternalString::cast(*this).GetChars(cage_base)
: CharTraits<Char>::String::cast(*this).GetChars(no_gc,
access_guard);
}
......@@ -717,9 +720,10 @@ ConsString String::VisitFlat(
int slice_offset = offset;
const int length = string.length();
DCHECK(offset <= length);
PtrComprCageBase cage_base = GetPtrComprCageBase(string);
while (true) {
int32_t type = string.map().instance_type();
switch (type & (kStringRepresentationMask | kStringEncodingMask)) {
int32_t tag = StringShape(string, cage_base).full_representation_tag();
switch (tag) {
case kSeqStringTag | kOneByteStringTag:
visitor->VisitOneByteString(
SeqOneByteString::cast(string).GetChars(no_gc, access_guard) +
......@@ -736,13 +740,15 @@ ConsString String::VisitFlat(
case kExternalStringTag | kOneByteStringTag:
visitor->VisitOneByteString(
ExternalOneByteString::cast(string).GetChars() + slice_offset,
ExternalOneByteString::cast(string).GetChars(cage_base) +
slice_offset,
length - offset);
return ConsString();
case kExternalStringTag | kTwoByteStringTag:
visitor->VisitTwoByteString(
ExternalTwoByteString::cast(string).GetChars() + slice_offset,
ExternalTwoByteString::cast(string).GetChars(cage_base) +
slice_offset,
length - offset);
return ConsString();
......@@ -750,7 +756,7 @@ ConsString String::VisitFlat(
case kSlicedStringTag | kTwoByteStringTag: {
SlicedString slicedString = SlicedString::cast(string);
slice_offset += slicedString.offset();
string = slicedString.parent();
string = slicedString.parent(cage_base);
continue;
}
......@@ -760,7 +766,7 @@ ConsString String::VisitFlat(
case kThinStringTag | kOneByteStringTag:
case kThinStringTag | kTwoByteStringTag:
string = ThinString::cast(string).actual();
string = ThinString::cast(string).actual(cage_base);
continue;
default:
......@@ -948,11 +954,13 @@ DEF_GETTER(ExternalOneByteString, mutable_resource,
void ExternalOneByteString::update_data_cache(Isolate* isolate) {
DisallowGarbageCollection no_gc;
if (is_uncached()) {
if (resource()->IsCacheable()) mutable_resource()->UpdateDataCache();
if (resource(isolate)->IsCacheable())
mutable_resource(isolate)->UpdateDataCache();
} else {
WriteExternalPointerField(kResourceDataOffset, isolate,
reinterpret_cast<Address>(resource()->data()),
kExternalStringResourceDataTag);
WriteExternalPointerField(
kResourceDataOffset, isolate,
reinterpret_cast<Address>(resource(isolate)->data()),
kExternalStringResourceDataTag);
}
}
......@@ -973,13 +981,15 @@ void ExternalOneByteString::set_resource(
if (resource != nullptr) update_data_cache(isolate);
}
const uint8_t* ExternalOneByteString::GetChars() const {
const uint8_t* ExternalOneByteString::GetChars(
PtrComprCageBase cage_base) const {
DisallowGarbageCollection no_gc;
auto res = resource(cage_base);
if (is_uncached()) {
if (resource()->IsCacheable()) {
if (res->IsCacheable()) {
// TODO(solanes): Teach TurboFan/CSA to not bailout to the runtime to
// avoid this call.
return reinterpret_cast<const uint8_t*>(resource()->cached_data());
return reinterpret_cast<const uint8_t*>(res->cached_data());
}
#if DEBUG
// Check that this method is called only from the main thread if we have an
......@@ -992,7 +1002,7 @@ const uint8_t* ExternalOneByteString::GetChars() const {
#endif
}
return reinterpret_cast<const uint8_t*>(resource()->data());
return reinterpret_cast<const uint8_t*>(res->data());
}
uint8_t ExternalOneByteString::Get(
......@@ -1000,7 +1010,7 @@ uint8_t ExternalOneByteString::Get(
const SharedStringAccessGuardIfNeeded& access_guard) const {
USE(access_guard);
DCHECK(index >= 0 && index < length());
return GetChars()[index];
return GetChars(cage_base)[index];
}
DEF_GETTER(ExternalTwoByteString, resource,
......@@ -1016,11 +1026,13 @@ DEF_GETTER(ExternalTwoByteString, mutable_resource,
void ExternalTwoByteString::update_data_cache(Isolate* isolate) {
DisallowGarbageCollection no_gc;
if (is_uncached()) {
if (resource()->IsCacheable()) mutable_resource()->UpdateDataCache();
if (resource(isolate)->IsCacheable())
mutable_resource(isolate)->UpdateDataCache();
} else {
WriteExternalPointerField(kResourceDataOffset, isolate,
reinterpret_cast<Address>(resource()->data()),
kExternalStringResourceDataTag);
WriteExternalPointerField(
kResourceDataOffset, isolate,
reinterpret_cast<Address>(resource(isolate)->data()),
kExternalStringResourceDataTag);
}
}
......@@ -1041,13 +1053,15 @@ void ExternalTwoByteString::set_resource(
if (resource != nullptr) update_data_cache(isolate);
}
const uint16_t* ExternalTwoByteString::GetChars() const {
const uint16_t* ExternalTwoByteString::GetChars(
PtrComprCageBase cage_base) const {
DisallowGarbageCollection no_gc;
auto res = resource(cage_base);
if (is_uncached()) {
if (resource()->IsCacheable()) {
if (res->IsCacheable()) {
// TODO(solanes): Teach TurboFan/CSA to not bailout to the runtime to
// avoid this call.
return resource()->cached_data();
return res->cached_data();
}
#if DEBUG
// Check that this method is called only from the main thread if we have an
......@@ -1060,7 +1074,7 @@ const uint16_t* ExternalTwoByteString::GetChars() const {
#endif
}
return resource()->data();
return res->data();
}
uint16_t ExternalTwoByteString::Get(
......@@ -1068,12 +1082,12 @@ uint16_t ExternalTwoByteString::Get(
const SharedStringAccessGuardIfNeeded& access_guard) const {
USE(access_guard);
DCHECK(index >= 0 && index < length());
return GetChars()[index];
return GetChars(cage_base)[index];
}
const uint16_t* ExternalTwoByteString::ExternalTwoByteStringGetData(
unsigned start) {
return GetChars() + start;
return GetChars(GetPtrComprCageBase(*this)) + start;
}
int ConsStringIterator::OffsetForDepth(int depth) { return depth & kDepthMask; }
......
......@@ -574,13 +574,14 @@ Address StringTable::Data::TryStringToIndexOrLookupExisting(Isolate* isolate,
std::unique_ptr<Char[]> buffer;
const Char* chars;
if (source.IsConsString()) {
DCHECK(!source.IsFlat());
SharedStringAccessGuardIfNeeded access_guard(isolate);
if (source.IsConsString(isolate)) {
DCHECK(!source.IsFlat(isolate));
buffer.reset(new Char[length]);
String::WriteToFlat(source, buffer.get(), 0, length);
String::WriteToFlat(source, buffer.get(), 0, length, isolate, access_guard);
chars = buffer.get();
} else {
chars = source.GetChars<Char>(no_gc) + start;
chars = source.GetChars<Char>(isolate, no_gc, access_guard) + start;
}
// TODO(verwaest): Internalize to one-byte when possible.
SequentialStringKey<Char> key(base::Vector<const Char>(chars, length), seed);
......
......@@ -15,6 +15,7 @@
#include "src/heap/memory-chunk.h"
#include "src/heap/read-only-heap.h"
#include "src/numbers/conversions.h"
#include "src/objects/instance-type.h"
#include "src/objects/map.h"
#include "src/objects/oddball.h"
#include "src/objects/string-comparator.h"
......@@ -546,29 +547,30 @@ String::FlatContent String::GetFlatContent(
}
#endif
USE(no_gc);
PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
int length = this->length();
StringShape shape(*this);
StringShape shape(*this, cage_base);
String string = *this;
int offset = 0;
if (shape.representation_tag() == kConsStringTag) {
ConsString cons = ConsString::cast(string);
if (cons.second().length() != 0) {
if (cons.second(cage_base).length() != 0) {
return FlatContent(no_gc);
}
string = cons.first();
shape = StringShape(string);
string = cons.first(cage_base);
shape = StringShape(string, cage_base);
} else if (shape.representation_tag() == kSlicedStringTag) {
SlicedString slice = SlicedString::cast(string);
offset = slice.offset();
string = slice.parent();
shape = StringShape(string);
string = slice.parent(cage_base);
shape = StringShape(string, cage_base);
DCHECK(shape.representation_tag() != kConsStringTag &&
shape.representation_tag() != kSlicedStringTag);
}
if (shape.representation_tag() == kThinStringTag) {
ThinString thin = ThinString::cast(string);
string = thin.actual();
shape = StringShape(string);
string = thin.actual(cage_base);
shape = StringShape(string, cage_base);
DCHECK(!shape.IsCons());
DCHECK(!shape.IsSliced());
}
......@@ -577,7 +579,7 @@ String::FlatContent String::GetFlatContent(
if (shape.representation_tag() == kSeqStringTag) {
start = SeqOneByteString::cast(string).GetChars(no_gc);
} else {
start = ExternalOneByteString::cast(string).GetChars();
start = ExternalOneByteString::cast(string).GetChars(cage_base);
}
return FlatContent(start + offset, length, no_gc);
} else {
......@@ -586,7 +588,7 @@ String::FlatContent String::GetFlatContent(
if (shape.representation_tag() == kSeqStringTag) {
start = SeqTwoByteString::cast(string).GetChars(no_gc);
} else {
start = ExternalTwoByteString::cast(string).GetChars();
start = ExternalTwoByteString::cast(string).GetChars(cage_base);
}
return FlatContent(start + offset, length, no_gc);
}
......@@ -664,12 +666,16 @@ void String::WriteToFlat(String source, sinkchar* sink, int start, int length,
DCHECK_LE(length, source.length());
switch (StringShape(source, cage_base).full_representation_tag()) {
case kOneByteStringTag | kExternalStringTag:
CopyChars(sink, ExternalOneByteString::cast(source).GetChars() + start,
length);
CopyChars(
sink,
ExternalOneByteString::cast(source).GetChars(cage_base) + start,
length);
return;
case kTwoByteStringTag | kExternalStringTag:
CopyChars(sink, ExternalTwoByteString::cast(source).GetChars() + start,
length);
CopyChars(
sink,
ExternalTwoByteString::cast(source).GetChars(cage_base) + start,
length);
return;
case kOneByteStringTag | kSeqStringTag:
CopyChars(sink,
......@@ -1377,7 +1383,7 @@ uint32_t HashString(String string, size_t start, int length, uint64_t seed,
access_guard);
chars = buffer.get();
} else {
chars = string.GetChars<Char>(no_gc, access_guard) + start;
chars = string.GetChars<Char>(cage_base, no_gc, access_guard) + start;
}
return StringHasher::HashSequentialString<Char>(chars, length, seed);
......@@ -1734,30 +1740,39 @@ const byte* String::AddressOfCharacterAt(
int start_index, const DisallowGarbageCollection& no_gc) {
DCHECK(IsFlat());
String subject = *this;
if (subject.IsConsString()) {
subject = ConsString::cast(subject).first();
} else if (subject.IsSlicedString()) {
PtrComprCageBase cage_base = GetPtrComprCageBase(subject);
StringShape shape(subject, cage_base);
if (subject.IsConsString(cage_base)) {
subject = ConsString::cast(subject).first(cage_base);
shape = StringShape(subject, cage_base);
} else if (subject.IsSlicedString(cage_base)) {
start_index += SlicedString::cast(subject).offset();
subject = SlicedString::cast(subject).parent();
subject = SlicedString::cast(subject).parent(cage_base);
shape = StringShape(subject, cage_base);
}
if (subject.IsThinString()) {
subject = ThinString::cast(subject).actual();
if (subject.IsThinString(cage_base)) {
subject = ThinString::cast(subject).actual(cage_base);
shape = StringShape(subject, cage_base);
}
CHECK_LE(0, start_index);
CHECK_LE(start_index, subject.length());
if (subject.IsSeqOneByteString()) {
return reinterpret_cast<const byte*>(
SeqOneByteString::cast(subject).GetChars(no_gc) + start_index);
} else if (subject.IsSeqTwoByteString()) {
return reinterpret_cast<const byte*>(
SeqTwoByteString::cast(subject).GetChars(no_gc) + start_index);
} else if (subject.IsExternalOneByteString()) {
return reinterpret_cast<const byte*>(
ExternalOneByteString::cast(subject).GetChars() + start_index);
} else {
DCHECK(subject.IsExternalTwoByteString());
return reinterpret_cast<const byte*>(
ExternalTwoByteString::cast(subject).GetChars() + start_index);
switch (shape.full_representation_tag()) {
case kOneByteStringTag | kSeqStringTag:
return reinterpret_cast<const byte*>(
SeqOneByteString::cast(subject).GetChars(no_gc) + start_index);
case kTwoByteStringTag | kSeqStringTag:
return reinterpret_cast<const byte*>(
SeqTwoByteString::cast(subject).GetChars(no_gc) + start_index);
case kOneByteStringTag | kExternalStringTag:
return reinterpret_cast<const byte*>(
ExternalOneByteString::cast(subject).GetChars(cage_base) +
start_index);
case kTwoByteStringTag | kExternalStringTag:
return reinterpret_cast<const byte*>(
ExternalTwoByteString::cast(subject).GetChars(cage_base) +
start_index);
default:
UNREACHABLE();
}
}
......
......@@ -185,12 +185,13 @@ class String : public TorqueGeneratedString<String, Name> {
// SharedStringAccessGuard is not needed (i.e. on the main thread or on
// read-only strings).
template <typename Char>
inline const Char* GetChars(const DisallowGarbageCollection& no_gc) const;
inline const Char* GetChars(PtrComprCageBase cage_base,
const DisallowGarbageCollection& no_gc) const;
// Get chars from sequential or external strings.
template <typename Char>
inline const Char* GetChars(
const DisallowGarbageCollection& no_gc,
PtrComprCageBase cage_base, const DisallowGarbageCollection& no_gc,
const SharedStringAccessGuardIfNeeded& access_guard) const;
// Returns the address of the character at an offset into this string.
......@@ -901,7 +902,7 @@ class ExternalOneByteString
// which the pointer cache has to be refreshed.
inline void update_data_cache(Isolate* isolate);
inline const uint8_t* GetChars() const;
inline const uint8_t* GetChars(PtrComprCageBase cage_base) const;
// Dispatched behavior.
inline uint8_t Get(int index, PtrComprCageBase cage_base,
......@@ -944,7 +945,7 @@ class ExternalTwoByteString
// which the pointer cache has to be refreshed.
inline void update_data_cache(Isolate* isolate);
inline const uint16_t* GetChars() const;
inline const uint16_t* GetChars(PtrComprCageBase cage_base) const;
// Dispatched behavior.
inline uint16_t Get(
......
......@@ -11,6 +11,7 @@
#include "include/v8-primitive.h"
#include "src/base/strings.h"
#include "src/common/globals.h"
#include "src/execution/isolate-utils.h"
#include "src/handles/handles.h"
#include "src/logging/runtime-call-stats-scope.h"
#include "src/objects/objects-inl.h"
......@@ -102,7 +103,7 @@ class ExternalStringStream {
ExternalStringStream(ExternalString string, size_t start_offset,
size_t length)
: lock_(string),
data_(string.GetChars() + start_offset),
data_(string.GetChars(GetPtrComprCageBase(string)) + start_offset),
length_(length) {}
ExternalStringStream(const ExternalStringStream& other) V8_NOEXCEPT
......
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