|
26 | 26 |
|
27 | 27 | package com.oracle.graal.python.builtins.objects.foreign;
|
28 | 28 |
|
| 29 | +import static com.oracle.graal.python.nodes.SpecialAttributeNames.__CLASS__; |
29 | 30 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__ADD__;
|
30 | 31 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__BOOL__;
|
31 | 32 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__CALL__;
|
32 | 33 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__DELATTR__;
|
| 34 | +import static com.oracle.graal.python.nodes.SpecialMethodNames.__DELETE__; |
33 | 35 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__DELITEM__;
|
34 | 36 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__DIR__;
|
35 | 37 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__FLOORDIV__;
|
36 | 38 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__GETATTRIBUTE__;
|
| 39 | +import static com.oracle.graal.python.nodes.SpecialMethodNames.__GETATTR__; |
37 | 40 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__GETITEM__;
|
| 41 | +import static com.oracle.graal.python.nodes.SpecialMethodNames.__GET__; |
38 | 42 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__GE__;
|
39 | 43 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__GT__;
|
40 | 44 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__ITER__;
|
|
50 | 54 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__RTRUEDIV__;
|
51 | 55 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__SETATTR__;
|
52 | 56 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__SETITEM__;
|
| 57 | +import static com.oracle.graal.python.nodes.SpecialMethodNames.__SET__; |
53 | 58 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__SUB__;
|
54 | 59 | import static com.oracle.graal.python.nodes.SpecialMethodNames.__TRUEDIV__;
|
55 | 60 | import static com.oracle.graal.python.runtime.exception.PythonErrorType.AttributeError;
|
|
64 | 69 | import com.oracle.graal.python.builtins.objects.PNone;
|
65 | 70 | import com.oracle.graal.python.builtins.objects.PNotImplemented;
|
66 | 71 | import com.oracle.graal.python.builtins.objects.function.PKeyword;
|
| 72 | +import com.oracle.graal.python.builtins.objects.function.PythonCallable; |
67 | 73 | import com.oracle.graal.python.builtins.objects.list.PList;
|
| 74 | +import com.oracle.graal.python.builtins.objects.type.PythonClass; |
68 | 75 | import com.oracle.graal.python.nodes.PGuards;
|
| 76 | +import com.oracle.graal.python.nodes.SpecialMethodNames; |
| 77 | +import com.oracle.graal.python.nodes.attributes.LookupAttributeInMRONode; |
| 78 | +import com.oracle.graal.python.nodes.attributes.LookupInheritedAttributeNode; |
| 79 | +import com.oracle.graal.python.nodes.call.special.CallTernaryMethodNode; |
69 | 80 | import com.oracle.graal.python.nodes.call.special.LookupAndCallBinaryNode;
|
70 | 81 | import com.oracle.graal.python.nodes.expression.BinaryArithmetic;
|
71 | 82 | import com.oracle.graal.python.nodes.expression.BinaryComparisonNode;
|
|
76 | 87 | import com.oracle.graal.python.nodes.function.builtins.PythonUnaryBuiltinNode;
|
77 | 88 | import com.oracle.graal.python.nodes.interop.PForeignToPTypeNode;
|
78 | 89 | import com.oracle.graal.python.nodes.interop.PTypeToForeignNode;
|
| 90 | +import com.oracle.graal.python.nodes.object.GetClassNode; |
79 | 91 | import com.oracle.graal.python.runtime.exception.PythonErrorType;
|
80 | 92 | import com.oracle.truffle.api.CompilerDirectives;
|
81 | 93 | import com.oracle.truffle.api.dsl.Cached;
|
|
92 | 104 | import com.oracle.truffle.api.interop.UnsupportedMessageException;
|
93 | 105 | import com.oracle.truffle.api.interop.UnsupportedTypeException;
|
94 | 106 | import com.oracle.truffle.api.nodes.Node;
|
| 107 | +import com.oracle.truffle.api.profiles.BranchProfile; |
| 108 | +import com.oracle.truffle.api.profiles.ConditionProfile; |
95 | 109 | import com.oracle.truffle.api.profiles.ValueProfile;
|
96 | 110 |
|
97 | 111 | @CoreFunctions(extendClasses = TruffleObject.class)
|
@@ -790,16 +804,149 @@ protected Object doGeneric(Object callee, @SuppressWarnings("unused") Object arg
|
790 | 804 |
|
791 | 805 | @Builtin(name = __GETATTRIBUTE__, fixedNumOfArguments = 2)
|
792 | 806 | @GenerateNodeFactory
|
793 |
| - abstract static class GetattributeNode extends UnboxNode { |
794 |
| - @Specialization(guards = "isForeignObject(object)") |
| 807 | + public abstract static class GetattributeNode extends PythonBinaryBuiltinNode { |
| 808 | + private final BranchProfile hasDescProfile = BranchProfile.create(); |
| 809 | + private final BranchProfile isDescProfile = BranchProfile.create(); |
| 810 | + private final BranchProfile hasValueProfile = BranchProfile.create(); |
| 811 | + private final BranchProfile errorProfile = BranchProfile.create(); |
| 812 | + private final ConditionProfile typeIsObjectProfile = ConditionProfile.createBinaryProfile(); |
| 813 | + |
| 814 | + @Child private LookupInheritedAttributeNode lookup = LookupInheritedAttributeNode.create(); |
| 815 | + private final ValueProfile typeProfile = ValueProfile.createIdentityProfile(); |
| 816 | + @Child private GetClassNode getObjectClassNode; |
| 817 | + @Child private GetClassNode getDataClassNode; |
| 818 | + @Child private LookupAttributeInMRONode lookupGetNode; |
| 819 | + @Child private LookupAttributeInMRONode lookupSetNode; |
| 820 | + @Child private LookupAttributeInMRONode lookupDeleteNode; |
| 821 | + @Child private CallTernaryMethodNode dispatchGet; |
| 822 | + @Child private Node attrReadNode; |
| 823 | + @Child private LookupAndCallBinaryNode getattrNode; |
| 824 | + |
| 825 | + @Specialization |
| 826 | + protected Object doIt(TruffleObject object, Object key) { |
| 827 | + Object descr = lookup.execute(object, key); |
| 828 | + PythonClass dataDescClass = null; |
| 829 | + if (descr != PNone.NO_VALUE) { |
| 830 | + hasDescProfile.enter(); |
| 831 | + dataDescClass = getDataClass(descr); |
| 832 | + Object delete = PNone.NO_VALUE; |
| 833 | + Object set = lookupSet(dataDescClass); |
| 834 | + if (set == PNone.NO_VALUE) { |
| 835 | + delete = lookupDelete(dataDescClass); |
| 836 | + } |
| 837 | + if (set != PNone.NO_VALUE || delete != PNone.NO_VALUE) { |
| 838 | + isDescProfile.enter(); |
| 839 | + Object get = lookupGet(dataDescClass); |
| 840 | + if (get instanceof PythonCallable) { |
| 841 | + // Only override if __get__ is defined, too, for compatibility with CPython. |
| 842 | + return dispatch(object, descr, get); |
| 843 | + } |
| 844 | + } |
| 845 | + } |
| 846 | + Object value = readAttribute(object, key); |
| 847 | + if (value != PNone.NO_VALUE) { |
| 848 | + hasValueProfile.enter(); |
| 849 | + return value; |
| 850 | + } |
| 851 | + if (descr != PNone.NO_VALUE) { |
| 852 | + hasDescProfile.enter(); |
| 853 | + Object get = lookupGet(dataDescClass); |
| 854 | + if (get == PNone.NO_VALUE) { |
| 855 | + return descr; |
| 856 | + } else if (get instanceof PythonCallable) { |
| 857 | + return dispatch(object, descr, get); |
| 858 | + } |
| 859 | + } |
| 860 | + errorProfile.enter(); |
| 861 | + return fallbackGetattr(object, key); |
| 862 | + } |
| 863 | + |
| 864 | + private Object fallbackGetattr(Object object, Object key) { |
| 865 | + if (getattrNode == null) { |
| 866 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 867 | + getattrNode = insert(LookupAndCallBinaryNode.create(SpecialMethodNames.__GETATTR__)); |
| 868 | + } |
| 869 | + return getattrNode.executeObject(object, key); |
| 870 | + } |
| 871 | + |
| 872 | + private Object readAttribute(TruffleObject object, Object key) { |
| 873 | + if (attrReadNode == null) { |
| 874 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 875 | + attrReadNode = insert(Message.READ.createNode()); |
| 876 | + } |
| 877 | + try { |
| 878 | + return ForeignAccess.sendRead(attrReadNode, object, key); |
| 879 | + } catch (UnknownIdentifierException | UnsupportedMessageException e) { |
| 880 | + return PNone.NO_VALUE; |
| 881 | + } |
| 882 | + } |
| 883 | + |
| 884 | + private Object dispatch(Object object, Object descr, Object get) { |
| 885 | + if (dispatchGet == null) { |
| 886 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 887 | + dispatchGet = insert(CallTernaryMethodNode.create()); |
| 888 | + } |
| 889 | + PythonClass type = getObjectClass(object); |
| 890 | + return dispatchGet.execute(get, descr, typeIsObjectProfile.profile(type == object) ? PNone.NONE : object, type); |
| 891 | + } |
| 892 | + |
| 893 | + private Object lookupGet(PythonClass dataDescClass) { |
| 894 | + if (lookupGetNode == null) { |
| 895 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 896 | + lookupGetNode = insert(LookupAttributeInMRONode.create()); |
| 897 | + } |
| 898 | + return lookupGetNode.execute(dataDescClass, __GET__); |
| 899 | + } |
| 900 | + |
| 901 | + private Object lookupDelete(PythonClass dataDescClass) { |
| 902 | + if (lookupDeleteNode == null) { |
| 903 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 904 | + lookupDeleteNode = insert(LookupAttributeInMRONode.create()); |
| 905 | + } |
| 906 | + return lookupDeleteNode.execute(dataDescClass, __DELETE__); |
| 907 | + } |
| 908 | + |
| 909 | + private Object lookupSet(PythonClass dataDescClass) { |
| 910 | + if (lookupSetNode == null) { |
| 911 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 912 | + lookupSetNode = insert(LookupAttributeInMRONode.create()); |
| 913 | + } |
| 914 | + return lookupSetNode.execute(dataDescClass, __SET__); |
| 915 | + } |
| 916 | + |
| 917 | + private PythonClass getObjectClass(Object object) { |
| 918 | + if (getObjectClassNode == null) { |
| 919 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 920 | + getObjectClassNode = insert(GetClassNode.create()); |
| 921 | + } |
| 922 | + return typeProfile.profile(getObjectClassNode.execute(object)); |
| 923 | + } |
| 924 | + |
| 925 | + private PythonClass getDataClass(Object descr) { |
| 926 | + if (getDataClassNode == null) { |
| 927 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 928 | + getDataClassNode = insert(GetClassNode.create()); |
| 929 | + } |
| 930 | + return getDataClassNode.execute(descr); |
| 931 | + } |
| 932 | + } |
| 933 | + |
| 934 | + @Builtin(name = __GETATTR__, fixedNumOfArguments = 3) |
| 935 | + @GenerateNodeFactory |
| 936 | + public abstract static class GetattrNode extends PythonBinaryBuiltinNode { |
| 937 | + @Specialization(guards = {"isForeignObject(object)"}) |
795 | 938 | protected Object doIt(TruffleObject object, Object key,
|
796 |
| - @Cached("READ.createNode()") Node readNode) { |
| 939 | + @Cached("createReadNode()") Node readNode) { |
797 | 940 | try {
|
798 | 941 | return ForeignAccess.sendRead(readNode, object, key);
|
799 | 942 | } catch (UnknownIdentifierException | UnsupportedMessageException e) {
|
800 | 943 | throw raise(PythonErrorType.AttributeError, "foreign object %s has no attribute %s", object, key);
|
801 | 944 | }
|
802 | 945 | }
|
| 946 | + |
| 947 | + protected Node createReadNode() { |
| 948 | + return Message.READ.createNode(); |
| 949 | + } |
803 | 950 | }
|
804 | 951 |
|
805 | 952 | @Builtin(name = __GETITEM__, fixedNumOfArguments = 2)
|
@@ -883,4 +1030,15 @@ protected Object doIt(TruffleObject object,
|
883 | 1030 | }
|
884 | 1031 | }
|
885 | 1032 | }
|
| 1033 | + |
| 1034 | + @Builtin(name = __CLASS__, fixedNumOfArguments = 1, isGetter = true) |
| 1035 | + @GenerateNodeFactory |
| 1036 | + public abstract static class ClassNode extends PythonUnaryBuiltinNode { |
| 1037 | + @Specialization(guards = {"isForeignObject(object)"}) |
| 1038 | + protected Object doIt(TruffleObject object, |
| 1039 | + @Cached("create()") GetClassNode getClassNode) { |
| 1040 | + return getClassNode.execute(object); |
| 1041 | + } |
| 1042 | + } |
| 1043 | + |
886 | 1044 | }
|
0 commit comments