koffi 1.0.1 → 1.0.4

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.
Files changed (50) hide show
  1. package/CMakeLists.txt +12 -11
  2. package/README.md +23 -20
  3. package/build/qemu/1.0.4/koffi_darwin_x64.tar.gz +0 -0
  4. package/build/qemu/1.0.4/koffi_freebsd_arm64.tar.gz +0 -0
  5. package/build/qemu/1.0.4/koffi_freebsd_ia32.tar.gz +0 -0
  6. package/build/qemu/1.0.4/koffi_freebsd_x64.tar.gz +0 -0
  7. package/build/qemu/1.0.4/koffi_linux_arm.tar.gz +0 -0
  8. package/build/qemu/1.0.4/koffi_linux_arm64.tar.gz +0 -0
  9. package/build/qemu/1.0.4/koffi_linux_ia32.tar.gz +0 -0
  10. package/build/qemu/1.0.4/koffi_linux_x64.tar.gz +0 -0
  11. package/build/qemu/1.0.4/koffi_win32_ia32.tar.gz +0 -0
  12. package/build/qemu/1.0.4/koffi_win32_x64.tar.gz +0 -0
  13. package/package.json +8 -4
  14. package/qemu/qemu.js +794 -0
  15. package/qemu/registry/machines.json +415 -0
  16. package/qemu/registry/sha256sum.txt +45 -0
  17. package/src/{call_arm32.cc → abi_arm32.cc} +153 -219
  18. package/src/{call_arm32_fwd.S → abi_arm32_fwd.S} +0 -0
  19. package/src/{call_arm64.cc → abi_arm64.cc} +130 -123
  20. package/src/{call_arm64_fwd.S → abi_arm64_fwd.S} +0 -0
  21. package/src/{call_x64_sysv.cc → abi_x64_sysv.cc} +138 -135
  22. package/src/{call_x64_sysv_fwd.S → abi_x64_sysv_fwd.S} +0 -0
  23. package/src/{call_x64_win.cc → abi_x64_win.cc} +107 -99
  24. package/src/{call_x64_win_fwd.asm → abi_x64_win_fwd.asm} +0 -0
  25. package/src/{call_x86.cc → abi_x86.cc} +110 -107
  26. package/src/{call_x86_fwd.S → abi_x86_fwd.S} +0 -0
  27. package/src/{call_x86_fwd.asm → abi_x86_fwd.asm} +0 -0
  28. package/src/call.cc +353 -0
  29. package/src/call.hh +132 -4
  30. package/src/ffi.cc +16 -2
  31. package/src/ffi.hh +8 -12
  32. package/src/util.cc +7 -280
  33. package/src/util.hh +0 -107
  34. package/test/CMakeLists.txt +1 -0
  35. package/test/misc.c +355 -0
  36. package/test/misc.def +3 -0
  37. package/test/misc.js +227 -0
  38. package/test/raylib.js +165 -0
  39. package/test/sqlite.js +104 -0
  40. package/vendor/libcc/libcc.hh +1 -1
  41. package/build/qemu/1.0.1/koffi_darwin_x64.tar.gz +0 -0
  42. package/build/qemu/1.0.1/koffi_freebsd_arm64.tar.gz +0 -0
  43. package/build/qemu/1.0.1/koffi_freebsd_ia32.tar.gz +0 -0
  44. package/build/qemu/1.0.1/koffi_freebsd_x64.tar.gz +0 -0
  45. package/build/qemu/1.0.1/koffi_linux_arm.tar.gz +0 -0
  46. package/build/qemu/1.0.1/koffi_linux_arm64.tar.gz +0 -0
  47. package/build/qemu/1.0.1/koffi_linux_ia32.tar.gz +0 -0
  48. package/build/qemu/1.0.1/koffi_linux_x64.tar.gz +0 -0
  49. package/build/qemu/1.0.1/koffi_win32_ia32.tar.gz +0 -0
  50. package/build/qemu/1.0.1/koffi_win32_x64.tar.gz +0 -0
package/src/call.cc ADDED
@@ -0,0 +1,353 @@
1
+ // This program is free software: you can redistribute it and/or modify
2
+ // it under the terms of the GNU Affero General Public License as published by
3
+ // the Free Software Foundation, either version 3 of the License, or
4
+ // (at your option) any later version.
5
+ //
6
+ // This program is distributed in the hope that it will be useful,
7
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
8
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9
+ // GNU Affero General Public License for more details.
10
+ //
11
+ // You should have received a copy of the GNU Affero General Public License
12
+ // along with this program. If not, see https://www.gnu.org/licenses/.
13
+
14
+ #include "vendor/libcc/libcc.hh"
15
+ #include "call.hh"
16
+ #include "ffi.hh"
17
+ #include "util.hh"
18
+
19
+ #include <napi.h>
20
+
21
+ namespace RG {
22
+
23
+ CallData::CallData(Napi::Env env, InstanceData *instance, const FunctionInfo *func)
24
+ : env(env), instance(instance), func(func),
25
+ stack_mem(&instance->stack_mem), heap_mem(&instance->heap_mem),
26
+ old_stack_mem(instance->stack_mem), old_heap_mem(instance->heap_mem)
27
+ {
28
+ RG_ASSERT(AlignUp(stack_mem->ptr, 16) == stack_mem->ptr);
29
+ RG_ASSERT(AlignUp(stack_mem->end(), 16) == stack_mem->end());
30
+ }
31
+
32
+ CallData::~CallData()
33
+ {
34
+ instance->stack_mem = old_stack_mem;
35
+ instance->heap_mem = old_heap_mem;
36
+ }
37
+
38
+ const char *CallData::PushString(const Napi::Value &value)
39
+ {
40
+ RG_ASSERT(value.IsString());
41
+
42
+ Napi::Env env = value.Env();
43
+
44
+ Span<char> buf;
45
+ size_t len = 0;
46
+ napi_status status;
47
+
48
+ buf.ptr = (char *)heap_mem->ptr;
49
+ buf.len = std::max((Size)0, heap_mem->len - Kibibytes(32));
50
+
51
+ status = napi_get_value_string_utf8(env, value, buf.ptr, (size_t)buf.len, &len);
52
+ RG_ASSERT(status == napi_ok);
53
+
54
+ len++;
55
+
56
+ if (RG_LIKELY(len < (size_t)buf.len)) {
57
+ heap_mem->ptr += (Size)len;
58
+ heap_mem->len -= (Size)len;
59
+ } else {
60
+ status = napi_get_value_string_utf8(env, value, nullptr, 0, &len);
61
+ RG_ASSERT(status == napi_ok);
62
+
63
+ len++;
64
+
65
+ buf.ptr = (char *)Allocator::Allocate(&big_alloc, (Size)len);
66
+ buf.len = (Size)len;
67
+
68
+ status = napi_get_value_string_utf8(env, value, buf.ptr, (size_t)buf.len, &len);
69
+ RG_ASSERT(status == napi_ok);
70
+ }
71
+
72
+ return buf.ptr;
73
+ }
74
+
75
+ const char16_t *CallData::PushString16(const Napi::Value &value)
76
+ {
77
+ RG_ASSERT(value.IsString());
78
+
79
+ Napi::Env env = value.Env();
80
+
81
+ Span<char16_t> buf;
82
+ size_t len = 0;
83
+ napi_status status;
84
+
85
+ buf.ptr = (char16_t *)heap_mem->ptr;
86
+ buf.len = std::max((Size)0, heap_mem->len - Kibibytes(32)) / 2;
87
+
88
+ status = napi_get_value_string_utf16(env, value, buf.ptr, (size_t)buf.len, &len);
89
+ RG_ASSERT(status == napi_ok);
90
+
91
+ len++;
92
+
93
+ if (RG_LIKELY(len < (size_t)buf.len)) {
94
+ heap_mem->ptr += (Size)len * 2;
95
+ heap_mem->len -= (Size)len * 2;
96
+ } else {
97
+ status = napi_get_value_string_utf16(env, value, nullptr, 0, &len);
98
+ RG_ASSERT(status == napi_ok);
99
+
100
+ len++;
101
+
102
+ buf.ptr = (char16_t *)Allocator::Allocate(&big_alloc, (Size)len * 2);
103
+ buf.len = (Size)len;
104
+
105
+ status = napi_get_value_string_utf16(env, value, buf.ptr, (size_t)buf.len, &len);
106
+ RG_ASSERT(status == napi_ok);
107
+ }
108
+
109
+ return buf.ptr;
110
+ }
111
+
112
+ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t *dest)
113
+ {
114
+ Napi::Env env = obj.Env();
115
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
116
+
117
+ RG_ASSERT(IsObject(obj));
118
+ RG_ASSERT(type->primitive == PrimitiveKind::Record);
119
+
120
+ for (const RecordMember &member: type->members) {
121
+ Napi::Value value = obj.Get(member.name);
122
+
123
+ if (RG_UNLIKELY(value.IsUndefined())) {
124
+ ThrowError<Napi::TypeError>(env, "Missing expected object property '%1'", member.name);
125
+ return false;
126
+ }
127
+
128
+ dest = AlignUp(dest, member.align);
129
+
130
+ switch (member.type->primitive) {
131
+ case PrimitiveKind::Void: { RG_UNREACHABLE(); } break;
132
+
133
+ case PrimitiveKind::Bool: {
134
+ if (RG_UNLIKELY(!value.IsBoolean())) {
135
+ ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected boolean", GetValueType(instance, value), member.name);
136
+ return false;
137
+ }
138
+
139
+ bool b = value.As<Napi::Boolean>();
140
+ *(bool *)dest = b;
141
+ } break;
142
+
143
+ case PrimitiveKind::Int8:
144
+ case PrimitiveKind::UInt8:
145
+ case PrimitiveKind::Int16:
146
+ case PrimitiveKind::UInt16:
147
+ case PrimitiveKind::Int32:
148
+ case PrimitiveKind::UInt32:
149
+ case PrimitiveKind::Int64:
150
+ case PrimitiveKind::UInt64: {
151
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
152
+ ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected number", GetValueType(instance, value), member.name);
153
+ return false;
154
+ }
155
+
156
+ int64_t v = CopyNumber<int64_t>(value);
157
+ memcpy(dest, &v, member.type->size); // Little Endian
158
+ } break;
159
+ case PrimitiveKind::String: {
160
+ if (RG_UNLIKELY(!value.IsString())) {
161
+ ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected string", GetValueType(instance, value), member.name);
162
+ return false;
163
+ }
164
+
165
+ const char *str = PushString(value);
166
+ if (RG_UNLIKELY(!str))
167
+ return false;
168
+ *(const char **)dest = str;
169
+ } break;
170
+ case PrimitiveKind::String16: {
171
+ if (RG_UNLIKELY(!value.IsString())) {
172
+ ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected string", GetValueType(instance, value), member.name);
173
+ return false;
174
+ }
175
+
176
+ const char16_t *str16 = PushString16(value);
177
+ if (RG_UNLIKELY(!str16))
178
+ return false;
179
+ *(const char16_t **)dest = str16;
180
+ } break;
181
+ case PrimitiveKind::Pointer: {
182
+ if (RG_UNLIKELY(!CheckValueTag(instance, value, member.type))) {
183
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member '%2', expected %3", GetValueType(instance, value), member.name, member.type->name);
184
+ return false;
185
+ }
186
+
187
+ Napi::External external = value.As<Napi::External<void>>();
188
+ void *ptr = external.Data();
189
+ *(void **)dest = ptr;
190
+ } break;
191
+ case PrimitiveKind::Record: {
192
+ if (RG_UNLIKELY(!IsObject(value))) {
193
+ ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected object", GetValueType(instance, value), member.name);
194
+ return false;
195
+ }
196
+
197
+ Napi::Object obj = value.As<Napi::Object>();
198
+ if (!PushObject(obj, member.type, dest))
199
+ return false;
200
+ } break;
201
+ case PrimitiveKind::Float32: {
202
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
203
+ ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected number", GetValueType(instance, value), member.name);
204
+ return false;
205
+ }
206
+
207
+ float f = CopyNumber<float>(value);
208
+ memcpy(dest, &f, 4);
209
+ } break;
210
+ case PrimitiveKind::Float64: {
211
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
212
+ ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected number", GetValueType(instance, value), member.name);
213
+ return false;
214
+ }
215
+
216
+ double d = CopyNumber<double>(value);
217
+ memcpy(dest, &d, 8);
218
+ } break;
219
+ }
220
+
221
+ dest += member.type->size;
222
+ }
223
+
224
+ return true;
225
+ }
226
+
227
+ void CallData::PopObject(Napi::Object obj, const uint8_t *ptr, const TypeInfo *type)
228
+ {
229
+ Napi::Env env = obj.Env();
230
+ InstanceData *instance = env.GetInstanceData<InstanceData>();
231
+
232
+ RG_ASSERT(type->primitive == PrimitiveKind::Record);
233
+
234
+ for (const RecordMember &member: type->members) {
235
+ ptr = AlignUp(ptr, member.align);
236
+
237
+ switch (member.type->primitive) {
238
+ case PrimitiveKind::Void: { RG_UNREACHABLE(); } break;
239
+
240
+ case PrimitiveKind::Bool: {
241
+ bool b = *(bool *)ptr;
242
+ obj.Set(member.name, Napi::Boolean::New(env, b));
243
+ } break;
244
+ case PrimitiveKind::Int8: {
245
+ double d = (double)*(int8_t *)ptr;
246
+ obj.Set(member.name, Napi::Number::New(env, d));
247
+ } break;
248
+ case PrimitiveKind::UInt8: {
249
+ double d = (double)*(uint8_t *)ptr;
250
+ obj.Set(member.name, Napi::Number::New(env, d));
251
+ } break;
252
+ case PrimitiveKind::Int16: {
253
+ double d = (double)*(int16_t *)ptr;
254
+ obj.Set(member.name, Napi::Number::New(env, d));
255
+ } break;
256
+ case PrimitiveKind::UInt16: {
257
+ double d = (double)*(uint16_t *)ptr;
258
+ obj.Set(member.name, Napi::Number::New(env, d));
259
+ } break;
260
+ case PrimitiveKind::Int32: {
261
+ double d = (double)*(int32_t *)ptr;
262
+ obj.Set(member.name, Napi::Number::New(env, d));
263
+ } break;
264
+ case PrimitiveKind::UInt32: {
265
+ double d = (double)*(uint32_t *)ptr;
266
+ obj.Set(member.name, Napi::Number::New(env, d));
267
+ } break;
268
+ case PrimitiveKind::Int64: {
269
+ int64_t v = *(int64_t *)ptr;
270
+ obj.Set(member.name, Napi::BigInt::New(env, v));
271
+ } break;
272
+ case PrimitiveKind::UInt64: {
273
+ uint64_t v = *(uint64_t *)ptr;
274
+ obj.Set(member.name, Napi::BigInt::New(env, v));
275
+ } break;
276
+ case PrimitiveKind::String: {
277
+ const char *str = *(const char **)ptr;
278
+ obj.Set(member.name, Napi::String::New(env, str));
279
+ } break;
280
+ case PrimitiveKind::String16: {
281
+ const char16_t *str16 = *(const char16_t **)ptr;
282
+ obj.Set(member.name, Napi::String::New(env, str16));
283
+ } break;
284
+ case PrimitiveKind::Pointer: {
285
+ void *ptr2 = *(void **)ptr;
286
+
287
+ Napi::External<void> external = Napi::External<void>::New(env, ptr2);
288
+ SetValueTag(instance, external, member.type);
289
+
290
+ obj.Set(member.name, external);
291
+ } break;
292
+ case PrimitiveKind::Record: {
293
+ Napi::Object obj2 = PopObject(ptr, member.type);
294
+ obj.Set(member.name, obj2);
295
+ } break;
296
+ case PrimitiveKind::Float32: {
297
+ float f;
298
+ memcpy(&f, ptr, 4);
299
+ obj.Set(member.name, Napi::Number::New(env, (double)f));
300
+ } break;
301
+ case PrimitiveKind::Float64: {
302
+ double d;
303
+ memcpy(&d, ptr, 8);
304
+ obj.Set(member.name, Napi::Number::New(env, d));
305
+ } break;
306
+ }
307
+
308
+ ptr += member.type->size;
309
+ }
310
+ }
311
+
312
+ Napi::Object CallData::PopObject(const uint8_t *ptr, const TypeInfo *type)
313
+ {
314
+ Napi::Object obj = Napi::Object::New(env);
315
+ PopObject(obj, ptr, type);
316
+ return obj;
317
+ }
318
+
319
+ static void DumpMemory(const char *type, Span<const uint8_t> bytes)
320
+ {
321
+ if (bytes.len) {
322
+ PrintLn(stderr, "%1 at 0x%2 (%3):", type, bytes.ptr, FmtMemSize(bytes.len));
323
+
324
+ for (const uint8_t *ptr = bytes.begin(); ptr < bytes.end();) {
325
+ Print(stderr, " [0x%1 %2 %3] ", FmtArg(ptr).Pad0(-16),
326
+ FmtArg((ptr - bytes.begin()) / sizeof(void *)).Pad(-4),
327
+ FmtArg(ptr - bytes.begin()).Pad(-4));
328
+ for (int i = 0; ptr < bytes.end() && i < (int)sizeof(void *); i++, ptr++) {
329
+ Print(stderr, " %1", FmtHex(*ptr).Pad0(-2));
330
+ }
331
+ PrintLn(stderr);
332
+ }
333
+ }
334
+ }
335
+
336
+ void CallData::DumpDebug() const
337
+ {
338
+ PrintLn(stderr, "%!..+---- %1 (%2) ----%!0", func->name, CallConventionNames[(int)func->convention]);
339
+
340
+ if (func->parameters.len) {
341
+ PrintLn(stderr, "Parameters:");
342
+ for (Size i = 0; i < func->parameters.len; i++) {
343
+ const ParameterInfo &param = func->parameters[i];
344
+ PrintLn(stderr, " %1 = %2 (%3)", i, param.type->name, FmtMemSize(param.type->size));
345
+ }
346
+ }
347
+ PrintLn(stderr, "Return: %1 (%2)", func->ret.type->name, FmtMemSize(func->ret.type->size));
348
+
349
+ DumpMemory("Stack", GetStack());
350
+ DumpMemory("Heap", GetHeap());
351
+ }
352
+
353
+ }
package/src/call.hh CHANGED
@@ -14,15 +14,143 @@
14
14
  #pragma once
15
15
 
16
16
  #include "vendor/libcc/libcc.hh"
17
+ #include "ffi.hh"
18
+ #include "util.hh"
17
19
 
18
20
  #include <napi.h>
19
21
 
20
22
  namespace RG {
21
23
 
22
- struct InstanceData;
23
- struct FunctionInfo;
24
-
25
24
  bool AnalyseFunction(InstanceData *instance, FunctionInfo *func);
26
- Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, const Napi::CallbackInfo &info);
25
+
26
+ class CallData {
27
+ Napi::Env env;
28
+ InstanceData *instance;
29
+ const FunctionInfo *func;
30
+
31
+ struct OutObject {
32
+ Napi::Object obj;
33
+ const uint8_t *ptr;
34
+ const TypeInfo *type;
35
+ };
36
+
37
+ Span<uint8_t> *stack_mem;
38
+ Span<uint8_t> *heap_mem;
39
+ LocalArray<OutObject, MaxOutParameters> out_objects;
40
+ BlockAllocator big_alloc;
41
+
42
+ Span<uint8_t> old_stack_mem;
43
+ Span<uint8_t> old_heap_mem;
44
+
45
+ union {
46
+ uint32_t u32;
47
+ uint64_t u64;
48
+ float f;
49
+ double d;
50
+ void *ptr;
51
+ uint8_t buf[32];
52
+ } result;
53
+ uint8_t *return_ptr = nullptr;
54
+
55
+ public:
56
+ CallData(Napi::Env env, InstanceData *instance, const FunctionInfo *func);
57
+ ~CallData();
58
+
59
+ Span<uint8_t> GetStack() const
60
+ {
61
+ uint8_t *sp = stack_mem->end();
62
+ Size len = old_stack_mem.end() - sp;
63
+
64
+ return MakeSpan(sp, len);
65
+ }
66
+ uint8_t *GetSP() const { return stack_mem->end(); };
67
+
68
+ Span<uint8_t> GetHeap() const
69
+ {
70
+ uint8_t *ptr = old_heap_mem.ptr;
71
+ Size len = heap_mem->ptr - ptr;
72
+
73
+ return MakeSpan(ptr, len);
74
+ }
75
+
76
+ bool Prepare(const Napi::CallbackInfo &info);
77
+ void Execute();
78
+ Napi::Value Complete();
79
+
80
+ Napi::Value Run(const Napi::CallbackInfo &info)
81
+ {
82
+ if (!RG_UNLIKELY(Prepare(info)))
83
+ return env.Null();
84
+
85
+ if (instance->debug) {
86
+ DumpDebug();
87
+ }
88
+
89
+ Execute();
90
+ return Complete();
91
+ }
92
+
93
+ void DumpDebug() const;
94
+
95
+ private:
96
+ template <typename T = void>
97
+ bool AllocStack(Size size, Size align, T **out_ptr = nullptr);
98
+ template <typename T = void>
99
+ bool AllocHeap(Size size, Size align, T **out_ptr = nullptr);
100
+
101
+ const char *PushString(const Napi::Value &value);
102
+ const char16_t *PushString16(const Napi::Value &value);
103
+ bool PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t *dest);
104
+
105
+ void PopObject(Napi::Object obj, const uint8_t *ptr, const TypeInfo *type);
106
+ Napi::Object PopObject(const uint8_t *ptr, const TypeInfo *type);
107
+ };
108
+
109
+ template <typename T>
110
+ bool CallData::AllocStack(Size size, Size align, T **out_ptr)
111
+ {
112
+ uint8_t *ptr = AlignDown(stack_mem->end() - size, align);
113
+ Size delta = stack_mem->end() - ptr;
114
+
115
+ if (RG_UNLIKELY(stack_mem->len < delta)) {
116
+ ThrowError<Napi::Error>(env, "FFI call is taking up too much memory");
117
+ return false;
118
+ }
119
+
120
+ if (instance->debug) {
121
+ memset(ptr, 0, delta);
122
+ }
123
+
124
+ stack_mem->len -= delta;
125
+
126
+ if (out_ptr) {
127
+ *out_ptr = (T *)ptr;
128
+ }
129
+ return true;
130
+ }
131
+
132
+ template <typename T>
133
+ bool CallData::AllocHeap(Size size, Size align, T **out_ptr)
134
+ {
135
+ uint8_t *ptr = AlignUp(heap_mem->ptr, align);
136
+ Size delta = size + (ptr - heap_mem->ptr);
137
+
138
+ if (RG_UNLIKELY(delta > heap_mem->len)) {
139
+ ThrowError<Napi::Error>(env, "FFI call is taking up too much memory");
140
+ return false;
141
+ }
142
+
143
+ if (instance->debug) {
144
+ memset(heap_mem->ptr, 0, (size_t)delta);
145
+ }
146
+
147
+ heap_mem->ptr += delta;
148
+ heap_mem->len -= delta;
149
+
150
+ if (out_ptr) {
151
+ *out_ptr = (T *)ptr;
152
+ }
153
+ return true;
154
+ }
27
155
 
28
156
  }
package/src/ffi.cc CHANGED
@@ -247,7 +247,13 @@ static Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
247
247
  InstanceData *instance = env.GetInstanceData<InstanceData>();
248
248
  FunctionInfo *func = (FunctionInfo *)info.Data();
249
249
 
250
- return TranslateCall(instance, func, info);
250
+ if (info.Length() < (uint32_t)func->parameters.len) {
251
+ ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, info.Length());
252
+ return env.Null();
253
+ }
254
+
255
+ CallData call(env, instance, func);
256
+ return call.Run(info);
251
257
  }
252
258
 
253
259
  static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
@@ -265,6 +271,10 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
265
271
  func.parameters.Leak();
266
272
  };
267
273
 
274
+ if (info.Length() < (uint32_t)func.parameters.len) {
275
+ ThrowError<Napi::TypeError>(env, "Expected %1 arguments or more, got %2", func.parameters.len, info.Length());
276
+ return env.Null();
277
+ }
268
278
  if ((info.Length() - func.parameters.len) % 2) {
269
279
  ThrowError<Napi::Error>(env, "Missing value argument for variadic call");
270
280
  return env.Null();
@@ -299,7 +309,8 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
299
309
  if (!AnalyseFunction(instance, &func))
300
310
  return env.Null();
301
311
 
302
- return TranslateCall(instance, &func, info);
312
+ CallData call(env, instance, &func);
313
+ return call.Run(info);
303
314
  }
304
315
 
305
316
  static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value ret,
@@ -573,6 +584,8 @@ static Napi::Object InitBaseTypes(Napi::Env env)
573
584
  RegisterPrimitiveType(instance, "char", PrimitiveKind::Int8, 1, 1);
574
585
  RegisterPrimitiveType(instance, "uchar", PrimitiveKind::UInt8, 1, 1);
575
586
  RegisterPrimitiveType(instance, "unsigned char", PrimitiveKind::UInt8, 1, 1);
587
+ RegisterPrimitiveType(instance, "char16", PrimitiveKind::Int16, 2, 2);
588
+ RegisterPrimitiveType(instance, "char16_t", PrimitiveKind::Int16, 2, 2);
576
589
  RegisterPrimitiveType(instance, "int16", PrimitiveKind::Int16, 2, 2);
577
590
  RegisterPrimitiveType(instance, "int16_t", PrimitiveKind::Int16, 2, 2);
578
591
  RegisterPrimitiveType(instance, "uint16", PrimitiveKind::UInt16, 2, 2);
@@ -603,6 +616,7 @@ static Napi::Object InitBaseTypes(Napi::Env env)
603
616
  RegisterPrimitiveType(instance, "float", PrimitiveKind::Float32, 4, alignof(float));
604
617
  RegisterPrimitiveType(instance, "double", PrimitiveKind::Float64, 8, alignof(double));
605
618
  RegisterPrimitiveType(instance, "string", PrimitiveKind::String, RG_SIZE(void *), alignof(void *));
619
+ RegisterPrimitiveType(instance, "string16", PrimitiveKind::String16, RG_SIZE(void *), alignof(void *));
606
620
 
607
621
  Napi::Object types = Napi::Object::New(env);
608
622
  for (TypeInfo &type: instance->types) {
package/src/ffi.hh CHANGED
@@ -26,7 +26,6 @@ extern const int TypeInfoMarker;
26
26
 
27
27
  enum class PrimitiveKind {
28
28
  Void,
29
-
30
29
  Bool,
31
30
  Int8,
32
31
  UInt8,
@@ -36,17 +35,15 @@ enum class PrimitiveKind {
36
35
  UInt32,
37
36
  Int64,
38
37
  UInt64,
39
- Float32,
40
- Float64,
41
38
  String,
42
-
39
+ String16,
43
40
  Pointer,
44
-
45
- Record
41
+ Record,
42
+ Float32,
43
+ Float64
46
44
  };
47
45
  static const char *const PrimitiveKindNames[] = {
48
46
  "Void",
49
-
50
47
  "Bool",
51
48
  "Int8",
52
49
  "UInt8",
@@ -56,13 +53,12 @@ static const char *const PrimitiveKindNames[] = {
56
53
  "UInt32",
57
54
  "Int64",
58
55
  "UInt64",
59
- "Float32",
60
- "Float64",
61
56
  "String",
62
-
57
+ "String16",
63
58
  "Pointer",
64
-
65
- "Record"
59
+ "Record",
60
+ "Float32",
61
+ "Float64"
66
62
  };
67
63
 
68
64
  struct TypeInfo;