Skip to content

Commit a1eb88f

Browse files
committed
Add load from memory in c loader.
1 parent 2c06892 commit a1eb88f

File tree

2 files changed

+146
-115
lines changed

2 files changed

+146
-115
lines changed

source/loaders/c_loader/source/c_loader_impl.cpp

Lines changed: 136 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -76,19 +76,81 @@ typedef struct loader_impl_c_type
7676

7777
} * loader_impl_c;
7878

79+
struct loader_impl_c_handle_base_type;
80+
81+
typedef struct loader_impl_c_handle_base_type *loader_impl_c_handle_base;
82+
83+
typedef struct c_loader_impl_discover_visitor_data_type
84+
{
85+
loader_impl impl;
86+
loader_impl_c_handle_base c_handle;
87+
scope sp;
88+
int result;
89+
90+
} * c_loader_impl_discover_visitor_data;
91+
92+
static CXChildVisitResult c_loader_impl_discover_visitor(CXCursor cursor, CXCursor, void *data);
93+
7994
typedef struct loader_impl_c_handle_base_type
8095
{
96+
public:
97+
virtual ~loader_impl_c_handle_base_type() {}
98+
99+
virtual bool recursive_includes() = 0;
100+
101+
virtual int discover(loader_impl impl, context ctx) = 0;
102+
103+
virtual const void *symbol(std::string &name) = 0;
104+
105+
virtual int discover_visitor(std::vector<const char *> &command_line_args, void *data) = 0;
106+
107+
} * loader_impl_c_handle_base;
108+
109+
typedef struct loader_impl_c_handle_file_type : loader_impl_c_handle_base_type
110+
{
81111
public:
82112
std::vector<std::string> files;
83113

84-
virtual ~loader_impl_c_handle_base_type() {}
114+
virtual ~loader_impl_c_handle_file_type() {}
85115

86116
virtual bool recursive_includes() = 0;
87117

88118
virtual int discover(loader_impl impl, context ctx) = 0;
89119

90120
virtual const void *symbol(std::string &name) = 0;
91121

122+
int discover_visitor(std::vector<const char *> &command_line_args, void *data)
123+
{
124+
for (std::string file : this->files)
125+
{
126+
/* Define the command line arguments (simulating compiler flags) */
127+
CXIndex index = clang_createIndex(0, 1);
128+
CXTranslationUnit unit = NULL;
129+
CXErrorCode error = clang_parseTranslationUnit2(
130+
index,
131+
file.c_str(),
132+
command_line_args.data(), command_line_args.size(),
133+
nullptr, 0,
134+
CXTranslationUnit_None,
135+
&unit);
136+
137+
if (error != CXError_Success)
138+
{
139+
log_write("metacall", LOG_LEVEL_ERROR, "Unable to parse translation unit of: %s with error code %d", file.c_str(), error);
140+
clang_disposeIndex(index);
141+
return -1;
142+
}
143+
144+
CXCursor cursor = clang_getTranslationUnitCursor(unit);
145+
clang_visitChildren(cursor, c_loader_impl_discover_visitor, data);
146+
147+
clang_disposeTranslationUnit(unit);
148+
clang_disposeIndex(index);
149+
}
150+
151+
return 0;
152+
}
153+
92154
void add(const loader_path path, size_t size)
93155
{
94156
if (this->is_ld_script(path, size) == false)
@@ -118,12 +180,65 @@ typedef struct loader_impl_c_handle_base_type
118180
return true;
119181
}
120182

121-
} * loader_impl_c_handle_base;
183+
} * loader_impl_c_handle_file;
184+
185+
typedef struct loader_impl_c_handle_memory_type : loader_impl_c_handle_base_type
186+
{
187+
public:
188+
std::string name;
189+
std::string buffer;
190+
191+
virtual ~loader_impl_c_handle_memory_type() {}
192+
193+
virtual bool recursive_includes() = 0;
194+
195+
virtual int discover(loader_impl impl, context ctx) = 0;
196+
197+
virtual const void *symbol(std::string &name) = 0;
198+
199+
int discover_visitor(std::vector<const char *> &command_line_args, void *data)
200+
{
201+
CXUnsavedFile unsaved_file;
202+
203+
/* Simulate an in-memory file */
204+
unsaved_file.Filename = this->name.c_str();
205+
unsaved_file.Contents = this->buffer.c_str();
206+
unsaved_file.Length = this->buffer.length();
207+
208+
/* Define the command line arguments (simulating compiler flags) */
209+
CXIndex index = clang_createIndex(0, 1);
210+
CXTranslationUnit unit = NULL;
211+
CXErrorCode error = clang_parseTranslationUnit2(
212+
index,
213+
this->name.c_str(),
214+
command_line_args.data(), command_line_args.size(),
215+
&unsaved_file, 1,
216+
CXTranslationUnit_None,
217+
&unit);
218+
219+
if (error != CXError_Success)
220+
{
221+
log_write("metacall", LOG_LEVEL_ERROR, "Unable to parse translation unit of: %s with error code %d", this->name.c_str(), error);
222+
clang_disposeIndex(index);
223+
return -1;
224+
}
225+
226+
CXCursor cursor = clang_getTranslationUnitCursor(unit);
227+
clang_visitChildren(cursor, c_loader_impl_discover_visitor, data);
228+
229+
clang_disposeTranslationUnit(unit);
230+
clang_disposeIndex(index);
231+
232+
return 0;
233+
}
234+
235+
} * loader_impl_c_handle_memory;
122236

123237
static void c_loader_impl_discover_symbols(void *ctx, const char *name, const void *addr);
124238
static int c_loader_impl_discover_ast(loader_impl impl, loader_impl_c_handle_base c_handle, context ctx);
125239

126-
typedef struct loader_impl_c_handle_tcc_type : loader_impl_c_handle_base_type
240+
template <typename T>
241+
struct loader_impl_c_handle_tcc_type : T
127242
{
128243
public:
129244
TCCState *state;
@@ -207,7 +322,7 @@ typedef struct loader_impl_c_handle_tcc_type : loader_impl_c_handle_base_type
207322
virtual int discover(loader_impl impl, context ctx)
208323
{
209324
/* Get all symbols */
210-
tcc_list_symbols(this->state, static_cast<void *>(this), &c_loader_impl_discover_symbols);
325+
tcc_list_symbols(this->state, static_cast<void *>(&symbols), &c_loader_impl_discover_symbols);
211326

212327
/* Parse the AST and register functions */
213328
return c_loader_impl_discover_ast(impl, this, ctx);
@@ -222,10 +337,15 @@ typedef struct loader_impl_c_handle_tcc_type : loader_impl_c_handle_base_type
222337

223338
return this->symbols[name];
224339
}
340+
};
341+
342+
typedef struct loader_impl_c_handle_tcc_type<loader_impl_c_handle_file_type> loader_impl_c_handle_tcc_file_type;
343+
typedef loader_impl_c_handle_tcc_file_type *loader_impl_c_handle_tcc_file;
225344

226-
} * loader_impl_c_handle_tcc;
345+
typedef struct loader_impl_c_handle_tcc_type<loader_impl_c_handle_memory_type> loader_impl_c_handle_tcc_memory_type;
346+
typedef loader_impl_c_handle_tcc_memory_type *loader_impl_c_handle_tcc_memory;
227347

228-
typedef struct loader_impl_c_handle_dynlink_type : loader_impl_c_handle_base_type
348+
typedef struct loader_impl_c_handle_dynlink_type : loader_impl_c_handle_file_type
229349
{
230350
public:
231351
dynlink lib;
@@ -385,15 +505,6 @@ typedef struct loader_impl_c_function_type
385505

386506
} * loader_impl_c_function;
387507

388-
typedef struct c_loader_impl_discover_visitor_data_type
389-
{
390-
loader_impl impl;
391-
loader_impl_c_handle_base c_handle;
392-
scope sp;
393-
int result;
394-
395-
} * c_loader_impl_discover_visitor_data;
396-
397508
/* Retrieve the equivalent FFI type from type id */
398509
static ffi_type *c_loader_impl_ffi_type(type_id id);
399510

@@ -681,9 +792,9 @@ void c_loader_impl_function_closure(ffi_cif *cif, void *ret, void *args[], void
681792

682793
static void c_loader_impl_discover_symbols(void *ctx, const char *name, const void *addr)
683794
{
684-
loader_impl_c_handle_tcc c_handle = static_cast<loader_impl_c_handle_tcc>(ctx);
795+
std::map<std::string, const void *> *symbols = static_cast<std::map<std::string, const void *> *>(ctx);
685796

686-
c_handle->symbols.insert(std::pair<std::string, const void *>(name, addr));
797+
symbols->insert(std::pair<std::string, const void *>(name, addr));
687798
}
688799

689800
static bool c_loader_impl_file_exists(const loader_path path)
@@ -1305,7 +1416,7 @@ static int c_loader_impl_discover_signature(loader_impl impl, loader_impl_c_hand
13051416
return 0;
13061417
}
13071418

1308-
static CXChildVisitResult c_loader_impl_discover_visitor(CXCursor cursor, CXCursor, void *data)
1419+
CXChildVisitResult c_loader_impl_discover_visitor(CXCursor cursor, CXCursor, void *data)
13091420
{
13101421
c_loader_impl_discover_visitor_data visitor_data = static_cast<c_loader_impl_discover_visitor_data>(data);
13111422

@@ -1353,91 +1464,9 @@ static int c_loader_impl_discover_ast(loader_impl impl, loader_impl_c_handle_bas
13531464
command_line_args.push_back(includes.back().c_str());
13541465
}
13551466

1356-
/* TODO: Load from memory (discover from memory) */
1357-
/*
1358-
#include <clang-c/Index.h>
1359-
#include <stdio.h>
1360-
#include <stdlib.h>
1361-
1362-
int main() {
1363-
const char *source_code =
1364-
"int add(int a, int b) {\n"
1365-
" return a + b;\n"
1366-
"}";
1367-
1368-
// Simulate an in-memory file
1369-
CXUnsavedFile unsaved_file;
1370-
unsaved_file.Filename = "example.c";
1371-
unsaved_file.Contents = source_code;
1372-
unsaved_file.Length = (unsigned long)strlen(source_code);
1373-
1374-
// Create index
1375-
CXIndex index = clang_createIndex(0, 0);
1376-
1377-
// Parse translation unit from buffer (unsaved file)
1378-
CXTranslationUnit tu;
1379-
CXErrorCode err = clang_parseTranslationUnit2(
1380-
index,
1381-
"example.c", // filename for context (matches unsaved file)
1382-
NULL, 0, // command line args
1383-
&unsaved_file, 1, // unsaved files
1384-
CXTranslationUnit_None, // options
1385-
&tu
1386-
);
1387-
1388-
if (err != CXError_Success) {
1389-
fprintf(stderr, "Failed to parse translation unit.\n");
1390-
return 1;
1391-
}
1392-
1393-
// Get the cursor to the root of the translation unit
1394-
CXCursor cursor = clang_getTranslationUnitCursor(tu);
1395-
1396-
// Visit each AST node
1397-
clang_visitChildren(
1398-
cursor,
1399-
[](CXCursor c, CXCursor parent, CXClientData client_data) {
1400-
CXString spelling = clang_getCursorSpelling(c);
1401-
CXString kind = clang_getCursorKindSpelling(clang_getCursorKind(c));
1402-
printf("Cursor: %s (%s)\n", clang_getCString(spelling), clang_getCString(kind));
1403-
clang_disposeString(spelling);
1404-
clang_disposeString(kind);
1405-
return CXChildVisit_Recurse;
1406-
},
1407-
NULL
1408-
);
1409-
1410-
// Clean up
1411-
clang_disposeTranslationUnit(tu);
1412-
clang_disposeIndex(index);
1413-
1414-
return 0;
1415-
}
1416-
*/
1417-
1418-
for (std::string file : c_handle->files)
1467+
if (c_handle->discover_visitor(command_line_args, static_cast<void *>(&data)) != 0)
14191468
{
1420-
/* Define the command line arguments (simulating compiler flags) */
1421-
CXIndex index = clang_createIndex(0, 1);
1422-
CXTranslationUnit unit = clang_parseTranslationUnit(
1423-
index,
1424-
file.c_str(),
1425-
command_line_args.data(), command_line_args.size(),
1426-
nullptr, 0,
1427-
CXTranslationUnit_None);
1428-
1429-
if (unit == nullptr)
1430-
{
1431-
log_write("metacall", LOG_LEVEL_ERROR, "Unable to parse translation unit of: %s", file.c_str());
1432-
clang_disposeIndex(index);
1433-
return -1;
1434-
}
1435-
1436-
CXCursor cursor = clang_getTranslationUnitCursor(unit);
1437-
clang_visitChildren(cursor, c_loader_impl_discover_visitor, static_cast<void *>(&data));
1438-
1439-
clang_disposeTranslationUnit(unit);
1440-
clang_disposeIndex(index);
1469+
return 1;
14411470
}
14421471

14431472
return data.result;
@@ -1455,7 +1484,7 @@ static int c_loader_impl_tcc_relocate(TCCState *state)
14551484
loader_handle c_loader_impl_load_from_file(loader_impl impl, const loader_path paths[], size_t size)
14561485
{
14571486
loader_impl_c c_impl = static_cast<loader_impl_c>(loader_impl_get(impl));
1458-
loader_impl_c_handle_tcc c_handle = new loader_impl_c_handle_tcc_type();
1487+
loader_impl_c_handle_tcc_file c_handle = new loader_impl_c_handle_tcc_file_type();
14591488

14601489
if (c_handle->initialize(c_impl) == false)
14611490
{
@@ -1522,7 +1551,7 @@ loader_handle c_loader_impl_load_from_file(loader_impl impl, const loader_path p
15221551
loader_handle c_loader_impl_load_from_memory(loader_impl impl, const loader_name name, const char *buffer, size_t size)
15231552
{
15241553
loader_impl_c c_impl = static_cast<loader_impl_c>(loader_impl_get(impl));
1525-
loader_impl_c_handle_tcc c_handle = new loader_impl_c_handle_tcc_type();
1554+
loader_impl_c_handle_tcc_memory c_handle = new loader_impl_c_handle_tcc_memory_type();
15261555

15271556
/* Apparently TCC has an unsafe API for compiling strings */
15281557
(void)size;
@@ -1544,7 +1573,9 @@ loader_handle c_loader_impl_load_from_memory(loader_impl impl, const loader_name
15441573
goto error;
15451574
}
15461575

1547-
/* TODO: Load the buffer with the parser while iterating after loading it with TCC */
1576+
c_handle->name = name;
1577+
c_handle->name.append(".c");
1578+
c_handle->buffer.assign(buffer, size);
15481579

15491580
return c_handle;
15501581

source/tests/metacall_c_test/source/metacall_c_test.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -284,21 +284,21 @@ TEST_F(metacall_c_test, DefaultConstructor)
284284
metacall_value_destroy(args[0]);
285285

286286
/* Memory */
287-
// TODO
288-
// const char c_buffer[] = {
289-
// "int compiled_mult(int a, int b) { return a * b; }"
290-
// };
287+
{
288+
const char c_buffer[] = {
289+
"int compiled_mult_memory(int a, int b) { return a * b; }"
290+
};
291291

292-
// EXPECT_EQ((int)0, (int)metacall_load_from_memory("c", c_buffer, sizeof(c_buffer), NULL));
292+
EXPECT_EQ((int)0, (int)metacall_load_from_memory("c", c_buffer, sizeof(c_buffer), NULL));
293293

294-
// TODO
295-
// void *ret = metacall("compiled_mult", 3, 4);
294+
void *ret = metacall("compiled_mult_memory", 3, 4);
296295

297-
// EXPECT_NE((void *)NULL, (void *)ret);
296+
EXPECT_NE((void *)NULL, (void *)ret);
298297

299-
// EXPECT_EQ((int)metacall_value_to_int(ret), (int)0);
298+
EXPECT_EQ((int)metacall_value_to_int(ret), (int)12);
300299

301-
// metacall_value_destroy(ret);
300+
metacall_value_destroy(ret);
301+
}
302302

303303
/* References (Native) */
304304
{

0 commit comments

Comments
 (0)