Skip to content

Commit a2ce3ab

Browse files
committed
[GR-22226] Avoid wrapping of sequences with native storages.
PullRequest: graalpython/895
2 parents 93f60c9 + a4f8e14 commit a2ce3ab

File tree

2 files changed

+102
-5
lines changed

2 files changed

+102
-5
lines changed

graalpython/com.oracle.graal.python.test/src/tests/cpyext/test_bytes.py

Lines changed: 82 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
1+
# Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
22
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
33
#
44
# The Universal Permissive License (UPL), Version 1.0
@@ -37,7 +37,7 @@
3737
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3838
# SOFTWARE.
3939

40-
from . import CPyExtTestCase, CPyExtFunction, CPyExtFunctionOutVars, unhandled_error_compare, GRAALPYTHON
40+
from . import CPyExtTestCase, CPyExtFunction, CPyExtFunctionOutVars, unhandled_error_compare
4141
__dir__ = __file__.rpartition("/")[0]
4242

4343

@@ -257,3 +257,83 @@ def compile_module(self, name):
257257
callfunction="mutate_bytes",
258258
cmpfunc=unhandled_error_compare
259259
)
260+
261+
test_PyBytes_Resize = CPyExtFunction(
262+
lambda args: args[0][:args[1]],
263+
lambda: (
264+
(b"hello_beatiful_world", 5),
265+
),
266+
code="""
267+
PyObject* wrap_PyBytes_Resize(PyObject* bytesObj, Py_ssize_t new_size) {
268+
/* we need to create a fresh bytes object */
269+
PyObject* res = PyBytes_FromString(PyBytes_AsString(bytesObj));
270+
_PyBytes_Resize(&res, new_size);
271+
return res;
272+
}
273+
""",
274+
resultspec="O",
275+
argspec="On",
276+
arguments=["PyObject* bytesObj", "Py_ssize_t new_size"],
277+
callfunction="wrap_PyBytes_Resize",
278+
cmpfunc=unhandled_error_compare
279+
)
280+
281+
test_PyBytes_Resize_NativeStorage = CPyExtFunction(
282+
lambda args: args[1],
283+
lambda: (
284+
(b"hello_beatiful_world", b"hello_world"),
285+
),
286+
code="""
287+
#include <stdio.h>
288+
289+
/* Copies content from 'smaller' to 'larger_content' and returns a pointer to the last char. */
290+
static char* do_pointer_arithmetics(char* larger_content, PyObject* smaller) {
291+
char* smaller_content = PyBytes_AS_STRING(smaller);
292+
Py_ssize_t smaller_len = PyBytes_Size(smaller);
293+
294+
// 'smaller_len + 1' also contains the null byte
295+
memcpy(larger_content, smaller_content, smaller_len + 1);
296+
return larger_content + smaller_len;
297+
}
298+
299+
PyObject* resize_bytes(PyObject* larger, PyObject* smaller) {
300+
char* data;
301+
char* dummy;
302+
char* end_ptr;
303+
Py_ssize_t len;
304+
Py_ssize_t new_len;
305+
PyObject* larger_copy;
306+
307+
Py_INCREF(larger);
308+
Py_INCREF(smaller);
309+
310+
/* we need to create a fresh bytes object */
311+
larger_copy = PyBytes_FromString(PyBytes_AsString(larger));
312+
Py_DECREF(larger);
313+
314+
len = PyBytes_Size(larger_copy) + 1;
315+
316+
dummy = (char*) calloc(len, sizeof(char));
317+
data = PyBytes_AS_STRING(larger_copy);
318+
319+
/* this will force the bytes object's content to native */
320+
snprintf(data, len, "%s", dummy);
321+
free(dummy);
322+
323+
/* copy smaller data and return the pointer to the last char */
324+
end_ptr = do_pointer_arithmetics(data, smaller);
325+
Py_DECREF(smaller);
326+
327+
/* compute new size */
328+
new_len = (Py_ssize_t) (end_ptr - PyBytes_AS_STRING(larger_copy));
329+
_PyBytes_Resize(&larger_copy, new_len);
330+
memcpy(PyBytes_AS_STRING(larger_copy), data, new_len * sizeof(char));
331+
return larger_copy;
332+
}
333+
""",
334+
resultspec="O",
335+
argspec="OO",
336+
arguments=["PyObject* larger", "PyObject* smaller"],
337+
callfunction="resize_bytes",
338+
cmpfunc=unhandled_error_compare
339+
)

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

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@
134134
import com.oracle.graal.python.runtime.interop.InteropArray;
135135
import com.oracle.graal.python.runtime.object.PythonObjectFactory;
136136
import com.oracle.graal.python.runtime.sequence.PSequence;
137+
import com.oracle.graal.python.runtime.sequence.storage.NativeSequenceStorage;
138+
import com.oracle.graal.python.runtime.sequence.storage.SequenceStorage;
137139
import com.oracle.truffle.api.CompilerAsserts;
138140
import com.oracle.truffle.api.CompilerDirectives;
139141
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
@@ -610,12 +612,22 @@ int doMaUsed(PDict object, @SuppressWarnings("unused") String key,
610612
}
611613

612614
@Specialization(guards = "eq(OB_SVAL, key)")
613-
Object doObSval(PBytes object, @SuppressWarnings("unused") String key) {
615+
Object doObSval(PBytes object, @SuppressWarnings("unused") String key,
616+
@Cached("createClassProfile()") ValueProfile classProfile) {
617+
SequenceStorage sequenceStorage = classProfile.profile(object.getSequenceStorage());
618+
if (sequenceStorage instanceof NativeSequenceStorage) {
619+
return ((NativeSequenceStorage) sequenceStorage).getPtr();
620+
}
614621
return new PySequenceArrayWrapper(object, 1);
615622
}
616623

617624
@Specialization(guards = "eq(OB_START, key)")
618-
Object doObStart(PByteArray object, @SuppressWarnings("unused") String key) {
625+
Object doObStart(PByteArray object, @SuppressWarnings("unused") String key,
626+
@Cached("createClassProfile()") ValueProfile classProfile) {
627+
SequenceStorage sequenceStorage = classProfile.profile(object.getSequenceStorage());
628+
if (sequenceStorage instanceof NativeSequenceStorage) {
629+
return ((NativeSequenceStorage) sequenceStorage).getPtr();
630+
}
619631
return new PySequenceArrayWrapper(object, 1);
620632
}
621633

@@ -632,7 +644,12 @@ Object doObFval(Object object, @SuppressWarnings("unused") String key,
632644
}
633645

634646
@Specialization(guards = "eq(OB_ITEM, key)")
635-
Object doObItem(PSequence object, @SuppressWarnings("unused") String key) {
647+
Object doObItem(PSequence object, @SuppressWarnings("unused") String key,
648+
@Cached("createClassProfile()") ValueProfile classProfile) {
649+
SequenceStorage sequenceStorage = classProfile.profile(object.getSequenceStorage());
650+
if (sequenceStorage instanceof NativeSequenceStorage) {
651+
return ((NativeSequenceStorage) sequenceStorage).getPtr();
652+
}
636653
return new PySequenceArrayWrapper(object, 4);
637654
}
638655

0 commit comments

Comments
 (0)