Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
Ziqi-Yang committed Aug 3, 2024
1 parent 161eabd commit f91e050
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 42 deletions.
7 changes: 3 additions & 4 deletions docs/source/development.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,9 @@ The ``PyContext::getGlobalContext()`` function here will cause problems. Accordi
to observation, the an PyContext object will be generated and managed by NanoBind
as long as you imported the library. When encountering memory bugs, you cannot see
concrete symbol name in the stacktrace in Debug mode. For commit
`285d53db92264e55a705195df9d1a6c7a024d3b6 <https://github.com/Ziqi-Yang/llvmpym/commit/285d53db92264e55a705195df9d1a6c7a024d3b6>`_, the code above and `example/llvmir_builder.py line 25 <https://github.com/Ziqi-Yang/llvmpym/blob/285d53db92264e55a705195df9d1a6c7a024d3b6/example/llvmir_builder.py#L25>`_ will cause
an memory bug (``free(): invalid pointer``) at the end of finishing the program, which
is seemingly irrelevant of the execution and may relate to underlying operating
principles of LLVM and NanoBind.
`285d53db92264e55a705195df9d1a6c7a024d3b6 <https://github.com/Ziqi-Yang/llvmpym/commit/285d53db92264e55a705195df9d1a6c7a024d3b6>`_, the code above, `example/llvmir_builder.py line 25 <https://github.com/Ziqi-Yang/llvmpym/blob/285d53db92264e55a705195df9d1a6c7a024d3b6/example/llvmir_builder.py#L25>`_ and the ``print(m)`` at the end of file will cause an memory bug (``free(): invalid pointer``)
when program is finishing, which is seemingly irrelevant of the execution
and may relate to underlying operating principles of LLVM and NanoBind.

As a contrast, the following went smooth.

Expand Down
7 changes: 5 additions & 2 deletions example/el_psy_congaroo.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@

import llvmpym.core as core

with core.Context() as c:
core.FunctionType()
c = core.Context.get_global_context()
s = r'target triple = "unknown-unknown-unknown"'
mem_buf = core.MemoryBuffer.from_str(s, "")
res = c.parse_ir(mem_buf)
print(res)
1 change: 0 additions & 1 deletion example/llvmir_builder.py → example/ir_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,4 @@
builder.position_at_end(bb_exit)
builder.ret(myint)


print(m)
10 changes: 5 additions & 5 deletions example/parse_ir_assmebly.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
'''

m = utils.parse_assembly(asm_str)
print(m)

# for f in m.functions:
# print(f'Function: {f.name}/`{f.type}`')
# m = f.parent
# # assert f.kind == core.ValueKind.Function
for f in m.functions:
print(f'Function: {f.name}/`{f.type}`')
m = f.parent
assert f.kind == core.ValueKind.Function
print(f"Functoin attributes: {}")
3 changes: 2 additions & 1 deletion note.typ
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ directory(e.g. `.venv/lib/python3.12/site-packages/llvmpym/llvmpym_ext`) to corr
- Doc: if document has `@see LLVMContext::setYieldCallback()`, then we need to also include documents for that function (in C++ header)
- TODO change all possible unsigned return value into corresponding enum type
- also parameter (like `kindID`?)
- Add cache to object properties
- LATER Add cache to object properties
- TODO delete all `destory` function

== More Python Style
1. iterator: next, prev ?
Expand Down
39 changes: 19 additions & 20 deletions src/llvm/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3375,20 +3375,20 @@ void bindOtherClasses(nb::module_ &m) {
},
":raises RuntimeError")
.def_static("from_str",
[](std::string &inputData, const char *BufferName, bool RequiresNullTerminator) {
[](std::string &inputData, bool RequiresNullTerminator, const char *BufferName) {
return PyMemoryBuffer(LLVMCreateMemoryBufferWithMemoryRange
(inputData.c_str(), inputData.size(),
BufferName, RequiresNullTerminator));
},
"input_data"_a, "buffer_name"_a, "requires_null_terminator"_a)
"input_data"_a, "requires_null_terminator"_a, "buffer_name"_a = "")
.def_static("from_str",
[](const std::string &inputData, const char *BufferName) ->
optional<PyMemoryBuffer>{
auto res = LLVMCreateMemoryBufferWithMemoryRangeCopy
(inputData.c_str(), inputData.size(), BufferName);
WRAP_OPTIONAL_RETURN(res, PyMemoryBuffer);
},
"input_data"_a, "buffer_name"_a)
"input_data"_a, "buffer_name"_a = "")
.def_prop_ro("buffer_start",
[](PyMemoryBuffer &self) {
return LLVMGetBufferStart(self.get());
Expand Down Expand Up @@ -4393,23 +4393,22 @@ void bindOtherClasses(nb::module_ &m) {
},
"callback"_a, "opaque_handle"_a,
"Set the yield callback function for this context.")
// .def("parse_ir",
// [](PyContext &self, PyMemoryBuffer &memBuf) {
// try {
// auto res = parseIR(self.get(), memBuf.get());
// memBuf.resetNoClean(); // We Cannot reuse the memory buffer again
// return res;
// } catch (const std::exception& ex) {
// // TODO test whether it is still available after a filed operation.
// memBuf.resetNoClean();
// throw ex;
// }
// },
// "memory_buffer"_a,
// "Read LLVM IR from a memory buffer and convert it into an in-memory Module"
// "object.\n\n"
// ":raises RuntimeError\n"
// "NOTE that you cannot use passed-in memory_buffer after this operation.")
.def("parse_ir",
[](PyContext &self, PyMemoryBuffer &memBuf) {
try {
auto res = parseIR(self.get(), memBuf.get());
memBuf.reset(); // We Cannot reuse the memory buffer again
return res;
} catch (const std::exception& ex) {
memBuf.reset();
throw ex;
}
},
"memory_buffer"_a,
"Read LLVM IR from a memory buffer and convert it into an in-memory Module"
"object.\n\n"
":raises RuntimeError\n"
"NOTE that you cannot use passed-in memory_buffer after this operation.")
.def("create_builder",
[](PyContext &self) {
return PyBuilder(LLVMCreateBuilderInContext(self.get()));
Expand Down
3 changes: 3 additions & 0 deletions src/llvm/_types/PyContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ LLVMContextRef PyContext::get() const {


void PyContext::LLVMContextDeleter::operator()(LLVMContextRef context) const {
// NOTE the parent object is actually I think, since
// all the state in the `parent` object is the state when we created
// LLVMContextDeleter object
if (context && parent && !parent->is_global_context) {
LLVMContextDispose(context);

Expand Down
34 changes: 25 additions & 9 deletions src/llvm/_types/PyMemoryBuffer.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "PyMemoryBuffer.h"
#include <iostream>

std::unordered_map<LLVMMemoryBufferRef,
std::weak_ptr<LLVMOpaqueMemoryBuffer>> PyMemoryBuffer::mb_map;
Expand All @@ -10,30 +11,45 @@ LLVMMemoryBufferRef PyMemoryBuffer::get() const {
return mb.get();
}

// This function doesn't call `reset` method on shared_ptr object, since
// it will then call deleter, which is undesired and will lead to crash.
void PyMemoryBuffer::reset() {
LLVMMemoryBufferRef m = mb.get();
if (m) {
std::lock_guard<std::mutex> lock(PyMemoryBuffer::map_mutex);
PyMemoryBuffer::mb_map.erase(m);
}
}


void PyMemoryBuffer::LLVMMemoryBufferRefDeleter::operator()
(LLVMMemoryBufferRef entries) const {
if (entries) {
LLVMDisposeMemoryBuffer(entries);

(LLVMMemoryBufferRef mb) const {
if (mb) {
std::lock_guard<std::mutex> lock(PyMemoryBuffer::map_mutex);
PyMemoryBuffer::mb_map.erase(entries);
auto it = PyMemoryBuffer::mb_map.find(mb);

// the logic here is specially designed for `reset` function
if (it != PyMemoryBuffer::mb_map.end()) {
LLVMDisposeMemoryBuffer(mb);

PyMemoryBuffer::mb_map.erase(mb);
}
}
}


std::shared_ptr<LLVMOpaqueMemoryBuffer> PyMemoryBuffer::get_shared_mb
(LLVMMemoryBufferRef entries) {
(LLVMMemoryBufferRef mb) {
std::lock_guard<std::mutex> lock(PyMemoryBuffer::map_mutex);
auto it = PyMemoryBuffer::mb_map.find(entries);
auto it = PyMemoryBuffer::mb_map.find(mb);

if (it != PyMemoryBuffer::mb_map.end()) {
if (auto shared = it->second.lock()) {
return shared;
}
}

auto shared = std::shared_ptr<LLVMOpaqueMemoryBuffer>(entries, LLVMMemoryBufferRefDeleter());
PyMemoryBuffer::mb_map[entries] = shared;
auto shared = std::shared_ptr<LLVMOpaqueMemoryBuffer>(mb, LLVMMemoryBufferRefDeleter());
PyMemoryBuffer::mb_map[mb] = shared;
return shared;
}
6 changes: 6 additions & 0 deletions src/llvm/_types/PyMemoryBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ class PyMemoryBuffer {
public:
explicit PyMemoryBuffer(LLVMMemoryBufferRef mb);
LLVMMemoryBufferRef get() const;

/*
* This function reset the PyMemoryBuffer object, preventing it from
* being automatically disposed
*/
void reset();

private:
std::shared_ptr<LLVMOpaqueMemoryBuffer> mb;
Expand Down

0 comments on commit f91e050

Please sign in to comment.