|
80 | 80 | import com.oracle.graal.python.builtins.objects.cext.PythonAbstractNativeObject;
|
81 | 81 | import com.oracle.graal.python.builtins.objects.cext.PythonNativeVoidPtr;
|
82 | 82 | import com.oracle.graal.python.builtins.objects.common.EconomicMapStorage;
|
83 |
| -import com.oracle.graal.python.builtins.objects.common.HashingCollectionNodes; |
84 | 83 | import com.oracle.graal.python.builtins.objects.common.HashingStorage;
|
85 | 84 | import com.oracle.graal.python.builtins.objects.common.HashingStorageLibrary;
|
86 | 85 | import com.oracle.graal.python.builtins.objects.common.SequenceNodes;
|
|
90 | 89 | import com.oracle.graal.python.builtins.objects.floats.PFloat;
|
91 | 90 | import com.oracle.graal.python.builtins.objects.ints.PInt;
|
92 | 91 | import com.oracle.graal.python.builtins.objects.list.PList;
|
| 92 | +import com.oracle.graal.python.builtins.objects.mappingproxy.PMappingproxy; |
93 | 93 | import com.oracle.graal.python.builtins.objects.object.ObjectNodesFactory.GetFullyQualifiedNameNodeGen;
|
94 | 94 | import com.oracle.graal.python.builtins.objects.set.PFrozenSet;
|
95 | 95 | import com.oracle.graal.python.builtins.objects.str.PString;
|
|
119 | 119 | import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
|
120 | 120 | import com.oracle.graal.python.nodes.object.IsForeignObjectNode;
|
121 | 121 | import com.oracle.graal.python.nodes.statement.ImportNode;
|
| 122 | +import com.oracle.graal.python.nodes.subscript.GetItemNode; |
122 | 123 | import com.oracle.graal.python.nodes.util.CannotCastException;
|
123 | 124 | import com.oracle.graal.python.nodes.util.CastToJavaStringNode;
|
124 | 125 | import com.oracle.graal.python.runtime.PythonContext;
|
125 | 126 | import com.oracle.graal.python.runtime.PythonOptions;
|
| 127 | +import com.oracle.graal.python.runtime.exception.PException; |
126 | 128 | import com.oracle.graal.python.runtime.object.IDUtils;
|
127 | 129 | import com.oracle.graal.python.runtime.object.PythonObjectFactory;
|
128 | 130 | import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
|
129 | 131 | import com.oracle.graal.python.util.PythonUtils;
|
130 | 132 | import com.oracle.truffle.api.Assumption;
|
131 | 133 | import com.oracle.truffle.api.CompilerDirectives;
|
| 134 | +import com.oracle.truffle.api.dsl.Bind; |
132 | 135 | import com.oracle.truffle.api.dsl.Cached;
|
133 | 136 | import com.oracle.truffle.api.dsl.Cached.Shared;
|
| 137 | +import com.oracle.truffle.api.dsl.Fallback; |
134 | 138 | import com.oracle.truffle.api.dsl.GenerateUncached;
|
135 | 139 | import com.oracle.truffle.api.dsl.ImportStatic;
|
136 | 140 | import com.oracle.truffle.api.dsl.Specialization;
|
@@ -524,21 +528,59 @@ Pair<Object, Object> doHasNeither(@SuppressWarnings("unused") PNone getNewArgsEx
|
524 | 528 |
|
525 | 529 | @ImportStatic({PythonOptions.class, PGuards.class})
|
526 | 530 | abstract static class GetSlotNamesNode extends Node {
|
527 |
| - public abstract Object execute(VirtualFrame frame, Object cls, Object copyReg); |
| 531 | + @Child PyObjectLookupAttr lookupAttr = PyObjectLookupAttr.create(); |
| 532 | + |
| 533 | + public final Object execute(VirtualFrame frame, Object cls, Object copyReg) { |
| 534 | + Object clsDict = lookupAttr.execute(frame, cls, __DICT__); |
| 535 | + return executeInternal(frame, cls, clsDict, copyReg); |
| 536 | + } |
| 537 | + |
| 538 | + abstract Object executeInternal(VirtualFrame frame, Object cls, Object clsDict, Object copyReg); |
528 | 539 |
|
529 | 540 | @Specialization
|
530 |
| - Object dispatch(VirtualFrame frame, Object cls, Object copyReg, |
531 |
| - @Cached GetSlotNamesInternalNode getSlotNamesInternalNode, |
532 |
| - @Cached HashingCollectionNodes.GetHashingStorageNode getHashingStorageNode, |
533 |
| - @Cached PyObjectLookupAttr lookupAttr, |
534 |
| - @CachedLibrary(limit = "1") HashingStorageLibrary hashLib) { |
| 541 | + Object dispatchDict(VirtualFrame frame, Object cls, PDict clsDict, Object copyReg, |
| 542 | + @Shared("internal") @Cached GetSlotNamesInternalNode getSlotNamesInternalNode, |
| 543 | + @Shared("storageLib") @CachedLibrary(limit = "3") HashingStorageLibrary storageLib) { |
| 544 | + Object slotNames = storageLib.getItem(clsDict.getDictStorage(), __SLOTNAMES__); |
| 545 | + slotNames = slotNames == null ? PNone.NO_VALUE : slotNames; |
| 546 | + return getSlotNamesInternalNode.execute(frame, cls, copyReg, slotNames); |
| 547 | + } |
| 548 | + |
| 549 | + // Fast paths for a common case of PMappingproxy and NO_VALUE |
| 550 | + @Specialization(guards = "isDict(mapping)") |
| 551 | + Object dispatchMappingProxy(VirtualFrame frame, Object cls, @SuppressWarnings("unused") PMappingproxy clsDict, Object copyReg, |
| 552 | + @Shared("internal") @Cached GetSlotNamesInternalNode getSlotNamesInternalNode, |
| 553 | + @Bind("clsDict.getMapping()") Object mapping, |
| 554 | + @Shared("storageLib") @CachedLibrary(limit = "3") HashingStorageLibrary storageLib) { |
| 555 | + PDict mappingDict = (PDict) mapping; |
| 556 | + return dispatchDict(frame, cls, mappingDict, copyReg, getSlotNamesInternalNode, storageLib); |
| 557 | + } |
| 558 | + |
| 559 | + @Specialization(guards = "isNoValue(noValue)") |
| 560 | + Object dispatchNoValue(VirtualFrame frame, Object cls, PNone noValue, Object copyReg, |
| 561 | + @Shared("internal") @Cached GetSlotNamesInternalNode getSlotNamesInternalNode) { |
| 562 | + return getSlotNamesInternalNode.execute(frame, cls, copyReg, noValue); |
| 563 | + } |
| 564 | + |
| 565 | + @Fallback |
| 566 | + Object dispatchGeneric(VirtualFrame frame, Object cls, Object clsDict, Object copyReg, |
| 567 | + @Shared("internal") @Cached GetSlotNamesInternalNode getSlotNamesInternalNode, |
| 568 | + @Cached GetItemNode getItemNode, |
| 569 | + @Cached IsBuiltinClassProfile isBuiltinClassProfile) { |
| 570 | + /* |
| 571 | + * CPython looks at tp_dict of the type and assumes that it must be a builtin |
| 572 | + * dictionary, otherwise it fails with type error. We do not have tp_dict for managed |
| 573 | + * classes and what comes here is __dict__, so among other things it may be a mapping |
| 574 | + * proxy, but also tp_dict for native classes. We "over-approximate" what CPython does |
| 575 | + * here a bit and just use __getitem__. |
| 576 | + */ |
| 577 | + |
535 | 578 | Object slotNames = PNone.NO_VALUE;
|
536 |
| - Object clsDict = lookupAttr.execute(frame, cls, __DICT__); |
537 | 579 | if (!PGuards.isNoValue(clsDict)) {
|
538 |
| - HashingStorage hashingStorage = getHashingStorageNode.execute(frame, clsDict); |
539 |
| - Object item = hashLib.getItem(hashingStorage, __SLOTNAMES__); |
540 |
| - if (item != null) { |
541 |
| - slotNames = item; |
| 580 | + try { |
| 581 | + slotNames = getItemNode.execute(frame, clsDict, __SLOTNAMES__); |
| 582 | + } catch (PException ex) { |
| 583 | + ex.expect(PythonBuiltinClassType.KeyError, isBuiltinClassProfile); |
542 | 584 | }
|
543 | 585 | }
|
544 | 586 | return getSlotNamesInternalNode.execute(frame, cls, copyReg, slotNames);
|
|
0 commit comments