Skip to content

Commit 51dbf7e

Browse files
committed
Fix: HPyObjectNewNode must call __new__ of super class
1 parent 40e5c72 commit 51dbf7e

File tree

1 file changed

+82
-17
lines changed

1 file changed

+82
-17
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/hpy/GraalHPyObjectBuiltins.java

Lines changed: 82 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -48,19 +48,25 @@
4848

4949
import com.oracle.graal.python.PythonLanguage;
5050
import com.oracle.graal.python.builtins.Builtin;
51+
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
5152
import com.oracle.graal.python.builtins.objects.PNone;
5253
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNodes.PCallHPyFunction;
5354
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNodesFactory.PCallHPyFunctionNodeGen;
5455
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyObjectBuiltinsFactory.HPyObjectNewNodeGen;
5556
import com.oracle.graal.python.builtins.objects.function.PBuiltinFunction;
5657
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;
5861
import com.oracle.graal.python.nodes.SpecialMethodNames;
62+
import com.oracle.graal.python.nodes.attributes.LookupCallableSlotInMRONode;
5963
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
6064
import com.oracle.graal.python.nodes.attributes.WriteAttributeToObjectNode;
65+
import com.oracle.graal.python.nodes.call.special.CallVarargsMethodNode;
6166
import com.oracle.graal.python.nodes.function.BuiltinFunctionRootNode;
6267
import com.oracle.graal.python.nodes.function.PythonBuiltinBaseNode;
6368
import com.oracle.graal.python.nodes.function.builtins.PythonVarargsBuiltinNode;
69+
import com.oracle.graal.python.nodes.object.IsBuiltinClassProfile;
6470
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
6571
import com.oracle.graal.python.util.PythonUtils;
6672
import com.oracle.truffle.api.CompilerAsserts;
@@ -117,48 +123,75 @@ public List<Class<? extends Node>> getExecutionSignature() {
117123

118124
}
119125

120-
@Builtin(name = SpecialMethodNames.__NEW__, minNumOfPositionalArgs = 1, parameterNames = "$self", takesVarArgs = true, takesVarKeywordArgs = true)
126+
@Builtin(name = SpecialMethodNames.__NEW__, takesVarArgs = true, takesVarKeywordArgs = true)
121127
abstract static class HPyObjectNewNode extends PythonVarargsBuiltinNode {
122128
private static final Builtin BUILTIN = HPyObjectNewNode.class.getAnnotation(Builtin.class);
123129
private static final TruffleLogger LOGGER = PythonLanguage.getLogger(HPyObjectNewNode.class);
124130

125131
@Child private PCallHPyFunction callHPyFunctionNode;
132+
@Child private LookupCallableSlotInMRONode lookupNewNode;
133+
@Child private CallVarargsMethodNode callNewNode;
134+
@Child private GetSuperClassNode getBaseClassNode;
126135
@Child private ReadAttributeFromObjectNode readBasicsizeNode;
127136
@Child private WriteAttributeToObjectNode writeNativeSpaceNode;
137+
@Child private IsBuiltinClassProfile isObjectProfile;
128138

129139
@Override
130140
public Object varArgExecute(VirtualFrame frame, Object self, Object[] arguments, PKeyword[] keywords) throws VarargsBuiltinDirectInvocationNotSupported {
131141
if (arguments.length >= 1) {
132-
return doGeneric(frame, arguments[0], PythonUtils.EMPTY_OBJECT_ARRAY, PKeyword.EMPTY_KEYWORDS);
142+
return doGeneric(frame, self, arguments, keywords);
133143
}
134144
CompilerDirectives.transferToInterpreterAndInvalidate();
135145
throw new VarargsBuiltinDirectInvocationNotSupported();
136146
}
137147

138148
@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;
141151

142152
// 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+
}
144175

145176
// allocate native space
146177
Object attrObj = ensureReadBasicsizeNode().execute(self, TYPE_HPY_BASICSIZE);
147178
if (attrObj != PNone.NO_VALUE) {
148179
// we fully control this attribute; if it is there, it's always a long
149180
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
160194
}
161-
// TODO(fa): add memory tracing
162195
}
163196
return pythonObject;
164197
}
@@ -187,6 +220,38 @@ private PCallHPyFunction ensureCallHPyFunctionNode() {
187220
return callHPyFunctionNode;
188221
}
189222

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+
190255
@TruffleBoundary
191256
public static PBuiltinFunction createBuiltinFunction(PythonLanguage language) {
192257
RootCallTarget callTarget = language.createCachedCallTarget(l -> new BuiltinFunctionRootNode(l, BUILTIN, new HPyObjectNewNodeFactory<>(HPyObjectNewNodeGen.create()), true),

0 commit comments

Comments
 (0)