Skip to content

Commit 4f22561

Browse files
committed
[GR-27735] [GR-27736] Various C API fixes.
PullRequest: graalpython/1637
2 parents 35dee66 + 86ea860 commit 4f22561

File tree

7 files changed

+146
-46
lines changed

7 files changed

+146
-46
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,11 @@ freefunc get_tp_free(PyTypeObject* obj) {
358358
return obj->tp_free;
359359
}
360360

361+
/** to be used from Java code only; reads native 'tp_as_buffer' field */
362+
PyBufferProcs* get_tp_as_buffer(PyTypeObject* obj) {
363+
return obj->tp_as_buffer;
364+
}
365+
361366
/** to be used from Java code only; reads native 'tp_flags' field */
362367
unsigned long get_tp_flags(PyTypeObject* obj) {
363368
return obj->tp_flags;

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1493,7 +1493,13 @@ long getHash() {
14931493
abstract static class PyTruffleFrameNewNode extends PythonBuiltinNode {
14941494
@Specialization
14951495
Object newFrame(Object threadState, PCode code, PythonObject globals, Object locals) {
1496-
return factory().createPFrame(threadState, code, globals, locals);
1496+
Object frameLocals;
1497+
if (locals == null || PGuards.isPNone(locals)) {
1498+
frameLocals = factory().createDict();
1499+
} else {
1500+
frameLocals = locals;
1501+
}
1502+
return factory().createPFrame(threadState, code, globals, frameLocals);
14971503
}
14981504
}
14991505

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -249,16 +249,16 @@ private PDict getSysDict() {
249249
return (PDict) getDictNode.execute(getContext().getCore().lookupBuiltinModule("sys"));
250250
}
251251

252-
private PDict getGlobalsDict(Object globals) {
252+
private Object getGlobalsDict(Object globals) {
253253
if (globals instanceof PDict) {
254-
return (PDict) globals;
254+
return globals;
255255
}
256256
if (getDictNode == null) {
257257
CompilerDirectives.transferToInterpreterAndInvalidate();
258258
reportPolymorphicSpecialize();
259259
getDictNode = insert(GetDictNode.create());
260260
}
261-
return (PDict) getDictNode.execute(globals);
261+
return getDictNode.execute(globals);
262262
}
263263

264264
private PFrame getCallerFrame(VirtualFrame frame, int stackLevel) {
@@ -710,7 +710,7 @@ private void setupContext(VirtualFrame frame, int stackLevel, String[] filename,
710710
lineno[0] = 1;
711711
} else {
712712
globals = getGlobalsDict(f.getGlobals());
713-
if (globals == null) {
713+
if (globals == null || globals instanceof PNone) {
714714
globals = getSysDict();
715715
}
716716
lineno[0] = f.getLine();

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/DynamicObjectNativeWrapper.java

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@
9898
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.TransformExceptionToNativeNode;
9999
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.WrapVoidPtrNode;
100100
import com.oracle.graal.python.builtins.objects.cext.capi.DynamicObjectNativeWrapperFactory.ReadTypeNativeMemberNodeGen;
101+
import com.oracle.graal.python.builtins.objects.cext.capi.PyDateTimeMRNode.DateTimeMode;
101102
import com.oracle.graal.python.builtins.objects.cext.capi.UnicodeObjectNodes.UnicodeAsWideCharNode;
102103
import com.oracle.graal.python.builtins.objects.common.DynamicObjectStorage;
103104
import com.oracle.graal.python.builtins.objects.common.HashingCollectionNodes;
@@ -162,6 +163,7 @@
162163
import com.oracle.truffle.api.CompilerDirectives.ValueType;
163164
import com.oracle.truffle.api.RootCallTarget;
164165
import com.oracle.truffle.api.TruffleLogger;
166+
import com.oracle.truffle.api.dsl.Bind;
165167
import com.oracle.truffle.api.dsl.Cached;
166168
import com.oracle.truffle.api.dsl.Cached.Exclusive;
167169
import com.oracle.truffle.api.dsl.Cached.Shared;
@@ -431,6 +433,7 @@ static Object doTpAsBuffer(PythonManagedClass object, @SuppressWarnings("unused"
431433
@Cached BranchProfile notMemoryview,
432434
@Cached BranchProfile notBuffer,
433435
@Cached BranchProfile notMmap,
436+
@Cached LookupNativeMemberInMRONode lookupTpAsBufferNode,
434437
@Shared("getNativeNullNode") @Cached GetNativeNullNode getNativeNullNode,
435438
@Shared("nullToSulongNode") @Cached ToSulongNode toSulongNode) {
436439
PythonBuiltinClass pBytes = context.getCore().lookupType(PythonBuiltinClassType.PBytes);
@@ -458,8 +461,16 @@ static Object doTpAsBuffer(PythonManagedClass object, @SuppressWarnings("unused"
458461
return new PyBufferProcsWrapper(pMmap);
459462
}
460463
notMmap.enter();
461-
// NULL pointer
462-
return toSulongNode.execute(getNativeNullNode.execute());
464+
/*
465+
* Managed classes don't store PyBufferProcs objects and so there is no attribute. This
466+
* is why we use managedMemberName == "".
467+
*/
468+
Object result = lookupTpAsBufferNode.execute(object, NativeMember.TP_AS_BUFFER, "");
469+
if (result == PNone.NO_VALUE) {
470+
// NULL pointer
471+
return toSulongNode.execute(getNativeNullNode.execute());
472+
}
473+
return toSulongNode.execute(result);
463474
}
464475

465476
@Specialization(guards = "eq(TP_AS_SEQUENCE, key)")
@@ -978,15 +989,15 @@ protected static boolean isPyDateTimeCAPI(PythonObject object, GetClassNode getC
978989
return isPyDateTimeCAPIType(getNameNode.execute(getClassNode.execute(object)));
979990
}
980991

981-
protected static boolean isPyDateTime(PythonObject object, GetClassNode getClassNode, GetNameNode getNameNode) {
982-
return "datetime".equals(getNameNode.execute(getClassNode.execute(object)));
983-
}
984-
985992
protected static boolean isPyDateTimeCAPIType(String className) {
986993
return "PyDateTime_CAPI".equals(className);
987994

988995
}
989996

997+
protected static DateTimeMode getDateTimeMode(PythonObject object, GetClassNode getClassNode, GetNameNode getNameNode) {
998+
return PyDateTimeMRNode.getModeFromTypeName(getNameNode.execute(getClassNode.execute(object)));
999+
}
1000+
9901001
@Specialization(guards = "isPyDateTimeCAPI(object, getClassNode, getNameNode)", limit = "1")
9911002
static Object doDatetimeCAPI(PythonObject object, @SuppressWarnings("unused") PythonNativeWrapper nativeWrapper, String key,
9921003
@Cached LookupAttributeInMRONode.Dynamic getAttrNode,
@@ -996,12 +1007,13 @@ static Object doDatetimeCAPI(PythonObject object, @SuppressWarnings("unused") Py
9961007
return toSulongNode.execute(getAttrNode.execute(getClassNode.execute(object), key));
9971008
}
9981009

999-
@Specialization(guards = "isPyDateTime(object, getClassNode, getNameNode)", limit = "1")
1010+
@Specialization(guards = "mode != null", limit = "1")
10001011
static Object doDatetimeData(PythonObject object, @SuppressWarnings("unused") PythonNativeWrapper nativeWrapper, @SuppressWarnings("unused") String key,
10011012
@Shared("getNameNode") @Cached @SuppressWarnings("unused") GetNameNode getNameNode,
10021013
@Shared("getClassNode") @Cached @SuppressWarnings("unused") GetClassNode getClassNode,
1014+
@Bind("getDateTimeMode(object, getClassNode, getNameNode)") DateTimeMode mode,
10031015
@Cached PyDateTimeMRNode pyDateTimeMRNode) {
1004-
return pyDateTimeMRNode.execute(object, key);
1016+
return pyDateTimeMRNode.execute(object, key, mode);
10051017
}
10061018

10071019
@Specialization(guards = "eq(F_LINENO, key)")
@@ -1024,13 +1036,19 @@ static Object doFCode(PFrame object, @SuppressWarnings("unused") PythonNativeWra
10241036
// TODO fallback guard
10251037
@Specialization
10261038
static Object doGeneric(@SuppressWarnings("unused") Object object, DynamicObjectNativeWrapper nativeWrapper, String key,
1027-
@CachedLibrary(limit = "1") HashingStorageLibrary lib) throws UnknownIdentifierException {
1039+
@CachedLibrary(limit = "1") HashingStorageLibrary lib,
1040+
@Shared("toSulongNode") @Cached ToSulongNode toSulongNode,
1041+
@Cached GetNativeNullNode getNativeNullNode) throws UnknownIdentifierException {
10281042
// This is the preliminary generic case: There are native members we know that they
10291043
// exist but we do currently not represent them. So, store them into a dynamic object
10301044
// such that native code at least reads the value that was written before.
10311045
if (nativeWrapper.isMemberReadable(key)) {
10321046
logGeneric(key);
1033-
return lib.getItem(nativeWrapper.getNativeMemberStore(), key);
1047+
DynamicObjectStorage nativeMemberStore = nativeWrapper.getNativeMemberStore();
1048+
if (nativeMemberStore != null) {
1049+
return lib.getItem(nativeMemberStore, key);
1050+
}
1051+
return toSulongNode.execute(getNativeNullNode.execute());
10341052
}
10351053
throw UnknownIdentifierException.create(key);
10361054
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/NativeCAPISymbol.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ public enum NativeCAPISymbol implements NativeCExtSymbol {
7979
FUN_GET_TP_DICTOFFSET("get_tp_dictoffset"),
8080
FUN_GET_TP_BASICSIZE("get_tp_basicsize"),
8181
FUN_GET_TP_ITEMSIZE("get_tp_itemsize"),
82+
FUN_GET_TP_AS_BUFFER("get_tp_as_buffer"),
8283
FUN_GET_BYTE_ARRAY_TYPE_ID("get_byte_array_typeid"),
8384
FUN_GET_PTR_ARRAY_TYPE_ID("get_ptr_array_typeid"),
8485
FUN_PTR_COMPARE("truffle_ptr_compare"),

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/NativeMember.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ public enum NativeMember {
226226

227227
// PyDateTime_Date
228228
DATETIME_DATA("data"),
229+
DATETIME_TZINFO("tzinfo"),
229230

230231
// PySetObject
231232
SET_USED("used", PRIMITIVE),

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/PyDateTimeMRNode.java

Lines changed: 100 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,15 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects.cext.capi;
4242

43+
import com.oracle.graal.python.builtins.objects.PNone;
4344
import com.oracle.graal.python.builtins.objects.PythonAbstractObject.PInteropGetAttributeNode;
4445
import com.oracle.graal.python.builtins.objects.cext.capi.CArrayWrappers.CByteArrayWrapper;
46+
import com.oracle.graal.python.builtins.objects.cext.capi.CExtNodes.ToSulongNode;
4547
import com.oracle.graal.python.builtins.objects.object.PythonObject;
4648
import com.oracle.graal.python.builtins.objects.object.PythonObjectLibrary;
47-
import com.oracle.graal.python.nodes.attributes.GetAttributeNode;
49+
import com.oracle.graal.python.nodes.attributes.ReadAttributeFromObjectNode;
4850
import com.oracle.graal.python.runtime.PythonOptions;
51+
import com.oracle.truffle.api.CompilerDirectives;
4952
import com.oracle.truffle.api.dsl.Cached;
5053
import com.oracle.truffle.api.dsl.GenerateUncached;
5154
import com.oracle.truffle.api.dsl.ImportStatic;
@@ -57,7 +60,24 @@
5760
@ImportStatic({NativeMember.class, PythonOptions.class})
5861
public abstract class PyDateTimeMRNode extends Node {
5962

60-
public abstract Object execute(PythonObject object, String key);
63+
public enum DateTimeMode {
64+
DATE,
65+
TIME,
66+
DATE_TIME
67+
}
68+
69+
static DateTimeMode getModeFromTypeName(String typeName) {
70+
if ("date".equals(typeName)) {
71+
return DateTimeMode.DATE;
72+
} else if ("datetime".equals(typeName)) {
73+
return DateTimeMode.DATE_TIME;
74+
} else if ("time".equals(typeName)) {
75+
return DateTimeMode.TIME;
76+
}
77+
return null;
78+
}
79+
80+
public abstract Object execute(PythonObject object, String key, DateTimeMode mode);
6181

6282
public static final String YEAR = "year";
6383
public static final String MONTH = "month";
@@ -66,12 +86,15 @@ public abstract class PyDateTimeMRNode extends Node {
6686
public static final String MIN = "minute";
6787
public static final String SEC = "second";
6888
public static final String USEC = "microsecond";
89+
public static final String TZINFO = "tzinfo";
6990

7091
/**
7192
* Fields are packed into successive bytes, each viewed as unsigned and big-endian, unless
7293
* otherwise noted:
7394
*
74-
* <code>
95+
* PyDateTime_DateTime:
96+
*
97+
* <pre>
7598
* byte offset
7699
* 0 year 2 bytes, 1-9999
77100
* 2 month 1 byte, 1-12
@@ -81,10 +104,32 @@ public abstract class PyDateTimeMRNode extends Node {
81104
* 6 second 1 byte, 0-59
82105
* 7 usecond 3 bytes, 0-999999
83106
* 10
84-
* </code>
107+
* </pre>
108+
*
109+
* PyDateTime_Date:
110+
*
111+
* <pre>
112+
* byte offset
113+
* 0 year 2 bytes, 1-9999
114+
* 2 month 1 byte, 1-12
115+
* 3 day 1 byte, 1-31
116+
* 10
117+
* </pre>
118+
*
119+
* PyDateTime_Time:
120+
*
121+
* <pre>
122+
* byte offset
123+
* 4 hour 1 byte, 0-23
124+
* 5 minute 1 byte, 0-59
125+
* 6 second 1 byte, 0-59
126+
* 7 usecond 3 bytes, 0-999999
127+
* 10
128+
* </pre>
85129
*/
86-
@Specialization(guards = "eq(DATETIME_DATA,key)")
87-
Object doData(PythonObject object, @SuppressWarnings("unused") String key,
130+
@Specialization(guards = {"eq(DATETIME_DATA, key)", "cachedMode == mode", "cachedMode != null"}, limit = "1")
131+
static Object doData(PythonObject object, @SuppressWarnings("unused") String key, @SuppressWarnings("unused") DateTimeMode mode,
132+
@Cached("mode") DateTimeMode cachedMode,
88133
@Cached PInteropGetAttributeNode getYearNode,
89134
@Cached PInteropGetAttributeNode getMonthNode,
90135
@Cached PInteropGetAttributeNode getDayNode,
@@ -93,39 +138,63 @@ Object doData(PythonObject object, @SuppressWarnings("unused") String key,
93138
@Cached PInteropGetAttributeNode getSecNode,
94139
@Cached PInteropGetAttributeNode getUSecNode,
95140
@CachedLibrary(limit = "getCallSiteInlineCacheMaxDepth()") PythonObjectLibrary lib) {
141+
96142
// passing null here should be ok, since we should be in an interop situation
97-
int year = lib.asSize(getYearNode.execute(object, YEAR));
98-
int month = lib.asSize(getMonthNode.execute(object, MONTH));
99-
int day = lib.asSize(getDayNode.execute(object, DAY));
100-
int hour = lib.asSize(getHourNode.execute(object, HOUR));
101-
int min = lib.asSize(getMinNode.execute(object, MIN));
102-
int sec = lib.asSize(getSecNode.execute(object, SEC));
103-
int usec = lib.asSize(getUSecNode.execute(object, USEC));
104-
assert year >= 0 && year < 0x10000;
105-
assert month >= 0 && month < 0x100;
106-
assert day >= 0 && day < 0x100;
107-
assert hour >= 0 && hour < 0x100;
108-
assert min >= 0 && min < 0x100;
109-
assert sec >= 0 && sec < 0x100;
110-
assert usec >= 0 && sec < 0x1000000;
111-
byte[] data = new byte[]{(byte) (year >> 8), (byte) year, (byte) month, (byte) day, (byte) hour, (byte) min, (byte) sec, (byte) (usec >> 16), (byte) (usec >> 8), (byte) usec};
143+
int year = -1;
144+
int month = -1;
145+
int day = -1;
146+
int hour = -1;
147+
int min = -1;
148+
int sec = -1;
149+
int usec = -1;
150+
if (cachedMode == DateTimeMode.DATE || cachedMode == DateTimeMode.DATE_TIME) {
151+
year = lib.asSize(getYearNode.execute(object, YEAR));
152+
month = lib.asSize(getMonthNode.execute(object, MONTH));
153+
day = lib.asSize(getDayNode.execute(object, DAY));
154+
assert year >= 0 && year < 0x10000;
155+
assert month >= 0 && month < 0x100;
156+
assert day >= 0 && day < 0x100;
157+
}
158+
if (cachedMode == DateTimeMode.TIME || cachedMode == DateTimeMode.DATE_TIME) {
159+
hour = lib.asSize(getHourNode.execute(object, HOUR));
160+
min = lib.asSize(getMinNode.execute(object, MIN));
161+
sec = lib.asSize(getSecNode.execute(object, SEC));
162+
usec = lib.asSize(getUSecNode.execute(object, USEC));
163+
assert hour >= 0 && hour < 0x100;
164+
assert min >= 0 && min < 0x100;
165+
assert sec >= 0 && sec < 0x100;
166+
assert usec >= 0 && sec < 0x1000000;
167+
}
112168

169+
byte[] data;
170+
switch (cachedMode) {
171+
case DATE:
172+
data = new byte[]{(byte) (year >> 8), (byte) year, (byte) month, (byte) day};
173+
break;
174+
case TIME:
175+
data = new byte[]{(byte) hour, (byte) min, (byte) sec, (byte) (usec >> 16), (byte) (usec >> 8), (byte) usec};
176+
break;
177+
case DATE_TIME:
178+
data = new byte[]{(byte) (year >> 8), (byte) year, (byte) month, (byte) day, (byte) hour, (byte) min, (byte) sec, (byte) (usec >> 16), (byte) (usec >> 8), (byte) usec};
179+
break;
180+
default:
181+
throw CompilerDirectives.shouldNotReachHere();
182+
}
113183
return new CByteArrayWrapper(data);
114184
}
115185

116-
protected static GetAttributeNode createAttr(String expected) {
117-
return GetAttributeNode.create(expected, null);
186+
@Specialization(guards = "eq(DATETIME_TZINFO, key)")
187+
static Object doTzinfo(PythonObject object, @SuppressWarnings("unused") String key, @SuppressWarnings("unused") DateTimeMode mode,
188+
@Cached ReadAttributeFromObjectNode getTzinfoNode,
189+
@Cached ToSulongNode toSulongNode) {
190+
Object value = getTzinfoNode.execute(object, TZINFO);
191+
if (value != PNone.NO_VALUE) {
192+
return toSulongNode.execute(value);
193+
}
194+
throw CompilerDirectives.shouldNotReachHere();
118195
}
119196

120197
protected static boolean eq(NativeMember expected, String actual) {
121198
return expected.getMemberName().equals(actual);
122199
}
123-
124-
public static PyDateTimeMRNode create() {
125-
return PyDateTimeMRNodeGen.create();
126-
}
127-
128-
public static PyDateTimeMRNode getUncached() {
129-
return PyDateTimeMRNodeGen.getUncached();
130-
}
131200
}

0 commit comments

Comments
 (0)