Skip to content

Conversation

@Vizonex
Copy link

@Vizonex Vizonex commented Dec 29, 2025

I recently saw this project as a good candidate for a new Javascript interpreter library for Python & Cython and as I was going about binding python and quickjs-ng together I came across an issue with using FILE* pointers since Python does not have a very clear way of gaining access to these FILE* pointers and I saw extracting objects from PyObject* to const char* types to be rather annoying and not very efficient and may limit what programmers may be able to do with this data so I decided to write a newer callback system to try and make up for this. annoyance. The way I plan to use it in Cython will be the following code.

But for the code I'm demonstrating I'll cut to the important stuff that makes use of these functions that I am needing.

cdef int js_write_memory_usage_cb(void* opaque, const char* data, size_t data_len) noexcept with gil:
    cdef str py_data
    cdef object write_cb = <object>opaque
    try:
        PyObject_CallOneArg(write_cb, PyUnicode_FromStringAndSize(data, data_len))
        # success!
        return 0
    except BaseException:
        # reraise later...
        return -1
 

cdef class Runtime:
    """
    Represents a JavaScript runtime corresponding to an
    object heap. Several runtimes can exist at the same time but they
    cannot exchange objects. Inside a given runtime, no multi-threading is
    supported.
    """
    cdef:
        JSRuntime* rt
    
    cpdef object dump_memory_usage(self, object io):
        """dumps memory to an StringIO type object or file type object"""
        cdef object write = io.write # SEE: https://docs.python.org/3/c-api/file.html
        cdef JSMemoryUsage memory_usage
        cdef int ret
        JS_ComputeMemoryUsage(self.rt, &memory_usage)
        
        ret = JS_WriteMemoryUsage(js_write_memory_usage_cb, memory_usage, self.rt, <void*>(write))
        if ret < 0:
            # Reraise Last Seen Python Exception
            raise

Please let me know if any names or things in these additions should be changed or if there's a better way for me to come up with a less costly implementation for the library I am planning to make.

@bnoordhuis
Copy link
Contributor

I can understand the issue with JS_DumpMemoryUsage() but can you explain why JS_ComputeMemoryUsage() is not sufficient for your use case?

Apropos FILE pointers, you can create one from a memory buffer with fmemopen().

@Vizonex
Copy link
Author

Vizonex commented Dec 31, 2025

@bnoordhuis Problem solved. Cython has a few unexposed functions that is doesn't utilize that I can use by having them shoved into a headerfile.

static PyObject* CYJS_FSConvert(PyObject* file){
    PyObject* filename_bytes = NULL;
    if (PyUnicode_FSConverter(file, &filename_bytes) < 0)
        return NULL;
    return filename_bytes;
}

static int CYJS_DumpMemoryUsage(JSRuntime* rt, PyObject* file){
    
    PyObject* filename_bytes = NULL;
    JSMemoryUsage mu;

    // Me being aggressive
    if (rt == NULL || file == NULL){
        PyErr_SetString(PyExc_TypeError, "(runtime & file) cannot be passed as NULL");
        return -1;
    }

    // Kinda stupid how cython doesn't make use of this function 
    // when it serves great importance with python's built-in open() function
    if (PyUnicode_FSConverter(file, &filename_bytes) < 0)
        return -1;

    // We need a file pointer.
    FILE* fp = fopen((const char*)PyBytes_AS_STRING(filename_bytes), "w");
    if (fp == NULL){
        PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, file);
        Py_CLEAR(filename_bytes);
        return -1;
    }
    JS_ComputeMemoryUsage(rt, &mu);
    JS_DumpMemoryUsage(fp, (const JSMemoryUsage*)(&mu), rt);
    fclose(fp);
    Py_CLEAR(filename_bytes);
    return 0;
}

You will find this code in my new library CYJS

@Vizonex Vizonex closed this Dec 31, 2025
@Vizonex Vizonex deleted the memory-dump-callback branch December 31, 2025 04:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants