CanadaHonk / porffor

A from-scratch experimental AOT JS engine, written in JS
https://porffor.dev
MIT License
2.59k stars 59 forks source link

[ffi] Failing to bind malloc() and free() in libc #191

Open shirakaba opened 2 months ago

shirakaba commented 2 months ago

I'm trying to use objcgetClassList(:_:) via Porffor's experimental FFI library. Here's an example of using it in C:

int numClasses;
Class * classes = NULL;

classes = NULL;
numClasses = objc_getClassList(NULL, 0);

if (numClasses > 0 )
{
    classes = malloc(sizeof(Class) * numClasses);
    numClasses = objc_getClassList(classes, numClasses);
    free(classes);
}

I'm referring to NodObjC, which demonstrates how to access libc and libobjc APIs via ffi-napi.

(Another more modern effort, objc also exists.)

Here's what I've got so far:

/// <reference types="porffor/compiler/builtins/porffor" />

const { malloc, free } = (Porffor as any).dlopen("libc.dylib", {
  malloc: { result: "pointer", parameters: ["size_t"] },
  free: { result: "void", parameters: ["pointer"] },
});

const { objc_getClassList } = (Porffor as any).dlopen("libobjc.dylib", {
  objc_getClassList: { result: "i32", parameters: ["pointer", "i32"] },
});

// FIXME: need to be able to express: sizeof(Class).
// For now we're hard-coding it based on:
// https://github.com/TooTallNate/NodObjC/blob/e4710fb8b73d3a2860de1e959e335a6de3e2191c/test/archive/core/getClassList.js#L13
const sizeofClass = 8;
const numClasses = objc_getClassList(null, 0);
const classes = malloc(numClasses * sizeofClass);
objc_getClassList(classes, 0);

console.log("Classes:", classes);
// TODO: Loop over Class*. Will require support for pointer manipulation like this:
// https://github.com/TooTallNate/NodObjC/blob/e4710fb8b73d3a2860de1e959e335a6de3e2191c/test/archive/core/getClassList.js#L13

free(classes);

It actually compiles if you leave out the malloc() and free() usages and just evaluate numClasses. But with the full example above, I'm getting some compilation errors:

porf --native dist/index.js

porffor_tmp.c:59:15: error: unknown type name 'undefined'
i32 (*malloc)(undefined l0);
              ^
porffor_tmp.c:59:7: error: redefinition of 'malloc' as different kind of symbol
i32 (*malloc)(undefined l0);
      ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/malloc/_malloc.h:54:7: note: previous definition is here
void *malloc(size_t __size) __result_use_check __alloc_size(1) _MALLOC_TYPED(malloc_type_malloc, 1);
      ^
porffor_tmp.c:60:13: error: unknown type name 'undefined'
i32 (*free)(undefined l0);
            ^
porffor_tmp.c:60:7: error: redefinition of 'free' as different kind of symbol
i32 (*free)(undefined l0);
      ^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/malloc/_malloc.h:56:7: note: previous definition is here
void  free(void * __unsafe_indexable);
      ^
porffor_tmp.c:10190:9: error: redefinition of '_dl'
  void* _dl = dlopen("libobjc.dylib", RTLD_LAZY);
        ^
porffor_tmp.c:10187:9: note: previous definition is here
  void* _dl = dlopen("libc.dylib", RTLD_LAZY);
        ^
porffor_tmp.c:10196:11: error: assigning to 'f64' (aka 'double') from incompatible type 'void *'
  classes = (*malloc)((i32)(numClasses * sizeofClass));
          ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6 errors generated.
Error: Command failed: clang porffor_tmp.c -o ./porffor_tmp -Ofast -flto=thin -march=native -s -ffast-math -fno-exceptions -fno-ident -fno-asynchronous-unwind-tables -ffunction-sections -fdata-sections
Rob23oba commented 2 months ago

size_t and void are currently not types supported by porffor, you might be able to use u64 and undefined instead