Skip to content

Commit

Permalink
src: v12.x-compatible DescriptorArray
Browse files Browse the repository at this point in the history
V8 changed DescriptorArray from a FixedArray to a proper HeapObject.
These changes update accessors for DescriptorArray fields to make them
compatible with FixedArray-like and HeapObject-like access.

Ref: #255
  • Loading branch information
mmarchini committed Dec 9, 2019
1 parent 37b3c26 commit 6238ada
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 49 deletions.
2 changes: 1 addition & 1 deletion src/llscan.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1563,7 +1563,7 @@ bool FindJSObjectsVisitor::MapCacheEntry::Load(v8::Map map,
if (is_histogram) type_name = heap_object.GetTypeName(err);

v8::HeapObject descriptors_obj = map.InstanceDescriptors(err);
if (err.Fail()) return false;
RETURN_IF_INVALID(descriptors_obj, false);

v8::DescriptorArray descriptors(descriptors_obj);
own_descriptors_count_ = map.NumberOfOwnDescriptors(err);
Expand Down
10 changes: 7 additions & 3 deletions src/llv8-constants.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ void Map::Load() {
"class_Map__constructor__Object");
kInstanceDescriptorsOffset = LoadConstant({
"class_Map__instance_descriptors__DescriptorArray",
"class_Map__instance_descriptors_offset",
});
kBitField3Offset =
LoadConstant("class_Map__bit_field3__int", "class_Map__bit_field3__SMI");
Expand Down Expand Up @@ -403,7 +404,7 @@ void JSArrayBufferView::Load() {


void DescriptorArray::Load() {
kDetailsOffset = LoadConstant("prop_desc_details");
kDetailsOffset = LoadConstant({"prop_desc_details"});
kKeyOffset = LoadConstant("prop_desc_key");
kValueOffset = LoadConstant("prop_desc_value");

Expand Down Expand Up @@ -455,8 +456,11 @@ void DescriptorArray::Load() {
kRepresentationDouble = 7;
}

kFirstIndex = LoadConstant("prop_idx_first");
kSize = LoadConstant("prop_desc_size");
// NOTE(mmarchini): removed from V8 7.2.
// https://github.com/v8/v8/commit/1ad0cd5
kFirstIndex = LoadOptionalConstant({"prop_idx_first"}, 0);
kSize = LoadConstant({"prop_desc_size"});
kHeaderSize = LoadOptionalConstant({"class_DescriptorArray__header_size__uintptr_t"}, 0);
}


Expand Down
8 changes: 5 additions & 3 deletions src/llv8-constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -406,7 +406,7 @@ class DescriptorArray : public Module {
public:
CONSTANTS_DEFAULT_METHODS(DescriptorArray);

int64_t kDetailsOffset;
Constant<int64_t> kDetailsOffset;
int64_t kKeyOffset;
int64_t kValueOffset;

Expand All @@ -417,8 +417,10 @@ class DescriptorArray : public Module {

int64_t kRepresentationDouble;

int64_t kFirstIndex;
int64_t kSize;
Constant<int64_t> kFirstIndex;
Constant<int64_t> kHeaderSize;
Constant<int64_t> kSize;
Constant<int64_t> kEntrySize;

// node.js <= 7
int64_t kPropertyTypeMask = -1;
Expand Down
73 changes: 60 additions & 13 deletions src/llv8-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ inline bool Context::IsContext(LLV8* v8, HeapObject heap_object, Error& err) {
}

inline int64_t Map::InObjectProperties(Error& err) {
RETURN_IF_THIS_INVALID(-1);
if (!IsJSObjectMap(err)) {
err = Error::Failure(
"Invalid call to Map::InObjectProperties with a non-JsObject type");
Expand Down Expand Up @@ -724,25 +725,71 @@ inline T FixedArray::Get(int index, Error& err) {
return LoadFieldValue<T>(off, err);
}

inline Smi DescriptorArray::GetDetails(int index, Error& err) {
return Get<Smi>(v8()->descriptor_array()->kFirstIndex +
index * v8()->descriptor_array()->kSize +
v8()->descriptor_array()->kDetailsOffset,
err);
inline Smi DescriptorArray::GetDetails(int index) {
// TODO(mmarchini): shouldn't need Error here.
Error err;
RETURN_IF_INVALID(v8()->descriptor_array()->kFirstIndex, Smi());
RETURN_IF_INVALID(v8()->descriptor_array()->kSize, Smi());
RETURN_IF_INVALID(v8()->descriptor_array()->kDetailsOffset, Smi());

index = index * *(v8()->descriptor_array()->kSize);
if (v8()->descriptor_array()->kFirstIndex.Loaded()) {
return Get<Smi>(*(v8()->descriptor_array()->kFirstIndex) +
index +
*(v8()->descriptor_array()->kDetailsOffset),
err);
} else if (v8()->descriptor_array()->kHeaderSize.Loaded()) {
index *= v8()->common()->kPointerSize;
index += *(v8()->descriptor_array()->kHeaderSize);
index += (v8()->common()->kPointerSize * *(v8()->descriptor_array()->kDetailsOffset));
return LoadFieldValue<Smi>(index, err);
} else {
PRINT_DEBUG("Missing FirstIndex and HeaderSize constants, can't get key from DescriptorArray");
return Smi();
}
}

inline Value DescriptorArray::GetKey(int index, Error& err) {
return Get<Value>(v8()->descriptor_array()->kFirstIndex +
index * v8()->descriptor_array()->kSize +
v8()->descriptor_array()->kKeyOffset,
err);
RETURN_IF_INVALID(v8()->descriptor_array()->kFirstIndex, Smi());
RETURN_IF_INVALID(v8()->descriptor_array()->kSize, Smi());

index = index * *(v8()->descriptor_array()->kSize);
if (v8()->descriptor_array()->kFirstIndex.Loaded()) {
// TODO(mmarchini): check on `Get`
return Get<Value>(*(v8()->descriptor_array()->kFirstIndex) +
index +
v8()->descriptor_array()->kKeyOffset,
err);
} else if (v8()->descriptor_array()->kHeaderSize.Loaded()) {
index *= v8()->common()->kPointerSize;
index += *(v8()->descriptor_array()->kHeaderSize);
index += v8()->descriptor_array()->kKeyOffset;
return LoadFieldValue<Value>(index, err);
} else {
PRINT_DEBUG("Missing FirstIndex and HeaderSize constants, can't get key from DescriptorArray");
return Value();
}
}

inline Value DescriptorArray::GetValue(int index, Error& err) {
return Get<Value>(v8()->descriptor_array()->kFirstIndex +
index * v8()->descriptor_array()->kSize +
v8()->descriptor_array()->kValueOffset,
err);
RETURN_IF_INVALID(v8()->descriptor_array()->kFirstIndex, Smi());
RETURN_IF_INVALID(v8()->descriptor_array()->kSize, Smi());

index = index * *(v8()->descriptor_array()->kSize);
if (v8()->descriptor_array()->kFirstIndex.Loaded()) {
return Get<Value>(*(v8()->descriptor_array()->kFirstIndex) +
index +
v8()->descriptor_array()->kValueOffset,
err);
} else if (v8()->descriptor_array()->kHeaderSize.Loaded()) {
index *= v8()->common()->kPointerSize;
index += *(v8()->descriptor_array()->kHeaderSize);
index += (v8()->common()->kPointerSize * v8()->descriptor_array()->kValueOffset);
return LoadFieldValue<Value>(index, err);
} else {
PRINT_DEBUG("Missing FirstIndex and HeaderSize constants, can't get key from DescriptorArray");
return Value();
}
}

inline bool DescriptorArray::IsDescriptorDetails(Smi details) {
Expand Down
31 changes: 22 additions & 9 deletions src/llv8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,8 @@ std::string Value::GetTypeName(Error& err) {


std::string Value::ToString(Error& err) {
RETURN_IF_THIS_INVALID(std::string());

Smi smi(this);
if (smi.Check()) return smi.ToString(err);

Expand Down Expand Up @@ -922,7 +924,7 @@ std::vector<std::pair<Value, Value>> JSObject::DictionaryEntries(Error& err) {
std::vector<std::pair<Value, Value>> JSObject::DescriptorEntries(Map map,
Error& err) {
HeapObject descriptors_obj = map.InstanceDescriptors(err);
if (err.Fail()) return {};
RETURN_IF_INVALID(descriptors_obj, {});

DescriptorArray descriptors(descriptors_obj);

Expand All @@ -942,8 +944,12 @@ std::vector<std::pair<Value, Value>> JSObject::DescriptorEntries(Map map,

std::vector<std::pair<Value, Value>> entries;
for (int64_t i = 0; i < own_descriptors_count; i++) {
Smi details = descriptors.GetDetails(i, err);
if (err.Fail()) continue;
Smi details = descriptors.GetDetails(i);
if (!details.Check()) {
PRINT_DEBUG("Failed to get details for index %ld", i);
entries.push_back(std::pair<Value, Value>(Value(), Value()));
continue;
}

Value key = descriptors.GetKey(i, err);
if (err.Fail()) continue;
Expand Down Expand Up @@ -1037,15 +1043,19 @@ void JSObject::DictionaryKeys(std::vector<std::string>& keys, Error& err) {
void JSObject::DescriptorKeys(std::vector<std::string>& keys, Map map,
Error& err) {
HeapObject descriptors_obj = map.InstanceDescriptors(err);
if (err.Fail()) return;
RETURN_IF_INVALID(descriptors_obj, );

DescriptorArray descriptors(descriptors_obj);
int64_t own_descriptors_count = map.NumberOfOwnDescriptors(err);
if (err.Fail()) return;

for (int64_t i = 0; i < own_descriptors_count; i++) {
Smi details = descriptors.GetDetails(i, err);
if (err.Fail()) return;
Smi details = descriptors.GetDetails(i);
if (!details.Check()) {
PRINT_DEBUG("Failed to get details for index %ld", i);
keys.push_back("???");
continue;
}

Value key = descriptors.GetKey(i, err);
if (err.Fail()) return;
Expand Down Expand Up @@ -1124,7 +1134,7 @@ Value JSObject::GetDictionaryProperty(std::string key_name, Error& err) {
Value JSObject::GetDescriptorProperty(std::string key_name, Map map,
Error& err) {
HeapObject descriptors_obj = map.InstanceDescriptors(err);
if (err.Fail()) return Value();
RETURN_IF_INVALID(descriptors_obj, Value());

DescriptorArray descriptors(descriptors_obj);
int64_t own_descriptors_count = map.NumberOfOwnDescriptors(err);
Expand All @@ -1142,8 +1152,11 @@ Value JSObject::GetDescriptorProperty(std::string key_name, Map map,
FixedArray extra_properties(extra_properties_obj);

for (int64_t i = 0; i < own_descriptors_count; i++) {
Smi details = descriptors.GetDetails(i, err);
if (err.Fail()) return Value();
Smi details = descriptors.GetDetails(i);
if (!details.Check()) {
PRINT_DEBUG("Failed to get details for index %ld", i);
continue;
}

Value key = descriptors.GetKey(i, err);
if (err.Fail()) return Value();
Expand Down
2 changes: 1 addition & 1 deletion src/llv8.h
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ class DescriptorArray : public FixedArray {
public:
V8_VALUE_DEFAULT_METHODS(DescriptorArray, FixedArray)

inline Smi GetDetails(int index, Error& err);
inline Smi GetDetails(int index);
inline Value GetKey(int index, Error& err);

// NOTE: Only for DATA_CONSTANT
Expand Down
62 changes: 43 additions & 19 deletions src/printer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -467,9 +467,7 @@ std::string Printer::Stringify(v8::JSArrayBufferView js_array_buffer_view,

template <>
std::string Printer::Stringify(v8::Map map, Error& err) {
v8::HeapObject descriptors_obj = map.InstanceDescriptors(err);
if (err.Fail()) return std::string();

// TODO(mmarchini): don't fail if can't load NumberOfOwnDescriptors
int64_t own_descriptors_count = map.NumberOfOwnDescriptors(err);
if (err.Fail()) return std::string();

Expand All @@ -492,25 +490,41 @@ std::string Printer::Stringify(v8::Map map, Error& err) {
char tmp[256];
std::stringstream ss;
ss << rang::fg::yellow
<< "<Map own_descriptors=%d %s=%d instance_size=%d "
"descriptors=0x%016" PRIx64
<< rang::fg::reset;
<< "<Map own_descriptors=%d %s=%d instance_size=%d descriptors=";

// TODO(mmarchini): this should be a reusable method
std::string descriptors_str = "???";
v8::HeapObject descriptors_obj = map.InstanceDescriptors(err);
if (descriptors_obj.Check()) {
char descriptors_raw[50];
snprintf(descriptors_raw, 50, "0x%016" PRIx64, descriptors_obj.raw());
ss << descriptors_raw;
} else {
PRINT_DEBUG("Failed to load InstanceDescriptors");
ss << rang::fg::red << "???";
}

ss << rang::fg::reset;

snprintf(tmp, sizeof(tmp), ss.str().c_str(),
static_cast<int>(own_descriptors_count),
in_object_properties_or_constructor.c_str(),
static_cast<int>(in_object_properties_or_constructor_index),
static_cast<int>(instance_size), descriptors_obj.raw());
static_cast<int>(instance_size));

if (!options_.detailed) {
return std::string(tmp) + ">";
}

v8::DescriptorArray descriptors(descriptors_obj);
if (err.Fail()) return std::string();
if (descriptors_obj.Check()) {
v8::DescriptorArray descriptors(descriptors_obj);
if (err.Fail()) return std::string();

return std::string(tmp) + ":" + Stringify<v8::FixedArray>(descriptors, err) +
">";
return std::string(tmp) + ":" + Stringify<v8::FixedArray>(descriptors, err) +
">";
} else {
std::string(tmp) + ">";
}
}

template <>
Expand Down Expand Up @@ -965,7 +979,7 @@ std::string Printer::StringifyDictionary(v8::JSObject js_object, Error& err) {
std::string Printer::StringifyDescriptors(v8::JSObject js_object, v8::Map map,
Error& err) {
v8::HeapObject descriptors_obj = map.InstanceDescriptors(err);
if (err.Fail()) return std::string();
RETURN_IF_INVALID(descriptors_obj, std::string());

v8::DescriptorArray descriptors(descriptors_obj);
int64_t own_descriptors_count = map.NumberOfOwnDescriptors(err);
Expand All @@ -987,21 +1001,31 @@ std::string Printer::StringifyDescriptors(v8::JSObject js_object, v8::Map map,
std::string res;
std::stringstream ss;
for (int64_t i = 0; i < own_descriptors_count; i++) {
v8::Smi details = descriptors.GetDetails(i, err);
if (err.Fail()) return std::string();
if (!res.empty()) res += ",\n";

v8::Value key = descriptors.GetKey(i, err);
if (err.Fail()) return std::string();

if (!res.empty()) res += ",\n";

ss.str("");
ss.clear();
ss << rang::style::bold << rang::fg::yellow << " ." + key.ToString(err)
<< rang::fg::reset << rang::style::reset;
ss << rang::style::bold << rang::fg::yellow << " .";
if (key.Check()) {
ss << key.ToString(err);
} else {
PRINT_DEBUG("Failed to get key for index %ld", i);
ss << "???";
}
ss << rang::fg::reset << rang::style::reset;

res += ss.str() + "=";
if (err.Fail()) return std::string();

v8::Smi details = descriptors.GetDetails(i);
if (!details.Check()) {
PRINT_DEBUG("Failed to get details for index %ld", i);
res += "???";
continue;
}

if (descriptors.IsConstFieldDetails(details) ||
descriptors.IsDescriptorDetails(details)) {
v8::Value value;
Expand Down

0 comments on commit 6238ada

Please sign in to comment.