|
38 | 38 | */
|
39 | 39 | package com.oracle.graal.python.nodes.call.special;
|
40 | 40 |
|
| 41 | +import java.util.function.Supplier; |
| 42 | + |
| 43 | +import com.oracle.graal.python.builtins.objects.PNone; |
| 44 | +import com.oracle.graal.python.builtins.objects.PNotImplemented; |
| 45 | +import com.oracle.graal.python.builtins.objects.type.PythonClass; |
| 46 | +import com.oracle.graal.python.nodes.EmptyNode; |
| 47 | +import com.oracle.graal.python.nodes.PBaseNode; |
| 48 | +import com.oracle.graal.python.nodes.PNode; |
41 | 49 | import com.oracle.graal.python.nodes.attributes.GetAttributeNode;
|
| 50 | +import com.oracle.graal.python.nodes.attributes.LookupInheritedAttributeNode; |
| 51 | +import com.oracle.graal.python.nodes.classes.IsSubtypeNode; |
42 | 52 | import com.oracle.graal.python.nodes.object.GetClassNode;
|
| 53 | +import com.oracle.truffle.api.CompilerDirectives; |
43 | 54 | import com.oracle.truffle.api.dsl.Cached;
|
| 55 | +import com.oracle.truffle.api.dsl.NodeChild; |
| 56 | +import com.oracle.truffle.api.dsl.NodeChildren; |
44 | 57 | import com.oracle.truffle.api.dsl.Specialization;
|
| 58 | +import com.oracle.truffle.api.profiles.BranchProfile; |
| 59 | + |
| 60 | +@NodeChildren({@NodeChild("arg"), @NodeChild("arg2"), @NodeChild("arg3")}) |
| 61 | +public abstract class LookupAndCallTernaryNode extends PNode { |
| 62 | + |
| 63 | + public abstract static class NotImplementedHandler extends PBaseNode { |
| 64 | + public abstract Object execute(Object arg, Object arg2, Object arg3); |
| 65 | + } |
45 | 66 |
|
46 |
| -public abstract class LookupAndCallTernaryNode extends LookupAndCallSpecialNode { |
47 | 67 | private final String name;
|
| 68 | + private final boolean isReversible; |
48 | 69 | @Child private CallTernaryMethodNode dispatchNode = CallTernaryMethodNode.create();
|
| 70 | + @Child private CallTernaryMethodNode reverseDispatchNode; |
| 71 | + @Child private CallTernaryMethodNode thirdDispatchNode; |
| 72 | + @Child private LookupInheritedAttributeNode getThirdAttrNode; |
| 73 | + @Child private NotImplementedHandler handler; |
| 74 | + protected final Supplier<NotImplementedHandler> handlerFactory; |
49 | 75 |
|
50 | 76 | public abstract Object execute(Object arg1, Object arg2, Object arg3);
|
51 | 77 |
|
52 | 78 | public abstract Object execute(Object arg1, int arg2, Object arg3);
|
53 | 79 |
|
54 | 80 | public static LookupAndCallTernaryNode create(String name) {
|
55 |
| - return LookupAndCallTernaryNodeGen.create(name); |
| 81 | + return LookupAndCallTernaryNodeGen.create(name, false, null, null, null, null); |
| 82 | + } |
| 83 | + |
| 84 | + public static LookupAndCallTernaryNode createReversible(String name, Supplier<NotImplementedHandler> handlerFactory) { |
| 85 | + return LookupAndCallTernaryNodeGen.create(name, true, handlerFactory, null, null, null); |
56 | 86 | }
|
57 | 87 |
|
58 |
| - LookupAndCallTernaryNode(String name) { |
| 88 | + public static LookupAndCallTernaryNode createReversible(String name, Supplier<NotImplementedHandler> handlerFactory, PNode x, PNode y) { |
| 89 | + return LookupAndCallTernaryNodeGen.create(name, true, handlerFactory, x, y, EmptyNode.create()); |
| 90 | + } |
| 91 | + |
| 92 | + LookupAndCallTernaryNode(String name, boolean isReversible, Supplier<NotImplementedHandler> handlerFactory) { |
59 | 93 | this.name = name;
|
| 94 | + this.isReversible = isReversible; |
| 95 | + this.handlerFactory = handlerFactory; |
60 | 96 | }
|
61 | 97 |
|
62 |
| - @Specialization |
| 98 | + protected boolean isReversible() { |
| 99 | + return isReversible; |
| 100 | + } |
| 101 | + |
| 102 | + @Specialization(guards = "!isReversible()") |
63 | 103 | Object callObject(Object arg1, int arg2, Object arg3,
|
64 | 104 | @Cached("create()") GetClassNode getclass,
|
65 | 105 | @Cached("create()") GetAttributeNode getattr) {
|
66 | 106 | return dispatchNode.execute(getattr.execute(getclass.execute(arg1), name), arg1, arg2, arg3);
|
67 | 107 | }
|
68 | 108 |
|
69 |
| - @Specialization |
| 109 | + @Specialization(guards = "!isReversible()") |
70 | 110 | Object callObject(Object arg1, Object arg2, Object arg3,
|
71 | 111 | @Cached("create()") GetClassNode getclass,
|
72 | 112 | @Cached("create()") GetAttributeNode getattr) {
|
73 | 113 | return dispatchNode.execute(getattr.execute(getclass.execute(arg1), name), arg1, arg2, arg3);
|
74 | 114 | }
|
| 115 | + |
| 116 | + private CallTernaryMethodNode ensureReverseDispatch() { |
| 117 | + // this also serves as a branch profile |
| 118 | + if (reverseDispatchNode == null) { |
| 119 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 120 | + reverseDispatchNode = insert(CallTernaryMethodNode.create()); |
| 121 | + } |
| 122 | + return reverseDispatchNode; |
| 123 | + } |
| 124 | + |
| 125 | + private LookupInheritedAttributeNode ensureGetAttrZ() { |
| 126 | + // this also serves as a branch profile |
| 127 | + if (getThirdAttrNode == null) { |
| 128 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 129 | + getThirdAttrNode = insert(LookupInheritedAttributeNode.create()); |
| 130 | + } |
| 131 | + return getThirdAttrNode; |
| 132 | + } |
| 133 | + |
| 134 | + private CallTernaryMethodNode ensureThirdDispatch() { |
| 135 | + // this also serves as a branch profile |
| 136 | + if (thirdDispatchNode == null) { |
| 137 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 138 | + thirdDispatchNode = insert(CallTernaryMethodNode.create()); |
| 139 | + } |
| 140 | + return thirdDispatchNode; |
| 141 | + } |
| 142 | + |
| 143 | + @Specialization(guards = "isReversible()") |
| 144 | + Object callObject(Object v, Object w, Object z, |
| 145 | + @Cached("create()") LookupInheritedAttributeNode getattr, |
| 146 | + @Cached("create()") LookupInheritedAttributeNode getattrR, |
| 147 | + @Cached("create()") GetClassNode getClass, |
| 148 | + @Cached("create()") GetClassNode getClassR, |
| 149 | + @Cached("create()") IsSubtypeNode isSubtype, |
| 150 | + @Cached("create()") BranchProfile notImplementedBranch) { |
| 151 | + Object result = PNotImplemented.NOT_IMPLEMENTED; |
| 152 | + Object leftCallable = getattr.execute(v, name); |
| 153 | + Object rightCallable = PNone.NO_VALUE; |
| 154 | + |
| 155 | + PythonClass leftClass = getClass.execute(v); |
| 156 | + PythonClass rightClass = getClassR.execute(w); |
| 157 | + if (leftClass != rightClass) { |
| 158 | + rightCallable = getattrR.execute(w, name); |
| 159 | + if (rightCallable == leftCallable) { |
| 160 | + rightCallable = PNone.NO_VALUE; |
| 161 | + } |
| 162 | + } |
| 163 | + if (leftCallable != PNone.NO_VALUE) { |
| 164 | + if (rightCallable != PNone.NO_VALUE && isSubtype.execute(rightClass, leftClass)) { |
| 165 | + result = ensureReverseDispatch().execute(rightCallable, v, w, z); |
| 166 | + if (result != PNotImplemented.NOT_IMPLEMENTED) { |
| 167 | + return result; |
| 168 | + } |
| 169 | + rightCallable = PNone.NO_VALUE; |
| 170 | + } |
| 171 | + result = dispatchNode.execute(leftCallable, v, w, z); |
| 172 | + if (result != PNotImplemented.NOT_IMPLEMENTED) { |
| 173 | + return result; |
| 174 | + } |
| 175 | + } |
| 176 | + if (rightCallable != PNone.NO_VALUE) { |
| 177 | + result = ensureReverseDispatch().execute(rightCallable, v, w, z); |
| 178 | + if (result != PNotImplemented.NOT_IMPLEMENTED) { |
| 179 | + return result; |
| 180 | + } |
| 181 | + } |
| 182 | + |
| 183 | + Object zCallable = ensureGetAttrZ().execute(z, name); |
| 184 | + if (zCallable != PNone.NO_VALUE && zCallable != leftCallable && zCallable != rightCallable) { |
| 185 | + ensureThirdDispatch().execute(zCallable, v, w, z); |
| 186 | + if (result != PNotImplemented.NOT_IMPLEMENTED) { |
| 187 | + return result; |
| 188 | + } |
| 189 | + } |
| 190 | + |
| 191 | + notImplementedBranch.enter(); |
| 192 | + if (handlerFactory != null) { |
| 193 | + if (handler == null) { |
| 194 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 195 | + handler = insert(handlerFactory.get()); |
| 196 | + } |
| 197 | + return handler.execute(v, w, z); |
| 198 | + } |
| 199 | + return result; |
| 200 | + } |
75 | 201 | }
|
0 commit comments