koffi 1.0.3 → 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 (36) hide show
  1. package/README.md +22 -21
  2. package/build/qemu/1.0.4/koffi_darwin_x64.tar.gz +0 -0
  3. package/build/qemu/1.0.4/koffi_freebsd_arm64.tar.gz +0 -0
  4. package/build/qemu/1.0.4/koffi_freebsd_ia32.tar.gz +0 -0
  5. package/build/qemu/1.0.4/koffi_freebsd_x64.tar.gz +0 -0
  6. package/build/qemu/1.0.4/koffi_linux_arm.tar.gz +0 -0
  7. package/build/qemu/1.0.4/koffi_linux_arm64.tar.gz +0 -0
  8. package/build/qemu/1.0.4/koffi_linux_ia32.tar.gz +0 -0
  9. package/build/qemu/1.0.4/koffi_linux_x64.tar.gz +0 -0
  10. package/build/qemu/1.0.4/koffi_win32_ia32.tar.gz +0 -0
  11. package/build/qemu/1.0.4/koffi_win32_x64.tar.gz +0 -0
  12. package/package.json +1 -1
  13. package/src/abi_arm32.cc +119 -211
  14. package/src/abi_arm64.cc +92 -113
  15. package/src/abi_x64_sysv.cc +106 -131
  16. package/src/abi_x64_win.cc +78 -94
  17. package/src/abi_x86.cc +80 -95
  18. package/src/call.cc +144 -19
  19. package/src/call.hh +39 -3
  20. package/src/ffi.cc +11 -2
  21. package/src/ffi.hh +6 -12
  22. package/src/util.cc +0 -127
  23. package/src/util.hh +0 -16
  24. package/test/misc.c +66 -0
  25. package/test/misc.js +47 -0
  26. package/vendor/libcc/libcc.hh +1 -1
  27. package/build/qemu/1.0.3/koffi_darwin_x64.tar.gz +0 -0
  28. package/build/qemu/1.0.3/koffi_freebsd_arm64.tar.gz +0 -0
  29. package/build/qemu/1.0.3/koffi_freebsd_ia32.tar.gz +0 -0
  30. package/build/qemu/1.0.3/koffi_freebsd_x64.tar.gz +0 -0
  31. package/build/qemu/1.0.3/koffi_linux_arm.tar.gz +0 -0
  32. package/build/qemu/1.0.3/koffi_linux_arm64.tar.gz +0 -0
  33. package/build/qemu/1.0.3/koffi_linux_ia32.tar.gz +0 -0
  34. package/build/qemu/1.0.3/koffi_linux_x64.tar.gz +0 -0
  35. package/build/qemu/1.0.3/koffi_win32_ia32.tar.gz +0 -0
  36. package/build/qemu/1.0.3/koffi_win32_x64.tar.gz +0 -0
package/src/abi_x86.cc CHANGED
@@ -82,33 +82,24 @@ bool AnalyseFunction(InstanceData *instance, FunctionInfo *func)
82
82
  return true;
83
83
  }
84
84
 
85
- Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
85
+ bool CallData::Prepare(const Napi::CallbackInfo &info)
86
86
  {
87
- // Sanity checks
88
- if (info.Length() < (uint32_t)func->parameters.len) {
89
- ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, info.Length());
90
- return env.Null();
91
- }
92
-
93
- uint8_t *return_ptr = nullptr;
94
87
  uint32_t *args_ptr = nullptr;
95
88
  uint32_t *fast_ptr = nullptr;
96
89
 
97
90
  // Pass return value in register or through memory
98
91
  if (RG_UNLIKELY(!AllocStack(func->args_size, 16, &args_ptr)))
99
- return env.Null();
92
+ return false;
100
93
  if (func->convention == CallConvention::Fastcall) {
101
94
  fast_ptr = args_ptr;
102
95
  args_ptr += 4;
103
96
  }
104
97
  if (!func->ret.trivial) {
105
98
  if (RG_UNLIKELY(!AllocHeap(func->ret.type->size, 16, &return_ptr)))
106
- return env.Null();
99
+ return false;
107
100
  *((func->ret.fast ? fast_ptr : args_ptr)++) = (uint32_t)return_ptr;
108
101
  }
109
102
 
110
- LocalArray<OutObject, MaxOutParameters> out_objects;
111
-
112
103
  // Push arguments
113
104
  for (Size i = 0; i < func->parameters.len; i++) {
114
105
  const ParameterInfo &param = func->parameters[i];
@@ -122,7 +113,7 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
122
113
  case PrimitiveKind::Bool: {
123
114
  if (RG_UNLIKELY(!value.IsBoolean())) {
124
115
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected boolean", GetValueType(instance, value), i + 1);
125
- return env.Null();
116
+ return false;
126
117
  }
127
118
 
128
119
  bool b = value.As<Napi::Boolean>();
@@ -136,7 +127,7 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
136
127
  case PrimitiveKind::UInt32: {
137
128
  if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
138
129
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
139
- return env.Null();
130
+ return false;
140
131
  }
141
132
 
142
133
  int32_t v = CopyNumber<int32_t>(value);
@@ -146,43 +137,24 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
146
137
  case PrimitiveKind::UInt64: {
147
138
  if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
148
139
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
149
- return env.Null();
140
+ return false;
150
141
  }
151
142
 
152
143
  int64_t v = CopyNumber<int64_t>(value);
153
144
  *(uint64_t *)args_ptr = (uint64_t)v;
154
145
  args_ptr += 2;
155
146
  } break;
156
- case PrimitiveKind::Float32: {
157
- if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
158
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
159
- return env.Null();
160
- }
161
-
162
- float f = CopyNumber<float>(value);
163
- *(float *)((param.fast ? fast_ptr : args_ptr)++) = f;
164
- } break;
165
- case PrimitiveKind::Float64: {
166
- if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
167
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
168
- return env.Null();
169
- }
170
-
171
- double d = CopyNumber<double>(value);
172
- *(double *)args_ptr = d;
173
- args_ptr += 2;
174
- } break;
175
147
  case PrimitiveKind::String: {
176
148
  const char *str;
177
149
  if (RG_LIKELY(value.IsString())) {
178
150
  str = PushString(value);
179
151
  if (RG_UNLIKELY(!str))
180
- return env.Null();
152
+ return false;
181
153
  } else if (IsNullOrUndefined(value)) {
182
154
  str = nullptr;
183
155
  } else {
184
156
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
185
- return env.Null();
157
+ return false;
186
158
  }
187
159
 
188
160
  *(const char **)((param.fast ? fast_ptr : args_ptr)++) = str;
@@ -192,12 +164,12 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
192
164
  if (RG_LIKELY(value.IsString())) {
193
165
  str16 = PushString16(value);
194
166
  if (RG_UNLIKELY(!str16))
195
- return env.Null();
167
+ return false;
196
168
  } else if (IsNullOrUndefined(value)) {
197
169
  str16 = nullptr;
198
170
  } else {
199
171
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
200
- return env.Null();
172
+ return false;
201
173
  }
202
174
 
203
175
  *(const char16_t **)((param.fast ? fast_ptr : args_ptr)++) = str16;
@@ -211,11 +183,11 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
211
183
  Napi::Object obj = value.As<Napi::Object>();
212
184
 
213
185
  if (RG_UNLIKELY(!AllocHeap(param.type->ref->size, 16, &ptr)))
214
- return env.Null();
186
+ return false;
215
187
 
216
188
  if (param.directions & 1) {
217
189
  if (!PushObject(obj, param.type->ref, ptr))
218
- return env.Null();
190
+ return false;
219
191
  } else {
220
192
  memset(ptr, 0, param.type->size);
221
193
  }
@@ -227,16 +199,15 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
227
199
  ptr = nullptr;
228
200
  } else {
229
201
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected %3", GetValueType(instance, value), i + 1, param.type->name);
230
- return env.Null();
202
+ return false;
231
203
  }
232
204
 
233
205
  *(uint8_t **)((param.fast ? fast_ptr : args_ptr)++) = ptr;
234
206
  } break;
235
-
236
207
  case PrimitiveKind::Record: {
237
208
  if (RG_UNLIKELY(!IsObject(value))) {
238
209
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected object", GetValueType(instance, value), i + 1);
239
- return env.Null();
210
+ return false;
240
211
  }
241
212
 
242
213
  Napi::Object obj = value.As<Napi::Object>();
@@ -244,93 +215,107 @@ Napi::Value CallData::Execute(const Napi::CallbackInfo &info)
244
215
  if (param.fast) {
245
216
  uint8_t *ptr = (uint8_t *)(fast_ptr++);
246
217
  if (!PushObject(obj, param.type, ptr))
247
- return env.Null();
218
+ return false;
248
219
  } else {
249
220
  uint8_t *ptr = (uint8_t *)AlignUp(args_ptr, param.type->align);
250
221
  if (!PushObject(obj, param.type, ptr))
251
- return env.Null();
222
+ return false;
252
223
  args_ptr = (uint32_t *)AlignUp(ptr + param.type->size, 4);
253
224
  }
254
225
  } break;
226
+ case PrimitiveKind::Float32: {
227
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
228
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
229
+ return false;
230
+ }
231
+
232
+ float f = CopyNumber<float>(value);
233
+ *(float *)((param.fast ? fast_ptr : args_ptr)++) = f;
234
+ } break;
235
+ case PrimitiveKind::Float64: {
236
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
237
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
238
+ return false;
239
+ }
240
+
241
+ double d = CopyNumber<double>(value);
242
+ *(double *)args_ptr = d;
243
+ args_ptr += 2;
244
+ } break;
255
245
  }
256
246
  }
257
247
 
258
- if (instance->debug) {
259
- DumpDebug();
260
- }
248
+ return true;
249
+ }
261
250
 
251
+ void CallData::Execute()
252
+ {
262
253
  #define PERFORM_CALL(Suffix) \
263
254
  ([&]() { \
264
255
  auto ret = (func->convention == CallConvention::Fastcall ? ForwardCallR ## Suffix(func->func, GetSP()) \
265
256
  : ForwardCall ## Suffix(func->func, GetSP())); \
266
- PopOutArguments(out_objects); \
267
257
  return ret; \
268
258
  })()
269
259
 
270
260
  // Execute and convert return value
271
261
  switch (func->ret.type->primitive) {
272
- case PrimitiveKind::Void: {
273
- PERFORM_CALL(G);
274
- return env.Null();
275
- } break;
276
- case PrimitiveKind::Bool: {
277
- uint32_t rax = (uint32_t)PERFORM_CALL(G);
278
- return Napi::Boolean::New(env, rax);
279
- } break;
262
+ case PrimitiveKind::Void:
263
+ case PrimitiveKind::Bool:
280
264
  case PrimitiveKind::Int8:
281
265
  case PrimitiveKind::UInt8:
282
266
  case PrimitiveKind::Int16:
283
267
  case PrimitiveKind::UInt16:
284
268
  case PrimitiveKind::Int32:
285
- case PrimitiveKind::UInt32: {
286
- uint32_t rax = (uint32_t)PERFORM_CALL(G);
287
- return Napi::Number::New(env, (double)rax);
288
- } break;
289
- case PrimitiveKind::Int64: {
290
- uint64_t ret = PERFORM_CALL(G);
291
- return Napi::BigInt::New(env, (int64_t)ret);
292
- } break;
293
- case PrimitiveKind::UInt64: {
294
- uint64_t ret = PERFORM_CALL(G);
295
- return Napi::BigInt::New(env, ret);
296
- } break;
297
- case PrimitiveKind::Float32: {
298
- float f = PERFORM_CALL(F);
299
- return Napi::Number::New(env, (double)f);
300
- } break;
301
- case PrimitiveKind::Float64: {
302
- double d = PERFORM_CALL(D);
303
- return Napi::Number::New(env, d);
304
- } break;
305
- case PrimitiveKind::String: {
306
- uint32_t rax = (uint32_t)PERFORM_CALL(G);
307
- return Napi::String::New(env, (const char *)rax);
308
- } break;
309
- case PrimitiveKind::String16: {
310
- uint32_t rax = (uint32_t)PERFORM_CALL(G);
311
- return Napi::String::New(env, (const char16_t *)rax);
312
- } break;
313
- case PrimitiveKind::Pointer: {
314
- uint32_t rax = (uint32_t)PERFORM_CALL(G);
315
- void *ptr = (void *)rax;
269
+ case PrimitiveKind::UInt32:
270
+ case PrimitiveKind::Int64:
271
+ case PrimitiveKind::UInt64:
272
+ case PrimitiveKind::String:
273
+ case PrimitiveKind::String16:
274
+ case PrimitiveKind::Pointer:
275
+ case PrimitiveKind::Record: { result.u64 = PERFORM_CALL(G); } break;
276
+ case PrimitiveKind::Float32: { result.f = PERFORM_CALL(F); } break;
277
+ case PrimitiveKind::Float64: { result.d = PERFORM_CALL(D); } break;
278
+ }
316
279
 
317
- Napi::External<void> external = Napi::External<void>::New(env, ptr);
280
+ #undef PERFORM_CALL
281
+ }
282
+
283
+ Napi::Value CallData::Complete()
284
+ {
285
+ for (const OutObject &obj: out_objects) {
286
+ PopObject(obj.obj, obj.ptr, obj.type);
287
+ }
288
+
289
+ switch (func->ret.type->primitive) {
290
+ case PrimitiveKind::Void: return env.Null();
291
+ case PrimitiveKind::Bool: return Napi::Boolean::New(env, result.u32);
292
+ case PrimitiveKind::Int8:
293
+ case PrimitiveKind::UInt8:
294
+ case PrimitiveKind::Int16:
295
+ case PrimitiveKind::UInt16:
296
+ case PrimitiveKind::Int32:
297
+ case PrimitiveKind::UInt32: return Napi::Number::New(env, (double)result.u32);
298
+ case PrimitiveKind::Int64: return Napi::BigInt::New(env, (int64_t)result.u64);
299
+ case PrimitiveKind::UInt64: return Napi::BigInt::New(env, result.u64);
300
+ case PrimitiveKind::String: return Napi::String::New(env, (const char *)result.ptr);
301
+ case PrimitiveKind::String16: return Napi::String::New(env, (const char16_t *)result.ptr);
302
+ case PrimitiveKind::Pointer: {
303
+ Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
318
304
  SetValueTag(instance, external, func->ret.type);
319
305
 
320
306
  return external;
321
307
  } break;
322
-
323
308
  case PrimitiveKind::Record: {
324
- uint64_t ret = PERFORM_CALL(G);
325
- const uint8_t *ptr = return_ptr ? return_ptr : (const uint8_t *)&ret;
309
+ const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
310
+ : (const uint8_t *)&result.buf;
326
311
 
327
- Napi::Object obj = PopObject(env, ptr, func->ret.type);
312
+ Napi::Object obj = PopObject(ptr, func->ret.type);
328
313
  return obj;
329
314
  } break;
315
+ case PrimitiveKind::Float32: return Napi::Number::New(env, (double)result.f);
316
+ case PrimitiveKind::Float64: return Napi::Number::New(env, result.d);
330
317
  }
331
318
 
332
- #undef PERFORM_CALL
333
-
334
319
  RG_UNREACHABLE();
335
320
  }
336
321
 
package/src/call.cc CHANGED
@@ -156,24 +156,6 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
156
156
  int64_t v = CopyNumber<int64_t>(value);
157
157
  memcpy(dest, &v, member.type->size); // Little Endian
158
158
  } break;
159
- case PrimitiveKind::Float32: {
160
- if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
161
- ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected number", GetValueType(instance, value), member.name);
162
- return false;
163
- }
164
-
165
- float f = CopyNumber<float>(value);
166
- memcpy(dest, &f, 4);
167
- } break;
168
- case PrimitiveKind::Float64: {
169
- if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
170
- ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected number", GetValueType(instance, value), member.name);
171
- return false;
172
- }
173
-
174
- double d = CopyNumber<double>(value);
175
- memcpy(dest, &d, 8);
176
- } break;
177
159
  case PrimitiveKind::String: {
178
160
  if (RG_UNLIKELY(!value.IsString())) {
179
161
  ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected string", GetValueType(instance, value), member.name);
@@ -206,7 +188,6 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
206
188
  void *ptr = external.Data();
207
189
  *(void **)dest = ptr;
208
190
  } break;
209
-
210
191
  case PrimitiveKind::Record: {
211
192
  if (RG_UNLIKELY(!IsObject(value))) {
212
193
  ThrowError<Napi::TypeError>(env, "Unexpected value %1 for member '%2', expected object", GetValueType(instance, value), member.name);
@@ -217,6 +198,24 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
217
198
  if (!PushObject(obj, member.type, dest))
218
199
  return false;
219
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;
220
219
  }
221
220
 
222
221
  dest += member.type->size;
@@ -225,4 +224,130 @@ bool CallData::PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t
225
224
  return true;
226
225
  }
227
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
+
228
353
  }
package/src/call.hh CHANGED
@@ -28,13 +28,30 @@ class CallData {
28
28
  InstanceData *instance;
29
29
  const FunctionInfo *func;
30
30
 
31
+ struct OutObject {
32
+ Napi::Object obj;
33
+ const uint8_t *ptr;
34
+ const TypeInfo *type;
35
+ };
36
+
31
37
  Span<uint8_t> *stack_mem;
32
38
  Span<uint8_t> *heap_mem;
39
+ LocalArray<OutObject, MaxOutParameters> out_objects;
33
40
  BlockAllocator big_alloc;
34
41
 
35
42
  Span<uint8_t> old_stack_mem;
36
43
  Span<uint8_t> old_heap_mem;
37
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
+
38
55
  public:
39
56
  CallData(Napi::Env env, InstanceData *instance, const FunctionInfo *func);
40
57
  ~CallData();
@@ -56,6 +73,26 @@ public:
56
73
  return MakeSpan(ptr, len);
57
74
  }
58
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:
59
96
  template <typename T = void>
60
97
  bool AllocStack(Size size, Size align, T **out_ptr = nullptr);
61
98
  template <typename T = void>
@@ -65,9 +102,8 @@ public:
65
102
  const char16_t *PushString16(const Napi::Value &value);
66
103
  bool PushObject(const Napi::Object &obj, const TypeInfo *type, uint8_t *dest);
67
104
 
68
- void DumpDebug() const;
69
-
70
- Napi::Value Execute(const Napi::CallbackInfo &info);
105
+ void PopObject(Napi::Object obj, const uint8_t *ptr, const TypeInfo *type);
106
+ Napi::Object PopObject(const uint8_t *ptr, const TypeInfo *type);
71
107
  };
72
108
 
73
109
  template <typename T>
package/src/ffi.cc CHANGED
@@ -247,8 +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
+ 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
+
250
255
  CallData call(env, instance, func);
251
- return call.Execute(info);
256
+ return call.Run(info);
252
257
  }
253
258
 
254
259
  static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
@@ -266,6 +271,10 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
266
271
  func.parameters.Leak();
267
272
  };
268
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
+ }
269
278
  if ((info.Length() - func.parameters.len) % 2) {
270
279
  ThrowError<Napi::Error>(env, "Missing value argument for variadic call");
271
280
  return env.Null();
@@ -301,7 +310,7 @@ static Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
301
310
  return env.Null();
302
311
 
303
312
  CallData call(env, instance, &func);
304
- return call.Execute(info);
313
+ return call.Run(info);
305
314
  }
306
315
 
307
316
  static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value ret,
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,18 +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
-
44
40
  Pointer,
45
-
46
- Record
41
+ Record,
42
+ Float32,
43
+ Float64
47
44
  };
48
45
  static const char *const PrimitiveKindNames[] = {
49
46
  "Void",
50
-
51
47
  "Bool",
52
48
  "Int8",
53
49
  "UInt8",
@@ -57,14 +53,12 @@ static const char *const PrimitiveKindNames[] = {
57
53
  "UInt32",
58
54
  "Int64",
59
55
  "UInt64",
60
- "Float32",
61
- "Float64",
62
56
  "String",
63
57
  "String16",
64
-
65
58
  "Pointer",
66
-
67
- "Record"
59
+ "Record",
60
+ "Float32",
61
+ "Float64"
68
62
  };
69
63
 
70
64
  struct TypeInfo;