koffi 1.1.0-beta.3 → 1.1.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CMakeLists.txt CHANGED
@@ -65,9 +65,6 @@ if(WIN32)
65
65
  target_compile_definitions(koffi PRIVATE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE)
66
66
  target_link_libraries(koffi PRIVATE ws2_32)
67
67
  endif()
68
- if(MSVC)
69
- target_compile_options(koffi PRIVATE /wd4200)
70
- else()
71
- target_compile_options(koffi PRIVATE -fno-exceptions -Wno-missing-field-initializers
72
- -fno-strict-aliasing)
68
+ if(NOT MSVC)
69
+ target_compile_options(koffi PRIVATE -fno-exceptions -fno-strict-aliasing)
73
70
  endif()
package/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  - [Introduction](#introduction)
4
4
  - [Get started](#get-started)
5
5
  - [Extra features](#extra-features)
6
+ * [Type information](#type-information)
6
7
  * [C arrays](#c-arrays)
7
8
  * [Variadic functions](#variadic-functions)
8
9
  * [Asynchronous calls](#asynchronous-calls)
@@ -218,6 +219,13 @@ while (!WindowShouldClose()) {
218
219
 
219
220
  # Extra features
220
221
 
222
+ ## Type information
223
+
224
+ Koffi exposes three functions to explore type information:
225
+ - `koffi.sizeof(type)` to get the size of a type
226
+ - `koffi.alignof(type)` to get the alignment of a type
227
+ - `koffi.introspect(type)` to get the definition of a type (only for structs for now)
228
+
221
229
  ## C arrays
222
230
 
223
231
  Fixed-size arrays are declared with `koffi.array(type, length)`. Just like in C, they cannot be passed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "koffi",
3
- "version": "1.1.0-beta.3",
3
+ "version": "1.1.0-beta.6",
4
4
  "description": "Fast and simple FFI (foreign function interface) for Node.js",
5
5
  "keywords": [
6
6
  "foreign",
package/src/call.cc CHANGED
@@ -20,8 +20,8 @@
20
20
 
21
21
  namespace RG {
22
22
 
23
- CallData::CallData(Napi::Env env, const FunctionInfo *func, InstanceMemory *mem, bool debug)
24
- : env(env), instance(env.GetInstanceData<InstanceData>()), func(func), debug(debug),
23
+ CallData::CallData(Napi::Env env, InstanceData *instance, const FunctionInfo *func, InstanceMemory *mem)
24
+ : env(env), instance(instance), func(func), debug(instance->debug),
25
25
  mem(mem), old_stack_mem(mem->stack), old_heap_mem(mem->heap)
26
26
  {
27
27
  mem->depth++;
@@ -67,7 +67,7 @@ const char *CallData::PushString(const Napi::Value &value)
67
67
 
68
68
  len++;
69
69
 
70
- buf.ptr = (char *)Allocator::Allocate(&mem->big_alloc, (Size)len);
70
+ buf.ptr = (char *)Allocator::Allocate(&call_alloc, (Size)len);
71
71
  buf.len = (Size)len;
72
72
 
73
73
  status = napi_get_value_string_utf8(env, value, buf.ptr, (size_t)buf.len, &len);
@@ -104,7 +104,7 @@ const char16_t *CallData::PushString16(const Napi::Value &value)
104
104
 
105
105
  len++;
106
106
 
107
- buf.ptr = (char16_t *)Allocator::Allocate(&mem->big_alloc, (Size)len * 2);
107
+ buf.ptr = (char16_t *)Allocator::Allocate(&call_alloc, (Size)len * 2);
108
108
  buf.len = (Size)len;
109
109
 
110
110
  status = napi_get_value_string_utf16(env, value, buf.ptr, (size_t)buf.len, &len);
@@ -822,6 +822,19 @@ Napi::Object CallData::PopArray(const uint8_t *src, const TypeInfo *type, int16_
822
822
  RG_UNREACHABLE();
823
823
  }
824
824
 
825
+ Napi::Value CallData::Run(const Napi::CallbackInfo &info)
826
+ {
827
+ if (!RG_UNLIKELY(Prepare(info)))
828
+ return env.Null();
829
+
830
+ if (debug) {
831
+ DumpDebug();
832
+ }
833
+ Execute();
834
+
835
+ return Complete();
836
+ }
837
+
825
838
  static void DumpMemory(const char *type, Span<const uint8_t> bytes)
826
839
  {
827
840
  if (bytes.len) {
package/src/call.hh CHANGED
@@ -55,26 +55,17 @@ class CallData {
55
55
  } result;
56
56
  uint8_t *return_ptr = nullptr;
57
57
 
58
+ LinkedAllocator call_alloc;
59
+
58
60
  public:
59
- CallData(Napi::Env env, const FunctionInfo *func, InstanceMemory *mem, bool debug);
61
+ CallData(Napi::Env env, InstanceData *instance, const FunctionInfo *func, InstanceMemory *mem);
60
62
  ~CallData();
61
63
 
62
64
  bool Prepare(const Napi::CallbackInfo &info);
63
65
  void Execute();
64
66
  Napi::Value Complete();
65
67
 
66
- Napi::Value Run(const Napi::CallbackInfo &info)
67
- {
68
- if (!RG_UNLIKELY(Prepare(info)))
69
- return env.Null();
70
-
71
- if (debug) {
72
- DumpDebug();
73
- }
74
- Execute();
75
-
76
- return Complete();
77
- }
68
+ Napi::Value Run(const Napi::CallbackInfo &info);
78
69
 
79
70
  void DumpDebug() const;
80
71
 
package/src/ffi.cc CHANGED
@@ -72,6 +72,8 @@ static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
72
72
 
73
73
  type->name = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
74
74
 
75
+ type->defn.Reset(obj, 1);
76
+
75
77
  type->primitive = PrimitiveKind::Record;
76
78
  type->align = 1;
77
79
 
@@ -296,6 +298,61 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
296
298
  return external;
297
299
  }
298
300
 
301
+ static Napi::Value GetTypeSize(const Napi::CallbackInfo &info)
302
+ {
303
+ Napi::Env env = info.Env();
304
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
305
+
306
+ if (info.Length() < 1) {
307
+ ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
308
+ return env.Null();
309
+ }
310
+
311
+ const TypeInfo *type = ResolveType(instance, info[0]);
312
+ if (!type)
313
+ return env.Null();
314
+
315
+ return Napi::Number::New(env, type->size);
316
+ }
317
+
318
+ static Napi::Value GetTypeAlign(const Napi::CallbackInfo &info)
319
+ {
320
+ Napi::Env env = info.Env();
321
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
322
+
323
+ if (info.Length() < 1) {
324
+ ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
325
+ return env.Null();
326
+ }
327
+
328
+ const TypeInfo *type = ResolveType(instance, info[0]);
329
+ if (!type)
330
+ return env.Null();
331
+
332
+ return Napi::Number::New(env, type->align);
333
+ }
334
+
335
+ static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
336
+ {
337
+ Napi::Env env = info.Env();
338
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
339
+
340
+ if (info.Length() < 1) {
341
+ ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
342
+ return env.Null();
343
+ }
344
+
345
+ const TypeInfo *type = ResolveType(instance, info[0]);
346
+ if (!type)
347
+ return env.Null();
348
+ if (type->defn.IsEmpty()) {
349
+ ThrowError<Napi::TypeError>(env, "Definition of type %1 is not available", type->name);
350
+ return env.Null();
351
+ }
352
+
353
+ return type->defn.Value();
354
+ }
355
+
299
356
  static Span<uint8_t> AllocateAndAlign16(Allocator *alloc, Size size)
300
357
  {
301
358
  RG_ASSERT(AlignLen(size, 16) == size);
@@ -344,7 +401,7 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
344
401
  }
345
402
 
346
403
  InstanceMemory *mem = AllocateCallMemory(instance);
347
- CallData call(env, func, mem, instance->debug);
404
+ CallData call(env, instance, func, mem);
348
405
 
349
406
  return call.Run(info);
350
407
  }
@@ -404,7 +461,7 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
404
461
  return env.Null();
405
462
 
406
463
  InstanceMemory *mem = AllocateCallMemory(instance);
407
- CallData call(env, &func, mem, instance->debug);
464
+ CallData call(env, instance, &func, mem);
408
465
 
409
466
  return call.Run(info);
410
467
  }
@@ -417,10 +474,10 @@ class AsyncCall: public Napi::AsyncWorker {
417
474
  bool prepared = false;
418
475
 
419
476
  public:
420
- AsyncCall(Napi::Env env, InstanceMemory *mem, FunctionInfo *func, bool debug,
421
- Napi::Function &callback)
477
+ AsyncCall(Napi::Env env, InstanceData *instance, const FunctionInfo *func,
478
+ InstanceMemory *mem, Napi::Function &callback)
422
479
  : Napi::AsyncWorker(callback), env(env), func(func->Ref()),
423
- call(env, func, mem, debug) {}
480
+ call(env, instance, func, mem) {}
424
481
  ~AsyncCall() { func->Unref(); }
425
482
 
426
483
  bool Prepare(const Napi::CallbackInfo &info) {
@@ -480,7 +537,7 @@ static Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
480
537
  }
481
538
 
482
539
  InstanceMemory *mem = AllocateCallMemory(instance);
483
- AsyncCall *async = new AsyncCall(env, mem, func, instance->debug, callback);
540
+ AsyncCall *async = new AsyncCall(env, instance, func, mem, callback);
484
541
 
485
542
  if (async->Prepare(info) && instance->debug) {
486
543
  async->DumpDebug();
@@ -870,6 +927,9 @@ static void SetExports(Napi::Env env, Func func)
870
927
  func("handle", Napi::Function::New(env, CreateHandleType));
871
928
  func("pointer", Napi::Function::New(env, CreatePointerType));
872
929
  func("array", Napi::Function::New(env, CreateArrayType));
930
+ func("sizeof", Napi::Function::New(env, GetTypeSize));
931
+ func("alignof", Napi::Function::New(env, GetTypeAlign));
932
+ func("introspect", Napi::Function::New(env, GetTypeDefinition));
873
933
  func("load", Napi::Function::New(env, LoadSharedLibrary));
874
934
  func("in", Napi::Function::New(env, MarkIn));
875
935
  func("out", Napi::Function::New(env, MarkOut));
package/src/ffi.hh CHANGED
@@ -70,6 +70,8 @@ struct TypeInfo {
70
70
  const char *name;
71
71
  napi_type_tag tag;
72
72
 
73
+ Napi::ObjectReference defn;
74
+
73
75
  PrimitiveKind primitive;
74
76
  int16_t size;
75
77
  int16_t align;
@@ -166,7 +168,6 @@ struct InstanceMemory {
166
168
 
167
169
  Span<uint8_t> stack;
168
170
  Span<uint8_t> heap;
169
- IndirectBlockAllocator big_alloc { &mem_alloc };
170
171
 
171
172
  int depth;
172
173
  bool temporary;