19
19
import com .google .devtools .build .lib .skyframe .serialization .ObjectCodec .MemoizationStrategy ;
20
20
import com .google .protobuf .CodedInputStream ;
21
21
import com .google .protobuf .CodedOutputStream ;
22
+ import it .unimi .dsi .fastutil .ints .Int2ObjectOpenHashMap ;
23
+ import it .unimi .dsi .fastutil .objects .Reference2IntOpenHashMap ;
22
24
import java .io .IOException ;
23
25
import java .util .ArrayDeque ;
24
26
import java .util .Deque ;
25
- import java .util .HashMap ;
26
- import java .util .IdentityHashMap ;
27
27
import javax .annotation .Nullable ;
28
28
29
29
/**
@@ -157,9 +157,8 @@ <T> void serialize(
157
157
}
158
158
}
159
159
160
- @ Nullable
161
- Integer getMemoizedIndex (Object obj ) {
162
- return memo .lookupNullable (obj );
160
+ int getMemoizedIndex (Object obj ) {
161
+ return memo .lookup (obj );
163
162
}
164
163
165
164
// Corresponds to MemoContent in the abstract grammar.
@@ -170,52 +169,55 @@ private <T> void serializeMemoContent(
170
169
CodedOutputStream codedOut ,
171
170
MemoizationStrategy strategy )
172
171
throws SerializationException , IOException {
173
- switch (strategy ) {
174
- case MEMOIZE_BEFORE : {
175
- int id = memo .memoize (obj );
176
- codedOut .writeInt32NoTag (id );
172
+ switch (strategy ) {
173
+ case MEMOIZE_BEFORE :
174
+ {
175
+ int id = memo .memoize (obj );
176
+ codedOut .writeInt32NoTag (id );
177
177
codec .serialize (context , obj , codedOut );
178
- break ;
179
- }
180
- case MEMOIZE_AFTER : {
178
+ break ;
179
+ }
180
+ case MEMOIZE_AFTER :
181
+ {
181
182
codec .serialize (context , obj , codedOut );
182
- // If serializing the children caused the parent object itself to be serialized due to a
183
- // cycle, then there's now a memo entry for the parent. Don't overwrite it with a new id.
184
- Integer cylicallyCreatedId = memo .lookupNullable (obj );
185
- int id = (cylicallyCreatedId != null ) ? cylicallyCreatedId : memo .memoize (obj );
186
- codedOut .writeInt32NoTag (id );
187
- break ;
188
- }
183
+ // If serializing the children caused the parent object itself to be serialized due to a
184
+ // cycle, then there's now a memo entry for the parent. Don't overwrite it with a new
185
+ // id.
186
+ int cylicallyCreatedId = memo .lookup (obj );
187
+ int id = (cylicallyCreatedId != -1 ) ? cylicallyCreatedId : memo .memoize (obj );
188
+ codedOut .writeInt32NoTag (id );
189
+ break ;
190
+ }
189
191
default :
190
192
throw new AssertionError ("Unreachable (strategy=" + strategy + ")" );
191
193
}
192
194
}
193
195
194
196
private static class SerializingMemoTable {
195
- private final IdentityHashMap <Object , Integer > table = new IdentityHashMap <>();
197
+ private final Reference2IntOpenHashMap <Object > table = new Reference2IntOpenHashMap <>();
198
+
199
+ SerializingMemoTable () {
200
+ table .defaultReturnValue (-1 );
201
+ }
196
202
197
203
/**
198
204
* Adds a new value to the memo table and returns its id. The value must not already be
199
205
* present.
200
206
*/
201
207
private int memoize (Object value ) {
202
208
Preconditions .checkArgument (
203
- !table .containsKey (value ),
204
- "Tried to memoize object '%s' multiple times" , value );
209
+ !table .containsKey (value ), "Tried to memoize object '%s' multiple times" , value );
205
210
// Ids count sequentially from 0.
206
211
int newId = table .size ();
207
212
table .put (value , newId );
208
213
return newId ;
209
214
}
210
215
211
216
/**
212
- * If the value is already memoized, return its on-the-wire id; otherwise return null. Opaque.
213
- *
214
- * <p>Beware accidental unboxing of a null result.
217
+ * If the value is already memoized, return its on-the-wire id; otherwise returns {@code -1}.
215
218
*/
216
- @ Nullable
217
- private Integer lookupNullable (Object value ) {
218
- return table .get (value );
219
+ private int lookup (Object value ) {
220
+ return table .getInt (value );
219
221
}
220
222
}
221
223
}
@@ -225,7 +227,7 @@ private Integer lookupNullable(Object value) {
225
227
*/
226
228
static class Deserializer {
227
229
private final DeserializingMemoTable memo = new DeserializingMemoTable ();
228
- @ Nullable private Integer tagForMemoizedBefore = null ;
230
+ private int tagForMemoizedBefore = - 1 ;
229
231
private final Deque <Object > memoizedBeforeStackForSanityChecking = new ArrayDeque <>();
230
232
231
233
/**
@@ -241,7 +243,7 @@ <T> T deserialize(
241
243
CodedInputStream codedIn )
242
244
throws SerializationException , IOException {
243
245
Preconditions .checkState (
244
- tagForMemoizedBefore == null ,
246
+ tagForMemoizedBefore == - 1 ,
245
247
"non-null memoized-before tag %s (%s)" ,
246
248
tagForMemoizedBefore ,
247
249
codec );
@@ -302,10 +304,10 @@ private static <T> T castedDeserialize(
302
304
}
303
305
304
306
<T > void registerInitialValue (T initialValue ) {
305
- int tag =
306
- Preconditions . checkNotNull (
307
- tagForMemoizedBefore , " Not called with memoize before: %s" , initialValue ) ;
308
- tagForMemoizedBefore = null ;
307
+ Preconditions . checkState (
308
+ tagForMemoizedBefore != - 1 , "Not called with memoize before: %s" , initialValue );
309
+ int tag = tagForMemoizedBefore ;
310
+ tagForMemoizedBefore = - 1 ;
309
311
memo .memoize (tag , initialValue );
310
312
memoizedBeforeStackForSanityChecking .addLast (initialValue );
311
313
}
@@ -348,18 +350,21 @@ private <T> T deserializeMemoAfterContent(
348
350
349
351
private static class DeserializingMemoTable {
350
352
351
- private HashMap < Integer , Object > table = new HashMap <>();
353
+ private final Int2ObjectOpenHashMap < Object > table = new Int2ObjectOpenHashMap <>();
352
354
353
355
/**
354
356
* Adds a new id -> object maplet to the memo table. The value must not already be present.
355
357
*/
356
358
private void memoize (int id , Object value ) {
357
359
Preconditions .checkNotNull (value );
358
360
Object prev = table .put (id , value );
359
- Preconditions .checkArgument (
360
- prev == null ,
361
- "Tried to memoize id %s to object '%s', when it is already memoized to object '%s'" ,
362
- id , value , prev );
361
+ if (prev != null ) { // Avoid boxing int with checkArgument.
362
+ throw new IllegalArgumentException (
363
+ String .format (
364
+ "Tried to memoize id %s to object '%s', when it is already memoized to object"
365
+ + " '%s'" ,
366
+ id , value , prev ));
367
+ }
363
368
}
364
369
365
370
/** If the id has been memoized, returns its corresponding object. Otherwise returns null. */
0 commit comments