29
29
import java .lang .foreign .MemoryAddress ;
30
30
import java .lang .foreign .MemorySegment ;
31
31
import java .lang .foreign .MemorySession ;
32
- import java .lang .foreign .SegmentAllocator ;
33
32
import org .openjdk .jextract .clang .libclang .CXCursorVisitor ;
34
33
import org .openjdk .jextract .clang .libclang .Index_h ;
35
34
36
- import java .util .ArrayList ;
37
- import java .util .stream .Stream ;
35
+ import java .util .function .Consumer ;
38
36
39
- import static org . openjdk . jextract . clang . LibClang . IMPLICIT_ALLOCATOR ;
37
+ public final class Cursor extends ClangDisposable . Owned {
40
38
41
- public final class Cursor {
42
-
43
- private final MemorySegment cursor ;
44
39
private final int kind ;
45
40
46
- Cursor (MemorySegment cursor ) {
47
- this . cursor = cursor ;
48
- kind = Index_h .clang_getCursorKind (cursor );
41
+ Cursor (MemorySegment segment , ClangDisposable owner ) {
42
+ super ( segment , owner ) ;
43
+ kind = Index_h .clang_getCursorKind (segment );
49
44
}
50
45
51
46
public boolean isDeclaration () {
@@ -61,32 +56,32 @@ public boolean isInvalid() {
61
56
}
62
57
63
58
public boolean isDefinition () {
64
- return Index_h .clang_isCursorDefinition (cursor ) != 0 ;
59
+ return Index_h .clang_isCursorDefinition (segment ) != 0 ;
65
60
}
66
61
67
62
public boolean isAttribute () { return Index_h .clang_isAttribute (kind ) != 0 ; }
68
63
69
64
public boolean isAnonymousStruct () {
70
- return Index_h .clang_Cursor_isAnonymousRecordDecl (cursor ) != 0 ;
65
+ return Index_h .clang_Cursor_isAnonymousRecordDecl (segment ) != 0 ;
71
66
}
72
67
73
68
public boolean isMacroFunctionLike () {
74
- return Index_h .clang_Cursor_isMacroFunctionLike (cursor ) != 0 ;
69
+ return Index_h .clang_Cursor_isMacroFunctionLike (segment ) != 0 ;
75
70
}
76
71
77
72
public String spelling () {
78
- return LibClang . CXStrToString ( allocator ->
79
- Index_h . clang_getCursorSpelling ( allocator , cursor ) );
73
+ var spelling = Index_h . clang_getCursorSpelling ( LibClang . STRING_ALLOCATOR , segment );
74
+ return LibClang . CXStrToString ( spelling );
80
75
}
81
76
82
77
public String USR () {
83
- return LibClang . CXStrToString ( allocator ->
84
- Index_h . clang_getCursorUSR ( allocator , cursor ) );
78
+ var USR = Index_h . clang_getCursorUSR ( LibClang . STRING_ALLOCATOR , segment );
79
+ return LibClang . CXStrToString ( USR );
85
80
}
86
81
87
82
public String prettyPrinted (PrintingPolicy policy ) {
88
- return LibClang . CXStrToString ( allocator ->
89
- Index_h . clang_getCursorPrettyPrinted ( allocator , cursor , policy . ptr ()) );
83
+ var prettyOutput = Index_h . clang_getCursorPrettyPrinted ( LibClang . STRING_ALLOCATOR , segment , policy . ptr ());
84
+ return LibClang . CXStrToString ( prettyOutput );
90
85
}
91
86
92
87
public String prettyPrinted () {
@@ -96,129 +91,169 @@ public String prettyPrinted() {
96
91
}
97
92
98
93
public String displayName () {
99
- return LibClang . CXStrToString ( allocator ->
100
- Index_h . clang_getCursorDisplayName ( allocator , cursor ) );
94
+ var displayName = Index_h . clang_getCursorDisplayName ( LibClang . STRING_ALLOCATOR , segment );
95
+ return LibClang . CXStrToString ( displayName );
101
96
}
102
97
103
98
public boolean equalCursor (Cursor other ) {
104
- return Index_h .clang_equalCursors (cursor , other .cursor ) != 0 ;
99
+ return Index_h .clang_equalCursors (segment , other .segment ) != 0 ;
105
100
}
106
101
107
102
public Type type () {
108
- return new Type (Index_h .clang_getCursorType (IMPLICIT_ALLOCATOR , cursor ));
103
+ var cursorType = Index_h .clang_getCursorType (owner , segment );
104
+ return new Type (cursorType , owner );
109
105
}
110
106
111
107
public Type getEnumDeclIntegerType () {
112
- return new Type (Index_h .clang_getEnumDeclIntegerType (IMPLICIT_ALLOCATOR , cursor ));
108
+ var enumType = Index_h .clang_getEnumDeclIntegerType (owner , segment );
109
+ return new Type (enumType , owner );
113
110
}
114
111
115
112
public Cursor getDefinition () {
116
- return new Cursor (Index_h .clang_getCursorDefinition (IMPLICIT_ALLOCATOR , cursor ));
113
+ var cursorDef = Index_h .clang_getCursorDefinition (owner , segment );
114
+ return new Cursor (cursorDef , owner );
117
115
}
118
116
119
117
public SourceLocation getSourceLocation () {
120
- MemorySegment loc = Index_h .clang_getCursorLocation (IMPLICIT_ALLOCATOR , cursor );
118
+ MemorySegment loc = Index_h .clang_getCursorLocation (owner , segment );
121
119
try (MemorySession session = MemorySession .openConfined ()) {
122
120
if (Index_h .clang_equalLocations (loc , Index_h .clang_getNullLocation (session )) != 0 ) {
123
121
return null ;
124
122
}
125
123
}
126
- return new SourceLocation (loc );
124
+ return new SourceLocation (loc , owner );
127
125
}
128
126
129
127
public SourceRange getExtent () {
130
- MemorySegment range = Index_h .clang_getCursorExtent (IMPLICIT_ALLOCATOR , cursor );
128
+ MemorySegment range = Index_h .clang_getCursorExtent (owner , segment );
131
129
if (Index_h .clang_Range_isNull (range ) != 0 ) {
132
130
return null ;
133
131
}
134
- return new SourceRange (range );
132
+ return new SourceRange (range , owner );
135
133
}
136
134
137
135
public int numberOfArgs () {
138
- return Index_h .clang_Cursor_getNumArguments (cursor );
136
+ return Index_h .clang_Cursor_getNumArguments (segment );
139
137
}
140
138
141
139
public Cursor getArgument (int idx ) {
142
- return new Cursor (Index_h .clang_Cursor_getArgument (IMPLICIT_ALLOCATOR , cursor , idx ));
140
+ var cursorArg = Index_h .clang_Cursor_getArgument (owner , segment , idx );
141
+ return new Cursor (cursorArg , owner );
143
142
}
144
143
145
144
// C long long, 64-bit
146
145
public long getEnumConstantValue () {
147
- return Index_h .clang_getEnumConstantDeclValue (cursor );
146
+ return Index_h .clang_getEnumConstantDeclValue (segment );
148
147
}
149
148
150
149
// C unsigned long long, 64-bit
151
150
public long getEnumConstantUnsignedValue () {
152
- return Index_h .clang_getEnumConstantDeclUnsignedValue (cursor );
151
+ return Index_h .clang_getEnumConstantDeclUnsignedValue (segment );
153
152
}
154
153
155
154
public boolean isBitField () {
156
- return Index_h .clang_Cursor_isBitField (cursor ) != 0 ;
155
+ return Index_h .clang_Cursor_isBitField (segment ) != 0 ;
157
156
}
158
157
159
158
public int getBitFieldWidth () {
160
- return Index_h .clang_getFieldDeclBitWidth (cursor );
159
+ return Index_h .clang_getFieldDeclBitWidth (segment );
161
160
}
162
161
163
162
public CursorKind kind () {
164
163
return CursorKind .valueOf (kind );
165
164
}
166
165
167
166
public CursorLanguage language () {
168
- return CursorLanguage .valueOf (Index_h .clang_getCursorLanguage (cursor ));
167
+ return CursorLanguage .valueOf (Index_h .clang_getCursorLanguage (segment ));
169
168
}
170
169
171
170
public int kind0 () {
172
171
return kind ;
173
172
}
174
173
175
174
/**
176
- * For a cursor that is a reference, retrieve a cursor representing the entity that it references.
175
+ * For a segment that is a reference, retrieve a segment representing the entity that it references.
177
176
*/
178
177
public Cursor getCursorReferenced () {
179
- return new Cursor (Index_h .clang_getCursorReferenced (
180
- IMPLICIT_ALLOCATOR , cursor ));
178
+ var referenced = Index_h .clang_getCursorReferenced (owner , segment );
179
+ return new Cursor (referenced , owner );
180
+ }
181
+
182
+ public void forEach (Consumer <Cursor > action ) {
183
+ CursorChildren .forEach (this , action );
181
184
}
182
185
186
+ /**
187
+ * We run the visitor action inside the upcall, so that we do not have to worry about
188
+ * having to copy cursors into separate off-heap storage. To do this, we have to setup
189
+ * some context for the upcall, so that the upcall code can call the "correct" user-defined visitor action.
190
+ * Note: exceptions must be delayed until after the upcall has returned; this is necessary as upcalls
191
+ * cannot throw (if they do, they cause a JVM crash).
192
+ */
183
193
private static class CursorChildren {
184
- private static final ArrayList <Cursor > children = new ArrayList <>();
194
+
195
+ static class Context {
196
+ private final Consumer <Cursor > action ;
197
+ private final ClangDisposable owner ;
198
+ private RuntimeException exception ;
199
+
200
+ Context (Consumer <Cursor > action , ClangDisposable owner ) {
201
+ this .action = action ;
202
+ this .owner = owner ;
203
+ }
204
+
205
+ boolean visit (MemorySegment segment ) {
206
+ // Note: the session of this cursor is smaller than that of the translation unit
207
+ // this is because the cursor will be destroyed when the upcall ends. This means
208
+ // that the cursor passed by the visitor must NOT be leaked into a field and accessed
209
+ // at a later time (or the liveness check will fail with IllegalStateException).
210
+ try {
211
+ // run the visitor action
212
+ action .accept (new Cursor (segment , owner ));
213
+ return true ;
214
+ } catch (RuntimeException ex ) {
215
+ // if we fail, record the exception, and return false to stop the visit
216
+ exception = ex ;
217
+ return false ;
218
+ }
219
+ }
220
+
221
+ void handleExceptions () {
222
+ if (exception != null ) {
223
+ throw exception ;
224
+ }
225
+ }
226
+ }
227
+
228
+ static Context pendingContext = null ;
229
+
185
230
private static final MemorySegment callback = CXCursorVisitor .allocate ((c , p , d ) -> {
186
- MemorySegment copy = MemorySegment . allocateNative ( c . byteSize (), MemorySession . openImplicit ());
187
- copy . copyFrom ( c );
188
- Cursor cursor = new Cursor ( copy );
189
- children . add ( cursor );
190
- return Index_h . CXChildVisit_Continue ();
231
+ if ( pendingContext . visit ( c )) {
232
+ return Index_h . CXChildVisit_Continue ( );
233
+ } else {
234
+ return Index_h . CXChildVisit_Break ( );
235
+ }
191
236
}, MemorySession .openImplicit ());
192
237
193
- synchronized static Stream <Cursor > get (Cursor c ) {
238
+ synchronized static void forEach (Cursor c , Consumer <Cursor > op ) {
239
+ // everything is confined, no need to synchronize
240
+ Context prevContext = pendingContext ;
194
241
try {
195
- Index_h .clang_visitChildren (c .cursor , callback , MemoryAddress .NULL );
196
- return new ArrayList <>(children ).stream ();
242
+ pendingContext = new Context (op , c .owner );
243
+ Index_h .clang_visitChildren (c .segment , callback , MemoryAddress .NULL );
244
+ pendingContext .handleExceptions ();
197
245
} finally {
198
- children . clear () ;
246
+ pendingContext = prevContext ;
199
247
}
200
248
}
201
249
}
202
250
203
- public Stream <Cursor > children () {
204
- return CursorChildren .get (this );
205
- }
206
-
207
- public Stream <Cursor > allChildren () {
208
- return children ().flatMap (c -> Stream .concat (Stream .of (c ), c .children ()));
209
- }
210
-
211
- public String getMangling () {
212
- return LibClang .CXStrToString (allocator ->
213
- Index_h .clang_Cursor_getMangling (allocator , cursor ));
214
- }
215
-
216
251
public TranslationUnit getTranslationUnit () {
217
- return new TranslationUnit (Index_h .clang_Cursor_getTranslationUnit (cursor ));
252
+ return new TranslationUnit (Index_h .clang_Cursor_getTranslationUnit (segment ));
218
253
}
219
254
220
255
private MemoryAddress eval0 () {
221
- return Index_h .clang_Cursor_Evaluate (cursor );
256
+ return Index_h .clang_Cursor_Evaluate (segment );
222
257
}
223
258
224
259
public EvalResult eval () {
@@ -227,7 +262,7 @@ public EvalResult eval() {
227
262
}
228
263
229
264
public PrintingPolicy getPrintingPolicy () {
230
- return new PrintingPolicy (Index_h .clang_getCursorPrintingPolicy (cursor ));
265
+ return new PrintingPolicy (Index_h .clang_getCursorPrintingPolicy (segment ));
231
266
}
232
267
233
268
@ Override
@@ -236,7 +271,7 @@ public boolean equals(Object other) {
236
271
return true ;
237
272
}
238
273
return other instanceof Cursor otherCursor &&
239
- (Index_h .clang_equalCursors (cursor , otherCursor .cursor ) != 0 );
274
+ (Index_h .clang_equalCursors (segment , otherCursor .segment ) != 0 );
240
275
}
241
276
242
277
@ Override
0 commit comments