Skip to content

Commit a2d7616

Browse files
committed
Emulate native member 'data' for datetime.date/time
1 parent 4bd57be commit a2d7616

File tree

3 files changed

+110
-37
lines changed

3 files changed

+110
-37
lines changed

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

Lines changed: 9 additions & 6 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;
@@ -978,15 +980,15 @@ protected static boolean isPyDateTimeCAPI(PythonObject object, GetClassNode getC
978980
return isPyDateTimeCAPIType(getNameNode.execute(getClassNode.execute(object)));
979981
}
980982

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

988986
}
989987

988+
protected static DateTimeMode getDateTimeMode(PythonObject object, GetClassNode getClassNode, GetNameNode getNameNode) {
989+
return PyDateTimeMRNode.getModeFromTypeName(getNameNode.execute(getClassNode.execute(object)));
990+
}
991+
990992
@Specialization(guards = "isPyDateTimeCAPI(object, getClassNode, getNameNode)", limit = "1")
991993
static Object doDatetimeCAPI(PythonObject object, @SuppressWarnings("unused") PythonNativeWrapper nativeWrapper, String key,
992994
@Cached LookupAttributeInMRONode.Dynamic getAttrNode,
@@ -996,12 +998,13 @@ static Object doDatetimeCAPI(PythonObject object, @SuppressWarnings("unused") Py
996998
return toSulongNode.execute(getAttrNode.execute(getClassNode.execute(object), key));
997999
}
9981000

999-
@Specialization(guards = "isPyDateTime(object, getClassNode, getNameNode)", limit = "1")
1001+
@Specialization(guards = "mode != null", limit = "1")
10001002
static Object doDatetimeData(PythonObject object, @SuppressWarnings("unused") PythonNativeWrapper nativeWrapper, @SuppressWarnings("unused") String key,
10011003
@Shared("getNameNode") @Cached @SuppressWarnings("unused") GetNameNode getNameNode,
10021004
@Shared("getClassNode") @Cached @SuppressWarnings("unused") GetClassNode getClassNode,
1005+
@Bind("getDateTimeMode(object, getClassNode, getNameNode)") DateTimeMode mode,
10031006
@Cached PyDateTimeMRNode pyDateTimeMRNode) {
1004-
return pyDateTimeMRNode.execute(object, key);
1007+
return pyDateTimeMRNode.execute(object, key, mode);
10051008
}
10061009

10071010
@Specialization(guards = "eq(F_LINENO, key)")

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)