3
3
// BSD-style license that can be found in the LICENSE file.
4
4
5
5
// Run this script to print out the generated augmentation library for an
6
- // example class.
6
+ // example class, created with fake data, and get some basic timing info:
7
7
//
8
- // This is primarily for illustration purposes, so we can get an idea of how
9
- // things would work on a real-ish example.
10
- library language.working.macros.example.run;
8
+ // dart benchmark/simple.dart
9
+ //
10
+ // You can also compile this benchmark to exe and run it as follows:
11
+ //
12
+ // dart compile exe benchmark/simple.dart && ./benchmark/simple.exe
13
+ //
14
+ // Pass `--help` for usage and configuration options.
15
+ library language.working.macros.benchmark.simple;
11
16
12
17
import 'dart:io' ;
13
18
19
+ import 'package:args/args.dart' ;
14
20
import 'package:dart_style/dart_style.dart' ;
15
21
16
22
// There is no public API exposed yet, the in progress api lives here.
@@ -22,6 +28,8 @@ import 'package:_fe_analyzer_shared/src/macros/executor.dart';
22
28
import 'package:_fe_analyzer_shared/src/macros/executor/introspection_impls.dart' ;
23
29
import 'package:_fe_analyzer_shared/src/macros/executor/remote_instance.dart' ;
24
30
import 'package:_fe_analyzer_shared/src/macros/executor/serialization.dart' ;
31
+ import 'package:_fe_analyzer_shared/src/macros/executor/isolated_executor.dart'
32
+ as isolatedExecutor;
25
33
import 'package:_fe_analyzer_shared/src/macros/executor/process_executor.dart'
26
34
as processExecutor;
27
35
@@ -30,22 +38,71 @@ void _log(String message) {
30
38
print ('${_watch .elapsed }: $message ' );
31
39
}
32
40
33
- const clientSerializationMode = SerializationMode .byteDataClient;
34
- const serverSerializationMode = SerializationMode .byteDataServer;
41
+ final argParser = ArgParser ()
42
+ ..addOption ('serialization-strategy' ,
43
+ allowed: ['bytedata' , 'json' ],
44
+ defaultsTo: 'bytedata' ,
45
+ help: 'The serialization strategy to use when talking to macro programs.' )
46
+ ..addOption ('macro-execution-strategy' ,
47
+ allowed: ['aot' , 'isolate' ],
48
+ defaultsTo: 'aot' ,
49
+ help: 'The execution strategy for precompiled macros.' )
50
+ ..addFlag ('help' , negatable: false , hide: true );
35
51
36
52
// Run this script to print out the generated augmentation library for an example class.
37
- void main () async {
38
- _log ('Preparing to run macros.' );
53
+ void main (List <String > args) async {
54
+ var parsedArgs = argParser.parse (args);
55
+
56
+ if (parsedArgs['help' ] == true ) {
57
+ print (argParser.usage);
58
+ return ;
59
+ }
60
+
61
+ // Set up all of our options
62
+ var parsedSerializationStrategy =
63
+ parsedArgs['serialization-strategy' ] as String ;
64
+ SerializationMode clientSerializationMode;
65
+ SerializationMode serverSerializationMode;
66
+ switch (parsedSerializationStrategy) {
67
+ case 'bytedata' :
68
+ clientSerializationMode = SerializationMode .byteDataClient;
69
+ serverSerializationMode = SerializationMode .byteDataServer;
70
+ break ;
71
+ case 'json' :
72
+ clientSerializationMode = SerializationMode .jsonClient;
73
+ serverSerializationMode = SerializationMode .jsonServer;
74
+ break ;
75
+ default :
76
+ throw ArgumentError (
77
+ 'Unrecognized serialization mode $parsedSerializationStrategy ' );
78
+ }
79
+
80
+ var macroExecutionStrategy = parsedArgs['macro-execution-strategy' ] as String ;
81
+ var hostMode = Platform .script.path.endsWith ('.dart' ) ||
82
+ Platform .script.path.endsWith ('.dill' )
83
+ ? 'jit'
84
+ : 'aot' ;
85
+ _log ('''
86
+ Running with the following options:
87
+
88
+ Serialization strategy: $parsedSerializationStrategy
89
+ Macro execution strategy: $macroExecutionStrategy
90
+ Host app mode: $hostMode
91
+ ''' );
92
+
39
93
// You must run from the `macros` directory, paths are relative to that.
40
- var thisFile = File ('example /data_class.dart' );
41
- if (! thisFile .existsSync ()) {
94
+ var dataClassFile = File ('lib /data_class.dart' );
95
+ if (! dataClassFile .existsSync ()) {
42
96
print ('This script must be ran from the `macros` directory.' );
43
97
exit (1 );
44
98
}
45
- var executor = await processExecutor.start (serverSerializationMode);
99
+ _log ('Preparing to run macros' );
100
+ var executor = macroExecutionStrategy == 'aot'
101
+ ? await processExecutor.start (serverSerializationMode)
102
+ : await isolatedExecutor.start (serverSerializationMode);
46
103
var tmpDir = Directory .systemTemp.createTempSync ('data_class_macro_example' );
47
104
try {
48
- var macroUri = thisFile.absolute.uri ;
105
+ var macroUri = Uri . parse ( 'package:macro_proposal/data_class.dart' ) ;
49
106
var macroName = 'DataClass' ;
50
107
51
108
var bootstrapContent = bootstrapMacroIsolate ({
@@ -61,8 +118,9 @@ void main() async {
61
118
_log ('Compiling DataClass macro' );
62
119
var buildSnapshotResult = await Process .run ('dart' , [
63
120
'compile' ,
64
- ' exe' ,
121
+ macroExecutionStrategy == 'aot' ? ' exe' : 'jit-snapshot ' ,
65
122
'--packages=.dart_tool/package_config.json' ,
123
+ '--enable-experiment=macros' ,
66
124
bootstrapFile.uri.toFilePath (),
67
125
'-o' ,
68
126
kernelOutputFile.uri.toFilePath (),
@@ -88,26 +146,32 @@ void main() async {
88
146
late Duration firstRunEnd;
89
147
late Duration first11RunsEnd;
90
148
for (var i = 1 ; i <= 111 ; i++ ) {
91
- var _shouldLog = i == 1 || i == 10 || i == 100 ;
149
+ var _shouldLog = i == 1 || i == 11 || i == 111 ;
92
150
if (_shouldLog) _log ('Running DataClass macro for the ${i }th time' );
93
151
if (instanceId.shouldExecute (DeclarationKind .clazz, Phase .types)) {
94
152
if (_shouldLog) _log ('Running types phase' );
95
- var result = await executor.executeTypesPhase (instanceId, myClass);
153
+ var result = await executor.executeTypesPhase (
154
+ instanceId, myClass, SimpleIdentifierResolver ());
96
155
if (i == 1 ) results.add (result);
97
156
}
98
157
if (instanceId.shouldExecute (DeclarationKind .clazz, Phase .declarations)) {
99
158
if (_shouldLog) _log ('Running declarations phase' );
100
159
var result = await executor.executeDeclarationsPhase (
101
- instanceId, myClass, FakeTypeResolver (), FakeClassIntrospector ());
160
+ instanceId,
161
+ myClass,
162
+ SimpleIdentifierResolver (),
163
+ SimpleTypeResolver (),
164
+ SimpleClassIntrospector ());
102
165
if (i == 1 ) results.add (result);
103
166
}
104
167
if (instanceId.shouldExecute (DeclarationKind .clazz, Phase .definitions)) {
105
168
if (_shouldLog) _log ('Running definitions phase' );
106
169
var result = await executor.executeDefinitionsPhase (
107
170
instanceId,
108
171
myClass,
109
- FakeTypeResolver (),
110
- FakeClassIntrospector (),
172
+ SimpleIdentifierResolver (),
173
+ SimpleTypeResolver (),
174
+ SimpleClassIntrospector (),
111
175
FakeTypeDeclarationResolver ());
112
176
if (i == 1 ) results.add (result);
113
177
}
@@ -123,10 +187,7 @@ void main() async {
123
187
124
188
_log ('Building augmentation library' );
125
189
var library = executor.buildAugmentationLibrary (results, (identifier) {
126
- if (identifier == boolIdentifier ||
127
- identifier == objectIdentifier ||
128
- identifier == stringIdentifier ||
129
- identifier == intIdentifier) {
190
+ if (['bool' , 'Object' , 'String' , 'int' ].contains (identifier.name)) {
130
191
return ResolvedIdentifier (
131
192
kind: IdentifierKind .topLevelMember,
132
193
name: identifier.name,
@@ -139,7 +200,7 @@ void main() async {
139
200
: IdentifierKind .instanceMember,
140
201
name: identifier.name,
141
202
staticScope: null ,
142
- uri: Platform .script. resolve ( 'data_class .dart' ));
203
+ uri: Uri . parse ( 'package:app/main .dart' ));
143
204
}
144
205
});
145
206
executor.close ();
@@ -299,7 +360,8 @@ abstract class Fake {
299
360
throw UnimplementedError (invocation.memberName.toString ());
300
361
}
301
362
302
- class FakeClassIntrospector extends Fake implements ClassIntrospector {
363
+ /// Returns data as if everything was [myClass] .
364
+ class SimpleClassIntrospector extends Fake implements ClassIntrospector {
303
365
@override
304
366
Future <List <ConstructorDeclaration >> constructorsOf (
305
367
covariant ClassDeclaration clazz) async =>
@@ -308,23 +370,59 @@ class FakeClassIntrospector extends Fake implements ClassIntrospector {
308
370
@override
309
371
Future <List <FieldDeclaration >> fieldsOf (
310
372
covariant ClassDeclaration clazz) async =>
311
- myClassFields;
373
+ clazz == myClass ? myClassFields : [] ;
312
374
313
375
@override
314
376
Future <List <MethodDeclaration >> methodsOf (
315
377
covariant ClassDeclaration clazz) async =>
316
- myClassMethods;
378
+ clazz == myClass ? myClassMethods : [] ;
317
379
318
380
@override
319
381
Future <ClassDeclaration ?> superclassOf (
320
382
covariant ClassDeclaration clazz) async =>
321
383
clazz == myClass ? objectClass : null ;
322
384
}
323
385
386
+ /// This is a very basic identifier resolver, it does no actual resolution.
387
+ class SimpleIdentifierResolver implements IdentifierResolver {
388
+ /// Just returns a new [Identifier] whose name is [name] .
389
+ @override
390
+ Future <Identifier > resolveIdentifier (Uri library, String name) async =>
391
+ IdentifierImpl (id: RemoteInstance .uniqueId, name: name);
392
+ }
393
+
324
394
class FakeTypeDeclarationResolver extends Fake
325
395
implements TypeDeclarationResolver {}
326
396
327
- class FakeTypeResolver extends Fake implements TypeResolver {}
397
+ /// Only supports named types with no type arguments.
398
+ class SimpleTypeResolver implements TypeResolver {
399
+ @override
400
+ Future <StaticType > resolve (TypeAnnotationCode type) async {
401
+ if (type is ! NamedTypeAnnotationCode ) {
402
+ throw UnsupportedError ('Only named type annotations are supported' );
403
+ }
404
+ if (type.typeArguments.isNotEmpty) {
405
+ throw UnsupportedError ('Type arguments are not supported' );
406
+ }
407
+ return SimpleNamedStaticType (type.name.name, isNullable: type.isNullable);
408
+ }
409
+ }
410
+
411
+ /// Only supports exact matching, and only goes off of the name and nullability.
412
+ class SimpleNamedStaticType implements NamedStaticType {
413
+ final bool isNullable;
414
+ final String name;
415
+
416
+ SimpleNamedStaticType (this .name, {this .isNullable = false });
417
+
418
+ @override
419
+ Future <bool > isExactly (covariant SimpleNamedStaticType other) async =>
420
+ isNullable == other.isNullable && name == other.name;
421
+
422
+ @override
423
+ Future <bool > isSubtypeOf (covariant StaticType other) =>
424
+ throw UnimplementedError ();
425
+ }
328
426
329
427
extension _ on Duration {
330
428
Duration dividedBy (int amount) =>
0 commit comments