|
55 | 55 | import com.oracle.graal.python.builtins.objects.common.HashingStorageLibrary.HashingStorageIterable;
|
56 | 56 | import com.oracle.graal.python.builtins.objects.common.HashingStorageLibrary.HashingStorageIterator;
|
57 | 57 | import com.oracle.graal.python.builtins.objects.common.HashingStorageLibrary.InjectIntoNode;
|
| 58 | +import com.oracle.graal.python.builtins.objects.common.SequenceNodes.LenNode; |
58 | 59 | import com.oracle.graal.python.builtins.objects.dict.PDict;
|
59 | 60 | import com.oracle.graal.python.builtins.objects.function.PArguments.ThreadState;
|
60 | 61 | import com.oracle.graal.python.builtins.objects.function.PKeyword;
|
@@ -134,7 +135,6 @@ public Assumption needNotPassExceptionAssumption() {
|
134 | 135 |
|
135 | 136 | public abstract HashingStorage execute(VirtualFrame frame, Object mapping, PKeyword[] kwargs);
|
136 | 137 |
|
137 |
| - @Child private GetNextNode nextNode; |
138 | 138 | @Child private LookupInheritedAttributeNode lookupKeysAttributeNode;
|
139 | 139 |
|
140 | 140 | protected boolean isEmpty(PKeyword[] kwargs) {
|
@@ -186,114 +186,36 @@ HashingStorage doPDictKwargs(VirtualFrame frame, PHashingCollection iterable, PK
|
186 | 186 | }
|
187 | 187 |
|
188 | 188 | @Specialization(guards = {"!isPDict(mapping)", "hasKeysAttribute(mapping)"})
|
189 |
| - HashingStorage doMapping(VirtualFrame frame, Object mapping, @SuppressWarnings("unused") PKeyword[] kwargs, |
| 189 | + HashingStorage doMapping(VirtualFrame frame, Object mapping, PKeyword[] kwargs, |
190 | 190 | @CachedLibrary(limit = "3") HashingStorageLibrary lib,
|
191 | 191 | @Cached("create(KEYS)") LookupAndCallUnaryNode callKeysNode,
|
192 | 192 | @Cached("create(__GETITEM__)") LookupAndCallBinaryNode callGetItemNode,
|
193 |
| - @Cached("create()") GetIteratorNode getIteratorNode, |
194 |
| - @Cached("create()") IsBuiltinClassProfile errorProfile) { |
| 193 | + @Cached GetIteratorNode getIteratorNode, |
| 194 | + @Cached GetNextNode nextNode, |
| 195 | + @Cached IsBuiltinClassProfile errorProfile) { |
195 | 196 | HashingStorage curStorage = PDict.createNewStorage(false, 0);
|
196 |
| - // That call must work since 'hasKeysAttribute' checks if it has the 'keys' attribute |
197 |
| - // before. |
198 |
| - Object keysIterable = callKeysNode.executeObject(frame, mapping); |
199 |
| - Object keysIt = getIteratorNode.executeWith(frame, keysIterable); |
200 |
| - while (true) { |
201 |
| - try { |
202 |
| - Object keyObj = getNextNode().execute(frame, keysIt); |
203 |
| - Object valueObj = callGetItemNode.executeObject(frame, mapping, keyObj); |
204 |
| - |
205 |
| - curStorage = lib.setItem(curStorage, keyObj, valueObj); |
206 |
| - } catch (PException e) { |
207 |
| - e.expectStopIteration(errorProfile); |
208 |
| - break; |
209 |
| - } |
210 |
| - } |
211 |
| - if (kwargs.length > 0) { |
212 |
| - curStorage = lib.addAllToOther(new KeywordsStorage(kwargs), curStorage); |
213 |
| - } |
214 |
| - return curStorage; |
215 |
| - } |
216 |
| - |
217 |
| - private GetNextNode getNextNode() { |
218 |
| - if (nextNode == null) { |
219 |
| - CompilerDirectives.transferToInterpreterAndInvalidate(); |
220 |
| - nextNode = insert(GetNextNode.create()); |
221 |
| - } |
222 |
| - return nextNode; |
| 197 | + return addMappingToStorage(frame, mapping, kwargs, curStorage, callKeysNode, callGetItemNode, getIteratorNode, nextNode, errorProfile, lib); |
223 | 198 | }
|
224 | 199 |
|
225 | 200 | @Specialization(guards = {"!isNoValue(iterable)", "!isPDict(iterable)", "!hasKeysAttribute(iterable)"})
|
226 | 201 | HashingStorage doSequence(VirtualFrame frame, PythonObject iterable, PKeyword[] kwargs,
|
227 | 202 | @CachedLibrary(limit = "3") HashingStorageLibrary lib,
|
228 | 203 | @Cached PRaiseNode raise,
|
229 |
| - @Cached("create()") GetIteratorNode getIterator, |
230 |
| - @Cached("create()") FastConstructListNode createListNode, |
| 204 | + @Cached GetIteratorNode getIterator, |
| 205 | + @Cached GetNextNode nextNode, |
| 206 | + @Cached FastConstructListNode createListNode, |
231 | 207 | @Cached("create(__GETITEM__)") LookupAndCallBinaryNode getItemNode,
|
232 |
| - @Cached("create()") SequenceNodes.LenNode seqLenNode, |
| 208 | + @Cached SequenceNodes.LenNode seqLenNode, |
233 | 209 | @Cached("createBinaryProfile()") ConditionProfile lengthTwoProfile,
|
234 |
| - @Cached("create()") IsBuiltinClassProfile errorProfile, |
235 |
| - @Cached("create()") IsBuiltinClassProfile isTypeErrorProfile) { |
236 |
| - |
237 |
| - Object it = getIterator.executeWith(frame, iterable); |
238 |
| - |
239 |
| - ArrayList<PSequence> elements = new ArrayList<>(); |
240 |
| - boolean isStringKey = false; |
241 |
| - try { |
242 |
| - while (true) { |
243 |
| - Object next = getNextNode().execute(frame, it); |
244 |
| - PSequence element = null; |
245 |
| - int len = 1; |
246 |
| - element = createListNode.execute(next); |
247 |
| - assert element != null; |
248 |
| - // This constructs a new list using the builtin type. So, the object cannot |
249 |
| - // be subclassed and we can directly call 'len()'. |
250 |
| - len = seqLenNode.execute(element); |
251 |
| - |
252 |
| - if (lengthTwoProfile.profile(len != 2)) { |
253 |
| - throw raise.raise(ValueError, ErrorMessages.DICT_UPDATE_SEQ_ELEM_HAS_LENGTH_2_REQUIRED, arrayListSize(elements), len); |
254 |
| - } |
255 |
| - |
256 |
| - // really check for Java String since PString can be subclassed |
257 |
| - isStringKey = isStringKey || getItemNode.executeObject(frame, element, 0) instanceof String; |
258 |
| - |
259 |
| - arrayListAdd(elements, element); |
260 |
| - } |
261 |
| - } catch (PException e) { |
262 |
| - if (isTypeErrorProfile.profileException(e, TypeError)) { |
263 |
| - throw raise.raise(TypeError, ErrorMessages.CANNOT_CONVERT_DICT_UPDATE_SEQ, arrayListSize(elements)); |
264 |
| - } else { |
265 |
| - e.expectStopIteration(errorProfile); |
266 |
| - } |
267 |
| - } |
| 210 | + @Cached IsBuiltinClassProfile errorProfile, |
| 211 | + @Cached IsBuiltinClassProfile isTypeErrorProfile) { |
268 | 212 |
|
269 |
| - HashingStorage storage = PDict.createNewStorage(isStringKey, arrayListSize(elements) + kwargs.length); |
270 |
| - for (int j = 0; j < arrayListSize(elements); j++) { |
271 |
| - PSequence element = arrayListGet(elements, j); |
272 |
| - Object key = getItemNode.executeObject(frame, element, 0); |
273 |
| - Object value = getItemNode.executeObject(frame, element, 1); |
274 |
| - storage = lib.setItem(storage, key, value); |
275 |
| - } |
276 |
| - if (kwargs.length > 0) { |
277 |
| - storage = lib.addAllToOther(new KeywordsStorage(kwargs), storage); |
278 |
| - } |
| 213 | + StorageSupplier newStorage = (boolean isStringKey, int length) -> PDict.createNewStorage(isStringKey, length); |
| 214 | + HashingStorage storage = addSequenceToStorage(frame, iterable, kwargs, newStorage, |
| 215 | + getIterator, nextNode, createListNode, seqLenNode, lengthTwoProfile, raise, getItemNode, isTypeErrorProfile, errorProfile, lib); |
279 | 216 | return storage;
|
280 | 217 | }
|
281 | 218 |
|
282 |
| - @TruffleBoundary(allowInlining = true) |
283 |
| - private static PSequence arrayListGet(ArrayList<PSequence> elements, int j) { |
284 |
| - return elements.get(j); |
285 |
| - } |
286 |
| - |
287 |
| - @TruffleBoundary(allowInlining = true) |
288 |
| - private static boolean arrayListAdd(ArrayList<PSequence> elements, PSequence element) { |
289 |
| - return elements.add(element); |
290 |
| - } |
291 |
| - |
292 |
| - @TruffleBoundary(allowInlining = true) |
293 |
| - private static int arrayListSize(ArrayList<PSequence> elements) { |
294 |
| - return elements.size(); |
295 |
| - } |
296 |
| - |
297 | 219 | public static InitNode create() {
|
298 | 220 | return InitNodeGen.create();
|
299 | 221 | }
|
@@ -680,4 +602,99 @@ protected long getHashWithState(Object key, PythonObjectLibrary lib, ThreadState
|
680 | 602 | }
|
681 | 603 | return lib.hashWithState(key, state);
|
682 | 604 | }
|
| 605 | + |
| 606 | + /** |
| 607 | + * Adds all items from the given mapping object to storage. It is the caller responsibility to |
| 608 | + * ensure, that mapping has the 'keys' attribute. |
| 609 | + */ |
| 610 | + public static HashingStorage addMappingToStorage(VirtualFrame frame, Object mapping, PKeyword[] kwargs, HashingStorage storage, |
| 611 | + LookupAndCallUnaryNode callKeysNode, LookupAndCallBinaryNode callGetItemNode, |
| 612 | + GetIteratorNode getIteratorNode, GetNextNode nextNode, |
| 613 | + IsBuiltinClassProfile errorProfile, HashingStorageLibrary lib) { |
| 614 | + Object keysIterable = callKeysNode.executeObject(frame, mapping); |
| 615 | + Object keysIt = getIteratorNode.executeWith(frame, keysIterable); |
| 616 | + HashingStorage curStorage = storage; |
| 617 | + while (true) { |
| 618 | + try { |
| 619 | + Object keyObj = nextNode.execute(frame, keysIt); |
| 620 | + Object valueObj = callGetItemNode.executeObject(frame, mapping, keyObj); |
| 621 | + |
| 622 | + curStorage = lib.setItem(curStorage, keyObj, valueObj); |
| 623 | + } catch (PException e) { |
| 624 | + e.expectStopIteration(errorProfile); |
| 625 | + break; |
| 626 | + } |
| 627 | + } |
| 628 | + if (kwargs.length > 0) { |
| 629 | + curStorage = lib.addAllToOther(new KeywordsStorage(kwargs), curStorage); |
| 630 | + } |
| 631 | + return curStorage; |
| 632 | + } |
| 633 | + |
| 634 | + @FunctionalInterface |
| 635 | + public interface StorageSupplier { |
| 636 | + HashingStorage get(boolean isStringKey, int length); |
| 637 | + } |
| 638 | + |
| 639 | + public static HashingStorage addSequenceToStorage(VirtualFrame frame, Object iterable, PKeyword[] kwargs, StorageSupplier storageSupplier, |
| 640 | + GetIteratorNode getIterator, GetNextNode nextNode, FastConstructListNode createListNode, LenNode seqLenNode, |
| 641 | + ConditionProfile lengthTwoProfile, PRaiseNode raise, LookupAndCallBinaryNode getItemNode, IsBuiltinClassProfile isTypeErrorProfile, |
| 642 | + IsBuiltinClassProfile errorProfile, HashingStorageLibrary lib) throws PException { |
| 643 | + Object it = getIterator.executeWith(frame, iterable); |
| 644 | + ArrayList<PSequence> elements = new ArrayList<>(); |
| 645 | + boolean isStringKey = false; |
| 646 | + try { |
| 647 | + while (true) { |
| 648 | + Object next = nextNode.execute(frame, it); |
| 649 | + PSequence element = null; |
| 650 | + int len = 1; |
| 651 | + element = createListNode.execute(next); |
| 652 | + assert element != null; |
| 653 | + // This constructs a new list using the builtin type. So, the object cannot |
| 654 | + // be subclassed and we can directly call 'len()'. |
| 655 | + len = seqLenNode.execute(element); |
| 656 | + |
| 657 | + if (lengthTwoProfile.profile(len != 2)) { |
| 658 | + throw raise.raise(ValueError, ErrorMessages.DICT_UPDATE_SEQ_ELEM_HAS_LENGTH_2_REQUIRED, arrayListSize(elements), len); |
| 659 | + } |
| 660 | + |
| 661 | + // really check for Java String since PString can be subclassed |
| 662 | + isStringKey = isStringKey || getItemNode.executeObject(frame, element, 0) instanceof String; |
| 663 | + |
| 664 | + arrayListAdd(elements, element); |
| 665 | + } |
| 666 | + } catch (PException e) { |
| 667 | + if (isTypeErrorProfile.profileException(e, TypeError)) { |
| 668 | + throw raise.raise(TypeError, ErrorMessages.CANNOT_CONVERT_DICT_UPDATE_SEQ, arrayListSize(elements)); |
| 669 | + } else { |
| 670 | + e.expectStopIteration(errorProfile); |
| 671 | + } |
| 672 | + } |
| 673 | + HashingStorage storage = storageSupplier.get(isStringKey, arrayListSize(elements) + kwargs.length); |
| 674 | + for (int j = 0; j < arrayListSize(elements); j++) { |
| 675 | + PSequence element = arrayListGet(elements, j); |
| 676 | + Object key = getItemNode.executeObject(frame, element, 0); |
| 677 | + Object value = getItemNode.executeObject(frame, element, 1); |
| 678 | + storage = lib.setItem(storage, key, value); |
| 679 | + } |
| 680 | + if (kwargs.length > 0) { |
| 681 | + storage = lib.addAllToOther(new KeywordsStorage(kwargs), storage); |
| 682 | + } |
| 683 | + return storage; |
| 684 | + } |
| 685 | + |
| 686 | + @TruffleBoundary(allowInlining = true) |
| 687 | + private static PSequence arrayListGet(ArrayList<PSequence> elements, int j) { |
| 688 | + return elements.get(j); |
| 689 | + } |
| 690 | + |
| 691 | + @TruffleBoundary(allowInlining = true) |
| 692 | + private static boolean arrayListAdd(ArrayList<PSequence> elements, PSequence element) { |
| 693 | + return elements.add(element); |
| 694 | + } |
| 695 | + |
| 696 | + @TruffleBoundary(allowInlining = true) |
| 697 | + private static int arrayListSize(ArrayList<PSequence> elements) { |
| 698 | + return elements.size(); |
| 699 | + } |
683 | 700 | }
|
0 commit comments