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-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/459a487d-1515-47e7-b9ee-55a1c99ce5a3n%40googlegroups.com.

Reply via email to