Skip to content

Commit f935739

Browse files
committed
initial ctypes support
1 parent d4153d0 commit f935739

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+10473
-65
lines changed
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* The Universal Permissive License (UPL), Version 1.0
6+
*
7+
* Subject to the condition set forth below, permission is hereby granted to any
8+
* person obtaining a copy of this software, associated documentation and/or
9+
* data (collectively the "Software"), free of charge and under any and all
10+
* copyright rights in the Software, and any and all patent rights owned or
11+
* freely licensable by each licensor hereunder covering either (i) the
12+
* unmodified Software as contributed to or provided by such licensor, or (ii)
13+
* the Larger Works (as defined below), to deal in both
14+
*
15+
* (a) the Software, and
16+
*
17+
* (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18+
* one is included with the Software each a "Larger Work" to which the Software
19+
* is contributed by such licensors),
20+
*
21+
* without restriction, including without limitation the rights to copy, create
22+
* derivative works of, display, perform, and distribute the Software and make,
23+
* use, sell, offer for sale, import, export, have made, and have sold the
24+
* Software and the Larger Work(s), and to sublicense the foregoing rights on
25+
* either these or other terms.
26+
*
27+
* This license is subject to the following condition:
28+
*
29+
* The above copyright notice and either this complete permission notice or at a
30+
* minimum a reference to the UPL must be included in all copies or substantial
31+
* portions of the Software.
32+
*
33+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39+
* SOFTWARE.
40+
*/
41+
42+
#define DEBUG 500
43+
44+
#include <stdlib.h>
45+
#include <string.h>
46+
47+
typedef char Byte; /* 8 bits */
48+
49+
// Integer.MAX_INT
50+
#define GRAALPYTHON_MAX_SIZE (INT_MAX)
51+
52+
#ifndef NDEBUG
53+
#include <stdio.h>
54+
#include <stdarg.h>
55+
static void debug_log(int level, char *file, int line, char *format, ...) {
56+
if (DEBUG > level) {
57+
return;
58+
}
59+
60+
char *type = "ALL";
61+
switch (level) {
62+
case 1000: type = "SEVERE"; break;
63+
case 900: type = "WARNING"; break;
64+
case 800: type = "INFO"; break;
65+
case 700: type = "CONFIG"; break;
66+
case 500: type = "FINE"; break;
67+
case 400: type = "FINER"; break;
68+
case 300: type = "FINEST"; break;
69+
}
70+
71+
va_list args;
72+
va_start(args, format);
73+
fprintf(stderr, "[%s %s:%d] ", type, file, line);
74+
vfprintf(stderr, format, args);
75+
// fprintf(stderr, "\n");
76+
77+
va_end(args);
78+
}
79+
80+
#define LOG_SEVERE(format, ...) \
81+
debug_log(1000, __FILE__, __LINE__, format, ## __VA_ARGS__);
82+
#define LOG_WARNING(format, ...) \
83+
debug_log(900, __FILE__, __LINE__, format, ## __VA_ARGS__);
84+
#define LOG_INFO(format, ...) \
85+
debug_log(800, __FILE__, __LINE__, format, ## __VA_ARGS__);
86+
#define LOG_CONFIG(format, ...) \
87+
debug_log(700, __FILE__, __LINE__, format, ## __VA_ARGS__);
88+
#define LOG_FINE(format, ...) \
89+
debug_log(500, __FILE__, __LINE__, format, ## __VA_ARGS__);
90+
#define LOG_FINER(format, ...) \
91+
debug_log(400, __FILE__, __LINE__, format, ## __VA_ARGS__);
92+
#define LOG_FINEST(format, ...) \
93+
debug_log(300, __FILE__, __LINE__, format, ## __VA_ARGS__);
94+
#else
95+
#define LOG_SEVERE(format, ...)
96+
#define LOG_WARNING(format, ...)
97+
#define LOG_INFO(format, ...)
98+
#define LOG_CONFIG(format, ...)
99+
#define LOG_FINE(format, ...)
100+
#define LOG_FINER(format, ...)
101+
#define LOG_FINEST(format, ...)
102+
#endif
103+
104+
// nfi_function: name('malloc')
105+
void* ctypesMalloc(size_t size) {
106+
void *m = malloc(size);
107+
LOG_FINER("malloc(address: %p, size: %u)\n", m, size);
108+
return m;
109+
}
110+
111+
// nfi_function: name('free')
112+
void ctypesFree(void *ptr) {
113+
LOG_FINER("free(%p)\n", ptr);
114+
free(ptr);
115+
}
116+
117+
// nfi_function: name('gcReleaseHelper') release(true)
118+
void CtypesGCHelper(void *ptr) {
119+
ctypesFree(ptr);
120+
}
121+
122+
// nfi_function: name('memcpy')
123+
void ctypesMemcpy(void *src, Byte *dest, size_t size, int free_src) {
124+
LOG_INFO("memcpy(%p)\n", src);
125+
memcpy(dest, src, size);
126+
if (free_src) {
127+
ctypesFree(src);
128+
}
129+
}
130+
131+
// nfi_function: name('toNative')
132+
void* ctypesToNative(Byte *src, size_t size) {
133+
void *m = malloc(size);
134+
memcpy(m, src, size);
135+
LOG_FINER("malloc(address: %p, size: %u)\n", m, size);
136+
return m;
137+
}

graalpython/com.oracle.graal.python.cext/setup.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,9 @@ def build(capi_home):
534534
libname="liblzmasupport",
535535
deps=[LZMADepedency("lzma", "xz==5.2.5", "XZ-5.2.5")],
536536
extra_link_args=["-Wl,-rpath,%s/lib/%s/" % (relative_rpath, SOABI)])
537+
build_nativelibsupport(capi_home,
538+
subdir="ctypes",
539+
libname="libctypes")
537540
build_libpython(capi_home)
538541
build_builtin_exts(capi_home)
539542
finally:

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/Python3Core.java

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959
import com.oracle.graal.python.builtins.modules.CollectionsModuleBuiltins;
6060
import com.oracle.graal.python.builtins.modules.ContextvarsModuleBuiltins;
6161
import com.oracle.graal.python.builtins.modules.CryptModuleBuiltins;
62-
import com.oracle.graal.python.builtins.modules.CtypesModuleBuiltins;
6362
import com.oracle.graal.python.builtins.modules.ErrnoModuleBuiltins;
6463
import com.oracle.graal.python.builtins.modules.FaulthandlerModuleBuiltins;
6564
import com.oracle.graal.python.builtins.modules.FcntlModuleBuiltins;
@@ -108,6 +107,24 @@
108107
import com.oracle.graal.python.builtins.modules.bz2.BZ2CompressorBuiltins;
109108
import com.oracle.graal.python.builtins.modules.bz2.BZ2DecompressorBuiltins;
110109
import com.oracle.graal.python.builtins.modules.bz2.BZ2ModuleBuiltins;
110+
import com.oracle.graal.python.builtins.modules.ctypes.CArgObjectBuiltins;
111+
import com.oracle.graal.python.builtins.modules.ctypes.CDataTypeBuiltins;
112+
import com.oracle.graal.python.builtins.modules.ctypes.CDataTypeSequenceBuiltins;
113+
import com.oracle.graal.python.builtins.modules.ctypes.CFieldBuiltins;
114+
import com.oracle.graal.python.builtins.modules.ctypes.CtypesModuleBuiltins;
115+
import com.oracle.graal.python.builtins.modules.ctypes.PyCArrayBuiltins;
116+
import com.oracle.graal.python.builtins.modules.ctypes.PyCArrayTypeBuiltins;
117+
import com.oracle.graal.python.builtins.modules.ctypes.PyCFuncPtrBuiltins;
118+
import com.oracle.graal.python.builtins.modules.ctypes.PyCFuncPtrTypeBuiltins;
119+
import com.oracle.graal.python.builtins.modules.ctypes.PyCPointerBuiltins;
120+
import com.oracle.graal.python.builtins.modules.ctypes.PyCPointerTypeBuiltins;
121+
import com.oracle.graal.python.builtins.modules.ctypes.PyCSimpleTypeBuiltins;
122+
import com.oracle.graal.python.builtins.modules.ctypes.PyCStructTypeBuiltins;
123+
import com.oracle.graal.python.builtins.modules.ctypes.SimpleCDataBuiltins;
124+
import com.oracle.graal.python.builtins.modules.ctypes.StgDictBuiltins;
125+
import com.oracle.graal.python.builtins.modules.ctypes.StructUnionTypeBuiltins;
126+
import com.oracle.graal.python.builtins.modules.ctypes.StructureBuiltins;
127+
import com.oracle.graal.python.builtins.modules.ctypes.UnionTypeBuiltins;
111128
import com.oracle.graal.python.builtins.modules.io.BufferedIOBaseBuiltins;
112129
import com.oracle.graal.python.builtins.modules.io.BufferedIOMixinBuiltins;
113130
import com.oracle.graal.python.builtins.modules.io.BufferedRWPairBuiltins;
@@ -293,7 +310,6 @@ private static String[] initializeCoreFiles() {
293310
"_sre",
294311
"function",
295312
"_sysconfig",
296-
"ctypes",
297313
"termios",
298314
"zipimport",
299315
"mmap",
@@ -470,7 +486,6 @@ private static PythonBuiltins[] initializeBuiltins(boolean nativeAccessAllowed)
470486
new BinasciiModuleBuiltins(),
471487
new PosixShMemModuleBuiltins(),
472488
new PosixSubprocessModuleBuiltins(),
473-
new CtypesModuleBuiltins(),
474489
new ReadlineModuleBuiltins(),
475490
new PyExpatModuleBuiltins(),
476491
new SysConfigModuleBuiltins(),
@@ -511,6 +526,26 @@ private static PythonBuiltins[] initializeBuiltins(boolean nativeAccessAllowed)
511526
new JSONScannerBuiltins(),
512527
new JSONEncoderBuiltins(),
513528

529+
// ctypes
530+
new CArgObjectBuiltins(),
531+
new CDataTypeBuiltins(),
532+
new CDataTypeSequenceBuiltins(),
533+
new CFieldBuiltins(),
534+
new CtypesModuleBuiltins(),
535+
new PyCArrayTypeBuiltins(),
536+
new PyCFuncPtrBuiltins(),
537+
new PyCFuncPtrTypeBuiltins(),
538+
new PyCPointerTypeBuiltins(),
539+
new PyCSimpleTypeBuiltins(),
540+
new PyCStructTypeBuiltins(),
541+
new StgDictBuiltins(),
542+
new StructUnionTypeBuiltins(),
543+
new StructureBuiltins(),
544+
new UnionTypeBuiltins(),
545+
new SimpleCDataBuiltins(),
546+
new PyCArrayBuiltins(),
547+
new PyCPointerBuiltins(),
548+
514549
// _hpy_universal
515550
new GraalHPyUniversalModuleBuiltins(),
516551

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/PythonBuiltinClassType.java

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,28 @@ public enum PythonBuiltinClassType implements TruffleObject {
219219
// HPy
220220
DebugHandle("DebugHandle", GraalHPyDebugModuleBuiltins.HPY_DEBUG, Flags.PUBLIC_DERIVED_WODICT),
221221

222+
// _ctype
223+
CArgObject("CArgObject", Flags.PUBLIC_BASE_WDICT),
224+
CThunkObject("CThunkObject", "_ctypes", Flags.PUBLIC_BASE_WDICT),
225+
StgDict("StgDict", Flags.PRIVATE_DERIVED_WODICT),
226+
PyCStructType("PyCStructType", "_ctypes", Flags.PUBLIC_BASE_WDICT),
227+
UnionType("UnionType", "_ctypes", Flags.PUBLIC_BASE_WDICT),
228+
PyCPointerType("PyCPointerType", "_ctypes", Flags.PUBLIC_BASE_WDICT),
229+
PyCArrayType("PyCArrayType", "_ctypes", Flags.PUBLIC_BASE_WDICT),
230+
PyCSimpleType("PyCSimpleType", "_ctypes", Flags.PUBLIC_BASE_WDICT),
231+
PyCFuncPtrType("PyCFuncPtrType", "_ctypes", Flags.PUBLIC_BASE_WDICT),
232+
Structure("Structure", "_ctypes", Flags.PUBLIC_BASE_WDICT), // type = PyCStructType
233+
Union("Union", "_ctypes", Flags.PUBLIC_BASE_WDICT), // type = UnionType
234+
PyCPointer("_Pointer", "_ctypes", Flags.PUBLIC_BASE_WDICT), // type = PyCPointerType
235+
PyCArray("Array", "_ctypes", Flags.PUBLIC_BASE_WDICT), // type = PyCArrayType
236+
PyCData("_CData", "_ctypes", Flags.PUBLIC_BASE_WDICT), // type = PyCStructType
237+
SimpleCData("_SimpleCData", "_ctypes", Flags.PUBLIC_BASE_WDICT), // type = PyCStructType
238+
PyCFuncPtr("PyCFuncPtr", "_ctypes", Flags.PUBLIC_BASE_WDICT), // type = PyCFuncPtrType
239+
CField("CField", "_ctypes", Flags.PUBLIC_BASE_WDICT),
240+
DictRemover("DictRemover", "_ctypes", Flags.PUBLIC_BASE_WDICT),
241+
StructParam("StructParam_Type", "_ctypes", Flags.PUBLIC_BASE_WDICT),
242+
ArgError("ArgumentError", "ctypes", Flags.EXCEPTION),
243+
222244
// Errors and exceptions:
223245

224246
// everything after BaseException is considered to be an exception
@@ -350,6 +372,7 @@ private static class Flags {
350372
private final boolean isException;
351373

352374
// initialized in static constructor
375+
@CompilationFinal private PythonBuiltinClassType type;
353376
@CompilationFinal private PythonBuiltinClassType base;
354377

355378
/**
@@ -403,6 +426,10 @@ public String getPrintName() {
403426
return printName;
404427
}
405428

429+
public PythonBuiltinClassType getType() {
430+
return type;
431+
}
432+
406433
public PythonBuiltinClassType getBase() {
407434
return base;
408435
}
@@ -475,6 +502,7 @@ public final Shape getInstanceShape(PythonLanguage lang) {
475502
// which are different for each context. We'd have to turn those factories into singletons
476503
// to guarantee their identity across contexts. For the sake of simplicity, we just ignore
477504
// those slots for now.
505+
PStruct.type = PythonClass;
478506
PStructRusage.redefinedSlots = reprAndNew;
479507
PStructPasswd.redefinedSlots = reprAndNew;
480508
PUnameResult.redefinedSlots = reprAndNew;
@@ -491,14 +519,7 @@ public final Shape getInstanceShape(PythonLanguage lang) {
491519
PFlags.redefinedSlots = repr;
492520
PTerminalSize.redefinedSlots = reprAndNew;
493521

494-
// set the base classes (and check uniqueness):
495-
496-
HashSet<String> set = new HashSet<>();
497-
for (PythonBuiltinClassType type : VALUES) {
498-
assert set.add(type.name) : type.name();
499-
type.base = PythonObject;
500-
}
501-
522+
PythonObject.type = PythonClass;
502523
PythonObject.base = null;
503524

504525
Boolean.base = PInt;
@@ -606,6 +627,9 @@ public final Shape getInstanceShape(PythonLanguage lang) {
606627
PThreadInfo.base = PTuple;
607628
PUnraisableHookArgs.base = PTuple;
608629

630+
PArrayIterator.type = PythonClass;
631+
PSocket.type = PythonClass;
632+
609633
// _io.UnsupportedOperation inherits from ValueError and OSError
610634
// done currently within IOModuleBuiltins class
611635
IOUnsupportedOperation.base = OSError;
@@ -622,7 +646,45 @@ public final Shape getInstanceShape(PythonLanguage lang) {
622646
PTextIOWrapper.base = PTextIOBase;
623647
PStringIO.base = PTextIOBase;
624648

649+
// _ctypes
650+
StgDict.base = PDict;
651+
PyCStructType.base = PythonClass;
652+
UnionType.base = PythonClass;
653+
PyCPointerType.base = PythonClass;
654+
PyCArrayType.base = PythonClass;
655+
PyCSimpleType.base = PythonClass;
656+
PyCFuncPtrType.base = PythonClass;
657+
Structure.type = PyCStructType;
658+
Structure.base = PyCData;
659+
Union.type = UnionType;
660+
Union.base = PyCData;
661+
PyCPointer.type = PyCPointerType;
662+
PyCPointer.base = PyCData;
663+
PyCArray.type = PyCArrayType;
664+
PyCArray.base = PyCData;
665+
SimpleCData.type = PyCSimpleType;
666+
SimpleCData.base = PyCData;
667+
PyCFuncPtr.type = PyCFuncPtrType;
668+
PyCFuncPtr.base = PyCData;
669+
625670
Empty.base = Exception;
671+
672+
HashSet<String> set = new HashSet<>();
673+
for (PythonBuiltinClassType type : VALUES) {
674+
assert set.add(type.name) : type.name(); // check uniqueness
675+
676+
/* Initialize type.base (defaults to PythonObject unless that's us) */
677+
if (type.base == null && type != PythonObject) {
678+
type.base = PythonObject;
679+
}
680+
681+
/*
682+
* Now the only way base can still be null is if type is PythonObject.
683+
*/
684+
if (type.type == null && type.base != null) {
685+
type.type = type.base.type;
686+
}
687+
}
626688
}
627689

628690
// Proxy InteropLibrary messages to the PythonBuiltinClass

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2145,7 +2145,7 @@ public abstract static class TypeNode extends PythonBuiltinNode {
21452145
@Child private GetObjectArrayNode getObjectArrayNode;
21462146
@Child private IsAcceptableBaseNode isAcceptableBaseNode;
21472147

2148-
protected abstract Object execute(VirtualFrame frame, Object cls, Object name, Object bases, Object dict, PKeyword[] kwds);
2148+
public abstract Object execute(VirtualFrame frame, Object cls, Object name, Object bases, Object dict, PKeyword[] kwds);
21492149

21502150
@Specialization(guards = {"isNoValue(bases)", "isNoValue(dict)"})
21512151
@SuppressWarnings("unused")
@@ -2224,7 +2224,7 @@ Object typeNew(VirtualFrame frame, Object cls, Object wName, PTuple bases, PDict
22242224
Object moduleAttr = ensureReadAttrNode().execute(newType, __MODULE__);
22252225
if (moduleAttr == PNone.NO_VALUE) {
22262226
PFrame callerFrame = getReadCallerFrameNode().executeWith(frame, 0);
2227-
PythonObject globals = callerFrame.getGlobals();
2227+
PythonObject globals = callerFrame != null ? callerFrame.getGlobals() : null;
22282228
if (globals != null) {
22292229
String moduleName = getModuleNameFromGlobals(globals, hashingStoragelib);
22302230
if (moduleName != null) {
@@ -2758,7 +2758,7 @@ protected boolean isSubType(VirtualFrame frame, Object subclass, Object supercla
27582758
return isSubtypeNode.execute(frame, subclass, superclass);
27592759
}
27602760

2761-
protected static TypeNode create() {
2761+
public static TypeNode create() {
27622762
return BuiltinConstructorsFactory.TypeNodeFactory.create(null);
27632763
}
27642764

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2131,8 +2131,8 @@ protected static boolean isPath(Object obj) {
21312131
/**
21322132
* Helper node that accepts either str or bytes and converts it to {@code PBytes}.
21332133
*/
2134-
abstract static class StringOrBytesToBytesNode extends PythonBuiltinBaseNode {
2135-
abstract PBytes execute(Object obj);
2134+
public abstract static class StringOrBytesToBytesNode extends PythonBuiltinBaseNode {
2135+
public abstract PBytes execute(Object obj);
21362136

21372137
@Specialization
21382138
PBytes doString(String str) {

0 commit comments

Comments
 (0)