Thanks Toon, will do. On Wednesday, April 9, 2025 at 7:52:48 AM UTC-4 Toon Verwaest wrote:
> Thanks for this report! That sounds like a ScopeInfo deserialization bug. > Presumably we rehash when we deserialize the NameToIndexHashTable but > forget that we directly point to an entry from the ScopeInfo. Care to file > a bug? > > On Wed, Apr 9, 2025 at 1:32 PM alex...@gmail.com <alex...@gmail.com> > wrote: > >> FWIW, one "thought" I had on this was that if saved_class_variable_info >> were an Smi if the local names are inlined and a String reference, if not, >> then there would never be a need to fix anything up during deserialization >> as the String reference could be used to do a lookup in the local names >> hash table. But this is just kibitzing. >> >> On Wednesday, April 9, 2025 at 12:14:53 AM UTC-4 alex...@gmail.com wrote: >> >>> Hey folks, >>> >>> I have a class with many private functions/properties (77 in the most >>> recent incarnation). When I get a stack trace (say to create an Error >>> object) when I'm inside a function in this class, we end up in >>> ClassScope::ClassScope in scopes.cc: >>> ``` >>> if (scope_info->HasSavedClassVariable()) { >>> Tagged<String> name; >>> int index; >>> std::tie(name, index) = scope_info->SavedClassVariable(); >>> ``` >>> >>> This ends up loading an index tacked on to the end of the context slots >>> in the ScopeInfo heap object which looks like: >>> >>> ``` >>> 0x25eabdda3541: [ScopeInfo] >>> - map: 0x2ad145840d71 <Map(SCOPE_INFO_TYPE)> >>> - parameters: 0 >>> - context locals : 79 >>> - local names in a hashtable: 0x25eabdda2d19 <Other heap object >>> (NAME_TO_INDEX_HASH_TABLE_TYPE)> >>> - scope type: CLASS_SCOPE >>> - language mode: strict >>> - class scope has private brand >>> - has saved class variable >>> - function kind: NormalFunction >>> - outer scope info: 0x25eabdda2801 <ScopeInfo MODULE_SCOPE> >>> - start position: 22541 >>> - end position: 282321 >>> - length: 87 >>> - context slots { >>> - 51: 0x1a45b21b8311 <String[17]: ##getTransactionId> >>> - 72: 0x1a45b21b7fc9 <String[13]: ##valueMatches> >>> - 0: 0x1a45b21b6d21 <String[17]: ##allowRunJsScript> >>> - 32: 0x1a45b21b71d1 <String[5]: ##call> >>> - 75: 0x1a45b21b9e59 <String[17]: ##writeNumericParm> >>> - 77: 0x2ad145846ae1 <String[6]: #.brand> >>> - 59: 0x1070007a8419 <String[13]: ##sendResponse> >>> - 29: 0x1a45b21b70a1 <String[9]: ##timeZone> >>> - 37: 0x1a45b21b84a9 <String[11]: ##createFind> >>> - 71: 0x1a45b21bcc91 <String[14]: ##updateRecords> >>> - 17: 0x1a45b21b6f69 <String[19]: ##pendingImageFields> >>> - 28: 0x1a45b21b7081 <String[14]: ##syncSemaphore> >>> - 27: 0x1a45b21b7061 <String[14]: ##syncQueueLock> >>> - 39: 0x1a45b21b8a31 <String[5]: ##find> >>> - 45: 0x1a45b21b91c1 <String[25]: ##getFindRecordTypeInfoSet> >>> - 8: 0x1a45b21b6df9 <String[9]: ##inBuffer> >>> - 44: 0x1a45b21b9d91 <String[12]: ##getFileInfo> >>> - 66: 0x1a45b21bd609 <String[16]: ##syncBuildRecord> >>> - 78: 0x208cca45af99 <String[10]: #Connection> >>> ``` >>> A lot more slots follow, but after them is the class variable info >>> retrieved by the TorqueGeneratedScopeInfo::saved_class_variable_info >>> function. FWIW, job in lldb does not show the value (23 in my example). >>> >>> That saved_class_variable_info is then used to index a name and value in >>> the local names hash table referenced by the ScopeInfo heap object. And >>> this table is used in ScopeInfo::SavedClassVariable to get the class name >>> and index: >>> ``` >>> if (HasInlinedLocalNames()) { >>> ... >>> } else { >>> // The saved class variable info corresponds to the offset in the >>> hash >>> // table storage. >>> InternalIndex entry(saved_class_variable_info()); >>> Tagged<NameToIndexHashTable> table = context_local_names_hashtable(); >>> Tagged<Object> name = table->KeyAt(entry); >>> DCHECK(IsString(name)); >>> return std::make_pair(Cast<String>(name), table->IndexAt(entry)); >>> } >>> ``` >>> The table is a hash table because it's gotten beyond a certain size. In >>> my example it looks like: >>> ``` >>> 0x25eabdda2d19: [NameToIndexHashTable] >>> - FixedArray length: 259 >>> - elements: 79 >>> - deleted: 0 >>> - capacity: 12 >>> - elements: { >>> 0: #getTransactionId -> 51 >>> 1: #valueMatches -> 72 >>> 4: #allowRunJsScript -> 0 >>> 5: #call -> 32 >>> 6: #writeNumericParm -> 75 >>> 7: .brand -> 77 >>> 9: #sendResponse -> 59 >>> 10: #timeZone -> 29 >>> 11: #createFind -> 37 >>> 12: #updateRecords -> 71 >>> 13: #pendingImageFields -> 17 >>> 14: #syncSemaphore -> 28 >>> 15: #syncQueueLock -> 27 >>> 16: #find -> 39 >>> 17: #getFindRecordTypeInfoSet -> 45 >>> 18: #inBuffer -> 8 >>> 20: #getFileInfo -> 44 >>> 21: #syncBuildRecord -> 66 >>> 23: Connection -> 78 >>> ``` >>> As noted before, the saved_class_variable_info has value 23 which does, >>> indeed, reference Connection, my class name. >>> >>> The problem occurs when I use the codeCache from the compilation on the >>> Isolate shown above on a different Isolate. The ScopeInfo heap object looks >>> largely identical to the first Isolate, but the local names hash table >>> looks like it's been rehashed (unsurprisingly): >>> ``` >>> 0x27b95eb86f19: [NameToIndexHashTable] >>> - FixedArray length: 259 >>> - elements: 79 >>> - deleted: 0 >>> - capacity: 128 >>> - elements: { >>> 0: #getTransactionId -> 51 >>> 1: #valueMatches -> 72 >>> 4: #allowRunJsScript -> 0 >>> 5: #call -> 32 >>> 6: #writeNumericParm -> 75 >>> 7: .brand -> 77 >>> 9: #sendResponse -> 59 >>> 10: #timeZone -> 29 >>> 11: #createFind -> 37 >>> 12: #updateRecords -> 71 >>> 13: #pendingImageFields -> 17 >>> 14: #syncSemaphore -> 28 >>> 15: #syncQueueLock -> 27 >>> 16: #find -> 39 >>> 17: Connection -> 78 >>> 18: #inBuffer -> 8 >>> 19: #getFindRecordTypeInfoSet -> 45 >>> 20: #getUpdateValue -> 49 >>> 21: #syncBuildRecord -> 66 >>> 24: #syncImagineFileObj -> 24 >>> ``` >>> Note that the class name Connection is now in slot 17 and slot 23 is >>> unused. So now, when we try to create the class ScopeInfo for a stack >>> trace, the 23 in saved_class_variable_info references an unused slot and I >>> get a seg fault or a failed DCHECK(isString(name)), depending on the type >>> of build. >>> >>> Unfortunately, the fix seems beyond my meager skills. It seems that in >>> deserialization for ScopeInfo, we would have to detect that we have a >>> saved_class_variable_info and so need to recalculate >>> saved_class_variable_info from the old value and the new hash table. But >>> I'm not sure we can control the order in which the local names hash table >>> and the ScopeInfo are deserialized and I'm not sure where in >>> deserialization one would check for the ScopeInfo. >>> >>> Maybe someone more knowledgeable in the snapshot code could fix this >>> relatively easily, suggest a work-around, or tell me what I'm doing wrong? >>> >>> FWIW, this problem occurs for me on V8 13.1.139 and 13.6.233.2. >>> >>> Thanks in advance! >>> >> -- >> -- >> v8-users mailing list >> v8-u...@googlegroups.com >> http://groups.google.com/group/v8-users >> --- >> You received this message because you are subscribed to the Google Groups >> "v8-users" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to v8-users+u...@googlegroups.com. >> To view this discussion visit >> https://groups.google.com/d/msgid/v8-users/afbfdb4c-81ea-4ce1-b3fc-db5aaea8d6b2n%40googlegroups.com >> >> <https://groups.google.com/d/msgid/v8-users/afbfdb4c-81ea-4ce1-b3fc-db5aaea8d6b2n%40googlegroups.com?utm_medium=email&utm_source=footer> >> . >> > -- -- v8-users mailing list v8-users@googlegroups.com http://groups.google.com/group/v8-users --- You received this message because you are subscribed to the Google Groups "v8-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to v8-users+unsubscr...@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/v8-users/1254ba45-a2c8-4172-8b39-47a4aaa8ef56n%40googlegroups.com.