49
49
import static com .oracle .graal .python .nodes .BuiltinNames .TUPLE ;
50
50
import static com .oracle .graal .python .nodes .BuiltinNames .TYPE ;
51
51
import static com .oracle .graal .python .nodes .BuiltinNames .ZIP ;
52
+ import static com .oracle .graal .python .nodes .SpecialAttributeNames .__DICT__ ;
52
53
import static com .oracle .graal .python .nodes .SpecialAttributeNames .__FILE__ ;
54
+ import static com .oracle .graal .python .nodes .SpecialAttributeNames .__SLOTS__ ;
53
55
import static com .oracle .graal .python .nodes .SpecialMethodNames .DECODE ;
54
56
import static com .oracle .graal .python .nodes .SpecialMethodNames .__SETITEM__ ;
55
57
import static com .oracle .graal .python .runtime .exception .PythonErrorType .NotImplementedError ;
91
93
import com .oracle .graal .python .builtins .objects .function .PFunction ;
92
94
import com .oracle .graal .python .builtins .objects .function .PKeyword ;
93
95
import com .oracle .graal .python .builtins .objects .function .PythonCallable ;
96
+ import com .oracle .graal .python .builtins .objects .getsetdescriptor .HiddenKeyDescriptor ;
94
97
import com .oracle .graal .python .builtins .objects .ints .PInt ;
95
98
import com .oracle .graal .python .builtins .objects .iterator .PZip ;
96
99
import com .oracle .graal .python .builtins .objects .list .PList ;
124
127
import com .oracle .graal .python .nodes .control .GetNextNode ;
125
128
import com .oracle .graal .python .nodes .datamodel .IsIndexNode ;
126
129
import com .oracle .graal .python .nodes .datamodel .IsSequenceNode ;
130
+ import com .oracle .graal .python .nodes .expression .CastToListNode ;
127
131
import com .oracle .graal .python .nodes .function .PythonBuiltinBaseNode ;
128
132
import com .oracle .graal .python .nodes .function .PythonBuiltinNode ;
129
133
import com .oracle .graal .python .nodes .function .builtins .PythonBinaryBuiltinNode ;
140
144
import com .oracle .graal .python .runtime .exception .PythonErrorType ;
141
145
import com .oracle .graal .python .runtime .sequence .PSequence ;
142
146
import com .oracle .graal .python .runtime .sequence .storage .ByteSequenceStorage ;
147
+ import com .oracle .graal .python .runtime .sequence .storage .SequenceStorage ;
143
148
import com .oracle .truffle .api .CompilerAsserts ;
144
149
import com .oracle .truffle .api .CompilerDirectives ;
145
150
import com .oracle .truffle .api .CompilerDirectives .CompilationFinal ;
151
156
import com .oracle .truffle .api .dsl .TypeSystemReference ;
152
157
import com .oracle .truffle .api .frame .VirtualFrame ;
153
158
import com .oracle .truffle .api .nodes .UnexpectedResultException ;
159
+ import com .oracle .truffle .api .object .HiddenKey ;
154
160
import com .oracle .truffle .api .profiles .BranchProfile ;
155
161
import com .oracle .truffle .api .profiles .ConditionProfile ;
156
162
@@ -1598,6 +1604,9 @@ public abstract static class TypeNode extends PythonBuiltinNode {
1598
1604
@ Child private ReadAttributeFromObjectNode readAttrNode ;
1599
1605
@ Child private WriteAttributeToObjectNode writeAttrNode ;
1600
1606
@ Child private CastToIndexNode castToInt ;
1607
+ @ Child private CastToListNode castToList ;
1608
+ @ Child private SequenceStorageNodes .LenNode slotLenNode ;
1609
+ @ Child private SequenceStorageNodes .GetItemNode getSlotItemNode ;
1601
1610
1602
1611
@ Specialization (guards = {"isNoValue(bases)" , "isNoValue(dict)" })
1603
1612
@ SuppressWarnings ("unused" )
@@ -1612,12 +1621,15 @@ public Object type(VirtualFrame frame, PythonClass cls, String name, PTuple base
1612
1621
@ Cached ("create(__NEW__)" ) LookupInheritedAttributeNode getNewFuncNode ,
1613
1622
@ Cached ("create()" ) CallDispatchNode callNewFuncNode ,
1614
1623
@ Cached ("create()" ) CreateArgumentsNode createArgs ) {
1624
+ // Determine the proper metatype to deal with this
1615
1625
PythonClass metaclass = calculate_metaclass (cls , bases , getMetaclassNode );
1626
+
1616
1627
if (metaclass != cls ) {
1617
1628
Object newFunc = getNewFuncNode .execute (metaclass );
1618
1629
if (newFunc instanceof PBuiltinFunction && (((PBuiltinFunction ) newFunc ).getFunctionRootNode () == getRootNode ())) {
1619
- // the new metaclass has the same __new__ function as we are in
1630
+ // the new metaclass has the same __new__ function as we are in, continue
1620
1631
} else {
1632
+ // Pass it to the winner
1621
1633
return callNewFuncNode .executeCall (frame , newFunc , createArgs .execute (metaclass , name , bases , namespace ), kwds );
1622
1634
}
1623
1635
}
@@ -1626,12 +1638,11 @@ public Object type(VirtualFrame frame, PythonClass cls, String name, PTuple base
1626
1638
1627
1639
@ TruffleBoundary
1628
1640
private Object typeMetaclass (String name , PTuple bases , PDict namespace , PythonClass metaclass ) {
1629
- if (name .indexOf ('\0' ) != -1 ) {
1630
- throw raise (ValueError , "type name must not contain null characters" );
1631
- }
1641
+
1632
1642
Object [] array = bases .getArray ();
1633
1643
PythonClass [] basesArray ;
1634
1644
if (array .length == 0 ) {
1645
+ // Adjust for empty tuple bases
1635
1646
basesArray = new PythonClass []{getCore ().lookupType (PythonBuiltinClassType .PythonObject )};
1636
1647
} else {
1637
1648
basesArray = new PythonClass [array .length ];
@@ -1645,15 +1656,106 @@ private Object typeMetaclass(String name, PTuple bases, PDict namespace, PythonC
1645
1656
}
1646
1657
}
1647
1658
assert metaclass != null ;
1659
+
1660
+ if (name .indexOf ('\0' ) != -1 ) {
1661
+ throw raise (ValueError , "type name must not contain null characters" );
1662
+ }
1648
1663
PythonClass pythonClass = factory ().createPythonClass (metaclass , name , basesArray );
1664
+
1665
+ // copy the dictionary slots over, as CPython does through PyDict_Copy
1666
+ // Also check for a __slots__ sequence variable in dict
1667
+ Object slots = null ;
1649
1668
for (DictEntry entry : namespace .entries ()) {
1650
- pythonClass .setAttribute (entry .getKey (), entry .getValue ());
1669
+ Object key = entry .getKey ();
1670
+ Object value = entry .getValue ();
1671
+ if (__SLOTS__ .equals (key )) {
1672
+ slots = value ;
1673
+ } else {
1674
+ pythonClass .setAttribute (key , value );
1675
+ }
1651
1676
}
1652
- addDictIfNative (pythonClass );
1677
+
1678
+ if (slots == null ) {
1679
+ // takes care of checking if we may_add_dict and adds it if needed
1680
+ addDictIfNative (pythonClass );
1681
+ // TODO: tfel - also deal with weaklistoffset
1682
+ } else {
1683
+ // have slots
1684
+
1685
+ // Make it into a list
1686
+ SequenceStorage slotList ;
1687
+ if (slots instanceof String ) {
1688
+ slotList = factory ().createList (new Object []{slots }).getSequenceStorage ();
1689
+ } else {
1690
+ slotList = getCastToListNode ().executeWith (slots ).getSequenceStorage ();
1691
+ }
1692
+ int slotlen = getListLenNode ().execute (slotList );
1693
+ // TODO: tfel - check if slots are allowed. They are not if the base class is var
1694
+ // sized
1695
+
1696
+ for (int i = 0 ; i < slotlen ; i ++) {
1697
+ String slotName ;
1698
+ Object element = getSlotItemNode ().execute (slotList , i );
1699
+ // Check valid slot name
1700
+ if (element instanceof String ) {
1701
+ slotName = (String ) element ;
1702
+ } else {
1703
+ throw raise (TypeError , "__slots__ items must be strings, not '%p'" , element );
1704
+ }
1705
+ if (__DICT__ .equals (slotName )) {
1706
+ // check that the native base does not already have tp_dictoffset
1707
+ if (addDictIfNative (pythonClass )) {
1708
+ throw raise (TypeError , "__dict__ slot disallowed: we already got one" );
1709
+ }
1710
+ } else {
1711
+ // TODO: check for __weakref__
1712
+ // TODO: Copy slots into a list, mangle names and sort them
1713
+ HiddenKey hiddenSlotKey = new HiddenKey (slotName );
1714
+ HiddenKeyDescriptor slotDesc = factory ().createHiddenKeyDescriptor (hiddenSlotKey , pythonClass );
1715
+ pythonClass .setAttribute (slotName , slotDesc );
1716
+ }
1717
+ // Make slots into a tuple
1718
+ }
1719
+ pythonClass .setAttribute (__SLOTS__ , factory ().createTuple (slotList ));
1720
+ if (basesArray .length > 1 ) {
1721
+ // TODO: tfel - check if secondary bases provide weakref or dict when we don't
1722
+ // already have one
1723
+ }
1724
+ }
1725
+
1726
+ // TODO: tfel special case __new__: if it's a plain function, make it a static function
1727
+ // TODO: tfel Special-case __init_subclass__: if it's a plain function, make it a
1728
+ // classmethod
1729
+
1653
1730
return pythonClass ;
1654
1731
}
1655
1732
1656
- private void addDictIfNative (PythonClass pythonClass ) {
1733
+ private SequenceStorageNodes .GetItemNode getSlotItemNode () {
1734
+ if (getSlotItemNode == null ) {
1735
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
1736
+ getSlotItemNode = insert (SequenceStorageNodes .GetItemNode .create ());
1737
+ }
1738
+ return getSlotItemNode ;
1739
+ }
1740
+
1741
+ private SequenceStorageNodes .LenNode getListLenNode () {
1742
+ if (slotLenNode == null ) {
1743
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
1744
+ slotLenNode = insert (SequenceStorageNodes .LenNode .create ());
1745
+ }
1746
+ return slotLenNode ;
1747
+ }
1748
+
1749
+ private CastToListNode getCastToListNode () {
1750
+ if (castToList == null ) {
1751
+ CompilerDirectives .transferToInterpreterAndInvalidate ();
1752
+ castToList = insert (CastToListNode .create ());
1753
+ }
1754
+ return castToList ;
1755
+ }
1756
+
1757
+ private boolean addDictIfNative (PythonClass pythonClass ) {
1758
+ boolean addedNewDict = false ;
1657
1759
for (Object cls : pythonClass .getMethodResolutionOrder ()) {
1658
1760
if (cls instanceof PythonNativeClass ) {
1659
1761
if (readAttrNode == null ) {
@@ -1666,6 +1768,7 @@ private void addDictIfNative(PythonClass pythonClass) {
1666
1768
long basicsize = castToInt .execute (readAttrNode .execute (cls , SpecialAttributeNames .__BASICSIZE__ ));
1667
1769
long itemsize = castToInt .execute (readAttrNode .execute (cls , SpecialAttributeNames .__ITEMSIZE__ ));
1668
1770
if (dictoffset == 0 ) {
1771
+ addedNewDict = true ;
1669
1772
// add_dict
1670
1773
if (itemsize != 0 ) {
1671
1774
dictoffset = -SIZEOF_PY_OBJECT_PTR ;
@@ -1680,6 +1783,7 @@ private void addDictIfNative(PythonClass pythonClass) {
1680
1783
break ;
1681
1784
}
1682
1785
}
1786
+ return addedNewDict ;
1683
1787
}
1684
1788
1685
1789
private PythonClass calculate_metaclass (PythonClass cls , PTuple bases , GetClassNode getMetaclassNode ) {
0 commit comments