Skip to content

Commit 24316e8

Browse files
committed
recursive struct handling, metagen command improved, regen macos types
1 parent 4fbba6f commit 24316e8

File tree

219 files changed

+358111
-64314
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

219 files changed

+358111
-64314
lines changed

NativeScript/cli/main.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "runtime/Runtime.h"
1010
#include "runtime/RuntimeConfig.h"
1111
#include "segappend.h"
12+
#include "ffi/Tasks.h"
1213

1314
using namespace nativescript;
1415

@@ -23,6 +24,8 @@ void bootFromBytecode(std::string baseDir, const void* data, size_t size) {
2324
// runtime.ExecuteBytecode(data, size);
2425

2526
runtime.RunLoop();
27+
28+
Tasks::Drain();
2629
}
2730

2831
void bootFromModuleSpec(std::string baseDir, std::string spec) {
@@ -40,6 +43,8 @@ void bootFromModuleSpec(std::string baseDir, std::string spec) {
4043
}
4144

4245
runtime.RunLoop();
46+
47+
Tasks::Drain();
4348
}
4449

4550
int main(int argc, char** argv) {

NativeScript/ffi/TypeConv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ class TypeConv {
4040
virtual void encode(std::string* encoding) {}
4141
};
4242

43+
// Cleanup function to clear thread-local struct type caches
44+
void clearStructTypeCaches();
45+
4346
} // namespace nativescript
4447

4548
#endif /* TYPE_CONV_H */

NativeScript/ffi/TypeConv.mm

Lines changed: 173 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,76 @@
1919
#include <memory>
2020
#include <string>
2121
#include <vector>
22+
#include <unordered_set>
23+
#include <unordered_map>
2224

2325
namespace nativescript {
2426

27+
// Forward declaration
28+
class StructTypeConv;
29+
30+
// Thread-local storage for tracking structs currently being processed to detect cycles
31+
thread_local std::unordered_set<MDSectionOffset> processingStructs;
32+
thread_local std::unordered_set<std::string> processingEncodingStructs;
33+
34+
// Cache for forward-declared struct types that need deferred resolution
35+
thread_local std::unordered_map<MDSectionOffset, ffi_type*> forwardDeclaredStructs;
36+
thread_local std::unordered_map<std::string, ffi_type*> forwardDeclaredEncodingStructs;
37+
38+
// Cache for StructTypeConv instances to avoid recreating them and handle recursion
39+
thread_local std::unordered_map<MDSectionOffset, std::shared_ptr<StructTypeConv>> structTypeCache;
40+
41+
// Cache for encoding-based structs to handle recursion
42+
thread_local std::unordered_map<std::string, std::shared_ptr<StructTypeConv>> encodingStructCache;
43+
2544
ffi_type* typeFromStruct(napi_env env, const char** encoding) {
45+
// Extract struct name for cycle detection
46+
std::string structname;
47+
const char* nameStart = *encoding + 1; // skip '{'
48+
const char* c = nameStart;
49+
while (*c != '=') {
50+
structname += *c;
51+
c++;
52+
}
53+
54+
// Check if we're already processing this struct (cycle detection)
55+
if (processingEncodingStructs.find(structname) != processingEncodingStructs.end()) {
56+
// Create a forward declaration placeholder
57+
ffi_type* forwardType = new ffi_type;
58+
forwardType->type = FFI_TYPE_STRUCT;
59+
forwardType->size = 0;
60+
forwardType->alignment = 0;
61+
forwardType->elements = nullptr;
62+
63+
// Cache this forward declaration for later resolution
64+
forwardDeclaredEncodingStructs[structname] = forwardType;
65+
66+
// Skip the struct encoding
67+
(*encoding)++; // skip '{'
68+
while (**encoding != '}') {
69+
(*encoding)++;
70+
}
71+
(*encoding)++; // skip '}'
72+
73+
return forwardType;
74+
}
75+
76+
// Check if we already have a forward declaration for this struct
77+
auto forwardIt = forwardDeclaredEncodingStructs.find(structname);
78+
if (forwardIt != forwardDeclaredEncodingStructs.end()) {
79+
// Skip the struct encoding
80+
(*encoding)++; // skip '{'
81+
while (**encoding != '}') {
82+
(*encoding)++;
83+
}
84+
(*encoding)++; // skip '}'
85+
86+
return forwardIt->second;
87+
}
88+
89+
// Mark this struct as being processed
90+
processingEncodingStructs.insert(structname);
91+
2692
ffi_type* type = new ffi_type;
2793
type->type = FFI_TYPE_STRUCT;
2894
type->size = 0;
@@ -53,11 +119,51 @@
53119
// null-terminate the array
54120
type->elements[elements.size()] = nullptr;
55121

122+
// If this was a forward declaration, update it with the real layout
123+
if (forwardIt != forwardDeclaredEncodingStructs.end()) {
124+
ffi_type* forwardType = forwardIt->second;
125+
forwardType->type = type->type;
126+
forwardType->size = type->size;
127+
forwardType->alignment = type->alignment;
128+
forwardType->elements = type->elements;
129+
130+
// Clean up the temporary type and use the forward declaration
131+
delete type;
132+
type = forwardType;
133+
forwardDeclaredEncodingStructs.erase(forwardIt);
134+
}
135+
136+
// Remove from processing set
137+
processingEncodingStructs.erase(structname);
138+
56139
return type;
57140
}
58141

59142
ffi_type* typeFromStruct(napi_env env, MDMetadataReader* reader, MDSectionOffset structOffset,
60143
bool isUnion) {
144+
// Check if we're already processing this struct (cycle detection)
145+
if (processingStructs.find(structOffset) != processingStructs.end()) {
146+
// Create a forward declaration placeholder
147+
ffi_type* forwardType = new ffi_type;
148+
forwardType->type = FFI_TYPE_STRUCT;
149+
forwardType->size = 0;
150+
forwardType->alignment = 0;
151+
forwardType->elements = nullptr;
152+
153+
// Cache this forward declaration for later resolution
154+
forwardDeclaredStructs[structOffset] = forwardType;
155+
return forwardType;
156+
}
157+
158+
// Check if we already have a forward declaration for this struct
159+
auto forwardIt = forwardDeclaredStructs.find(structOffset);
160+
if (forwardIt != forwardDeclaredStructs.end()) {
161+
return forwardIt->second;
162+
}
163+
164+
// Mark this struct as being processed
165+
processingStructs.insert(structOffset);
166+
61167
ffi_type* type = new ffi_type;
62168
type->type = FFI_TYPE_STRUCT;
63169
type->size = 0;
@@ -67,21 +173,21 @@
67173
MDSectionOffset nameOffset = reader->getOffset(structOffset);
68174
auto name = reader->resolveString(nameOffset);
69175
bool next = true;
70-
structOffset += sizeof(MDSectionOffset); // skip name
71-
structOffset += sizeof(uint16_t); // skip size
176+
MDSectionOffset currentOffset = structOffset + sizeof(MDSectionOffset); // skip name
177+
currentOffset += sizeof(uint16_t); // skip size
72178

73179
std::vector<ffi_type*> elements;
74180

75181
while (next) {
76-
nameOffset = reader->getOffset(structOffset);
182+
nameOffset = reader->getOffset(currentOffset);
77183
next = nameOffset & mdSectionOffsetNext;
78184
nameOffset &= ~mdSectionOffsetNext;
79185
if (nameOffset == MD_SECTION_OFFSET_NULL) {
80186
break;
81187
}
82-
structOffset += sizeof(MDSectionOffset); // skip name
83-
if (!isUnion) structOffset += sizeof(uint16_t); // skip offset
84-
ffi_type* elementType = TypeConv::Make(env, reader, &structOffset, 1)->type;
188+
currentOffset += sizeof(MDSectionOffset); // skip name
189+
if (!isUnion) currentOffset += sizeof(uint16_t); // skip offset
190+
ffi_type* elementType = TypeConv::Make(env, reader, &currentOffset, 1)->type;
85191
elements.push_back(elementType);
86192
}
87193

@@ -92,6 +198,23 @@
92198
// null-terminate the array
93199
type->elements[elements.size()] = nullptr;
94200

201+
// If this was a forward declaration, update it with the real layout
202+
if (forwardIt != forwardDeclaredStructs.end()) {
203+
ffi_type* forwardType = forwardIt->second;
204+
forwardType->type = type->type;
205+
forwardType->size = type->size;
206+
forwardType->alignment = type->alignment;
207+
forwardType->elements = type->elements;
208+
209+
// Clean up the temporary type and use the forward declaration
210+
delete type;
211+
type = forwardType;
212+
forwardDeclaredStructs.erase(forwardIt);
213+
}
214+
215+
// Remove from processing set
216+
processingStructs.erase(structOffset);
217+
95218
return type;
96219
}
97220

@@ -1511,12 +1634,24 @@ void toNative(napi_env env, napi_value value, void* result, bool* shouldFree,
15111634
structname += *c;
15121635
c++;
15131636
}
1637+
1638+
// Check if we already have a cached StructTypeConv for this encoding-based struct
1639+
auto cacheIt = encodingStructCache.find(structname);
1640+
if (cacheIt != encodingStructCache.end()) {
1641+
return cacheIt->second;
1642+
}
1643+
15141644
auto bridgeState = ObjCBridgeState::InstanceData(env);
15151645
// NSLog(@"struct: %s, %d", structname.c_str(),
15161646
// bridgeState->structOffsets[structname]);
15171647
auto structOffset = bridgeState->structOffsets[structname];
15181648
auto type = typeFromStruct(env, encoding);
1519-
return std::make_shared<StructTypeConv>(StructTypeConv(structOffset, type));
1649+
auto structTypeConv = std::make_shared<StructTypeConv>(StructTypeConv(structOffset, type));
1650+
1651+
// Cache the StructTypeConv
1652+
encodingStructCache[structname] = structTypeConv;
1653+
1654+
return structTypeConv;
15201655
}
15211656
case 'b': {
15221657
(*encoding)++;
@@ -1687,9 +1822,27 @@ void toNative(napi_env env, napi_value value, void* result, bool* shouldFree,
16871822
}
16881823
structOffset += isUnion ? reader->unionsOffset : reader->structsOffset;
16891824
auto structName = reader->getString(structOffset);
1690-
auto type =
1691-
opaquePointers == 2 ? nullptr : typeFromStruct(env, reader, structOffset, isUnion);
1692-
return std::make_shared<StructTypeConv>(structOffset, type);
1825+
1826+
// Check if we already have a cached StructTypeConv for this struct
1827+
auto cacheIt = structTypeCache.find(structOffset);
1828+
if (cacheIt != structTypeCache.end()) {
1829+
return cacheIt->second;
1830+
}
1831+
1832+
// Check if we're currently processing this struct (recursion detection)
1833+
bool isRecursive = processingStructs.find(structOffset) != processingStructs.end();
1834+
1835+
ffi_type* type = nullptr;
1836+
if (opaquePointers != 2 && !isRecursive) {
1837+
type = typeFromStruct(env, reader, structOffset, isUnion);
1838+
}
1839+
1840+
auto structTypeConv = std::make_shared<StructTypeConv>(structOffset, type);
1841+
1842+
// Cache the StructTypeConv to handle recursion and avoid duplicates
1843+
structTypeCache[structOffset] = structTypeConv;
1844+
1845+
return structTypeConv;
16931846
}
16941847

16951848
case mdTypePointer: {
@@ -1738,4 +1891,14 @@ void toNative(napi_env env, napi_value value, void* result, bool* shouldFree,
17381891
}
17391892
}
17401893

1894+
// Cleanup function to clear thread-local caches
1895+
void clearStructTypeCaches() {
1896+
processingStructs.clear();
1897+
processingEncodingStructs.clear();
1898+
forwardDeclaredStructs.clear();
1899+
forwardDeclaredEncodingStructs.clear();
1900+
structTypeCache.clear();
1901+
encodingStructCache.clear();
1902+
}
1903+
17411904
} // namespace nativescript

build_nativescript.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ function cmake_build () {
8686

8787
for arch in x86_64 arm64; do
8888

89-
METADATA_SIZE=$(($METADATA_SIZE > $(stat -f%z "./metadata-generator/metadata/metadata.$platform.$arch.nsmd") ? $METADATA_SIZE : $(stat -f%z "./metadata-generator/metadata.$platform.$arch.nsmd")))
89+
METADATA_SIZE=$(($METADATA_SIZE > $(stat -f%z "./metadata-generator/metadata/metadata.$platform.$arch.nsmd") ? $METADATA_SIZE : $(stat -f%z "./metadata-generator/metadata/metadata.$platform.$arch.nsmd")))
9090

9191
done
9292

0 commit comments

Comments
 (0)