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
@@ -51,31 +51,19 @@ bool AnalyseFunction(InstanceData *, FunctionInfo *func)
51
51
  return true;
52
52
  }
53
53
 
54
- Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, const Napi::CallbackInfo &info)
54
+ bool CallData::Prepare(const Napi::CallbackInfo &info)
55
55
  {
56
- Napi::Env env = info.Env();
57
- CallData call(env, instance, func);
58
-
59
- // Sanity checks
60
- if (info.Length() < (uint32_t)func->parameters.len) {
61
- ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, info.Length());
62
- return env.Null();
63
- }
64
-
65
- uint8_t *return_ptr = nullptr;
66
56
  uint64_t *args_ptr = nullptr;
67
57
 
68
58
  // Pass return value in register or through memory
69
- if (RG_UNLIKELY(!call.AllocStack(func->args_size, 16, &args_ptr)))
70
- return env.Null();
59
+ if (RG_UNLIKELY(!AllocStack(func->args_size, 16, &args_ptr)))
60
+ return false;
71
61
  if (!func->ret.regular) {
72
- if (RG_UNLIKELY(!call.AllocHeap(func->ret.type->size, 16, &return_ptr)))
73
- return env.Null();
62
+ if (RG_UNLIKELY(!AllocHeap(func->ret.type->size, 16, &return_ptr)))
63
+ return false;
74
64
  *(uint8_t **)(args_ptr++) = return_ptr;
75
65
  }
76
66
 
77
- LocalArray<OutObject, MaxOutParameters> out_objects;
78
-
79
67
  // Push arguments
80
68
  for (Size i = 0; i < func->parameters.len; i++) {
81
69
  const ParameterInfo &param = func->parameters[i];
@@ -89,7 +77,7 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
89
77
  case PrimitiveKind::Bool: {
90
78
  if (RG_UNLIKELY(!value.IsBoolean())) {
91
79
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected boolean", GetValueType(instance, value), i + 1);
92
- return env.Null();
80
+ return false;
93
81
  }
94
82
 
95
83
  bool b = value.As<Napi::Boolean>();
@@ -106,46 +94,42 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
106
94
  case PrimitiveKind::UInt64: {
107
95
  if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
108
96
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
109
- return env.Null();
97
+ return false;
110
98
  }
111
99
 
112
100
  int64_t v = CopyNumber<int64_t>(value);
113
101
  *(args_ptr++) = (uint64_t)v;
114
102
  } break;
115
- case PrimitiveKind::Float32: {
116
- if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
117
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
118
- return env.Null();
119
- }
120
-
121
- float f = CopyNumber<float>(value);
122
- *(float *)(args_ptr++) = f;
123
- } break;
124
- case PrimitiveKind::Float64: {
125
- if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
126
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
127
- return env.Null();
128
- }
129
-
130
- double d = CopyNumber<double>(value);
131
- *(double *)(args_ptr++) = d;
132
- } break;
133
103
  case PrimitiveKind::String: {
134
104
  const char *str;
135
105
  if (RG_LIKELY(value.IsString())) {
136
- str = call.PushString(value);
106
+ str = PushString(value);
137
107
  if (RG_UNLIKELY(!str))
138
- return env.Null();
108
+ return false;
139
109
  } else if (IsNullOrUndefined(value)) {
140
110
  str = nullptr;
141
111
  } else {
142
112
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
143
- return env.Null();
113
+ return false;
144
114
  }
145
115
 
146
116
  *(const char **)(args_ptr++) = str;
147
117
  } break;
118
+ case PrimitiveKind::String16: {
119
+ const char16_t *str16;
120
+ if (RG_LIKELY(value.IsString())) {
121
+ str16 = PushString16(value);
122
+ if (RG_UNLIKELY(!str16))
123
+ return false;
124
+ } else if (IsNullOrUndefined(value)) {
125
+ str16 = nullptr;
126
+ } else {
127
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
128
+ return false;
129
+ }
148
130
 
131
+ *(const char16_t **)(args_ptr++) = str16;
132
+ } break;
149
133
  case PrimitiveKind::Pointer: {
150
134
  uint8_t *ptr;
151
135
 
@@ -154,12 +138,12 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
154
138
  } else if (IsObject(value) && param.type->ref->primitive == PrimitiveKind::Record) {
155
139
  Napi::Object obj = value.As<Napi::Object>();
156
140
 
157
- if (RG_UNLIKELY(!call.AllocHeap(param.type->ref->size, 16, &ptr)))
158
- return env.Null();
141
+ if (RG_UNLIKELY(!AllocHeap(param.type->ref->size, 16, &ptr)))
142
+ return false;
159
143
 
160
144
  if (param.directions & 1) {
161
- if (!call.PushObject(obj, param.type->ref, ptr))
162
- return env.Null();
145
+ if (!PushObject(obj, param.type->ref, ptr))
146
+ return false;
163
147
  } else {
164
148
  memset(ptr, 0, param.type->size);
165
149
  }
@@ -171,97 +155,121 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
171
155
  ptr = nullptr;
172
156
  } else {
173
157
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected %3", GetValueType(instance, value), i + 1, param.type->name);
174
- return env.Null();
158
+ return false;
175
159
  }
176
160
 
177
161
  *(uint8_t **)(args_ptr++) = ptr;
178
162
  } break;
179
-
180
163
  case PrimitiveKind::Record: {
181
164
  if (RG_UNLIKELY(!IsObject(value))) {
182
165
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected object", GetValueType(instance, value), i + 1);
183
- return env.Null();
166
+ return false;
184
167
  }
185
168
 
186
169
  uint8_t *ptr;
187
170
  if (param.regular) {
188
171
  ptr = (uint8_t *)(args_ptr++);
189
172
  } else {
190
- if (RG_UNLIKELY(!call.AllocHeap(param.type->size, 16, &ptr)))
191
- return env.Null();
173
+ if (RG_UNLIKELY(!AllocHeap(param.type->size, 16, &ptr)))
174
+ return false;
192
175
  *(uint8_t **)(args_ptr++) = ptr;
193
176
  }
194
177
 
195
178
  Napi::Object obj = value.As<Napi::Object>();
196
- if (!call.PushObject(obj, param.type, ptr))
197
- return env.Null();
179
+ if (!PushObject(obj, param.type, ptr))
180
+ return false;
181
+ } break;
182
+ case PrimitiveKind::Float32: {
183
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
184
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
185
+ return false;
186
+ }
187
+
188
+ float f = CopyNumber<float>(value);
189
+ *(float *)(args_ptr++) = f;
190
+ } break;
191
+ case PrimitiveKind::Float64: {
192
+ if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
193
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
194
+ return false;
195
+ }
196
+
197
+ double d = CopyNumber<double>(value);
198
+ *(double *)(args_ptr++) = d;
198
199
  } break;
199
200
  }
200
201
  }
201
202
 
202
- if (instance->debug) {
203
- call.DumpDebug();
204
- }
203
+ return true;
204
+ }
205
205
 
206
+ void CallData::Execute()
207
+ {
206
208
  #define PERFORM_CALL(Suffix) \
207
209
  ([&]() { \
208
- auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, call.GetSP()) \
209
- : ForwardCall ## Suffix(func->func, call.GetSP())); \
210
- PopOutArguments(out_objects); \
210
+ auto ret = (func->forward_fp ? ForwardCallX ## Suffix(func->func, GetSP()) \
211
+ : ForwardCall ## Suffix(func->func, GetSP())); \
211
212
  return ret; \
212
213
  })()
213
214
 
214
- // Execute and convert return value
215
215
  switch (func->ret.type->primitive) {
216
- case PrimitiveKind::Float32: {
217
- float f = PERFORM_CALL(F);
216
+ case PrimitiveKind::Void:
217
+ case PrimitiveKind::Bool:
218
+ case PrimitiveKind::Int8:
219
+ case PrimitiveKind::UInt8:
220
+ case PrimitiveKind::Int16:
221
+ case PrimitiveKind::UInt16:
222
+ case PrimitiveKind::Int32:
223
+ case PrimitiveKind::UInt32:
224
+ case PrimitiveKind::Int64:
225
+ case PrimitiveKind::UInt64:
226
+ case PrimitiveKind::String:
227
+ case PrimitiveKind::String16:
228
+ case PrimitiveKind::Pointer:
229
+ case PrimitiveKind::Record: { result.u64 = PERFORM_CALL(G); } break;
230
+ case PrimitiveKind::Float32: { result.f = PERFORM_CALL(F); } break;
231
+ case PrimitiveKind::Float64: { result.d = PERFORM_CALL(D); } break;
232
+ }
218
233
 
219
- return Napi::Number::New(env, (double)f);
220
- } break;
234
+ #undef PERFORM_CALL
235
+ }
221
236
 
222
- case PrimitiveKind::Float64: {
223
- double d = PERFORM_CALL(D);
237
+ Napi::Value CallData::Complete()
238
+ {
239
+ for (const OutObject &obj: out_objects) {
240
+ PopObject(obj.obj, obj.ptr, obj.type);
241
+ }
224
242
 
225
- return Napi::Number::New(env, d);
243
+ switch (func->ret.type->primitive) {
244
+ case PrimitiveKind::Void: return env.Null();
245
+ case PrimitiveKind::Bool: return Napi::Boolean::New(env, result.u32);
246
+ case PrimitiveKind::Int8:
247
+ case PrimitiveKind::UInt8:
248
+ case PrimitiveKind::Int16:
249
+ case PrimitiveKind::UInt16:
250
+ case PrimitiveKind::Int32:
251
+ case PrimitiveKind::UInt32: return Napi::Number::New(env, (double)result.u32);
252
+ case PrimitiveKind::Int64: return Napi::BigInt::New(env, (int64_t)result.u64);
253
+ case PrimitiveKind::UInt64: return Napi::BigInt::New(env, result.u64);
254
+ case PrimitiveKind::String: return Napi::String::New(env, (const char *)result.ptr);
255
+ case PrimitiveKind::String16: return Napi::String::New(env, (const char16_t *)result.ptr);
256
+ case PrimitiveKind::Pointer: {
257
+ Napi::External<void> external = Napi::External<void>::New(env, result.ptr);
258
+ SetValueTag(instance, external, func->ret.type);
259
+
260
+ return external;
226
261
  } break;
262
+ case PrimitiveKind::Record: {
263
+ const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
264
+ : (const uint8_t *)&result.buf;
227
265
 
228
- default: {
229
- uint64_t rax = PERFORM_CALL(G);
230
-
231
- switch (func->ret.type->primitive) {
232
- case PrimitiveKind::Void: return env.Null();
233
- case PrimitiveKind::Bool: return Napi::Boolean::New(env, rax);
234
- case PrimitiveKind::Int8: return Napi::Number::New(env, (double)rax);
235
- case PrimitiveKind::UInt8: return Napi::Number::New(env, (double)rax);
236
- case PrimitiveKind::Int16: return Napi::Number::New(env, (double)rax);
237
- case PrimitiveKind::UInt16: return Napi::Number::New(env, (double)rax);
238
- case PrimitiveKind::Int32: return Napi::Number::New(env, (double)rax);
239
- case PrimitiveKind::UInt32: return Napi::Number::New(env, (double)rax);
240
- case PrimitiveKind::Int64: return Napi::BigInt::New(env, (int64_t)rax);
241
- case PrimitiveKind::UInt64: return Napi::BigInt::New(env, rax);
242
- case PrimitiveKind::Float32: { RG_UNREACHABLE(); } break;
243
- case PrimitiveKind::Float64: { RG_UNREACHABLE(); } break;
244
- case PrimitiveKind::String: return Napi::String::New(env, (const char *)rax);
245
- case PrimitiveKind::Pointer: {
246
- void *ptr = (void *)rax;
247
-
248
- Napi::External<void> external = Napi::External<void>::New(env, ptr);
249
- SetValueTag(instance, external, func->ret.type);
250
-
251
- return external;
252
- } break;
253
-
254
- case PrimitiveKind::Record: {
255
- const uint8_t *ptr = return_ptr ? return_ptr : (const uint8_t *)&rax;
256
- Napi::Object obj = PopObject(env, ptr, func->ret.type);
257
- return obj;
258
- } break;
259
- }
266
+ Napi::Object obj = PopObject(ptr, func->ret.type);
267
+ return obj;
260
268
  } break;
269
+ case PrimitiveKind::Float32: return Napi::Number::New(env, (double)result.f);
270
+ case PrimitiveKind::Float64: return Napi::Number::New(env, result.d);
261
271
  }
262
272
 
263
- #undef PERFORM_CALL
264
-
265
273
  RG_UNREACHABLE();
266
274
  }
267
275
 
@@ -82,36 +82,24 @@ bool AnalyseFunction(InstanceData *instance, FunctionInfo *func)
82
82
  return true;
83
83
  }
84
84
 
85
- Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, const Napi::CallbackInfo &info)
85
+ bool CallData::Prepare(const Napi::CallbackInfo &info)
86
86
  {
87
- Napi::Env env = info.Env();
88
- CallData call(env, instance, func);
89
-
90
- // Sanity checks
91
- if (info.Length() < (uint32_t)func->parameters.len) {
92
- ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, info.Length());
93
- return env.Null();
94
- }
95
-
96
- uint8_t *return_ptr = nullptr;
97
87
  uint32_t *args_ptr = nullptr;
98
88
  uint32_t *fast_ptr = nullptr;
99
89
 
100
90
  // Pass return value in register or through memory
101
- if (RG_UNLIKELY(!call.AllocStack(func->args_size, 16, &args_ptr)))
102
- return env.Null();
91
+ if (RG_UNLIKELY(!AllocStack(func->args_size, 16, &args_ptr)))
92
+ return false;
103
93
  if (func->convention == CallConvention::Fastcall) {
104
94
  fast_ptr = args_ptr;
105
95
  args_ptr += 4;
106
96
  }
107
97
  if (!func->ret.trivial) {
108
- if (RG_UNLIKELY(!call.AllocHeap(func->ret.type->size, 16, &return_ptr)))
109
- return env.Null();
98
+ if (RG_UNLIKELY(!AllocHeap(func->ret.type->size, 16, &return_ptr)))
99
+ return false;
110
100
  *((func->ret.fast ? fast_ptr : args_ptr)++) = (uint32_t)return_ptr;
111
101
  }
112
102
 
113
- LocalArray<OutObject, MaxOutParameters> out_objects;
114
-
115
103
  // Push arguments
116
104
  for (Size i = 0; i < func->parameters.len; i++) {
117
105
  const ParameterInfo &param = func->parameters[i];
@@ -125,7 +113,7 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
125
113
  case PrimitiveKind::Bool: {
126
114
  if (RG_UNLIKELY(!value.IsBoolean())) {
127
115
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected boolean", GetValueType(instance, value), i + 1);
128
- return env.Null();
116
+ return false;
129
117
  }
130
118
 
131
119
  bool b = value.As<Napi::Boolean>();
@@ -139,7 +127,7 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
139
127
  case PrimitiveKind::UInt32: {
140
128
  if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
141
129
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
142
- return env.Null();
130
+ return false;
143
131
  }
144
132
 
145
133
  int32_t v = CopyNumber<int32_t>(value);
@@ -149,47 +137,43 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
149
137
  case PrimitiveKind::UInt64: {
150
138
  if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
151
139
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
152
- return env.Null();
140
+ return false;
153
141
  }
154
142
 
155
143
  int64_t v = CopyNumber<int64_t>(value);
156
144
  *(uint64_t *)args_ptr = (uint64_t)v;
157
145
  args_ptr += 2;
158
146
  } break;
159
- case PrimitiveKind::Float32: {
160
- if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
161
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
162
- return env.Null();
163
- }
164
-
165
- float f = CopyNumber<float>(value);
166
- *(float *)((param.fast ? fast_ptr : args_ptr)++) = f;
167
- } break;
168
- case PrimitiveKind::Float64: {
169
- if (RG_UNLIKELY(!value.IsNumber() && !value.IsBigInt())) {
170
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected number", GetValueType(instance, value), i + 1);
171
- return env.Null();
172
- }
173
-
174
- double d = CopyNumber<double>(value);
175
- *(double *)args_ptr = d;
176
- args_ptr += 2;
177
- } break;
178
147
  case PrimitiveKind::String: {
179
148
  const char *str;
180
149
  if (RG_LIKELY(value.IsString())) {
181
- str = call.PushString(value);
150
+ str = PushString(value);
182
151
  if (RG_UNLIKELY(!str))
183
- return env.Null();
152
+ return false;
184
153
  } else if (IsNullOrUndefined(value)) {
185
154
  str = nullptr;
186
155
  } else {
187
156
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
188
- return env.Null();
157
+ return false;
189
158
  }
190
159
 
191
160
  *(const char **)((param.fast ? fast_ptr : args_ptr)++) = str;
192
161
  } break;
162
+ case PrimitiveKind::String16: {
163
+ const char16_t *str16;
164
+ if (RG_LIKELY(value.IsString())) {
165
+ str16 = PushString16(value);
166
+ if (RG_UNLIKELY(!str16))
167
+ return false;
168
+ } else if (IsNullOrUndefined(value)) {
169
+ str16 = nullptr;
170
+ } else {
171
+ ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected string", GetValueType(instance, value), i + 1);
172
+ return false;
173
+ }
174
+
175
+ *(const char16_t **)((param.fast ? fast_ptr : args_ptr)++) = str16;
176
+ } break;
193
177
  case PrimitiveKind::Pointer: {
194
178
  uint8_t *ptr;
195
179
 
@@ -198,12 +182,12 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
198
182
  } else if (IsObject(value) && param.type->ref->primitive == PrimitiveKind::Record) {
199
183
  Napi::Object obj = value.As<Napi::Object>();
200
184
 
201
- if (RG_UNLIKELY(!call.AllocHeap(param.type->ref->size, 16, &ptr)))
202
- return env.Null();
185
+ if (RG_UNLIKELY(!AllocHeap(param.type->ref->size, 16, &ptr)))
186
+ return false;
203
187
 
204
188
  if (param.directions & 1) {
205
- if (!call.PushObject(obj, param.type->ref, ptr))
206
- return env.Null();
189
+ if (!PushObject(obj, param.type->ref, ptr))
190
+ return false;
207
191
  } else {
208
192
  memset(ptr, 0, param.type->size);
209
193
  }
@@ -215,104 +199,123 @@ Napi::Value TranslateCall(InstanceData *instance, const FunctionInfo *func, cons
215
199
  ptr = nullptr;
216
200
  } else {
217
201
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected %3", GetValueType(instance, value), i + 1, param.type->name);
218
- return env.Null();
202
+ return false;
219
203
  }
220
204
 
221
205
  *(uint8_t **)((param.fast ? fast_ptr : args_ptr)++) = ptr;
222
206
  } break;
223
-
224
207
  case PrimitiveKind::Record: {
225
208
  if (RG_UNLIKELY(!IsObject(value))) {
226
209
  ThrowError<Napi::TypeError>(env, "Unexpected %1 value for argument %2, expected object", GetValueType(instance, value), i + 1);
227
- return env.Null();
210
+ return false;
228
211
  }
229
212
 
230
213
  Napi::Object obj = value.As<Napi::Object>();
231
214
 
232
215
  if (param.fast) {
233
216
  uint8_t *ptr = (uint8_t *)(fast_ptr++);
234
- if (!call.PushObject(obj, param.type, ptr))
235
- return env.Null();
217
+ if (!PushObject(obj, param.type, ptr))
218
+ return false;
236
219
  } else {
237
220
  uint8_t *ptr = (uint8_t *)AlignUp(args_ptr, param.type->align);
238
- if (!call.PushObject(obj, param.type, ptr))
239
- return env.Null();
221
+ if (!PushObject(obj, param.type, ptr))
222
+ return false;
240
223
  args_ptr = (uint32_t *)AlignUp(ptr + param.type->size, 4);
241
224
  }
242
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;
243
245
  }
244
246
  }
245
247
 
246
- if (instance->debug) {
247
- call.DumpDebug();
248
- }
248
+ return true;
249
+ }
249
250
 
251
+ void CallData::Execute()
252
+ {
250
253
  #define PERFORM_CALL(Suffix) \
251
254
  ([&]() { \
252
- auto ret = (func->convention == CallConvention::Fastcall ? ForwardCallR ## Suffix(func->func, call.GetSP()) \
253
- : ForwardCall ## Suffix(func->func, call.GetSP())); \
254
- PopOutArguments(out_objects); \
255
+ auto ret = (func->convention == CallConvention::Fastcall ? ForwardCallR ## Suffix(func->func, GetSP()) \
256
+ : ForwardCall ## Suffix(func->func, GetSP())); \
255
257
  return ret; \
256
258
  })()
257
259
 
258
260
  // Execute and convert return value
259
261
  switch (func->ret.type->primitive) {
260
- case PrimitiveKind::Float32: {
261
- float f = PERFORM_CALL(F);
262
+ case PrimitiveKind::Void:
263
+ case PrimitiveKind::Bool:
264
+ case PrimitiveKind::Int8:
265
+ case PrimitiveKind::UInt8:
266
+ case PrimitiveKind::Int16:
267
+ case PrimitiveKind::UInt16:
268
+ case PrimitiveKind::Int32:
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
+ }
262
279
 
263
- return Napi::Number::New(env, (double)f);
264
- } break;
280
+ #undef PERFORM_CALL
281
+ }
265
282
 
266
- case PrimitiveKind::Float64: {
267
- double d = PERFORM_CALL(D);
283
+ Napi::Value CallData::Complete()
284
+ {
285
+ for (const OutObject &obj: out_objects) {
286
+ PopObject(obj.obj, obj.ptr, obj.type);
287
+ }
268
288
 
269
- return Napi::Number::New(env, d);
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);
304
+ SetValueTag(instance, external, func->ret.type);
305
+
306
+ return external;
270
307
  } break;
308
+ case PrimitiveKind::Record: {
309
+ const uint8_t *ptr = return_ptr ? (const uint8_t *)return_ptr
310
+ : (const uint8_t *)&result.buf;
271
311
 
272
- default: {
273
- // We can't directly use the struct as a return value, because not all platforms
274
- // treat it the same: it is trivial only on Windows (see AnalyseFunction).
275
- uint64_t raw = PERFORM_CALL(G);
276
- struct {
277
- uint32_t rax;
278
- uint32_t rdx;
279
- } ret;
280
- memcpy(&ret, &raw, RG_SIZE(raw));
281
-
282
- switch (func->ret.type->primitive) {
283
- case PrimitiveKind::Void: return env.Null();
284
- case PrimitiveKind::Bool: return Napi::Boolean::New(env, ret.rax);
285
- case PrimitiveKind::Int8: return Napi::Number::New(env, (double)ret.rax);
286
- case PrimitiveKind::UInt8: return Napi::Number::New(env, (double)ret.rax);
287
- case PrimitiveKind::Int16: return Napi::Number::New(env, (double)ret.rax);
288
- case PrimitiveKind::UInt16: return Napi::Number::New(env, (double)ret.rax);
289
- case PrimitiveKind::Int32: return Napi::Number::New(env, (double)ret.rax);
290
- case PrimitiveKind::UInt32: return Napi::Number::New(env, (double)ret.rax);
291
- case PrimitiveKind::Int64: return Napi::BigInt::New(env, (int64_t)raw);
292
- case PrimitiveKind::UInt64: return Napi::BigInt::New(env, raw);
293
- case PrimitiveKind::Float32: { RG_UNREACHABLE(); } break;
294
- case PrimitiveKind::Float64: { RG_UNREACHABLE(); } break;
295
- case PrimitiveKind::String: return Napi::String::New(env, (const char *)ret.rax);
296
- case PrimitiveKind::Pointer: {
297
- void *ptr = (void *)ret.rax;
298
-
299
- Napi::External<void> external = Napi::External<void>::New(env, ptr);
300
- SetValueTag(instance, external, func->ret.type);
301
-
302
- return external;
303
- } break;
304
-
305
- case PrimitiveKind::Record: {
306
- const uint8_t *ptr = return_ptr ? return_ptr : (const uint8_t *)&ret;
307
- Napi::Object obj = PopObject(env, ptr, func->ret.type);
308
- return obj;
309
- } break;
310
- }
312
+ Napi::Object obj = PopObject(ptr, func->ret.type);
313
+ return obj;
311
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);
312
317
  }
313
318
 
314
- #undef PERFORM_CALL
315
-
316
319
  RG_UNREACHABLE();
317
320
  }
318
321
 
File without changes
File without changes