Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(245)

Side by Side Diff: pkg/compiler/lib/src/native/behavior.dart

Issue 969093002: dart2js: Allow to encode side-effects in the spec-string of JS and similar built-ins. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Fix another bad type annotation. Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/compiler/lib/src/universe/side_effects.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of native; 5 part of native;
6 6
7 /// This class is a temporary work-around until we get a more powerful DartType. 7 /// This class is a temporary work-around until we get a more powerful DartType.
8 class SpecialType { 8 class SpecialType {
9 final String name; 9 final String name;
10 const SpecialType._(this.name); 10 const SpecialType._(this.name);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 /// [DartType]s or [SpecialType]s instantiated by the native element. 53 /// [DartType]s or [SpecialType]s instantiated by the native element.
54 final List typesInstantiated = []; 54 final List typesInstantiated = [];
55 55
56 // If this behavior is for a JS expression, [codeTemplate] contains the 56 // If this behavior is for a JS expression, [codeTemplate] contains the
57 // parsed tree. 57 // parsed tree.
58 js.Template codeTemplate; 58 js.Template codeTemplate;
59 59
60 final SideEffects sideEffects = new SideEffects.empty(); 60 final SideEffects sideEffects = new SideEffects.empty();
61 61
62 /// Processes the type specification string of a call to JS and stores the 62 /// Processes the type specification string of a call to JS and stores the
63 /// result in the [typesReturned] and [typesInstantiated]. 63 /// result in the [typesReturned] and [typesInstantiated]. It furthermore
64 /// computes the side effects, and, if given, invokes [setSideEffects] with
65 /// the computed effects. If no side effects are encoded in the [specString]
66 /// the [setSideEffects] method is not invoked.
64 /// 67 ///
65 /// Two forms of the string is supported: 68 /// Two forms of the string is supported:
66 /// 1) A single type string of the form 'void', '', 'var' or 'T1|...|Tn' 69 /// 1) A single type string of the form 'void', '', 'var' or 'T1|...|Tn'
67 /// which defines the types returned and for the later form also created by 70 /// which defines the types returned and for the later form also created by
68 /// the call to JS. 71 /// the call to JS.
69 /// 2) A sequence of the form '<tag>:<type-string>;' where <tag> is either 72 /// 2) A sequence of the form
70 /// 'returns' or 'creates' and where <type-string> is a type string like in 73 /// '<type-tag>:<type-string>;<effect-tag>:<effect-string>'
71 /// 1). The type string marked by 'returns' defines the types returned and 74 /// where <type-tag> is either 'returns' or 'creates' and where
72 /// 'creates' defines the types created by the call to JS. Each tag kind 75 /// <type-string> is a type string like in 1). The type string marked by
73 /// can only occur once in the sequence. 76 /// 'returns' defines the types returned and 'creates' defines the types
77 /// created by the call to JS.
78 ///
79 /// The <effect-tag> is either 'effects' or 'depends' and
80 /// <effect-string> is either 'all', 'none' or a comma-separated list of
81 /// 'no-index', 'no-instance', 'no-static'.
82 ///
83 /// The flag 'all' indicates that the call affects/depends on every
84 /// side-effect. The flag 'none' indicates that the call does not affect
85 /// (resp. depends on) anything.
86 ///
87 /// 'no-index' indicates that the call does *not* do any array index-store
88 /// (for 'effects'), or depends on any value in an array (for 'depends').
89 /// The flag 'no-instance' indicates that the call does not modify (resp.
90 /// depends on) any instance variable. Similarly static variables are
91 /// indicated with 'no-static'. The flags 'effects' and 'depends' must be
92 /// used in unison (either both are present or none is).
93 ///
94 /// Each tag kind (including the 'type-tag's) can only occur once in the
95 /// sequence.
74 /// 96 ///
75 /// [specString] is the specification string, [resolveType] resolves named 97 /// [specString] is the specification string, [resolveType] resolves named
76 /// types into type values, [typesReturned] and [typesInstantiated] collects 98 /// types into type values, [typesReturned] and [typesInstantiated] collects
77 /// the types defined by the specification string, and [objectType] and 99 /// the types defined by the specification string, and [objectType] and
78 /// [nullType] define the types for `Object` and `Null`, respectively. The 100 /// [nullType] define the types for `Object` and `Null`, respectively. The
79 /// latter is used for the type strings of the form '' and 'var'. 101 /// latter is used for the type strings of the form '' and 'var'.
80 // TODO(johnniwinther): Use ';' as a separator instead of a terminator. 102 // TODO(johnniwinther): Use ';' as a separator instead of a terminator.
81 static void processSpecString( 103 static void processSpecString(
82 DiagnosticListener listener, 104 DiagnosticListener listener,
83 Spannable spannable, 105 Spannable spannable,
84 String specString, 106 String specString,
85 {dynamic resolveType(String typeString), 107 {void setSideEffects(SideEffects newEffects),
108 dynamic resolveType(String typeString),
86 List typesReturned, List typesInstantiated, 109 List typesReturned, List typesInstantiated,
87 objectType, nullType}) { 110 objectType, nullType}) {
88 111
89 /// Resolve a type string of one of the three forms: 112 /// Resolve a type string of one of the three forms:
90 /// * 'void' - in which case [onVoid] is called, 113 /// * 'void' - in which case [onVoid] is called,
91 /// * '' or 'var' - in which case [onVar] is called, 114 /// * '' or 'var' - in which case [onVar] is called,
92 /// * 'T1|...|Tn' - in which case [onType] is called for each Ti. 115 /// * 'T1|...|Tn' - in which case [onType] is called for each Ti.
93 void resolveTypesString(String typesString, 116 void resolveTypesString(String typesString,
94 {onVoid(), onVar(), onType(type)}) { 117 {onVoid(), onVar(), onType(type)}) {
95 // Various things that are not in fact types. 118 // Various things that are not in fact types.
96 if (typesString == 'void') { 119 if (typesString == 'void') {
97 if (onVoid != null) { 120 if (onVoid != null) {
98 onVoid(); 121 onVoid();
99 } 122 }
100 return; 123 return;
101 } 124 }
102 if (typesString == '' || typesString == 'var') { 125 if (typesString == '' || typesString == 'var') {
103 if (onVar != null) { 126 if (onVar != null) {
104 onVar(); 127 onVar();
105 } 128 }
106 return; 129 return;
107 } 130 }
108 for (final typeString in typesString.split('|')) { 131 for (final typeString in typesString.split('|')) {
109 onType(resolveType(typeString)); 132 onType(resolveType(typeString));
110 } 133 }
111 } 134 }
112 135
136
113 if (specString.contains(':')) { 137 if (specString.contains(':')) {
114 /// Find and remove a substring of the form 'tag:<type-string>;' from 138 /// Find and remove a substring of the form 'tag:<string>;' from
115 /// [specString]. 139 /// [specString].
116 String getTypesString(String tag) { 140 String getTagString(String tag) {
117 String marker = '$tag:'; 141 String marker = '$tag:';
118 int startPos = specString.indexOf(marker); 142 int startPos = specString.indexOf(marker);
119 if (startPos == -1) return null; 143 if (startPos == -1) return null;
120 int endPos = specString.indexOf(';', startPos); 144 int endPos = specString.indexOf(';', startPos);
121 if (endPos == -1) return null; 145 if (endPos == -1) return null;
122 String typeString = 146 String typeString =
123 specString.substring(startPos + marker.length, endPos); 147 specString.substring(startPos + marker.length, endPos);
124 specString = '${specString.substring(0, startPos)}' 148 specString = '${specString.substring(0, startPos)}'
125 '${specString.substring(endPos + 1)}'.trim(); 149 '${specString.substring(endPos + 1)}'.trim();
126 return typeString; 150 return typeString;
127 } 151 }
128 152
129 String returns = getTypesString('returns'); 153 String returns = getTagString('returns');
130 if (returns != null) { 154 if (returns != null) {
131 resolveTypesString(returns, onVar: () { 155 resolveTypesString(returns, onVar: () {
132 typesReturned.add(objectType); 156 typesReturned.add(objectType);
133 typesReturned.add(nullType); 157 typesReturned.add(nullType);
134 }, onType: (type) { 158 }, onType: (type) {
135 typesReturned.add(type); 159 typesReturned.add(type);
136 }); 160 });
137 } 161 }
138 162
139 String creates = getTypesString('creates'); 163 String creates = getTagString('creates');
140 if (creates != null) { 164 if (creates != null) {
141 resolveTypesString(creates, onVoid: () { 165 resolveTypesString(creates, onVoid: () {
142 listener.internalError(spannable, 166 listener.internalError(spannable,
143 "Invalid type string 'creates:$creates'"); 167 "Invalid type string 'creates:$creates'");
144 }, onVar: () { 168 }, onVar: () {
145 listener.internalError(spannable, 169 listener.internalError(spannable,
146 "Invalid type string 'creates:$creates'"); 170 "Invalid type string 'creates:$creates'");
147 }, onType: (type) { 171 }, onType: (type) {
148 typesInstantiated.add(type); 172 typesInstantiated.add(type);
149 }); 173 });
150 } 174 }
151 175
176 String effects = getTagString('effects');
177 String depends = getTagString('depends');
178 if (effects != null && depends == null ||
179 effects == null && depends != null) {
180 listener.internalError(spannable,
181 "Invalid JS spec string. "
182 "'effects' and 'depends' must occur together.");
183 }
184
185 if (effects != null) {
186 SideEffects sideEffects = new SideEffects();
187 if (effects == "none") {
188 sideEffects.clearAllSideEffects();
189 } else if (effects == "all") {
190 // Don't do anything.
191 } else {
192 List<String> splitEffects = effects.split(",");
193 if (splitEffects.isEmpty) {
194 listener.internalError(spannable, "Missing side-effect flag.");
195 }
196 for (String effect in splitEffects) {
197 switch (effect) {
198 case "no-index":
199 sideEffects.clearChangesIndex();
200 break;
201 case "no-instance":
202 sideEffects.clearChangesInstanceProperty();
203 break;
204 case "no-static":
205 sideEffects.clearChangesStaticProperty();
206 break;
207 default:
208 listener.internalError(spannable,
209 "Unrecognized side-effect flag: $effect.");
210 }
211 }
212 }
213
214 if (depends == "none") {
215 sideEffects.clearAllDependencies();
216 } else if (depends == "all") {
217 // Don't do anything.
218 } else {
219 List<String> splitDependencies = depends.split(",");
220 if (splitDependencies.isEmpty) {
221 listener.internalError(spannable,
222 "Missing side-effect dependency flag.");
223 }
224 for (String dependency in splitDependencies) {
225 switch (dependency) {
226 case "no-index":
227 sideEffects.clearDependsOnIndexStore();
228 break;
229 case "no-instance":
230 sideEffects.clearDependsOnInstancePropertyStore();
231 break;
232 case "no-static":
233 sideEffects.clearDependsOnStaticPropertyStore();
234 break;
235 default:
236 listener.internalError(spannable,
237 "Unrecognized side-effect flag: $dependency.");
238 }
239 }
240 }
241
242 setSideEffects(sideEffects);
243 }
244
152 if (!specString.isEmpty) { 245 if (!specString.isEmpty) {
153 listener.internalError(spannable, "Invalid JS type string."); 246 listener.internalError(spannable, "Invalid JS spec string.");
154 } 247 }
155 } else { 248 } else {
156 resolveTypesString(specString, onVar: () { 249 resolveTypesString(specString, onVar: () {
157 typesReturned.add(objectType); 250 typesReturned.add(objectType);
158 typesReturned.add(nullType); 251 typesReturned.add(nullType);
159 }, onType: (type) { 252 }, onType: (type) {
160 typesInstantiated.add(type); 253 typesInstantiated.add(type);
161 typesReturned.add(type); 254 typesReturned.add(type);
162 }); 255 });
163 } 256 }
(...skipping 19 matching lines...) Expand all
183 LiteralString specLiteral = argNodes.head.asLiteralString(); 276 LiteralString specLiteral = argNodes.head.asLiteralString();
184 if (specLiteral == null) { 277 if (specLiteral == null) {
185 // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It 278 // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It
186 // is not very satisfactory because it does not work for void, dynamic. 279 // is not very satisfactory because it does not work for void, dynamic.
187 compiler.internalError(argNodes.head, "Unexpected JS first argument."); 280 compiler.internalError(argNodes.head, "Unexpected JS first argument.");
188 } 281 }
189 282
190 NativeBehavior behavior = new NativeBehavior(); 283 NativeBehavior behavior = new NativeBehavior();
191 behavior.codeTemplate = 284 behavior.codeTemplate =
192 js.js.parseForeignJS(code.dartString.slowToString()); 285 js.js.parseForeignJS(code.dartString.slowToString());
193 new SideEffectsVisitor(behavior.sideEffects)
194 .visit(behavior.codeTemplate.ast);
195 286
196 String specString = specLiteral.dartString.slowToString(); 287 String specString = specLiteral.dartString.slowToString();
197 288
198 resolveType(String typeString) { 289 dynamic resolveType(String typeString) {
199 return _parseType( 290 return _parseType(
200 typeString, 291 typeString,
201 compiler, 292 compiler,
202 (name) => resolver.resolveTypeFromString(specLiteral, name), 293 (name) => resolver.resolveTypeFromString(specLiteral, name),
203 jsCall); 294 jsCall);
204 } 295 }
205 296
297 bool sideEffectsAreEncodedInSpecString = false;
298
299 void setSideEffects(SideEffects newEffects) {
300 sideEffectsAreEncodedInSpecString = true;
301 behavior.sideEffects.setTo(newEffects);
302 }
303
206 processSpecString(compiler, jsCall, 304 processSpecString(compiler, jsCall,
207 specString, 305 specString,
306 setSideEffects: setSideEffects,
208 resolveType: resolveType, 307 resolveType: resolveType,
209 typesReturned: behavior.typesReturned, 308 typesReturned: behavior.typesReturned,
210 typesInstantiated: behavior.typesInstantiated, 309 typesInstantiated: behavior.typesInstantiated,
211 objectType: compiler.objectClass.computeType(compiler), 310 objectType: compiler.objectClass.computeType(compiler),
212 nullType: compiler.nullClass.computeType(compiler)); 311 nullType: compiler.nullClass.computeType(compiler));
213 312
313 if (!sideEffectsAreEncodedInSpecString) {
314 new SideEffectsVisitor(behavior.sideEffects)
315 .visit(behavior.codeTemplate.ast);
316 }
317
214 return behavior; 318 return behavior;
215 } 319 }
216 320
217 static NativeBehavior ofJsEmbeddedGlobalCall(Send jsGlobalCall, 321 static NativeBehavior ofJsEmbeddedGlobalCall(Send jsGlobalCall,
218 Compiler compiler, 322 Compiler compiler,
219 resolver) { 323 resolver) {
220 // The first argument of a JS-embedded global call is a string encoding 324 // The first argument of a JS-embedded global call is a string encoding
221 // the type of the code. 325 // the type of the code.
222 // 326 //
223 // 'Type1|Type2'. A union type. 327 // 'Type1|Type2'. A union type.
(...skipping 20 matching lines...) Expand all
244 if (specLiteral == null) { 348 if (specLiteral == null) {
245 // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It 349 // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It
246 // is not very satisfactory because it does not work for void, dynamic. 350 // is not very satisfactory because it does not work for void, dynamic.
247 compiler.internalError(argNodes.head, "Unexpected first argument."); 351 compiler.internalError(argNodes.head, "Unexpected first argument.");
248 } 352 }
249 353
250 NativeBehavior behavior = new NativeBehavior(); 354 NativeBehavior behavior = new NativeBehavior();
251 355
252 String specString = specLiteral.dartString.slowToString(); 356 String specString = specLiteral.dartString.slowToString();
253 357
254 resolveType(String typeString) { 358 dynamic resolveType(String typeString) {
255 return _parseType( 359 return _parseType(
256 typeString, 360 typeString,
257 compiler, 361 compiler,
258 (name) => resolver.resolveTypeFromString(specLiteral, name), 362 (name) => resolver.resolveTypeFromString(specLiteral, name),
259 jsGlobalCall); 363 jsGlobalCall);
260 } 364 }
261 365
366 void setSideEffects(SideEffects newEffects) {
367 compiler.internalError(jsGlobalCall,
368 'Embedded global calls may not have any side-effect overwrites: '
369 '$specString');
370 }
371
262 processSpecString(compiler, jsGlobalCall, 372 processSpecString(compiler, jsGlobalCall,
263 specString, 373 specString,
374 setSideEffects: setSideEffects,
264 resolveType: resolveType, 375 resolveType: resolveType,
265 typesReturned: behavior.typesReturned, 376 typesReturned: behavior.typesReturned,
266 typesInstantiated: behavior.typesInstantiated, 377 typesInstantiated: behavior.typesInstantiated,
267 objectType: compiler.objectClass.computeType(compiler), 378 objectType: compiler.objectClass.computeType(compiler),
268 nullType: compiler.nullClass.computeType(compiler)); 379 nullType: compiler.nullClass.computeType(compiler));
269 380
270 return behavior; 381 return behavior;
271 } 382 }
272 383
273 static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) { 384 static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) {
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 FunctionType functionType = type; 508 FunctionType functionType = type;
398 _capture(functionType.returnType, compiler); 509 _capture(functionType.returnType, compiler);
399 for (DartType parameter in functionType.parameterTypes) { 510 for (DartType parameter in functionType.parameterTypes) {
400 _escape(parameter, compiler); 511 _escape(parameter, compiler);
401 } 512 }
402 } else { 513 } else {
403 typesInstantiated.add(type); 514 typesInstantiated.add(type);
404 } 515 }
405 } 516 }
406 517
407 static _parseType(String typeString, Compiler compiler, 518 static dynamic _parseType(String typeString, Compiler compiler,
408 lookup(name), locationNodeOrElement) { 519 lookup(name), locationNodeOrElement) {
409 if (typeString == '=Object') return SpecialType.JsObject; 520 if (typeString == '=Object') return SpecialType.JsObject;
410 if (typeString == 'dynamic') { 521 if (typeString == 'dynamic') {
411 return const DynamicType(); 522 return const DynamicType();
412 } 523 }
413 DartType type = lookup(typeString); 524 var type = lookup(typeString);
414 if (type != null) return type; 525 if (type != null) return type;
415 526
416 int index = typeString.indexOf('<'); 527 int index = typeString.indexOf('<');
417 if (index < 1) { 528 if (index < 1) {
418 compiler.internalError( 529 compiler.internalError(
419 _errorNode(locationNodeOrElement, compiler), 530 _errorNode(locationNodeOrElement, compiler),
420 "Type '$typeString' not found."); 531 "Type '$typeString' not found.");
421 } 532 }
422 type = lookup(typeString.substring(0, index)); 533 type = lookup(typeString.substring(0, index));
423 if (type != null) { 534 if (type != null) {
424 // TODO(sra): Parse type parameters. 535 // TODO(sra): Parse type parameters.
425 return type; 536 return type;
426 } 537 }
427 compiler.internalError( 538 compiler.internalError(
428 _errorNode(locationNodeOrElement, compiler), 539 _errorNode(locationNodeOrElement, compiler),
429 "Type '$typeString' not found."); 540 "Type '$typeString' not found.");
541 return null;
430 } 542 }
431 543
432 static _errorNode(locationNodeOrElement, compiler) { 544 static _errorNode(locationNodeOrElement, compiler) {
433 if (locationNodeOrElement is Node) return locationNodeOrElement; 545 if (locationNodeOrElement is Node) return locationNodeOrElement;
434 return locationNodeOrElement.parseNode(compiler); 546 return locationNodeOrElement.parseNode(compiler);
435 } 547 }
436 } 548 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/universe/side_effects.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698