|
42 | 42 |
|
43 | 43 | import com.oracle.graal.python.builtins.Builtin;
|
44 | 44 | import com.oracle.graal.python.builtins.PythonBuiltinClassType;
|
45 |
| -import com.oracle.graal.python.builtins.objects.cext.PythonNativeClass; |
46 | 45 | import com.oracle.graal.python.builtins.objects.function.PArguments;
|
47 | 46 | import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
|
48 |
| -import com.oracle.graal.python.builtins.objects.type.PythonAbstractClass; |
49 |
| -import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass; |
50 | 47 | import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetBaseClassesNode;
|
51 | 48 | import com.oracle.graal.python.builtins.objects.type.TypeNodes.IsTypeNode;
|
52 |
| -import com.oracle.graal.python.builtins.objects.type.TypeNodesFactory.GetBaseClassesNodeGen; |
53 | 49 | import com.oracle.graal.python.nodes.PRaiseNode;
|
54 | 50 | import com.oracle.graal.python.nodes.SpecialMethodNames;
|
55 | 51 | import com.oracle.graal.python.nodes.attributes.LookupAttributeInMRONode;
|
|
59 | 55 | import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
|
60 | 56 | import com.oracle.truffle.api.dsl.NodeFactory;
|
61 | 57 | import com.oracle.truffle.api.frame.VirtualFrame;
|
62 |
| -import com.oracle.truffle.api.nodes.ExplodeLoop; |
63 | 58 | import com.oracle.truffle.api.nodes.NodeCost;
|
64 | 59 |
|
65 | 60 | /**
|
@@ -123,98 +118,33 @@ public Object execute(VirtualFrame frame) {
|
123 | 118 | "%s.__new__(%N): %N is not a subtype of %s",
|
124 | 119 | getOwner().getName(), arg0, arg0, getOwner().getName());
|
125 | 120 | }
|
126 |
| - if (getBases == null) { |
| 121 | + // CPython walks the bases and checks that the first non-heaptype base has the new that |
| 122 | + // we're in. We have our optimizations for this lookup that the compiler can then |
| 123 | + // (hopefully) merge with the initial lookup of the new method before entering it. |
| 124 | + if (lookupNewNode == null) { |
127 | 125 | CompilerDirectives.transferToInterpreterAndInvalidate();
|
128 |
| - reportPolymorphicSpecialize(); |
129 |
| - getBases = insert(GetBaseClassesNodeGen.create()); |
130 |
| - } |
131 |
| - PythonAbstractClass[] bases = getBases.execute(arg0); |
132 |
| - if ((state & MRO_LENGTH_MASK) == 0) { |
133 |
| - CompilerDirectives.transferToInterpreterAndInvalidate(); |
134 |
| - int length = bases.length; |
135 |
| - if (length < MRO_LENGTH_MASK) { |
136 |
| - state |= length; |
137 |
| - } else { |
138 |
| - state |= MRO_LENGTH_MASK; |
139 |
| - } |
| 126 | + lookupNewNode = insert(LookupAttributeInMRONode.createForLookupOfUnmanagedClasses(SpecialMethodNames.__NEW__)); |
140 | 127 | }
|
141 |
| - boolean isSafeNew = true; |
142 |
| - if ((state & MRO_LENGTH_MASK) == bases.length) { |
143 |
| - // cached mro, explode loop |
144 |
| - isSafeNew = checkSafeNew(bases, state & MRO_LENGTH_MASK); |
145 |
| - } else { |
146 |
| - if ((state & NONCONSTANT_MRO) == 0) { |
147 |
| - CompilerDirectives.transferToInterpreterAndInvalidate(); |
148 |
| - reportPolymorphicSpecialize(); |
149 |
| - state |= NONCONSTANT_MRO; |
150 |
| - } |
151 |
| - // mro too long to cache or different from the cached one, no explode loop |
152 |
| - isSafeNew = checkSafeNew(bases); |
153 |
| - } |
154 |
| - if (!isSafeNew) { |
155 |
| - if ((state & IS_UNSAFE_STATE) == 0) { |
156 |
| - CompilerDirectives.transferToInterpreterAndInvalidate(); |
157 |
| - reportPolymorphicSpecialize(); |
158 |
| - state |= IS_UNSAFE_STATE; |
159 |
| - } |
160 |
| - throw getRaiseNode().raise(PythonBuiltinClassType.TypeError, |
161 |
| - "%s.__new__(%N) is not safe, use %N.__new__()", |
162 |
| - getOwner().getName(), arg0, arg0); |
163 |
| - } |
164 |
| - } |
165 |
| - return super.execute(frame); |
166 |
| - } |
167 |
| - |
168 |
| - @ExplodeLoop |
169 |
| - private boolean checkSafeNew(PythonAbstractClass[] bases, int length) { |
170 |
| - for (int i = 0; i < length; i++) { |
171 |
| - byte safe = isSafe(bases, i); |
172 |
| - if (safe != -1) { |
173 |
| - return safe == 0 ? false : true; |
174 |
| - } |
175 |
| - } |
176 |
| - CompilerDirectives.transferToInterpreterAndInvalidate(); |
177 |
| - throw new IllegalStateException("there is no non-heap type in the mro, broken class"); |
178 |
| - } |
179 |
| - |
180 |
| - private boolean checkSafeNew(PythonAbstractClass[] bases) { |
181 |
| - for (int i = 0; i < bases.length; i++) { |
182 |
| - byte safe = isSafe(bases, i); |
183 |
| - if (safe != -1) { |
184 |
| - return safe == 0 ? false : true; |
185 |
| - } |
186 |
| - } |
187 |
| - CompilerDirectives.transferToInterpreterAndInvalidate(); |
188 |
| - throw new IllegalStateException("there is no non-heap type in the mro, broken class"); |
189 |
| - } |
190 |
| - |
191 |
| - private byte isSafe(PythonAbstractClass[] mro, int i) { |
192 |
| - PythonAbstractClass base = mro[i]; |
193 |
| - if (base instanceof PythonBuiltinClass) { |
194 |
| - if (((PythonBuiltinClass) base).getType() == getOwner()) { |
195 |
| - return 1; |
196 |
| - } else { |
197 |
| - if (lookupNewNode == null) { |
198 |
| - CompilerDirectives.transferToInterpreterAndInvalidate(); |
199 |
| - lookupNewNode = insert(LookupAttributeInMRONode.create(SpecialMethodNames.__NEW__)); |
200 |
| - } |
201 |
| - Object newMethod = lookupNewNode.execute(base); |
202 |
| - if (newMethod instanceof PBuiltinFunction) { |
203 |
| - NodeFactory<? extends PythonBuiltinBaseNode> factory = ((PBuiltinFunction) newMethod).getBuiltinNodeFactory(); |
204 |
| - if (factory != null) { |
205 |
| - return factory.getNodeClass().isAssignableFrom(getNode().getClass()) ? (byte)1 : (byte)0; |
| 128 | + Object newMethod = lookupNewNode.execute(arg0); |
| 129 | + if (newMethod instanceof PBuiltinFunction) { |
| 130 | + NodeFactory<? extends PythonBuiltinBaseNode> factory = ((PBuiltinFunction) newMethod).getBuiltinNodeFactory(); |
| 131 | + if (factory != null) { |
| 132 | + if (!factory.getNodeClass().isAssignableFrom(getNode().getClass())) { |
| 133 | + if ((state & IS_UNSAFE_STATE) == 0) { |
| 134 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 135 | + reportPolymorphicSpecialize(); |
| 136 | + state |= IS_UNSAFE_STATE; |
| 137 | + } |
| 138 | + throw getRaiseNode().raise(PythonBuiltinClassType.TypeError, |
| 139 | + "%s.__new__(%N) is not safe, use %N.__new__()", |
| 140 | + getOwner().getName(), arg0, arg0); |
206 | 141 | }
|
207 | 142 | }
|
208 |
| - // we explicitly allow non-Java builtin functions to pass, since a |
209 |
| - // PythonBuiltinClass with a non-java function is explicitly written in the core to |
210 |
| - // allow this |
211 |
| - return 1; |
| 143 | + // we explicitly allow non-Java functions to pass here, since a PythonBuiltinClass |
| 144 | + // with a non-java function is explicitly written in the core to allow this |
212 | 145 | }
|
213 |
| - } else if (PythonNativeClass.isInstance(base)) { |
214 |
| - // should have called the native tp_new in any case |
215 |
| - return 0; |
216 | 146 | }
|
217 |
| - return -1; |
| 147 | + return super.execute(frame); |
218 | 148 | }
|
219 | 149 |
|
220 | 150 | private final PRaiseNode getRaiseNode() {
|
|
0 commit comments