@@ -1113,32 +1113,171 @@ class RetainingPath {
1113
1113
const Object& to_;
1114
1114
TraversalRules traversal_rules_;
1115
1115
1116
+ class FindObjectVisitor : public ObjectPointerVisitor {
1117
+ public:
1118
+ FindObjectVisitor (IsolateGroup* isolate_group, ObjectPtr target)
1119
+ : ObjectPointerVisitor(isolate_group), target_(target), index_(0 ) {}
1120
+
1121
+ void VisitPointers (ObjectPtr* from, ObjectPtr* to) override {
1122
+ for (ObjectPtr* ptr = from; ptr <= to; ptr++, index_++) {
1123
+ if (*ptr == target_) {
1124
+ break ;
1125
+ }
1126
+ }
1127
+ }
1128
+
1129
+ #if defined(DART_COMPRESSED_POINTERS)
1130
+ void VisitCompressedPointers (uword heap_base,
1131
+ CompressedObjectPtr* from,
1132
+ CompressedObjectPtr* to) override {
1133
+ for (ObjectPtr* ptr = from; ptr <= to; ptr++, index_++) {
1134
+ if (ptr->Decompress (heap_base) == target_) {
1135
+ break ;
1136
+ }
1137
+ }
1138
+ }
1139
+ #endif
1140
+
1141
+ intptr_t index () { return index_; }
1142
+
1143
+ private:
1144
+ ObjectPtr target_;
1145
+ intptr_t index_;
1146
+ };
1147
+
1116
1148
const char * CollectPath (MallocGrowableArray<ObjectPtr>* const working_list) {
1149
+ Object& previous_object = Object::Handle (zone_);
1117
1150
Object& object = Object::Handle (zone_);
1151
+ Field& field = Field::Handle (zone_);
1118
1152
Class& klass = Class::Handle (zone_);
1119
1153
Library& library = Library::Handle (zone_);
1120
1154
String& library_url = String::Handle (zone_);
1155
+ Context& context = Context::Handle (zone_);
1156
+ Closure& closure = Closure::Handle (zone_);
1157
+ Function& function = Function::Handle (zone_);
1158
+ #if !defined(DART_PRECOMPILED_RUNTIME)
1159
+ Code& code = Code::Handle (zone_);
1160
+ LocalVarDescriptors& var_descriptors = LocalVarDescriptors::Handle (zone_);
1161
+ String& name = String::Handle (zone_);
1162
+ #endif
1163
+
1164
+ const char * saved_context_location = nullptr ;
1165
+ intptr_t saved_context_object_index = -1 ;
1166
+ intptr_t saved_context_depth = 0 ;
1121
1167
const char * retaining_path = " " ;
1122
1168
1123
1169
ObjectPtr raw = to_.ptr ();
1124
- // Skip all remaining children until null-separator, so we get the parent
1125
1170
do {
1171
+ previous_object = raw;
1172
+ // Skip all remaining children until null-separator, so we get the parent
1126
1173
do {
1127
1174
raw = working_list->RemoveLast ();
1128
1175
} while (raw != Object::null () && raw != from_.ptr ());
1129
1176
if (raw == Object::null ()) {
1130
1177
raw = working_list->RemoveLast ();
1131
1178
object = raw;
1132
1179
klass = object.clazz ();
1133
- library = klass.library ();
1134
- if (library.IsNull ()) {
1135
- retaining_path = OS::SCreate (zone_, " %s <- %s\n " , retaining_path,
1136
- object.ToCString ());
1180
+
1181
+ const char * location = object.ToCString ();
1182
+
1183
+ if (object.IsContext ()) {
1184
+ context ^= raw;
1185
+ if (saved_context_object_index == -1 ) {
1186
+ // If this is the first context, remember index of the
1187
+ // [previous_object] in the Context.
1188
+ // We will need it later if get to see the Closure next.
1189
+ saved_context_depth = 0 ;
1190
+ for (intptr_t i = 0 ; i < context.num_variables (); i++) {
1191
+ if (context.At (i) == previous_object.ptr ()) {
1192
+ saved_context_object_index = i;
1193
+ break ;
1194
+ }
1195
+ }
1196
+ } else {
1197
+ // Keep track of context depths in case of nested contexts;
1198
+ saved_context_depth++;
1199
+ }
1137
1200
} else {
1201
+ if (object.IsInstance ()) {
1202
+ if (object.IsClosure ()) {
1203
+ closure ^= raw;
1204
+ function ^= closure.function ();
1205
+ // Use function's class when looking for a library information.
1206
+ klass ^= function.Owner ();
1207
+ #if defined(DART_PRECOMPILED_RUNTIME)
1208
+ // Use function's name instead of closure's.
1209
+ location = function.QualifiedUserVisibleNameCString ();
1210
+ #else // defined(DART_PRECOMPILED_RUNTIME) \
1211
+ // Attempt to convert "instance <- Context+ <- Closure" into \
1212
+ // "instance <- local var name in Closure".
1213
+ if (!function.ForceOptimize ()) {
1214
+ function.EnsureHasCompiledUnoptimizedCode ();
1215
+ }
1216
+ code ^= function.unoptimized_code ();
1217
+ ASSERT (!code.IsNull ());
1218
+ var_descriptors ^= code.GetLocalVarDescriptors ();
1219
+ for (intptr_t i = 0 ; i < var_descriptors.Length (); i++) {
1220
+ UntaggedLocalVarDescriptors::VarInfo info;
1221
+ var_descriptors.GetInfo (i, &info);
1222
+ if (info.scope_id == -saved_context_depth &&
1223
+ info.kind () ==
1224
+ UntaggedLocalVarDescriptors::VarInfoKind::kContextVar &&
1225
+ info.index () == saved_context_object_index) {
1226
+ name ^= var_descriptors.GetName (i);
1227
+ location =
1228
+ OS::SCreate (zone_, " field %s in %s" , name.ToCString (),
1229
+ function.QualifiedUserVisibleNameCString ());
1230
+ // Won't need saved context location after all.
1231
+ saved_context_location = nullptr ;
1232
+ break ;
1233
+ }
1234
+ }
1235
+ #endif // defined(DART_PRECOMPILED_RUNTIME)
1236
+ } else {
1237
+ // Attempt to find field name for the field that holds the
1238
+ // [previous_object] instance.
1239
+ FindObjectVisitor visitor (isolate_->group (),
1240
+ previous_object.ptr ());
1241
+ raw->untag ()->VisitPointers (&visitor);
1242
+ field ^= klass.FieldFromIndex (visitor.index ());
1243
+ if (!field.IsNull ()) {
1244
+ location =
1245
+ OS::SCreate (zone_, " %s in %s" ,
1246
+ field.UserVisibleNameCString (), location);
1247
+ }
1248
+ }
1249
+ }
1250
+ // Saved context object index stays up for only one cycle - just to
1251
+ // accommodate short chains Closure -> Context -> instance.
1252
+ saved_context_object_index = -1 ;
1253
+ saved_context_depth = -1 ;
1254
+ }
1255
+ // Add library url to the location if library is available.
1256
+ library = klass.library ();
1257
+ if (!library.IsNull ()) {
1138
1258
library_url = library.url ();
1259
+ location = OS::SCreate (zone_, " %s (from %s)" , location,
1260
+ library_url.ToCString ());
1261
+ }
1262
+
1263
+ if (object.IsContext ()) {
1264
+ // Save context string placeholder in case we don't find closure next
1265
+ if (saved_context_location == nullptr ) {
1266
+ saved_context_location = location;
1267
+ } else {
1268
+ // Append saved contexts
1269
+ saved_context_location = OS::SCreate (
1270
+ zone_, " %s <- %s\n " , saved_context_location, location);
1271
+ }
1272
+ } else {
1273
+ if (saved_context_location != nullptr ) {
1274
+ // Could not use saved context, insert it into retaining path now.
1275
+ retaining_path = OS::SCreate (zone_, " %s <- %s" , retaining_path,
1276
+ saved_context_location);
1277
+ saved_context_location = nullptr ;
1278
+ }
1139
1279
retaining_path =
1140
- OS::SCreate (zone_, " %s <- %s (from %s)\n " , retaining_path,
1141
- object.ToCString (), library_url.ToCString ());
1280
+ OS::SCreate (zone_, " %s <- %s\n " , retaining_path, location);
1142
1281
}
1143
1282
}
1144
1283
} while (raw != from_.ptr ());
0 commit comments