Skip to content

Commit 7c04110

Browse files
committed
Free HPy native space if object dies
1 parent 43bbb5e commit 7c04110

File tree

9 files changed

+395
-9
lines changed

9 files changed

+395
-9
lines changed

graalpython/com.oracle.graal.python.cext/hpy/hpy.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,3 +527,17 @@ void graal_hpy_write_ptr(void* object, HPy_ssize_t offset, void* value) {
527527

528528
#undef WRAP
529529
#undef UNWRAP
530+
531+
/* to be used from Java code only */
532+
int graal_hpy_bulk_free(void* ptrArray[], int64_t len) {
533+
int64_t i;
534+
void* obj;
535+
536+
for (i=0; i < len; i++) {
537+
obj = ptrArray[i];
538+
if (obj != NULL) {
539+
free(obj);
540+
}
541+
}
542+
return 0;
543+
}

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

Lines changed: 279 additions & 1 deletion
Large diffs are not rendered by default.

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import static com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyContextFunctions.FunctionMode.OBJECT;
4949
import static com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyDef.OBJECT_HPY_NATIVE_SPACE;
5050
import static com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyDef.TYPE_HPY_BASICSIZE;
51+
import static com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyDef.TYPE_HPY_DESTROY;
5152
import static com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNativeSymbols.GRAAL_HPY_DEF_GET_KIND;
5253
import static com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNativeSymbols.GRAAL_HPY_DEF_GET_METH;
5354
import static com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNativeSymbols.GRAAL_HPY_FROM_HPY_MODULE_DEF;
@@ -1387,6 +1388,7 @@ Object execute(Object[] arguments,
13871388
@Cached HPyRaiseNode raiseNode,
13881389
@Cached PythonObjectFactory factory,
13891390
@Cached WriteAttributeToObjectNode writeNativeSpaceNode,
1391+
@Cached ReadAttributeFromObjectNode readAttributeFromObjectNode,
13901392
@Cached PCallHPyFunction callMallocNode,
13911393
@Cached PCallHPyFunction callWriteDataNode,
13921394
@Cached HPyAsHandleNode asHandleNode) throws ArityException {
@@ -1413,16 +1415,14 @@ Object execute(Object[] arguments,
14131415
long basicsize = (long) attrObj;
14141416
Object dataPtr = callMallocNode.call(context, GraalHPyNativeSymbols.GRAAL_HPY_CALLOC, basicsize, 1L);
14151417
writeNativeSpaceNode.execute(pythonObject, OBJECT_HPY_NATIVE_SPACE, dataPtr);
1418+
Object destroyFunc = readAttributeFromObjectNode.execute(type, TYPE_HPY_DESTROY);
1419+
context.createHandleReference(pythonObject, dataPtr, destroyFunc != PNone.NO_VALUE ? destroyFunc : null);
14161420

14171421
// write data pointer to out var
14181422
callWriteDataNode.call(context, GRAAL_HPY_WRITE_PTR, dataOutVar, 0L, dataPtr);
14191423

14201424
LOGGER.fine(() -> String.format("Allocated HPy object with native space of size %d at %s", basicsize, dataPtr));
14211425
// TODO(fa): add memory tracing
1422-
1423-
// TODO(fa): Here we allocated some native memory but we do never free it. We need
1424-
// to create a weakref to the Python object and if it dies, we need to free the
1425-
// native space.
14261426
}
14271427
return asHandleNode.execute(pythonObject);
14281428
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,6 @@ enum HPySlot {
198198
HPY_TP_REPR(66, SpecialMethodNames.__REPR__, HPyFuncSignature.REPRFUNC),
199199
HPY_NB_MATRIX_MULTIPLY(75, SpecialMethodNames.__MATMUL__, HPyFuncSignature.BINARYFUNC),
200200
HPY_NB_INPLACE_MATRIX_MULTIPLY(76, SpecialMethodNames.__IMATMUL__, HPyFuncSignature.BINARYFUNC),
201-
// TODO(fa): use a hidden key ?
202201
HPY_TP_DESTROY(1000, TYPE_HPY_DESTROY, HPyFuncSignature.DESTROYFUNC);
203202

204203
/** The corresponding C enum value. */

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
*/
4141
package com.oracle.graal.python.builtins.objects.cext.hpy;
4242

43+
import java.lang.ref.PhantomReference;
44+
import java.lang.ref.ReferenceQueue;
45+
4346
import com.oracle.graal.python.PythonLanguage;
4447
import com.oracle.graal.python.builtins.objects.PythonAbstractObject;
4548
import com.oracle.graal.python.builtins.objects.cext.PythonNativeWrapperLibrary;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,5 @@ public abstract class GraalHPyNativeSymbols {
117117
public static final String GRAAL_HPY_WRITE_HPY_SSIZE_T = "graal_hpy_write_HPy_ssize_t";
118118
public static final String GRAAL_HPY_WRITE_PTR = "graal_hpy_write_ptr";
119119

120+
public static final String GRAAL_HPY_BULK_FREE = "graal_hpy_bulk_free";
120121
}

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
package com.oracle.graal.python.builtins.objects.cext.hpy;
4242

4343
import static com.oracle.graal.python.builtins.PythonBuiltinClassType.SystemError;
44+
import static com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyDef.HPySlot.HPY_TP_DESTROY;
4445
import static com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyDef.HPySlot.HPY_TP_NEW;
4546
import static com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNativeSymbols.GRAAL_HPY_DEF_GET_GETSET;
4647
import static com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyNativeSymbols.GRAAL_HPY_DEF_GET_KIND;
@@ -808,8 +809,15 @@ static HPyProperty doIt(GraalHPyContext context, Object enclosingType, Object sl
808809

809810
String methodNameStr = methodName instanceof HiddenKey ? ((HiddenKey) methodName).getName() : (String) methodName;
810811

811-
PBuiltinFunction function = HPyExternalFunctionNodes.createWrapperFunction(language, slot.getSignature(), methodNameStr, methodFunctionPointer,
812-
HPY_TP_NEW.equals(slot) ? null : enclosingType, factory);
812+
Object function;
813+
if (HPY_TP_DESTROY.equals(slot)) {
814+
// special case: DESTROYFUNC
815+
// This won't be usable from Python, so we just store the bare pointer object into
816+
// the hidden attribute.
817+
function = methodFunctionPointer;
818+
} else {
819+
function = HPyExternalFunctionNodes.createWrapperFunction(language, slot.getSignature(), methodNameStr, methodFunctionPointer, HPY_TP_NEW.equals(slot) ? null : enclosingType, factory);
820+
}
813821
return new HPyProperty(methodName, function);
814822
}
815823

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
* Copyright (c) 2020, 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+
package com.oracle.graal.python.builtins.objects.cext.hpy;
42+
43+
import com.oracle.graal.python.builtins.objects.PNone;
44+
import com.oracle.graal.python.builtins.objects.cext.hpy.GraalHPyContext.GraalHPyHandleReference;
45+
import com.oracle.truffle.api.interop.InteropLibrary;
46+
import com.oracle.truffle.api.interop.TruffleObject;
47+
import com.oracle.truffle.api.library.ExportLibrary;
48+
import com.oracle.truffle.api.library.ExportMessage;
49+
50+
@ExportLibrary(InteropLibrary.class)
51+
final class NativeSpaceArrayWrapper implements TruffleObject {
52+
53+
final GraalHPyHandleReference[] data;
54+
55+
public NativeSpaceArrayWrapper(GraalHPyHandleReference[] data) {
56+
this.data = data;
57+
}
58+
59+
@ExportMessage
60+
boolean hasArrayElements() {
61+
return true;
62+
}
63+
64+
@ExportMessage
65+
long getArraySize() {
66+
return data.length;
67+
}
68+
69+
@ExportMessage
70+
boolean isArrayElementReadable(long i) {
71+
return i < data.length;
72+
}
73+
74+
@ExportMessage
75+
Object readArrayElement(long i) {
76+
GraalHPyHandleReference ref = data[(int) i];
77+
if (ref != null) {
78+
return ref.getNativeSpace();
79+
}
80+
// return something that responds to 'isNull' with 'true'
81+
return PNone.NO_VALUE;
82+
}
83+
}

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/runtime/AsyncHandler.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ public final void execute(PythonContext context) {
126126
}
127127
}
128128

129-
private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(3, new ThreadFactory() {
129+
private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(4, new ThreadFactory() {
130130
public Thread newThread(Runnable r) {
131131
Thread t = Executors.defaultThreadFactory().newThread(r);
132132
t.setDaemon(true);

0 commit comments

Comments
 (0)