Skip to content

Commit 0105f05

Browse files
committed
Intrinsify PyStructSequence_New
1 parent 2210630 commit 0105f05

File tree

4 files changed

+107
-27
lines changed

4 files changed

+107
-27
lines changed

graalpython/com.oracle.graal.python.cext/src/structseq.c

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ structseq_dealloc(PyStructSequence *obj)
5757
PyObject_GC_Del(obj);
5858
}
5959

60-
/* StructSequences a.k.a. 'namedtuple' */
61-
UPCALL_ID(PyStructSequence_New);
60+
typedef PyObject *(*structseq_new_fun_t)(PyTypeObject *);
61+
UPCALL_TYPED_ID(PyStructSequence_New, structseq_new_fun_t);
6262
PyObject* PyStructSequence_New(PyTypeObject* o) {
63-
return UPCALL_CEXT_O(_jls_PyStructSequence_New, native_type_to_java(o));
63+
return _jls_PyStructSequence_New(native_type_to_java(o));
6464
}
6565

6666
static Py_ssize_t
@@ -127,26 +127,36 @@ int PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
127127
);
128128
}
129129

130+
typedef PyTypeObject *(*structseq_newtype_fun_t)(void *, void *, void *, void *, int);
131+
UPCALL_TYPED_ID(PyStructSequence_NewType, structseq_newtype_fun_t);
130132
PyTypeObject* PyStructSequence_NewType(PyStructSequence_Desc *desc) {
131-
Py_ssize_t n_members = desc->n_in_sequence;
133+
Py_ssize_t n_members, n_unnamed_members, n_named_members;
132134
Py_ssize_t i;
133135

134-
// put field names and doc strings into two tuples
135-
PyObject* field_names = PyTuple_New(n_members);
136-
PyObject* field_docs = PyTuple_New(n_members);
136+
n_members = count_members(desc, &n_unnamed_members);
137+
n_named_members = n_members - n_unnamed_members;
138+
// put field names and doc strings into two lists
139+
void** field_names = (void **) truffle_managed_malloc(n_named_members * sizeof(void *));
140+
void** field_docs = (void **) truffle_managed_malloc(n_named_members * sizeof(void *));
137141
PyStructSequence_Field* fields = desc->fields;
142+
int j = 0;
138143
for (i = 0; i < n_members; i++) {
139-
PyTuple_SetItem(field_names, i, polyglot_from_string(fields[i].name, SRC_CS));
140-
PyTuple_SetItem(field_docs, i, polyglot_from_string(fields[i].doc, SRC_CS));
144+
if (fields[i].name != PyStructSequence_UnnamedField) {
145+
field_names[j] = polyglot_from_string(fields[i].name, SRC_CS);
146+
field_docs[j] = polyglot_from_string(fields[i].doc, SRC_CS);
147+
j++;
148+
}
141149
}
142150

143151
// we create the new type managed
144-
PyTypeObject* newType = (PyTypeObject*) UPCALL_CEXT_O(_jls_PyStructSequence_InitType2,
145-
polyglot_from_string(desc->name, SRC_CS),
146-
polyglot_from_string(desc->doc, SRC_CS),
147-
native_to_java(field_names),
148-
native_to_java(field_docs));
149-
return newType;
152+
return _jls_PyStructSequence_NewType(
153+
polyglot_from_string(desc->name, SRC_CS),
154+
polyglot_from_string(desc->doc, SRC_CS),
155+
/* TODO(fa): use polyglot_from_VoidPtr_array once this is visible */
156+
polyglot_from_PyObjectPtr_array((PyObjectPtr *) field_names, (uint64_t) n_members),
157+
polyglot_from_PyObjectPtr_array((PyObjectPtr *) field_docs, (uint64_t) n_members),
158+
desc->n_in_sequence
159+
);
150160
}
151161

152162
// taken from CPython "Objects/structseq.c"

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/modules/PythonCextBuiltins.java

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4039,9 +4039,16 @@ abstract static class PyStructSequenceInitType2 extends NativeBuiltin {
40394039
@Specialization(limit = "1")
40404040
static int doGeneric(Object klass, String typeName, String typeDoc, Object fieldNamesObj, Object fieldDocsObj, int nInSequence,
40414041
@CachedLanguage PythonLanguage language,
4042+
@Cached AsPythonObjectNode asPythonObjectNode,
40424043
@CachedLibrary("fieldNamesObj") InteropLibrary lib,
4043-
@Cached(parameters = "true") WriteAttributeToObjectNode clearNewNode,
4044-
@Cached PRaiseNativeNode raiseNode) {
4044+
@Cached(parameters = "true") WriteAttributeToObjectNode clearNewNode) {
4045+
return initializeStructType(asPythonObjectNode.execute(klass), typeName, typeDoc, fieldNamesObj, fieldDocsObj, nInSequence, language, lib, clearNewNode);
4046+
}
4047+
4048+
static int initializeStructType(Object klass, String typeName, String typeDoc, Object fieldNamesObj, Object fieldDocsObj, int nInSequence,
4049+
PythonLanguage language,
4050+
InteropLibrary lib,
4051+
WriteAttributeToObjectNode clearNewNode) {
40454052
// 'fieldNames' and 'fieldDocs' must be of same type; they share the interop lib
40464053
assert fieldNamesObj.getClass() == fieldDocsObj.getClass();
40474054

@@ -4076,4 +4083,63 @@ private static String cast(Object object) {
40764083
throw CompilerDirectives.shouldNotReachHere("object is expected to be a Java string");
40774084
}
40784085
}
4086+
4087+
// directly called without landing function
4088+
@Builtin(name = "PyStructSequence_NewType", minNumOfPositionalArgs = 5)
4089+
@GenerateNodeFactory
4090+
abstract static class PyStructSequenceNewType extends NativeBuiltin {
4091+
4092+
@Specialization(limit = "1")
4093+
Object doGeneric(VirtualFrame frame, String typeName, String typeDoc, Object fieldNamesObj, Object fieldDocsObj, int nInSequence,
4094+
@CachedLanguage PythonLanguage language,
4095+
@Cached ReadAttributeFromObjectNode readTypeBuiltinNode,
4096+
@Cached CallNode callTypeNewNode,
4097+
@CachedLibrary("fieldNamesObj") InteropLibrary lib,
4098+
@Cached(parameters = "true") WriteAttributeToObjectNode clearNewNode,
4099+
@Cached GetNativeNullNode getNativeNullNode,
4100+
@Cached ToNewRefNode toNewRefNode) {
4101+
try {
4102+
Object typeBuiltin = readTypeBuiltinNode.execute(getCore().getBuiltins(), BuiltinNames.TYPE);
4103+
PTuple bases = factory().createTuple(new Object[]{PythonBuiltinClassType.PTuple});
4104+
PDict namespace = factory().createDict(new PKeyword[]{new PKeyword(SpecialAttributeNames.__DOC__, typeDoc)});
4105+
Object cls = callTypeNewNode.execute(typeBuiltin, typeName, bases, namespace);
4106+
PyStructSequenceInitType2.initializeStructType(cls, typeName, typeDoc, fieldNamesObj, fieldDocsObj, nInSequence, language, lib, clearNewNode);
4107+
return toNewRefNode.execute(cls);
4108+
} catch (PException e) {
4109+
transformToNative(frame, e);
4110+
return getNativeNullNode.execute();
4111+
}
4112+
}
4113+
}
4114+
4115+
// directly called without landing function
4116+
@Builtin(name = "PyStructSequence_New", minNumOfPositionalArgs = 1)
4117+
@GenerateNodeFactory
4118+
abstract static class PyStructSequenceNew extends PythonUnaryBuiltinNode {
4119+
4120+
@Specialization
4121+
Object doGeneric(Object clsPtr,
4122+
@Cached AsPythonObjectNode asPythonObjectNode,
4123+
@Cached("createForceType()") ReadAttributeFromObjectNode readRealSizeNode,
4124+
@Cached CastToJavaIntExactNode castToIntNode,
4125+
@Cached TransformExceptionToNativeNode transformExceptionToNativeNode,
4126+
@Cached GetNativeNullNode getNativeNullNode,
4127+
@Cached ToNewRefNode toNewRefNode) {
4128+
try {
4129+
Object cls = asPythonObjectNode.execute(clsPtr);
4130+
Object realSizeObj = readRealSizeNode.execute(cls, StructSequence.N_FIELDS);
4131+
Object res;
4132+
if (realSizeObj == PNone.NO_VALUE) {
4133+
PRaiseNativeNode.raiseNative(null, SystemError, ErrorMessages.BAD_ARG_TO_INTERNAL_FUNC, PythonUtils.EMPTY_OBJECT_ARRAY, getRaiseNode(), transformExceptionToNativeNode);
4134+
res = getNativeNullNode.execute();
4135+
} else {
4136+
int realSize = castToIntNode.execute(realSizeObj);
4137+
res = factory().createTuple(cls, new Object[realSize]);
4138+
}
4139+
return toNewRefNode.execute(res);
4140+
} catch (CannotCastException e) {
4141+
throw CompilerDirectives.shouldNotReachHere("attribute 'n_fields' is expected to be a Java int");
4142+
}
4143+
}
4144+
}
40794145
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/tuple/StructSequence.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,15 @@
112112
*/
113113
public class StructSequence {
114114

115+
/** The <it>visible</it> length (excludes unnamed fields) of the structseq type. */
116+
public static final String N_SEQUENCE_FIELDS = "n_sequence_fields";
117+
118+
/** The <it>real</it> length (includes unnamed fields) of the structseq type. */
119+
public static final String N_FIELDS = "n_fields";
120+
121+
/** The number of unnamed fields. */
122+
public static final String N_UNNAMED_FIELDS = "n_unnamed_fields";
123+
115124
abstract static class Descriptor {
116125
public final String docString;
117126
public final int inSequence;
@@ -216,9 +225,9 @@ public static void initType(PythonLanguage language, Object klass, Descriptor de
216225
if (ReadAttributeFromObjectNode.getUncachedForceType().execute(klass, __DOC__) == PNone.NO_VALUE) {
217226
writeAttrNode.execute(klass, __DOC__, desc.docString);
218227
}
219-
writeAttrNode.execute(klass, "n_sequence_fields", desc.inSequence);
220-
writeAttrNode.execute(klass, "n_fields", desc.fieldNames.length);
221-
writeAttrNode.execute(klass, "n_unnamed_fields", unnamedFields);
228+
writeAttrNode.execute(klass, N_SEQUENCE_FIELDS, desc.inSequence);
229+
writeAttrNode.execute(klass, N_FIELDS, desc.fieldNames.length);
230+
writeAttrNode.execute(klass, N_UNNAMED_FIELDS, unnamedFields);
222231

223232
if (ReadAttributeFromObjectNode.getUncachedForceType().execute(klass, __NEW__) == PNone.NO_VALUE) {
224233
if (desc.allowInstances) {
@@ -244,7 +253,7 @@ private static void createMethod(PythonLanguage language, Object klass, Descript
244253
NodeFactory<PythonBuiltinBaseNode> nodeFactory = new StandaloneBuiltinFactory<>(nodeSupplier.apply(desc));
245254
return new BuiltinFunctionRootNode(l, builtin, nodeFactory, true);
246255
}, nodeClass, desc);
247-
PBuiltinFunction function = PythonObjectFactory.getUncached().createBuiltinFunction(builtin.name(), klass, 0, callTarget);
256+
PBuiltinFunction function = PythonObjectFactory.getUncached().createBuiltinFunction(builtin.name(), PythonBuiltinClassType.PTuple, 0, callTarget);
248257
WriteAttributeToObjectNode.getUncached(true).execute(klass, builtin.name(), function);
249258
}
250259

@@ -256,7 +265,7 @@ private static void createConstructor(PythonLanguage language, Object klass, Des
256265
NodeFactory<PythonBuiltinBaseNode> nodeFactory = new StandaloneBuiltinFactory<>(nodeSupplier.apply(desc));
257266
return new BuiltinFunctionRootNode(l, builtin, nodeFactory, true, PythonBuiltinClassType.PTuple);
258267
}, nodeClass, desc);
259-
PBuiltinFunction function = PythonObjectFactory.getUncached().createBuiltinFunction(builtin.name(), klass, 1, callTarget);
268+
PBuiltinFunction function = PythonObjectFactory.getUncached().createBuiltinFunction(builtin.name(), PythonBuiltinClassType.PTuple, 1, callTarget);
260269
WriteAttributeToObjectNode.getUncached(true).execute(klass, __NEW__, function);
261270
}
262271

graalpython/lib-graalpython/python_cext.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -795,11 +795,6 @@ def PyModule_AddObject(m, k, v):
795795
return 0
796796

797797

798-
@may_raise
799-
def PyStructSequence_New(typ):
800-
return typ([None] * typ.n_fields)
801-
802-
803798
def METH_UNSUPPORTED():
804799
raise NotImplementedError("unsupported message type")
805800

0 commit comments

Comments
 (0)