54
54
r"package\s.*?;" ,
55
55
re .DOTALL | re .MULTILINE | re .UNICODE )
56
56
57
+ PTRN_GILNODE_ARG = re .compile (
58
+ r"(?P<start>,)(?P<arg>.*?@Cached GilNode gil)" ,
59
+ re .MULTILINE | re .UNICODE )
60
+
61
+ PTRN_REM_GIL_TRY_CATCH = re .compile (
62
+ r"(boolean mustRelease = gil\.acquire\(\);\s+)?try\s\{\s(?P<body>.+?)\s+\} finally \{\s+gil\.release\(mustRelease\);\s+\}" ,
63
+ re .DOTALL | re .MULTILINE | re .UNICODE )
64
+
65
+ PTRN_REM_GIL_ARGS = re .compile (
66
+ r'(,\s+)?@((Cached\.)?Exclusive|Shared\("gil"\))\s@Cached GilNode gil' ,
67
+ re .DOTALL | re .MULTILINE | re .UNICODE )
68
+
69
+ PTRN_REM_GIL_BIND = re .compile (
70
+ r'(,\s+)?@Bind.*?\sboolean mustRelease' ,
71
+ re .DOTALL | re .MULTILINE | re .UNICODE )
72
+
73
+ PTRN_LIB_MSG = re .compile (
74
+ r'^ \w(?P<header>.*?)\s(?P<method>[a-zA-Z][a-zA-Z0-9]*)\((?P<args>.*?)\)(?P<throws>\sthrows .*?)?\s\{' ,
75
+ re .MULTILINE | re .UNICODE )
76
+
77
+ PTRN_LIB_MSG_ABS = re .compile (
78
+ r'^ \w(?P<header>.*?)\s(?P<method>[a-zA-Z][a-zA-Z0-9]*)\((?P<args>.*?)\)(?P<throws>\sthrows .*?)?;' ,
79
+ re .MULTILINE | re .UNICODE )
80
+
57
81
RUNTIME_PACKAGE = "package com.oracle.graal.python.runtime;"
58
82
GIL_NODE_IMPORT = "import com.oracle.graal.python.runtime.GilNode;"
59
83
CACHED_IMPORT = "import com.oracle.truffle.api.dsl.Cached;"
@@ -126,6 +150,19 @@ def is_fallback(self):
126
150
def is_with_gil (self ):
127
151
return "GilNode gil" in self .source
128
152
153
+ @property
154
+ def is_class (self ):
155
+ return ' class ' in self .match .group ('header' )
156
+
157
+ @property
158
+ def name (self ):
159
+ rv = self .match .group ('method' )
160
+ if self .is_class :
161
+ hdr = self .match .group ('header' ).split ()
162
+ name = hdr [hdr .index ('class' ) + 1 ]
163
+ rv = name [:1 ].lower () + name [1 :]
164
+ return rv .strip ()
165
+
129
166
@property
130
167
def source_with_gil (self ):
131
168
# handle varargs ...
@@ -134,7 +171,7 @@ def source_with_gil(self):
134
171
_uncached_gil = "GilNode gil = GilNode.getUncached();"
135
172
else :
136
173
_uncached_gil = ""
137
- _args += ", " if self .args else ""
174
+ _args += ",\n " if self .args else ""
138
175
if self ._shared and ('limit = ' not in self .header or 'limit = "1"' in self .header ):
139
176
_args += '@Shared("gil")'
140
177
else :
@@ -152,13 +189,21 @@ def source_with_gil(self):
152
189
}
153
190
}""" % (self .header , _args , self .throws , _uncached_gil , self .body .strip ())
154
191
155
- def apply_gil (self ):
156
- return
192
+ @property
193
+ def source_without_gil (self ):
194
+ source = self .source
195
+ source = re .sub (PTRN_REM_GIL_TRY_CATCH , lambda match : match .group ('body' ), source , 1 )
196
+ source = re .sub (PTRN_REM_GIL_ARGS , "" , source , 1 )
197
+ source = re .sub (PTRN_REM_GIL_BIND , "" , source , 1 )
198
+ return source
157
199
158
200
def __str__ (self ):
159
201
return "START: {}, ARGS {}:{}, BODY_START: {}, STOP: {}, CONTENT:\n {}" .format (
160
202
self ._start , self ._args_start , self ._args_end , self ._body_start , self ._end , self .source )
161
203
204
+ def __repr__ (self ):
205
+ return 'Message({})' .format (self .name )
206
+
162
207
163
208
def message_is_class (match ):
164
209
return ' class ' in match .group ('header' )
@@ -206,62 +251,113 @@ def file_names_filter(f_name, names):
206
251
return False
207
252
208
253
209
- def main (sources , add = True , dry_run = True , check_style = True , single_source = False , source_filter = None ,
210
- ignore_filter = None , count = False , sharing = False ):
254
+ def fix_gilnode_arg (source ):
255
+ def repl (match ):
256
+ return match .group ("start" ) + "\n " + match .group ("arg" )
257
+ return re .sub (PTRN_GILNODE_ARG , repl , source )
258
+
259
+
260
+ def get_lib_messages (lib , files ):
261
+ if lib is None :
262
+ return None
263
+ lib_file = next (f for f in files if lib in f )
264
+ print ("got lib source: {}" .format (lib_file ))
265
+ with open (lib_file , 'r' ) as SRC :
266
+ src = SRC .read ()
267
+ messages = set ()
268
+ for m in re .finditer (PTRN_LIB_MSG , src ):
269
+ messages .add (m .group ('method' ))
270
+ for m in re .finditer (PTRN_LIB_MSG_ABS , src ):
271
+ messages .add (m .group ('method' ))
272
+ return messages
273
+
274
+
275
+ def main (sources , add = True , lib = None , dry_run = True , check_style = True , single_source = False , source_filter = None ,
276
+ ignore_filter = None , count = False , sharing = False , fix_style = False ):
211
277
files = glob .glob ("{}**/*.java" .format (sources ), recursive = True )
278
+ lib_messages = get_lib_messages (lib , files )
279
+ if lib :
280
+ from pprint import pprint
281
+ print ("[{}] messages: " .format (lib ))
282
+ pprint (lib_messages )
283
+
212
284
if ignore_filter :
213
285
files = list (filter (lambda f : not file_names_filter (f , ignore_filter ), files ))
214
286
if source_filter and not count :
215
287
files = list (filter (lambda f : file_names_filter (f , source_filter ), files ))
216
288
289
+ remove = not add
217
290
cnt = 0
218
291
for java_file in files :
219
292
with open (java_file , 'r+' ) as SRC :
220
293
source = SRC .read ()
221
- if add :
294
+ if fix_style :
295
+ if "GilNode" in source :
296
+ print ("[process] {}" .format (java_file ))
297
+ source = fix_gilnode_arg (source )
298
+ SRC .seek (0 )
299
+ SRC .write (source )
300
+ continue
301
+ else :
222
302
messages , shared = get_messages (source , PTRN_MESSAGE , sharing = sharing )
223
303
if len (messages ) > 0 :
224
- if 'GilNode gil' in source or SKIP_GIL in source :
225
- print ("[skipping] {}" .format (java_file ))
226
- continue
227
-
228
304
if count :
229
305
cnt += 1
230
306
continue
231
307
232
308
print ("[process] dry run: {}, add: {}. messages: {}, {}" .format (
233
309
dry_run , add , len (messages ), java_file ))
234
- source_with_gil = []
310
+
311
+ def get_mod_source (msg ):
312
+ return msg .source_with_gil if add else msg .source_without_gil
313
+
314
+ if (add and 'GilNode gil' in source ) or \
315
+ (remove and 'GilNode gil' not in source ) or \
316
+ SKIP_GIL in source :
317
+ print ("[skipping] {}" .format (java_file ))
318
+ continue
319
+
320
+ if remove and '@ExportLibrary({}.class)' .format (lib ) not in source :
321
+ print ("[skipping] {}" .format (java_file ))
322
+ continue
323
+
324
+ if lib :
325
+ messages = list (filter (lambda m : m .name in lib_messages and m .is_with_gil , messages ))
326
+ print ("process messages: " , messages )
327
+
328
+ if len (messages ) == 0 :
329
+ continue
330
+
331
+ _src_parts = []
235
332
m = messages [0 ]
236
333
if len (messages ) == 1 :
237
- source_with_gil = [source [:m .start ], m . source_with_gil , source [m .end :]]
334
+ _src_parts = [source [:m .start ], get_mod_source ( m ) , source [m .end :]]
238
335
else :
239
- source_with_gil .append (source [:m .start ])
336
+ _src_parts .append (source [:m .start ])
240
337
for m1 , m2 in zip (messages [:- 1 ], messages [1 :]):
241
- source_with_gil .append (m1 .source_with_gil )
242
- source_with_gil .append (source [m1 .end : m2 .start ])
243
- source_with_gil .append (m2 .source_with_gil )
244
- source_with_gil .append (source [m2 .end :])
338
+ _src_parts .append (get_mod_source (m1 ))
339
+ _src_parts .append (source [m1 .end : m2 .start ])
340
+ _src_parts .append (get_mod_source (m2 ))
341
+ _src_parts .append (source [m2 .end :])
342
+
343
+ modified_source = '' .join (_src_parts )
344
+ if add :
345
+ modified_source = add_import (modified_source , shared = shared )
245
346
246
- source_with_gil = '' .join (source_with_gil )
247
- source_with_gil = add_import (source_with_gil , shared = shared )
248
347
if dry_run :
249
- print (source_with_gil )
348
+ print (modified_source )
250
349
return
251
350
else :
351
+ SRC .truncate (0 )
252
352
SRC .seek (0 )
253
- SRC .write (source_with_gil )
353
+ if modified_source :
354
+ SRC .write (modified_source )
254
355
if single_source :
255
356
break
256
- else :
257
- print ("removal of the GIL not yet supported" )
258
- return
259
357
260
358
if count :
261
359
print ("TO PROCESS: {} files" .format (cnt ))
262
360
if check_style and not count :
263
- # running the checkstyle gate (twice)
264
- # for i in range(2):
265
361
os .system ("mx python-gate --tags style,python-license" )
266
362
267
363
@@ -271,14 +367,16 @@ def main(sources, add=True, dry_run=True, check_style=True, single_source=False,
271
367
action = "store_true" )
272
368
parser .add_argument ("--count" , help = "count how many files may need the GIL" , action = "store_true" )
273
369
parser .add_argument ("--remove" , help = "remove the GIL" , action = "store_true" )
370
+ parser .add_argument ("--lib" , type = str , help = "the internal library for which messages to remove the GIL" )
274
371
parser .add_argument ("--no_style" , help = "do not run the style checker" , action = "store_true" )
275
372
parser .add_argument ("--sharing" , help = "use @Shared" , action = "store_true" )
276
373
parser .add_argument ("--single" , help = "stop after modifying the first source" , action = "store_true" )
277
374
parser .add_argument ("--filter" , type = str , help = "filter for source name(s) (comma separated)" )
278
375
parser .add_argument ("--ignore" , type = str , help = "ignore filter for source name(s) (comma separated)" )
376
+ parser .add_argument ("--fix_style" , help = "fix GilNode related style issue" , action = "store_true" )
279
377
parser .add_argument ("sources" , type = str , help = "location of sources" )
280
378
args = parser .parse_args ()
281
379
282
- main (args .sources , add = not args .remove , dry_run = args .dry_run , check_style = not args .no_style ,
380
+ main (args .sources , add = not args .remove , lib = args . lib , dry_run = args .dry_run , check_style = not args .no_style ,
283
381
single_source = args .single , source_filter = args .filter , ignore_filter = args .ignore , count = args .count ,
284
- sharing = args .sharing )
382
+ sharing = args .sharing , fix_style = args . fix_style )
0 commit comments