From 7f1e791392566bf682cdc5da578a961ff9e98987 Mon Sep 17 00:00:00 2001 From: Matheus Marchini Date: Tue, 15 May 2018 15:36:11 -0300 Subject: [PATCH] src: fix object inspection for V8 6.4 (#192) V8 6.4 "replaces the in-object properties count byte in the map with the byte that stores the start offset of in-object properties". Object inspection on llnode relies on in-object properties being count bytes, so these are minimal changes to make object inspection work again with V8 6.4 while keeping compatibility with previous versions. Ref: https://chromium-review.googlesource.com/c/v8/v8/+/776720 Fixes: https://github.com/nodejs/llnode/issues/158 --- src/llv8-constants.cc | 5 ++++- src/llv8-constants.h | 3 +++ src/llv8-inl.h | 38 +++++++++++++++++++++++++++++++++++++- src/llv8.cc | 16 +++++++++++++--- src/llv8.h | 3 +++ 5 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/llv8-constants.cc b/src/llv8-constants.cc index 7238d3f5..a2234501 100644 --- a/src/llv8-constants.cc +++ b/src/llv8-constants.cc @@ -204,11 +204,12 @@ void Map::Load() { "class_Map__inobject_properties_or_constructor_function_index__int", "class_Map__inobject_properties__int"); if (kInObjectPropertiesOffset == -1) { - kInObjectPropertiesOffset = LoadConstant( + kInObjectPropertiesStartOffset = LoadConstant( "class_Map__inobject_properties_start_or_constructor_function_index__" "char"); } + kInstanceTypeOffset = LoadConstant("class_Map__instance_type__uint16_t"); kInstanceSizeOffset = LoadConstant("class_Map__instance_size__int", "class_Map__instance_size_in_words__char"); kDictionaryMapShift = LoadConstant("bit_field3_dictionary_map_shift", @@ -574,6 +575,8 @@ void Frame::Load() { void Types::Load() { kFirstNonstringType = LoadConstant("FirstNonstringType"); + kFirstJSObjectType = + LoadConstant("type_JSGlobalObject__JS_GLOBAL_OBJECT_TYPE"); kHeapNumberType = LoadConstant("type_HeapNumber__HEAP_NUMBER_TYPE"); kMapType = LoadConstant("type_Map__MAP_TYPE"); diff --git a/src/llv8-constants.h b/src/llv8-constants.h index 9c237153..d8b37620 100644 --- a/src/llv8-constants.h +++ b/src/llv8-constants.h @@ -94,7 +94,9 @@ class Map : public Module { int64_t kInstanceDescriptorsOffset; int64_t kBitField3Offset; int64_t kInObjectPropertiesOffset; + int64_t kInObjectPropertiesStartOffset; int64_t kInstanceSizeOffset; + int64_t kInstanceTypeOffset; int64_t kNumberOfOwnDescriptorsMask; int64_t kNumberOfOwnDescriptorsShift; @@ -479,6 +481,7 @@ class Types : public Module { MODULE_DEFAULT_METHODS(Types); int64_t kFirstNonstringType; + int64_t kFirstJSObjectType; int64_t kHeapNumberType; int64_t kMapType; diff --git a/src/llv8-inl.h b/src/llv8-inl.h index 6d726222..d774d6bd 100644 --- a/src/llv8-inl.h +++ b/src/llv8-inl.h @@ -159,8 +159,44 @@ inline int64_t Map::BitField3(Error& err) { return v8()->LoadUnsigned(LeaField(v8()->map()->kBitField3Offset), 4, err); } +inline int64_t Map::InstanceType(Error& err) { + return v8()->LoadUnsigned(LeaField(v8()->map()->kInstanceTypeOffset), 2, err); +} + +inline bool Map::IsJSObjectMap(Error& err) { + return InstanceType(err) >= v8()->types()->kFirstJSObjectType; +} + + inline int64_t Map::InObjectProperties(Error& err) { - return LoadField(v8()->map()->kInObjectPropertiesOffset, err) & 0xff; + if (!IsJSObjectMap(err)) { + err = Error::Failure( + "Invalid call to Map::InObjectProperties with a non-JsObject type"); + return 0; + } + if (v8()->map()->kInObjectPropertiesOffset != -1) { + return LoadField(v8()->map()->kInObjectPropertiesOffset, err) & 0xff; + } else { + // NOTE(mmarchini): V8 6.4 changed semantics for + // in_objects_properties_offset (see + // https://chromium-review.googlesource.com/c/v8/v8/+/776720). To keep + // changes to a minimum on llnode and to comply with V8, we're using the + // same implementation from + // https://chromium-review.googlesource.com/c/v8/v8/+/776720/9/src/objects-inl.h#3027. + int64_t in_object_properties_start_offset = + LoadField(v8()->map()->kInObjectPropertiesStartOffset, err) & 0xff; + int64_t instance_size = + v8()->LoadUnsigned(LeaField(v8()->map()->kInstanceSizeOffset), 1, err); + return instance_size - in_object_properties_start_offset; + } +} + +inline int64_t Map::ConstructorFunctionIndex(Error& err) { + if (v8()->map()->kInObjectPropertiesOffset != -1) { + return LoadField(v8()->map()->kInObjectPropertiesOffset, err) & 0xff; + } else { + return LoadField(v8()->map()->kInObjectPropertiesStartOffset, err) & 0xff; + } } inline int64_t Map::InstanceSize(Error& err) { diff --git a/src/llv8.cc b/src/llv8.cc index 0bc972dc..31220811 100644 --- a/src/llv8.cc +++ b/src/llv8.cc @@ -1278,7 +1278,16 @@ std::string Map::Inspect(InspectOptions* options, Error& err) { int64_t own_descriptors_count = NumberOfOwnDescriptors(err); if (err.Fail()) return std::string(); - int64_t in_object_properties = InObjectProperties(err); + std::string in_object_properties_or_constructor; + int64_t in_object_properties_or_constructor_index; + if (IsJSObjectMap(err)) { + if (err.Fail()) return std::string(); + in_object_properties_or_constructor_index = InObjectProperties(err); + in_object_properties_or_constructor = std::string("in_object_size"); + } else { + in_object_properties_or_constructor_index = ConstructorFunctionIndex(err); + in_object_properties_or_constructor = std::string("constructor_index"); + } if (err.Fail()) return std::string(); int64_t instance_size = InstanceSize(err); @@ -1286,10 +1295,11 @@ std::string Map::Inspect(InspectOptions* options, Error& err) { char tmp[256]; snprintf(tmp, sizeof(tmp), - "(own_descriptors_count), - static_cast(in_object_properties), + in_object_properties_or_constructor.c_str(), + static_cast(in_object_properties_or_constructor_index), static_cast(instance_size), descriptors_obj.raw()); if (!options->detailed) { return std::string(tmp) + ">"; diff --git a/src/llv8.h b/src/llv8.h index f67eb28a..1bd7bc3b 100644 --- a/src/llv8.h +++ b/src/llv8.h @@ -137,9 +137,12 @@ class Map : public HeapObject { inline HeapObject InstanceDescriptors(Error& err); inline int64_t BitField3(Error& err); inline int64_t InObjectProperties(Error& err); + inline int64_t ConstructorFunctionIndex(Error& err); inline int64_t InstanceSize(Error& err); + inline int64_t InstanceType(Error& err); inline bool IsDictionary(Error& err); + inline bool IsJSObjectMap(Error& err); inline int64_t NumberOfOwnDescriptors(Error& err); std::string Inspect(InspectOptions* options, Error& err);