Commit 1a815e44 authored by Seth Brenith's avatar Seth Brenith Committed by Commit Bot

[tools][torque]Improve postmortem API behavior on strings

This change adds the indexed field for the characters in the definition
of sequential string types, and introduces support for recognizing the
various specific string types in v8_debug_helper. In an attempt to
avoid duplicating info about string instance types, it also refactors
String::Get so that StringShape (a simple class usable by postmortem
tools) can dispatch using a class that defines behaviors for each
concrete type.

Bug: v8:9376
Change-Id: Id0653040f6decddc004c73f8fe93d2187828c2c6
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1735795
Commit-Queue: Seth Brenith <seth.brenith@microsoft.com>
Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#63352}
parent a9ab7912
...@@ -56,6 +56,8 @@ type uint16 extends uint31 ...@@ -56,6 +56,8 @@ type uint16 extends uint31
type int8 extends int16 generates 'TNode<Int8T>' constexpr 'int8_t'; type int8 extends int16 generates 'TNode<Int8T>' constexpr 'int8_t';
type uint8 extends uint16 type uint8 extends uint16
generates 'TNode<Uint8T>' constexpr 'uint8_t'; generates 'TNode<Uint8T>' constexpr 'uint8_t';
type char8 extends int8 constexpr 'char';
type char16 extends uint16 constexpr 'char16_t';
type int64 generates 'TNode<Int64T>' constexpr 'int64_t'; type int64 generates 'TNode<Int64T>' constexpr 'int64_t';
type intptr generates 'TNode<IntPtrT>' constexpr 'intptr_t'; type intptr generates 'TNode<IntPtrT>' constexpr 'intptr_t';
type uintptr generates 'TNode<UintPtrT>' constexpr 'uintptr_t'; type uintptr generates 'TNode<UintPtrT>' constexpr 'uintptr_t';
...@@ -136,9 +138,11 @@ extern class SeqString extends String { ...@@ -136,9 +138,11 @@ extern class SeqString extends String {
} }
@generateCppClass @generateCppClass
extern class SeqOneByteString extends SeqString { extern class SeqOneByteString extends SeqString {
chars[length]: char8;
} }
@generateCppClass @generateCppClass
extern class SeqTwoByteString extends SeqString { extern class SeqTwoByteString extends SeqString {
chars[length]: char16;
} }
@generateCppClass @generateCppClass
......
...@@ -137,6 +137,65 @@ STATIC_ASSERT((kExternalStringTag | kTwoByteStringTag) == ...@@ -137,6 +137,65 @@ STATIC_ASSERT((kExternalStringTag | kTwoByteStringTag) ==
STATIC_ASSERT(v8::String::TWO_BYTE_ENCODING == kTwoByteStringTag); STATIC_ASSERT(v8::String::TWO_BYTE_ENCODING == kTwoByteStringTag);
template <typename TDispatcher, typename TResult, typename... TArgs>
inline TResult StringShape::DispatchToSpecificTypeWithoutCast(TArgs&&... args) {
switch (full_representation_tag()) {
case kSeqStringTag | kOneByteStringTag:
return TDispatcher::HandleSeqOneByteString(std::forward<TArgs>(args)...);
case kSeqStringTag | kTwoByteStringTag:
return TDispatcher::HandleSeqTwoByteString(std::forward<TArgs>(args)...);
case kConsStringTag | kOneByteStringTag:
case kConsStringTag | kTwoByteStringTag:
return TDispatcher::HandleConsString(std::forward<TArgs>(args)...);
case kExternalStringTag | kOneByteStringTag:
return TDispatcher::HandleExternalOneByteString(
std::forward<TArgs>(args)...);
case kExternalStringTag | kTwoByteStringTag:
return TDispatcher::HandleExternalTwoByteString(
std::forward<TArgs>(args)...);
case kSlicedStringTag | kOneByteStringTag:
case kSlicedStringTag | kTwoByteStringTag:
return TDispatcher::HandleSlicedString(std::forward<TArgs>(args)...);
case kThinStringTag | kOneByteStringTag:
case kThinStringTag | kTwoByteStringTag:
return TDispatcher::HandleThinString(std::forward<TArgs>(args)...);
default:
return TDispatcher::HandleInvalidString(std::forward<TArgs>(args)...);
}
}
// All concrete subclasses of String (leaves of the inheritance tree).
#define STRING_CLASS_TYPES(V) \
V(SeqOneByteString) \
V(SeqTwoByteString) \
V(ConsString) \
V(ExternalOneByteString) \
V(ExternalTwoByteString) \
V(SlicedString) \
V(ThinString)
template <typename TDispatcher, typename TResult, typename... TArgs>
inline TResult StringShape::DispatchToSpecificType(String str,
TArgs&&... args) {
class CastingDispatcher : public AllStatic {
public:
#define DEFINE_METHOD(Type) \
static inline TResult Handle##Type(String str, TArgs&&... args) { \
return TDispatcher::Handle##Type(Type::cast(str), \
std::forward<TArgs>(args)...); \
}
STRING_CLASS_TYPES(DEFINE_METHOD)
#undef DEFINE_METHOD
static inline TResult HandleInvalidString(String str, TArgs&&... args) {
return TDispatcher::HandleInvalidString(str,
std::forward<TArgs>(args)...);
}
};
return DispatchToSpecificTypeWithoutCast<CastingDispatcher, TResult>(
str, std::forward<TArgs>(args)...);
}
DEF_GETTER(String, IsOneByteRepresentation, bool) { DEF_GETTER(String, IsOneByteRepresentation, bool) {
uint32_t type = map(isolate).instance_type(); uint32_t type = map(isolate).instance_type();
return (type & kStringEncodingMask) == kOneByteStringTag; return (type & kStringEncodingMask) == kOneByteStringTag;
...@@ -340,29 +399,22 @@ Handle<String> String::Flatten(Isolate* isolate, Handle<String> string, ...@@ -340,29 +399,22 @@ Handle<String> String::Flatten(Isolate* isolate, Handle<String> string,
uint16_t String::Get(int index) { uint16_t String::Get(int index) {
DCHECK(index >= 0 && index < length()); DCHECK(index >= 0 && index < length());
switch (StringShape(*this).full_representation_tag()) {
case kSeqStringTag | kOneByteStringTag: class StringGetDispatcher : public AllStatic {
return SeqOneByteString::cast(*this).Get(index); public:
case kSeqStringTag | kTwoByteStringTag: #define DEFINE_METHOD(Type) \
return SeqTwoByteString::cast(*this).Get(index); static inline uint16_t Handle##Type(Type str, int index) { \
case kConsStringTag | kOneByteStringTag: return str.Get(index); \
case kConsStringTag | kTwoByteStringTag:
return ConsString::cast(*this).Get(index);
case kExternalStringTag | kOneByteStringTag:
return ExternalOneByteString::cast(*this).Get(index);
case kExternalStringTag | kTwoByteStringTag:
return ExternalTwoByteString::cast(*this).Get(index);
case kSlicedStringTag | kOneByteStringTag:
case kSlicedStringTag | kTwoByteStringTag:
return SlicedString::cast(*this).Get(index);
case kThinStringTag | kOneByteStringTag:
case kThinStringTag | kTwoByteStringTag:
return ThinString::cast(*this).Get(index);
default:
break;
} }
STRING_CLASS_TYPES(DEFINE_METHOD)
#undef DEFINE_METHOD
static inline uint16_t HandleInvalidString(String str, int index) {
UNREACHABLE();
}
};
UNREACHABLE(); return StringShape(*this)
.DispatchToSpecificType<StringGetDispatcher, uint16_t>(*this, index);
} }
void String::Set(int index, uint16_t value) { void String::Set(int index, uint16_t value) {
......
...@@ -61,6 +61,13 @@ class StringShape { ...@@ -61,6 +61,13 @@ class StringShape {
inline void invalidate() {} inline void invalidate() {}
#endif #endif
// Run different behavior for each concrete string class type, as defined by
// the dispatcher.
template <typename TDispatcher, typename TResult, typename... TArgs>
inline TResult DispatchToSpecificTypeWithoutCast(TArgs&&... args);
template <typename TDispatcher, typename TResult, typename... TArgs>
inline TResult DispatchToSpecificType(String str, TArgs&&... args);
private: private:
uint32_t type_; uint32_t type_;
#ifdef DEBUG #ifdef DEBUG
......
...@@ -87,16 +87,32 @@ void GenerateClassDebugReader(const ClassType& type, std::ostream& h_contents, ...@@ -87,16 +87,32 @@ void GenerateClassDebugReader(const ClassType& type, std::ostream& h_contents,
std::string indexed_field_info; std::string indexed_field_info;
if (field.index) { if (field.index) {
if ((*field.index)->name_and_type.type != TypeOracle::GetSmiType()) { const Type* index_type = (*field.index)->name_and_type.type;
Error("Non-SMI values are not (yet) supported as indexes."); std::string index_type_name;
std::string index_value;
if (index_type == TypeOracle::GetSmiType()) {
index_type_name = "uintptr_t";
index_value =
"i::PlatformSmiTagging::SmiToInt(indexed_field_count.value)";
} else if (!index_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
const Type* constexpr_index = index_type->ConstexprVersion();
if (constexpr_index == nullptr) {
Error("Type '", index_type->ToString(),
"' requires a constexpr representation");
continue;
}
index_type_name = constexpr_index->GetGeneratedTypeName();
index_value = "indexed_field_count.value";
} else {
Error("Unsupported index type: ", index_type);
continue; continue;
} }
get_props_impl << " Value<uintptr_t> indexed_field_count = Get" get_props_impl << " Value<" << index_type_name
<< "> indexed_field_count = Get"
<< CamelifyString((*field.index)->name_and_type.name) << CamelifyString((*field.index)->name_and_type.name)
<< "Value(accessor);\n"; << "Value(accessor);\n";
indexed_field_info = indexed_field_info =
", i::PlatformSmiTagging::SmiToInt(indexed_field_count.value), " ", " + index_value + ", GetArrayKind(indexed_field_count.validity)";
"GetArrayKind(indexed_field_count.validity)";
} }
get_props_impl get_props_impl
<< " result.push_back(v8::base::make_unique<ObjectProperty>(\"" << " result.push_back(v8::base::make_unique<ObjectProperty>(\""
......
...@@ -2738,15 +2738,31 @@ class FieldOffsetsGenerator { ...@@ -2738,15 +2738,31 @@ class FieldOffsetsGenerator {
public: public:
explicit FieldOffsetsGenerator(const ClassType* type) : type_(type) {} explicit FieldOffsetsGenerator(const ClassType* type) : type_(type) {}
virtual void WriteField(const Field& f) = 0; virtual void WriteField(const Field& f, const std::string& size_string) = 0;
virtual void WriteMarker(const std::string& marker) = 0; virtual void WriteMarker(const std::string& marker) = 0;
virtual void BeginPrivateOffsets() = 0;
virtual ~FieldOffsetsGenerator() { CHECK(is_finished_); } virtual ~FieldOffsetsGenerator() { CHECK(is_finished_); }
void RecordOffsetFor(const Field& f) { void RecordOffsetFor(const Field& f) {
CHECK(!is_finished_); CHECK(!is_finished_);
UpdateSection(f); UpdateSection(f);
WriteField(f); // We don't know statically how much space an indexed field takes, so report
// it as zero.
std::string size_string = "0";
if (!f.index.has_value()) {
size_t field_size;
std::tie(field_size, size_string) = f.GetFieldSizeInformation();
}
WriteField(f, size_string);
// Offsets for anything after an indexed field are likely to cause
// confusion, because the indexed field itself takes up a variable amount of
// space. We could not emit them at all, but that might allow an inherited
// kSize to be accessible (and wrong), so we emit them as private.
if (f.index.has_value()) {
BeginPrivateOffsets();
}
} }
void Finish() { void Finish() {
...@@ -2827,17 +2843,16 @@ class MacroFieldOffsetsGenerator : public FieldOffsetsGenerator { ...@@ -2827,17 +2843,16 @@ class MacroFieldOffsetsGenerator : public FieldOffsetsGenerator {
out_ << "TORQUE_GENERATED_" << CapifyStringWithUnderscores(type_->name()) out_ << "TORQUE_GENERATED_" << CapifyStringWithUnderscores(type_->name())
<< "_FIELDS(V) \\\n"; << "_FIELDS(V) \\\n";
} }
virtual void WriteField(const Field& f) { void WriteField(const Field& f, const std::string& size_string) override {
size_t field_size;
std::string size_string;
std::string machine_type;
std::tie(field_size, size_string) = f.GetFieldSizeInformation();
out_ << "V(k" << CamelifyString(f.name_and_type.name) << "Offset, " out_ << "V(k" << CamelifyString(f.name_and_type.name) << "Offset, "
<< size_string << ") \\\n"; << size_string << ") \\\n";
} }
virtual void WriteMarker(const std::string& marker) { void WriteMarker(const std::string& marker) override {
out_ << "V(" << marker << ", 0) \\\n"; out_ << "V(" << marker << ", 0) \\\n";
} }
void BeginPrivateOffsets() override {
// Can't do anything meaningful here in the macro generator.
}
private: private:
std::ostream& out_; std::ostream& out_;
...@@ -2950,11 +2965,7 @@ class ClassFieldOffsetGenerator : public FieldOffsetsGenerator { ...@@ -2950,11 +2965,7 @@ class ClassFieldOffsetGenerator : public FieldOffsetsGenerator {
: FieldOffsetsGenerator(type), : FieldOffsetsGenerator(type),
hdr_(header), hdr_(header),
previous_field_end_("P::kHeaderSize") {} previous_field_end_("P::kHeaderSize") {}
virtual void WriteField(const Field& f) { void WriteField(const Field& f, const std::string& size_string) override {
size_t field_size;
std::string size_string;
std::string machine_type;
std::tie(field_size, size_string) = f.GetFieldSizeInformation();
std::string field = "k" + CamelifyString(f.name_and_type.name) + "Offset"; std::string field = "k" + CamelifyString(f.name_and_type.name) + "Offset";
std::string field_end = field + "End"; std::string field_end = field + "End";
hdr_ << " static constexpr int " << field << " = " << previous_field_end_ hdr_ << " static constexpr int " << field << " = " << previous_field_end_
...@@ -2963,10 +2974,15 @@ class ClassFieldOffsetGenerator : public FieldOffsetsGenerator { ...@@ -2963,10 +2974,15 @@ class ClassFieldOffsetGenerator : public FieldOffsetsGenerator {
<< size_string << " - 1;\n"; << size_string << " - 1;\n";
previous_field_end_ = field_end + " + 1"; previous_field_end_ = field_end + " + 1";
} }
virtual void WriteMarker(const std::string& marker) { void WriteMarker(const std::string& marker) override {
hdr_ << " static constexpr int " << marker << " = " << previous_field_end_ hdr_ << " static constexpr int " << marker << " = " << previous_field_end_
<< ";\n"; << ";\n";
} }
void BeginPrivateOffsets() override {
// The following section must re-establish public mode (currently done by
// GenerateClassConstructors).
hdr_ << " private:\n";
}
private: private:
std::ostream& hdr_; std::ostream& hdr_;
...@@ -3022,7 +3038,7 @@ void CppClassGenerator::GenerateClass() { ...@@ -3022,7 +3038,7 @@ void CppClassGenerator::GenerateClass() {
hdr_ << " static_assert(std::is_same<" << super_->name() << ", P>::value,\n" hdr_ << " static_assert(std::is_same<" << super_->name() << ", P>::value,\n"
<< " \"Pass in " << super_->name() << " \"Pass in " << super_->name()
<< " as second template parameter for " << gen_name_ << ".\");\n"; << " as second template parameter for " << gen_name_ << ".\");\n";
hdr_ << "public: \n"; hdr_ << " public: \n";
hdr_ << " using Super = P;\n"; hdr_ << " using Super = P;\n";
for (const Field& f : type_->fields()) { for (const Field& f : type_->fields()) {
GenerateFieldAccessor(f); GenerateFieldAccessor(f);
...@@ -3074,7 +3090,7 @@ void CppClassGenerator::GenerateClassCasts() { ...@@ -3074,7 +3090,7 @@ void CppClassGenerator::GenerateClassCasts() {
} }
void CppClassGenerator::GenerateClassConstructors() { void CppClassGenerator::GenerateClassConstructors() {
hdr_ << "public:\n"; hdr_ << " public:\n";
hdr_ << " template <class DAlias = D>\n"; hdr_ << " template <class DAlias = D>\n";
hdr_ << " constexpr " << gen_name_ << "() : P() {\n"; hdr_ << " constexpr " << gen_name_ << "() : P() {\n";
hdr_ << " static_assert(std::is_base_of<" << gen_name_ << ", \n"; hdr_ << " static_assert(std::is_base_of<" << gen_name_ << ", \n";
......
...@@ -168,9 +168,9 @@ bool IsKeywordLikeName(const std::string& s) { ...@@ -168,9 +168,9 @@ bool IsKeywordLikeName(const std::string& s) {
// naming convention and are those exempt from the normal type convention. // naming convention and are those exempt from the normal type convention.
bool IsMachineType(const std::string& s) { bool IsMachineType(const std::string& s) {
static const char* const machine_types[]{ static const char* const machine_types[]{
"void", "never", "int8", "uint8", "int16", "uint16", "void", "never", "int8", "uint8", "int16", "uint16", "int31",
"int31", "uint31", "int32", "uint32", "int64", "intptr", "uint31", "int32", "uint32", "int64", "intptr", "uintptr", "float32",
"uintptr", "float32", "float64", "bool", "string", "bint"}; "float64", "bool", "string", "bint", "char8", "char16"};
return std::find(std::begin(machine_types), std::end(machine_types), s) != return std::find(std::begin(machine_types), std::end(machine_types), s) !=
std::end(machine_types); std::end(machine_types);
......
...@@ -79,7 +79,7 @@ TEST(GetObjectProperties) { ...@@ -79,7 +79,7 @@ TEST(GetObjectProperties) {
CHECK(props->type == std::string("v8::internal::Smi")); CHECK(props->type == std::string("v8::internal::Smi"));
CHECK_EQ(props->num_properties, 0); CHECK_EQ(props->num_properties, 0);
v = CompileRun("[\"a\", \"b\"]"); v = CompileRun("[\"a\", \"bc\"]");
o = v8::Utils::OpenHandle(*v); o = v8::Utils::OpenHandle(*v);
props = d::GetObjectProperties(o->ptr(), &ReadMemory, roots); props = d::GetObjectProperties(o->ptr(), &ReadMemory, roots);
CHECK(props->type_check_result == d::TypeCheckResult::kUsedMap); CHECK(props->type_check_result == d::TypeCheckResult::kUsedMap);
...@@ -144,11 +144,17 @@ TEST(GetObjectProperties) { ...@@ -144,11 +144,17 @@ TEST(GetObjectProperties) {
props->properties[2]->address + sizeof(i::Tagged_t)); props->properties[2]->address + sizeof(i::Tagged_t));
props = d::GetObjectProperties(second_string_address, &ReadMemory, roots); props = d::GetObjectProperties(second_string_address, &ReadMemory, roots);
CHECK(props->type_check_result == d::TypeCheckResult::kUsedMap); CHECK(props->type_check_result == d::TypeCheckResult::kUsedMap);
CHECK(props->type == std::string("v8::internal::String")); CHECK(props->type == std::string("v8::internal::SeqOneByteString"));
CHECK_EQ(props->num_properties, 3); CHECK_EQ(props->num_properties, 4);
CheckProp(*props->properties[0], "v8::internal::Map", "map"); CheckProp(*props->properties[0], "v8::internal::Map", "map");
CheckProp(*props->properties[1], "uint32_t", "hash_field"); CheckProp(*props->properties[1], "uint32_t", "hash_field");
CheckProp(*props->properties[2], "int32_t", "length", 1); CheckProp(*props->properties[2], "int32_t", "length", 2);
CheckProp(*props->properties[3], "char", "chars",
d::PropertyKind::kArrayOfKnownSize, 2);
CHECK_EQ(
strncmp("bc",
reinterpret_cast<const char*>(props->properties[3]->address), 2),
0);
// Read the second string again, using a type hint instead of the map. All of // Read the second string again, using a type hint instead of the map. All of
// its properties should match what we read last time. // its properties should match what we read last time.
...@@ -170,7 +176,7 @@ TEST(GetObjectProperties) { ...@@ -170,7 +176,7 @@ TEST(GetObjectProperties) {
*reinterpret_cast<i::Tagged_t*>(props->properties[0]->address)); *reinterpret_cast<i::Tagged_t*>(props->properties[0]->address));
CheckProp(*props2->properties[1], "uint32_t", "hash_field", CheckProp(*props2->properties[1], "uint32_t", "hash_field",
*reinterpret_cast<int32_t*>(props->properties[1]->address)); *reinterpret_cast<int32_t*>(props->properties[1]->address));
CheckProp(*props2->properties[2], "int32_t", "length", 1); CheckProp(*props2->properties[2], "int32_t", "length", 2);
} }
// Try a weak reference. // Try a weak reference.
...@@ -179,13 +185,13 @@ TEST(GetObjectProperties) { ...@@ -179,13 +185,13 @@ TEST(GetObjectProperties) {
std::string weak_ref_prefix = "weak ref to "; std::string weak_ref_prefix = "weak ref to ";
CHECK(weak_ref_prefix + props->brief == props2->brief); CHECK(weak_ref_prefix + props->brief == props2->brief);
CHECK(props2->type_check_result == d::TypeCheckResult::kUsedMap); CHECK(props2->type_check_result == d::TypeCheckResult::kUsedMap);
CHECK(props2->type == std::string("v8::internal::String")); CHECK(props2->type == std::string("v8::internal::SeqOneByteString"));
CHECK_EQ(props2->num_properties, 3); CHECK_EQ(props2->num_properties, 4);
CheckProp(*props2->properties[0], "v8::internal::Map", "map", CheckProp(*props2->properties[0], "v8::internal::Map", "map",
*reinterpret_cast<i::Tagged_t*>(props->properties[0]->address)); *reinterpret_cast<i::Tagged_t*>(props->properties[0]->address));
CheckProp(*props2->properties[1], "uint32_t", "hash_field", CheckProp(*props2->properties[1], "uint32_t", "hash_field",
*reinterpret_cast<i::Tagged_t*>(props->properties[1]->address)); *reinterpret_cast<i::Tagged_t*>(props->properties[1]->address));
CheckProp(*props2->properties[2], "int32_t", "length", 1); CheckProp(*props2->properties[2], "int32_t", "length", 2);
} }
} // namespace internal } // namespace internal
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "heap-constants.h" #include "heap-constants.h"
#include "include/v8-internal.h" #include "include/v8-internal.h"
#include "src/common/ptr-compr-inl.h" #include "src/common/ptr-compr-inl.h"
#include "src/objects/string-inl.h"
#include "torque-generated/class-debug-readers-tq.h" #include "torque-generated/class-debug-readers-tq.h"
namespace i = v8::internal; namespace i = v8::internal;
...@@ -141,71 +142,117 @@ std::string AppendAddressAndType(const std::string& brief, uintptr_t address, ...@@ -141,71 +142,117 @@ std::string AppendAddressAndType(const std::string& brief, uintptr_t address,
: brief + " (" + brief_stream.str() + ")"; : brief + " (" + brief_stream.str() + ")";
} }
struct TypeNameAndProps {
TypeNameAndProps(d::TypeCheckResult type_check_result, std::string&& type,
std::vector<std::unique_ptr<ObjectProperty>>&& properties)
: type_check_result(type_check_result),
type_name(std::move(type)),
props(std::move(properties)) {}
explicit TypeNameAndProps(d::TypeCheckResult type_check_result)
: type_check_result(type_check_result) {}
d::TypeCheckResult type_check_result;
std::string type_name;
std::vector<std::unique_ptr<ObjectProperty>> props;
};
TypeNameAndProps GetTypeNameAndPropsByHint(uintptr_t address,
d::MemoryAccessor accessor,
std::string type_hint_string) {
#define TYPE_NAME_CASE(ClassName, ...) \
if (type_hint_string == "v8::internal::" #ClassName) { \
return {d::TypeCheckResult::kUsedTypeHint, #ClassName, \
Tq##ClassName(address).GetProperties(accessor)}; \
}
TQ_INSTANCE_TYPES_SINGLE(TYPE_NAME_CASE)
TQ_INSTANCE_TYPES_RANGE(TYPE_NAME_CASE)
#undef TYPE_NAME_CASE
return TypeNameAndProps(d::TypeCheckResult::kUnknownTypeHint);
}
TypeNameAndProps GetTypeNameAndPropsForString(uintptr_t address,
d::MemoryAccessor accessor,
i::InstanceType type) {
class StringGetDispatcher : public i::AllStatic {
public:
#define DEFINE_METHOD(ClassName) \
static inline TypeNameAndProps Handle##ClassName( \
uintptr_t address, d::MemoryAccessor accessor) { \
return {d::TypeCheckResult::kUsedMap, #ClassName, \
Tq##ClassName(address).GetProperties(accessor)}; \
}
STRING_CLASS_TYPES(DEFINE_METHOD)
#undef DEFINE_METHOD
static inline TypeNameAndProps HandleInvalidString(
uintptr_t address, d::MemoryAccessor accessor) {
return TypeNameAndProps(d::TypeCheckResult::kUnknownInstanceType);
}
};
return i::StringShape(type)
.DispatchToSpecificTypeWithoutCast<StringGetDispatcher, TypeNameAndProps>(
address, accessor);
}
std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties( std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties(
uintptr_t address, d::MemoryAccessor accessor, Value<i::InstanceType> type, uintptr_t address, d::MemoryAccessor accessor, Value<i::InstanceType> type,
const char* type_hint, std::string brief) { const char* type_hint, std::string brief) {
std::vector<std::unique_ptr<ObjectProperty>> props; TypeNameAndProps tnp(d::TypeCheckResult::kUsedMap);
std::string type_name;
d::TypeCheckResult type_check_result = d::TypeCheckResult::kUsedMap;
if (type.validity == d::MemoryAccessResult::kOk) { if (type.validity == d::MemoryAccessResult::kOk) {
// Dispatch to the appropriate method for each instance type. After calling // Dispatch to the appropriate method for each instance type. After calling
// the generated method to fetch properties, we can add custom properties. // the generated method to fetch properties, we can add custom properties.
switch (type.value) { switch (type.value) {
#define INSTANCE_TYPE_CASE(ClassName, INSTANCE_TYPE) \ #define INSTANCE_TYPE_CASE(ClassName, INSTANCE_TYPE) \
case i::INSTANCE_TYPE: \ case i::INSTANCE_TYPE: \
type_name = #ClassName; \ tnp.type_name = #ClassName; \
props = Tq##ClassName(address).GetProperties(accessor); \ tnp.props = Tq##ClassName(address).GetProperties(accessor); \
break; break;
TQ_INSTANCE_TYPES_SINGLE(INSTANCE_TYPE_CASE) TQ_INSTANCE_TYPES_SINGLE(INSTANCE_TYPE_CASE)
#undef INSTANCE_TYPE_CASE #undef INSTANCE_TYPE_CASE
default: default:
// Special case: concrete subtypes of String are not included in the
// main instance type list because they use the low bits of the instance
// type enum as flags.
if (type.value <= i::LAST_STRING_TYPE) {
tnp = GetTypeNameAndPropsForString(address, accessor, type.value);
break;
}
#define INSTANCE_RANGE_CASE(ClassName, FIRST_TYPE, LAST_TYPE) \ #define INSTANCE_RANGE_CASE(ClassName, FIRST_TYPE, LAST_TYPE) \
if (type.value >= i::FIRST_TYPE && type.value <= i::LAST_TYPE) { \ if (type.value >= i::FIRST_TYPE && type.value <= i::LAST_TYPE) { \
type_name = #ClassName; \ tnp.type_name = #ClassName; \
props = Tq##ClassName(address).GetProperties(accessor); \ tnp.props = Tq##ClassName(address).GetProperties(accessor); \
break; \ break; \
} }
TQ_INSTANCE_TYPES_RANGE(INSTANCE_RANGE_CASE) TQ_INSTANCE_TYPES_RANGE(INSTANCE_RANGE_CASE)
#undef INSTANCE_RANGE_CASE #undef INSTANCE_RANGE_CASE
type_check_result = d::TypeCheckResult::kUnknownInstanceType; tnp.type_check_result = d::TypeCheckResult::kUnknownInstanceType;
break; break;
} }
} else if (type_hint != nullptr) { } else if (type_hint != nullptr) {
// Try to use the provided type hint, since the real instance type is // Try to use the provided type hint, since the real instance type is
// unavailable. // unavailable.
std::string type_hint_string(type_hint); tnp = GetTypeNameAndPropsByHint(address, accessor, type_hint);
type_check_result = d::TypeCheckResult::kUsedTypeHint;
#define TYPE_NAME_CASE(ClassName, ...) \
if (type_hint_string == "v8::internal::" #ClassName) { \
type_name = #ClassName; \
props = Tq##ClassName(address).GetProperties(accessor); \
} else
TQ_INSTANCE_TYPES_SINGLE(TYPE_NAME_CASE)
TQ_INSTANCE_TYPES_RANGE(TYPE_NAME_CASE)
/*else*/ {
type_check_result = d::TypeCheckResult::kUnknownTypeHint;
}
#undef TYPE_NAME_CASE
} else { } else {
// TODO(v8:9376): Use known maps here. If known map is just a guess (because // TODO(v8:9376): Use known maps here. If known map is just a guess (because
// root pointers weren't provided), then create a synthetic property with // root pointers weren't provided), then create a synthetic property with
// the more specific type. Then the caller could presumably ask us again // the more specific type. Then the caller could presumably ask us again
// with the type hint we provided. Otherwise, just go ahead and use it to // with the type hint we provided. Otherwise, just go ahead and use it to
// generate properties. // generate properties.
type_check_result = tnp.type_check_result =
type.validity == d::MemoryAccessResult::kAddressNotValid type.validity == d::MemoryAccessResult::kAddressNotValid
? d::TypeCheckResult::kMapPointerInvalid ? d::TypeCheckResult::kMapPointerInvalid
: d::TypeCheckResult::kMapPointerValidButInaccessible; : d::TypeCheckResult::kMapPointerValidButInaccessible;
} }
if (type_name.empty()) { if (tnp.type_name.empty()) {
type_name = "Object"; tnp.type_name = "Object";
} }
// TODO(v8:9376): Many object types need additional data that is not included // TODO(v8:9376): Many object types need additional data that is not included
...@@ -215,10 +262,11 @@ std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties( ...@@ -215,10 +262,11 @@ std::unique_ptr<ObjectPropertiesResult> GetHeapObjectProperties(
// is available, we should instead represent those properties (and any out-of- // is available, we should instead represent those properties (and any out-of-
// object properties) using their JavaScript property names. // object properties) using their JavaScript property names.
brief = AppendAddressAndType(brief, address, type_name.c_str()); brief = AppendAddressAndType(brief, address, tnp.type_name.c_str());
return v8::base::make_unique<ObjectPropertiesResult>( return v8::base::make_unique<ObjectPropertiesResult>(
type_check_result, brief, "v8::internal::" + type_name, std::move(props)); tnp.type_check_result, brief, "v8::internal::" + tnp.type_name,
std::move(tnp.props));
} }
#undef STRUCT_INSTANCE_TYPE_ADAPTER #undef STRUCT_INSTANCE_TYPE_ADAPTER
......
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