Skip to content

Commit 6d3dfc2

Browse files
authored
fix(catalyst): variable-length arrays (#275)
1 parent cd93a88 commit 6d3dfc2

File tree

2 files changed

+329
-306
lines changed

2 files changed

+329
-306
lines changed

NativeScript/runtime/FFICall.h

Lines changed: 96 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -2,117 +2,127 @@
22
#define FFICall_h
33

44
#include <malloc/malloc.h>
5+
56
#include <map>
6-
#include "robin_hood.h"
7-
#include "Metadata.h"
7+
88
#include "DataWrapper.h"
9+
#include "Metadata.h"
910
#include "libffi.h"
11+
#include "robin_hood.h"
1012

1113
namespace tns {
1214

1315
class BaseCall {
14-
public:
15-
BaseCall(uint8_t* buffer, size_t returnOffset = 0)
16-
: buffer_(buffer),
17-
returnOffset_(returnOffset) {
18-
}
16+
public:
17+
BaseCall(uint8_t* buffer, size_t returnOffset = 0)
18+
: buffer_(buffer), returnOffset_(returnOffset) {}
1919

20-
~BaseCall() {
21-
}
20+
~BaseCall() {}
2221

23-
inline void* ResultBuffer() {
24-
return this->buffer_ + this->returnOffset_;
25-
}
22+
inline void* ResultBuffer() { return this->buffer_ + this->returnOffset_; }
2623

27-
template <typename T>
28-
inline T& GetResult() {
29-
return *static_cast<T*>(this->ResultBuffer());
30-
}
31-
protected:
32-
uint8_t* buffer_;
33-
size_t returnOffset_;
24+
template <typename T>
25+
inline T& GetResult() {
26+
return *static_cast<T*>(this->ResultBuffer());
27+
}
28+
29+
protected:
30+
uint8_t* buffer_;
31+
size_t returnOffset_;
3432
};
3533

3634
class ParametrizedCall {
37-
public:
38-
ParametrizedCall(ffi_cif* cif)
39-
: Cif(cif),
40-
ReturnOffset(0),
41-
StackSize(0) {
42-
unsigned int argsCount = cif->nargs;
43-
this->StackSize = 0;
44-
45-
if (argsCount > 0) {
46-
this->StackSize = malloc_good_size(sizeof(void* [argsCount]));
47-
}
48-
49-
this->ReturnOffset = this->StackSize;
50-
51-
this->StackSize += malloc_good_size(std::max(cif->rtype->size, sizeof(ffi_arg)));
52-
53-
this->ArgValueOffsets.reserve(argsCount);
54-
for (size_t i = 0; i < argsCount; i++) {
55-
this->ArgValueOffsets.push_back(this->StackSize);
56-
ffi_type* argType = cif->arg_types[i];
57-
this->StackSize += malloc_good_size(std::max(argType->size, sizeof(ffi_arg)));
58-
}
35+
public:
36+
ParametrizedCall(ffi_cif* cif) : Cif(cif), ReturnOffset(0), StackSize(0) {
37+
unsigned int argsCount = cif->nargs;
38+
this->StackSize = 0;
39+
40+
if (argsCount > 0) {
41+
// compute total bytes = number of pointers × size of a pointer
42+
size_t needed = sizeof(void*) * static_cast<size_t>(argsCount);
43+
this->StackSize = malloc_good_size(needed);
5944
}
6045

61-
static ParametrizedCall* Get(const TypeEncoding* typeEncoding, const int initialParameterIndex, const int argsCount);
46+
this->ReturnOffset = this->StackSize;
6247

63-
ffi_cif* Cif;
64-
size_t ReturnOffset;
65-
size_t StackSize;
66-
std::vector<size_t> ArgValueOffsets;
67-
private:
68-
static robin_hood::unordered_map<const TypeEncoding*, ParametrizedCall*> callsCache_;
69-
};
48+
this->StackSize +=
49+
malloc_good_size(std::max(cif->rtype->size, sizeof(ffi_arg)));
7050

71-
class FFICall: public BaseCall {
72-
public:
73-
FFICall(ParametrizedCall* parametrizedCall): BaseCall(nullptr) {
74-
this->returnOffset_ = parametrizedCall->ReturnOffset;
75-
this->useDynamicBuffer_ = parametrizedCall->StackSize > 512;
76-
if(this->useDynamicBuffer_) {
77-
this->buffer_ = reinterpret_cast<uint8_t*>(malloc(parametrizedCall->StackSize));
78-
} else {
79-
this->buffer_ = reinterpret_cast<uint8_t*>(this->staticBuffer);
80-
}
81-
82-
this->argsArray_ = reinterpret_cast<void**>(this->buffer_);
83-
for (size_t i = 0; i < parametrizedCall->Cif->nargs; i++) {
84-
this->argsArray_[i] = this->buffer_ + parametrizedCall->ArgValueOffsets[i];
85-
}
51+
this->ArgValueOffsets.reserve(argsCount);
52+
for (size_t i = 0; i < argsCount; i++) {
53+
this->ArgValueOffsets.push_back(this->StackSize);
54+
ffi_type* argType = cif->arg_types[i];
55+
this->StackSize +=
56+
malloc_good_size(std::max(argType->size, sizeof(ffi_arg)));
8657
}
58+
}
8759

88-
~FFICall() {
89-
if(this->useDynamicBuffer_) {
90-
free(this->buffer_);
91-
}
92-
}
60+
static ParametrizedCall* Get(const TypeEncoding* typeEncoding,
61+
const int initialParameterIndex,
62+
const int argsCount);
9363

94-
/**
95-
When calling this, always make another call to DisposeFFIType with the same parameters
96-
*/
97-
static ffi_type* GetArgumentType(const TypeEncoding* typeEncoding, bool isStructMember = false);
98-
static void DisposeFFIType(ffi_type* type, const TypeEncoding* typeEncoding);
99-
static StructInfo GetStructInfo(const StructMeta* structMeta, std::string structName = "");
100-
static StructInfo GetStructInfo(size_t fieldsCount, const TypeEncoding* fieldEncoding, const String* fieldNames, std::string structName = "");
64+
ffi_cif* Cif;
65+
size_t ReturnOffset;
66+
size_t StackSize;
67+
std::vector<size_t> ArgValueOffsets;
68+
69+
private:
70+
static robin_hood::unordered_map<const TypeEncoding*, ParametrizedCall*>
71+
callsCache_;
72+
};
73+
74+
class FFICall : public BaseCall {
75+
public:
76+
FFICall(ParametrizedCall* parametrizedCall) : BaseCall(nullptr) {
77+
this->returnOffset_ = parametrizedCall->ReturnOffset;
78+
this->useDynamicBuffer_ = parametrizedCall->StackSize > 512;
79+
if (this->useDynamicBuffer_) {
80+
this->buffer_ =
81+
reinterpret_cast<uint8_t*>(malloc(parametrizedCall->StackSize));
82+
} else {
83+
this->buffer_ = reinterpret_cast<uint8_t*>(this->staticBuffer);
84+
}
10185

102-
inline void* ArgumentBuffer(unsigned index) {
103-
return this->argsArray_[index];
86+
this->argsArray_ = reinterpret_cast<void**>(this->buffer_);
87+
for (size_t i = 0; i < parametrizedCall->Cif->nargs; i++) {
88+
this->argsArray_[i] =
89+
this->buffer_ + parametrizedCall->ArgValueOffsets[i];
10490
}
91+
}
10592

106-
inline void** ArgsArray() {
107-
return this->argsArray_;
93+
~FFICall() {
94+
if (this->useDynamicBuffer_) {
95+
free(this->buffer_);
10896
}
109-
private:
110-
static robin_hood::unordered_map<std::string, StructInfo> structInfosCache_;
111-
void** argsArray_;
112-
bool useDynamicBuffer_;
113-
uint8_t staticBuffer[512];
97+
}
98+
99+
/**
100+
When calling this, always make another call to DisposeFFIType with the same
101+
parameters
102+
*/
103+
static ffi_type* GetArgumentType(const TypeEncoding* typeEncoding,
104+
bool isStructMember = false);
105+
static void DisposeFFIType(ffi_type* type, const TypeEncoding* typeEncoding);
106+
static StructInfo GetStructInfo(const StructMeta* structMeta,
107+
std::string structName = "");
108+
static StructInfo GetStructInfo(size_t fieldsCount,
109+
const TypeEncoding* fieldEncoding,
110+
const String* fieldNames,
111+
std::string structName = "");
112+
113+
inline void* ArgumentBuffer(unsigned index) {
114+
return this->argsArray_[index];
115+
}
116+
117+
inline void** ArgsArray() { return this->argsArray_; }
118+
119+
private:
120+
static robin_hood::unordered_map<std::string, StructInfo> structInfosCache_;
121+
void** argsArray_;
122+
bool useDynamicBuffer_;
123+
uint8_t staticBuffer[512];
114124
};
115125

116-
}
126+
} // namespace tns
117127

118128
#endif /* FFICall_h */

0 commit comments

Comments
 (0)