62
62
import com .oracle .graal .python .nodes .PGuards ;
63
63
import com .oracle .graal .python .nodes .PNodeWithContext ;
64
64
import com .oracle .graal .python .nodes .util .CastToTruffleStringNode ;
65
+ import com .oracle .truffle .api .CompilerDirectives ;
65
66
import com .oracle .truffle .api .HostCompilerDirectives .InliningCutoff ;
66
67
import com .oracle .truffle .api .dsl .Bind ;
67
68
import com .oracle .truffle .api .dsl .Cached ;
@@ -122,8 +123,8 @@ abstract static class SetValueHashingStorageNode extends PNodeWithContext {
122
123
123
124
@ Specialization
124
125
static HashingStorage doEconomicStorage (VirtualFrame frame , Node inliningTarget , EconomicMapStorage map , Object value ,
125
- @ Cached PutUnsafeNode putNode ,
126
- @ Cached InlinedLoopConditionProfile loopProfile ) {
126
+ @ Shared ( "putNode" ) @ Cached PutUnsafeNode putNode ,
127
+ @ Shared ( "loopProfile" ) @ Cached InlinedLoopConditionProfile loopProfile ) {
127
128
// We want to avoid calling __hash__() during map.put
128
129
map .setValueForAllKeys (frame , inliningTarget , value , putNode , loopProfile );
129
130
return map ;
@@ -135,14 +136,25 @@ static HashingStorage doGeneric(VirtualFrame frame, Node inliningTarget, Hashing
135
136
@ Cached HashingStorageSetItem setItem ,
136
137
@ Cached HashingStorageGetIterator getIterator ,
137
138
@ Cached HashingStorageIteratorNext itNext ,
138
- @ Cached HashingStorageIteratorKey itKey ) {
139
+ @ Cached HashingStorageIteratorKey itKey ,
140
+ @ Shared ("putNode" ) @ Cached PutUnsafeNode putNode ,
141
+ @ Shared ("loopProfile" ) @ Cached InlinedLoopConditionProfile loopProfile ) {
139
142
HashingStorageIterator it = getIterator .execute (inliningTarget , map );
140
- HashingStorage storage = map ;
141
143
while (itNext .execute (inliningTarget , map , it )) {
142
- Object key = itKey .execute (inliningTarget , storage , it );
143
- storage = setItem .execute (frame , inliningTarget , storage , key , value );
144
+ Object key = itKey .execute (inliningTarget , map , it );
145
+ HashingStorage newStorage = setItem .execute (frame , inliningTarget , map , key , value );
146
+ if (newStorage != map ) {
147
+ // when the storage changes, the iterator state is not a reliable cursor
148
+ // anymore and we need to restart.
149
+ if (newStorage instanceof EconomicMapStorage mapStorage ) {
150
+ mapStorage .setValueForAllKeys (frame , inliningTarget , value , putNode , loopProfile );
151
+ return mapStorage ;
152
+ } else {
153
+ throw CompilerDirectives .shouldNotReachHere ("We only generalize to EconomicMapStorage" );
154
+ }
155
+ }
144
156
}
145
- return storage ;
157
+ return map ;
146
158
}
147
159
148
160
protected static boolean isEconomicMapStorage (Object o ) {
0 commit comments