Starlark: faster dict.keys

Calling `Dict.entries()` to implement `keys` is suboptimal because it:
* wraps with unmodifiable map
* creates `Map.Entry` object for each iteration

This commit also calls `contents.entrySet()` for `items`, but that's
done mostly for consistency.

Test:

```
def test():
    for i in range(10):
        d = {1: 2, 3: 4}
        for j in range(3000000):
            d.keys()

test()
```

Result:

```
A: N=17, r=4.813+-0.260
B: N=17, r=4.373+-0.212
B/A: 0.909
```

Closes #12480.

PiperOrigin-RevId: 419645062
diff --git a/src/main/java/net/starlark/java/eval/Dict.java b/src/main/java/net/starlark/java/eval/Dict.java
index 229b84c..4dff1c3 100644
--- a/src/main/java/net/starlark/java/eval/Dict.java
+++ b/src/main/java/net/starlark/java/eval/Dict.java
@@ -361,7 +361,7 @@
   public StarlarkList<?> items(StarlarkThread thread) throws EvalException {
     Object[] array = new Object[size()];
     int i = 0;
-    for (Map.Entry<?, ?> e : entrySet()) {
+    for (Map.Entry<?, ?> e : contents.entrySet()) {
       array[i++] = Tuple.pair(e.getKey(), e.getValue());
     }
     return StarlarkList.wrap(thread.mutability(), array);
@@ -377,8 +377,8 @@
   public StarlarkList<?> keys(StarlarkThread thread) throws EvalException {
     Object[] array = new Object[size()];
     int i = 0;
-    for (Map.Entry<?, ?> e : entrySet()) {
-      array[i++] = e.getKey();
+    for (K e : contents.keySet()) {
+      array[i++] = e;
     }
     return StarlarkList.wrap(thread.mutability(), array);
   }