|
48 | 48 |
|
49 | 49 | import com.oracle.graal.python.PythonLanguage;
|
50 | 50 | import com.oracle.graal.python.builtins.Builtin;
|
| 51 | +import com.oracle.graal.python.builtins.PythonBuiltinClassType; |
51 | 52 | import com.oracle.graal.python.builtins.objects.PNone;
|
52 | 53 | import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNodes.PCallHPyFunction;
|
53 | 54 | import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNodesFactory.PCallHPyFunctionNodeGen;
|
54 | 55 | import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyObjectBuiltinsFactory.HPyObjectNewNodeGen;
|
55 | 56 | import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
|
56 | 57 | import com.oracle.graal.python.builtins.objects.function.PKeyword;
|
57 |
| -import com.oracle.graal.python.builtins.objects.object.PythonObject; |
| 58 | +import com.oracle.graal.python.builtins.objects.type.SpecialMethodSlot; |
| 59 | +import com.oracle.graal.python.builtins.objects.type.TypeNodes.GetSuperClassNode; |
| 60 | +import com.oracle.graal.python.builtins.objects.type.TypeNodesFactory.GetSuperClassNodeGen; |
58 | 61 | import com.oracle.graal.python.nodes.SpecialMethodNames;
|
| 62 | +import com.oracle.graal.python.nodes.attributes.LookupCallableSlotInMRONode; |
59 | 63 | import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
|
60 | 64 | import com.oracle.graal.python.nodes.attributes.WriteAttributeToObjectNode;
|
| 65 | +import com.oracle.graal.python.nodes.call.special.CallVarargsMethodNode; |
61 | 66 | import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode;
|
62 | 67 | import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
|
63 | 68 | import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode;
|
| 69 | +import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile; |
64 | 70 | import com.oracle.graal.python.runtime.object.PythonObjectFactory;
|
65 | 71 | import com.oracle.graal.python.util.PythonUtils;
|
66 | 72 | import com.oracle.truffle.api.CompilerAsserts;
|
@@ -117,48 +123,75 @@ public List<Class<? extends Node>> getExecutionSignature() {
|
117 | 123 |
|
118 | 124 | }
|
119 | 125 |
|
120 |
| - @Builtin(name = SpecialMethodNames.__NEW__, minNumOfPositionalArgs = 1, parameterNames = "$self", takesVarArgs = true, takesVarKeywordArgs = true) |
| 126 | + @Builtin(name = SpecialMethodNames.__NEW__, takesVarArgs = true, takesVarKeywordArgs = true) |
121 | 127 | abstract static class HPyObjectNewNode extends PythonVarargsBuiltinNode {
|
122 | 128 | private static final Builtin BUILTIN = HPyObjectNewNode.class.getAnnotation(Builtin.class);
|
123 | 129 | private static final TruffleLogger LOGGER = PythonLanguage.getLogger(HPyObjectNewNode.class);
|
124 | 130 |
|
125 | 131 | @Child private PCallHPyFunction callHPyFunctionNode;
|
| 132 | + @Child private LookupCallableSlotInMRONode lookupNewNode; |
| 133 | + @Child private CallVarargsMethodNode callNewNode; |
| 134 | + @Child private GetSuperClassNode getBaseClassNode; |
126 | 135 | @Child private ReadAttributeFromObjectNode readBasicsizeNode;
|
127 | 136 | @Child private WriteAttributeToObjectNode writeNativeSpaceNode;
|
| 137 | + @Child private IsBuiltinClassProfile isObjectProfile; |
128 | 138 |
|
129 | 139 | @Override
|
130 | 140 | public Object varArgExecute(VirtualFrame frame, Object self, Object[] arguments, PKeyword[] keywords) throws VarargsBuiltinDirectInvocationNotSupported {
|
131 | 141 | if (arguments.length >= 1) {
|
132 |
| - return doGeneric(frame, arguments[0], PythonUtils.EMPTY_OBJECT_ARRAY, PKeyword.EMPTY_KEYWORDS); |
| 142 | + return doGeneric(frame, self, arguments, keywords); |
133 | 143 | }
|
134 | 144 | CompilerDirectives.transferToInterpreterAndInvalidate();
|
135 | 145 | throw new VarargsBuiltinDirectInvocationNotSupported();
|
136 | 146 | }
|
137 | 147 |
|
138 | 148 | @Specialization
|
139 |
| - @SuppressWarnings("unused") |
140 |
| - PythonObject doGeneric(VirtualFrame frame, Object self, Object[] arguments, PKeyword[] keywords) { |
| 149 | + Object doGeneric(VirtualFrame frame, Object explicitSelf, Object[] arguments, PKeyword[] keywords) { |
| 150 | + assert explicitSelf != null; |
141 | 151 |
|
142 | 152 | // create the managed Python object
|
143 |
| - PythonObject pythonObject = factory().createPythonObject(self); |
| 153 | + |
| 154 | + // delegate to the best base's constructor |
| 155 | + Object self; |
| 156 | + Object[] argsWithSelf; |
| 157 | + if (explicitSelf == PNone.NO_VALUE) { |
| 158 | + argsWithSelf = arguments; |
| 159 | + self = argsWithSelf[0]; |
| 160 | + } else { |
| 161 | + argsWithSelf = new Object[arguments.length + 1]; |
| 162 | + argsWithSelf[0] = explicitSelf; |
| 163 | + PythonUtils.arraycopy(arguments, 0, argsWithSelf, 1, arguments.length); |
| 164 | + self = explicitSelf; |
| 165 | + } |
| 166 | + Object baseClass = ensureGetBaseClassNode().execute(self); |
| 167 | + Object pythonObject; |
| 168 | + if (ensureIsObjectProfile().profileClass(baseClass, PythonBuiltinClassType.PythonObject)) { |
| 169 | + // fast-path if the super class is 'object' |
| 170 | + pythonObject = factory().createPythonObject(self); |
| 171 | + } else { |
| 172 | + Object superNew = ensureLookupNewNode().execute(baseClass); |
| 173 | + pythonObject = ensureCallNewNode().execute(frame, superNew, argsWithSelf, keywords); |
| 174 | + } |
144 | 175 |
|
145 | 176 | // allocate native space
|
146 | 177 | Object attrObj = ensureReadBasicsizeNode().execute(self, TYPE_HPY_BASICSIZE);
|
147 | 178 | if (attrObj != PNone.NO_VALUE) {
|
148 | 179 | // we fully control this attribute; if it is there, it's always a long
|
149 | 180 | long basicsize = (long) attrObj;
|
150 |
| - /* |
151 |
| - * This is just calling 'calloc' which is a pure helper function. Therefore, we can |
152 |
| - * take any HPy context and don't need to attach a context to this __new__ function |
153 |
| - * for that since the helper function won't deal with handles. |
154 |
| - */ |
155 |
| - Object dataPtr = ensureCallHPyFunctionNode().call(getContext().getHPyContext(), GraalHPyNativeSymbol.GRAAL_HPY_CALLOC, basicsize, 1L); |
156 |
| - ensureWriteNativeSpaceNode().execute(pythonObject, OBJECT_HPY_NATIVE_SPACE, dataPtr); |
157 |
| - |
158 |
| - if (LOGGER.isLoggable(Level.FINEST)) { |
159 |
| - LOGGER.finest(() -> String.format("Allocated HPy object with native space of size %d at %s", basicsize, dataPtr)); |
| 181 | + if (basicsize > 0) { |
| 182 | + /* |
| 183 | + * This is just calling 'calloc' which is a pure helper function. Therefore, we |
| 184 | + * can take any HPy context and don't need to attach a context to this __new__ |
| 185 | + * function for that since the helper function won't deal with handles. |
| 186 | + */ |
| 187 | + Object dataPtr = ensureCallHPyFunctionNode().call(getContext().getHPyContext(), GraalHPyNativeSymbol.GRAAL_HPY_CALLOC, basicsize, 1L); |
| 188 | + ensureWriteNativeSpaceNode().execute(pythonObject, OBJECT_HPY_NATIVE_SPACE, dataPtr); |
| 189 | + |
| 190 | + if (LOGGER.isLoggable(Level.FINEST)) { |
| 191 | + LOGGER.finest(() -> String.format("Allocated HPy object with native space of size %d at %s", basicsize, dataPtr)); |
| 192 | + } |
| 193 | + // TODO(fa): add memory tracing |
160 | 194 | }
|
161 |
| - // TODO(fa): add memory tracing |
162 | 195 | }
|
163 | 196 | return pythonObject;
|
164 | 197 | }
|
@@ -187,6 +220,38 @@ private PCallHPyFunction ensureCallHPyFunctionNode() {
|
187 | 220 | return callHPyFunctionNode;
|
188 | 221 | }
|
189 | 222 |
|
| 223 | + private CallVarargsMethodNode ensureCallNewNode() { |
| 224 | + if (callNewNode == null) { |
| 225 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 226 | + callNewNode = insert(CallVarargsMethodNode.create()); |
| 227 | + } |
| 228 | + return callNewNode; |
| 229 | + } |
| 230 | + |
| 231 | + private LookupCallableSlotInMRONode ensureLookupNewNode() { |
| 232 | + if (lookupNewNode == null) { |
| 233 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 234 | + lookupNewNode = insert(LookupCallableSlotInMRONode.create(SpecialMethodSlot.New)); |
| 235 | + } |
| 236 | + return lookupNewNode; |
| 237 | + } |
| 238 | + |
| 239 | + private GetSuperClassNode ensureGetBaseClassNode() { |
| 240 | + if (getBaseClassNode == null) { |
| 241 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 242 | + getBaseClassNode = insert(GetSuperClassNodeGen.create()); |
| 243 | + } |
| 244 | + return getBaseClassNode; |
| 245 | + } |
| 246 | + |
| 247 | + private IsBuiltinClassProfile ensureIsObjectProfile() { |
| 248 | + if (isObjectProfile == null) { |
| 249 | + CompilerDirectives.transferToInterpreterAndInvalidate(); |
| 250 | + isObjectProfile = insert(IsBuiltinClassProfile.create()); |
| 251 | + } |
| 252 | + return isObjectProfile; |
| 253 | + } |
| 254 | + |
190 | 255 | @TruffleBoundary
|
191 | 256 | public static PBuiltinFunction createBuiltinFunction(PythonLanguage language) {
|
192 | 257 | RootCallTarget callTarget = language.createCachedCallTarget(l -> new BuiltinFunctionRootNode(l, BUILTIN, new HPyObjectNewNodeFactory<>(HPyObjectNewNodeGen.create()), true),
|
|
0 commit comments