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

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 type annotations 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].
sra1 2015/03/03 01:49:49 mention setSideEffects?
floitsch 2015/03/03 19:53:19 Done.
64 /// 64 ///
65 /// Two forms of the string is supported: 65 /// Two forms of the string is supported:
66 /// 1) A single type string of the form 'void', '', 'var' or 'T1|...|Tn' 66 /// 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 67 /// which defines the types returned and for the later form also created by
68 /// the call to JS. 68 /// the call to JS.
69 /// 2) A sequence of the form '<tag>:<type-string>;' where <tag> is either 69 /// 2) A sequence of the form
sra1 2015/03/03 01:49:50 It is OK to describe this here, but please make a
floitsch 2015/03/03 19:53:19 I don't know of any place where the doc can be vie
70 /// 'returns' or 'creates' and where <type-string> is a type string like in 70 /// '<type-tag>:<type-string>;<effect-tag>:<effect-string>'
71 /// 1). The type string marked by 'returns' defines the types returned and 71 /// where <type-tag> is either 'returns' or 'creates' and where
72 /// 'creates' defines the types created by the call to JS. Each tag kind 72 /// <type-string> is a type string like in 1). The type string marked by
73 /// can only occur once in the sequence. 73 /// 'returns' defines the types returned and 'creates' defines the types
74 /// created by the call to JS.
75 /// The <effect-tag> is either 'effects' or 'depends' and
76 /// <effect-string> is either 'all', 'empty' or a comma-separated list of
sra1 2015/03/03 01:49:49 effects:none would read easier than effects:empty
floitsch 2015/03/03 19:53:19 Done.
77 /// '-index', '-instance', '-static'. The flag 'all' indicates
sra1 2015/03/03 01:49:49 So you might write effects:-index Why the '-'? Is
floitsch 2015/03/03 19:53:19 It's to indicate that this effect is *not* happeni
78 /// that the call affects/depends on every side-effect. The flag
79 /// 'empty' indicates that the call does not affect (resp. depends on)
80 /// anything.
81 /// '-index' indicates that the call does not do any array index-store (for
82 /// 'effects'), or depends on any value in an array (for 'depends').
83 /// The flag '-instance' indicates that the call does not modify (resp.
84 /// depends on) any instance variable. Similarly static variables are
sra1 2015/03/03 01:49:49 The instance/index seems a bit dangerous for the D
floitsch 2015/03/03 19:53:19 agreed. But it's still an option here.
85 /// indicated with '-static'. The flags 'effects' and 'depends' must be
86 /// used in unison (either both are present or none is).
87 /// Each tag kind (including the 'type-tag's) can only occur once in the
88 /// sequence.
sra1 2015/03/03 01:49:49 The formating of this comment is extremely dense.
floitsch 2015/03/03 19:53:19 My fault. I wasn't sure if paragraphs were allowed
74 /// 89 ///
75 /// [specString] is the specification string, [resolveType] resolves named 90 /// [specString] is the specification string, [resolveType] resolves named
76 /// types into type values, [typesReturned] and [typesInstantiated] collects 91 /// types into type values, [typesReturned] and [typesInstantiated] collects
77 /// the types defined by the specification string, and [objectType] and 92 /// the types defined by the specification string, and [objectType] and
78 /// [nullType] define the types for `Object` and `Null`, respectively. The 93 /// [nullType] define the types for `Object` and `Null`, respectively. The
79 /// latter is used for the type strings of the form '' and 'var'. 94 /// latter is used for the type strings of the form '' and 'var'.
80 // TODO(johnniwinther): Use ';' as a separator instead of a terminator. 95 // TODO(johnniwinther): Use ';' as a separator instead of a terminator.
81 static void processSpecString( 96 static void processSpecString(
82 DiagnosticListener listener, 97 DiagnosticListener listener,
83 Spannable spannable, 98 Spannable spannable,
84 String specString, 99 String specString,
85 {dynamic resolveType(String typeString), 100 {void setSideEffects(SideEffects newEffects),
101 dynamic resolveType(String typeString),
86 List typesReturned, List typesInstantiated, 102 List typesReturned, List typesInstantiated,
87 objectType, nullType}) { 103 objectType, nullType}) {
88 104
89 /// Resolve a type string of one of the three forms: 105 /// Resolve a type string of one of the three forms:
90 /// * 'void' - in which case [onVoid] is called, 106 /// * 'void' - in which case [onVoid] is called,
91 /// * '' or 'var' - in which case [onVar] is called, 107 /// * '' or 'var' - in which case [onVar] is called,
92 /// * 'T1|...|Tn' - in which case [onType] is called for each Ti. 108 /// * 'T1|...|Tn' - in which case [onType] is called for each Ti.
93 void resolveTypesString(String typesString, 109 void resolveTypesString(String typesString,
94 {onVoid(), onVar(), onType(type)}) { 110 {onVoid(), onVar(), onType(type)}) {
95 // Various things that are not in fact types. 111 // Various things that are not in fact types.
96 if (typesString == 'void') { 112 if (typesString == 'void') {
97 if (onVoid != null) { 113 if (onVoid != null) {
98 onVoid(); 114 onVoid();
99 } 115 }
100 return; 116 return;
101 } 117 }
102 if (typesString == '' || typesString == 'var') { 118 if (typesString == '' || typesString == 'var') {
103 if (onVar != null) { 119 if (onVar != null) {
104 onVar(); 120 onVar();
105 } 121 }
106 return; 122 return;
107 } 123 }
108 for (final typeString in typesString.split('|')) { 124 for (final typeString in typesString.split('|')) {
109 onType(resolveType(typeString)); 125 onType(resolveType(typeString));
110 } 126 }
111 } 127 }
112 128
129
113 if (specString.contains(':')) { 130 if (specString.contains(':')) {
114 /// Find and remove a substring of the form 'tag:<type-string>;' from 131 /// Find and remove a substring of the form 'tag:<string>;' from
115 /// [specString]. 132 /// [specString].
116 String getTypesString(String tag) { 133 String getTagString(String tag) {
117 String marker = '$tag:'; 134 String marker = '$tag:';
118 int startPos = specString.indexOf(marker); 135 int startPos = specString.indexOf(marker);
119 if (startPos == -1) return null; 136 if (startPos == -1) return null;
120 int endPos = specString.indexOf(';', startPos); 137 int endPos = specString.indexOf(';', startPos);
121 if (endPos == -1) return null; 138 if (endPos == -1) return null;
122 String typeString = 139 String typeString =
123 specString.substring(startPos + marker.length, endPos); 140 specString.substring(startPos + marker.length, endPos);
124 specString = '${specString.substring(0, startPos)}' 141 specString = '${specString.substring(0, startPos)}'
125 '${specString.substring(endPos + 1)}'.trim(); 142 '${specString.substring(endPos + 1)}'.trim();
126 return typeString; 143 return typeString;
127 } 144 }
128 145
129 String returns = getTypesString('returns'); 146 String returns = getTagString('returns');
130 if (returns != null) { 147 if (returns != null) {
131 resolveTypesString(returns, onVar: () { 148 resolveTypesString(returns, onVar: () {
132 typesReturned.add(objectType); 149 typesReturned.add(objectType);
133 typesReturned.add(nullType); 150 typesReturned.add(nullType);
134 }, onType: (type) { 151 }, onType: (type) {
135 typesReturned.add(type); 152 typesReturned.add(type);
136 }); 153 });
137 } 154 }
138 155
139 String creates = getTypesString('creates'); 156 String creates = getTagString('creates');
140 if (creates != null) { 157 if (creates != null) {
141 resolveTypesString(creates, onVoid: () { 158 resolveTypesString(creates, onVoid: () {
142 listener.internalError(spannable, 159 listener.internalError(spannable,
143 "Invalid type string 'creates:$creates'"); 160 "Invalid type string 'creates:$creates'");
144 }, onVar: () { 161 }, onVar: () {
145 listener.internalError(spannable, 162 listener.internalError(spannable,
146 "Invalid type string 'creates:$creates'"); 163 "Invalid type string 'creates:$creates'");
147 }, onType: (type) { 164 }, onType: (type) {
148 typesInstantiated.add(type); 165 typesInstantiated.add(type);
149 }); 166 });
150 } 167 }
151 168
169 String effects = getTagString('effects');
170 String depends = getTagString('depends');
171 if (effects != null && depends == null ||
172 effects == null && depends != null) {
173 listener.internalError(spannable,
174 "Invalid JS spec string. "
175 "'effects' and 'depends' must occur together");
176 }
177
178 if (effects != null) {
179 SideEffects sideEffects = new SideEffects();
180 if (effects == "empty") {
181 sideEffects.clearAllSideEffects();
182 } else if (effects == "all") {
183 // Don't do anything.
184 } else {
185 List<String> splitEffects = effects.split(",");
186 if (splitEffects.isEmpty) {
187 listener.internalError(spannable, "Empty side-effect flag");
sra1 2015/03/03 01:49:49 Empty -> Missing
floitsch 2015/03/03 19:53:19 Done.
188 }
189 for (String effect in splitEffects) {
190 switch (effect) {
191 case "-index":
192 sideEffects.clearChangesIndex();
193 break;
194 case "-instance":
195 sideEffects.clearChangesInstanceProperty();
196 break;
197 case "-static":
198 sideEffects.clearChangesStaticProperty();
199 break;
200 default:
201 listener.internalError(spannable,
202 "Unrecognized side-effect flag: $effect");
203 }
204 }
205 }
206
207 if (depends == "empty") {
208 sideEffects.clearAllDependencies();
209 } else if (depends == "all") {
210 // Don't do anything.
211 } else {
212 List<String> splitDependencies = depends.split(",");
213 if (splitDependencies.isEmpty) {
214 listener.internalError(spannable, "Empty side-effect flag");
sra1 2015/03/03 01:49:50 "Missing side-effect dependency flag"
floitsch 2015/03/03 19:53:19 Done.
215 }
216 for (String dependency in splitDependencies) {
217 switch (dependency) {
218 case "-index":
219 sideEffects.clearDependsOnIndexStore();
220 break;
221 case "-instance":
222 sideEffects.clearDependsOnInstancePropertyStore();
223 break;
224 case "-static":
225 sideEffects.clearDependsOnStaticPropertyStore();
226 break;
227 default:
228 listener.internalError(spannable,
229 "Unrecognized side-effect flag: $dependency");
230 }
231 }
232 }
233
234 setSideEffects(sideEffects);
235 }
236
152 if (!specString.isEmpty) { 237 if (!specString.isEmpty) {
153 listener.internalError(spannable, "Invalid JS type string."); 238 listener.internalError(spannable, "Invalid JS spec string.");
154 } 239 }
155 } else { 240 } else {
156 resolveTypesString(specString, onVar: () { 241 resolveTypesString(specString, onVar: () {
157 typesReturned.add(objectType); 242 typesReturned.add(objectType);
158 typesReturned.add(nullType); 243 typesReturned.add(nullType);
159 }, onType: (type) { 244 }, onType: (type) {
160 typesInstantiated.add(type); 245 typesInstantiated.add(type);
161 typesReturned.add(type); 246 typesReturned.add(type);
162 }); 247 });
163 } 248 }
(...skipping 19 matching lines...) Expand all
183 LiteralString specLiteral = argNodes.head.asLiteralString(); 268 LiteralString specLiteral = argNodes.head.asLiteralString();
184 if (specLiteral == null) { 269 if (specLiteral == null) {
185 // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It 270 // 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. 271 // is not very satisfactory because it does not work for void, dynamic.
187 compiler.internalError(argNodes.head, "Unexpected JS first argument."); 272 compiler.internalError(argNodes.head, "Unexpected JS first argument.");
188 } 273 }
189 274
190 NativeBehavior behavior = new NativeBehavior(); 275 NativeBehavior behavior = new NativeBehavior();
191 behavior.codeTemplate = 276 behavior.codeTemplate =
192 js.js.parseForeignJS(code.dartString.slowToString()); 277 js.js.parseForeignJS(code.dartString.slowToString());
193 new SideEffectsVisitor(behavior.sideEffects)
194 .visit(behavior.codeTemplate.ast);
195 278
196 String specString = specLiteral.dartString.slowToString(); 279 String specString = specLiteral.dartString.slowToString();
197 280
198 resolveType(String typeString) { 281 DartType resolveType(String typeString) {
199 return _parseType( 282 return _parseType(
200 typeString, 283 typeString,
201 compiler, 284 compiler,
202 (name) => resolver.resolveTypeFromString(specLiteral, name), 285 (name) => resolver.resolveTypeFromString(specLiteral, name),
203 jsCall); 286 jsCall);
204 } 287 }
205 288
289 bool sideEffectsAreEncodedInSpecString = false;
290
291 void setSideEffects(SideEffects newEffects) {
292 sideEffectsAreEncodedInSpecString = true;
293 behavior.sideEffects.setTo(newEffects);
294 }
295
206 processSpecString(compiler, jsCall, 296 processSpecString(compiler, jsCall,
207 specString, 297 specString,
298 setSideEffects: setSideEffects,
208 resolveType: resolveType, 299 resolveType: resolveType,
209 typesReturned: behavior.typesReturned, 300 typesReturned: behavior.typesReturned,
210 typesInstantiated: behavior.typesInstantiated, 301 typesInstantiated: behavior.typesInstantiated,
211 objectType: compiler.objectClass.computeType(compiler), 302 objectType: compiler.objectClass.computeType(compiler),
212 nullType: compiler.nullClass.computeType(compiler)); 303 nullType: compiler.nullClass.computeType(compiler));
213 304
305 if (!sideEffectsAreEncodedInSpecString) {
306 new SideEffectsVisitor(behavior.sideEffects)
307 .visit(behavior.codeTemplate.ast);
308 }
309
214 return behavior; 310 return behavior;
215 } 311 }
216 312
217 static NativeBehavior ofJsEmbeddedGlobalCall(Send jsGlobalCall, 313 static NativeBehavior ofJsEmbeddedGlobalCall(Send jsGlobalCall,
218 Compiler compiler, 314 Compiler compiler,
219 resolver) { 315 resolver) {
220 // The first argument of a JS-embedded global call is a string encoding 316 // The first argument of a JS-embedded global call is a string encoding
221 // the type of the code. 317 // the type of the code.
222 // 318 //
223 // 'Type1|Type2'. A union type. 319 // 'Type1|Type2'. A union type.
(...skipping 20 matching lines...) Expand all
244 if (specLiteral == null) { 340 if (specLiteral == null) {
245 // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It 341 // 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. 342 // is not very satisfactory because it does not work for void, dynamic.
247 compiler.internalError(argNodes.head, "Unexpected first argument."); 343 compiler.internalError(argNodes.head, "Unexpected first argument.");
248 } 344 }
249 345
250 NativeBehavior behavior = new NativeBehavior(); 346 NativeBehavior behavior = new NativeBehavior();
251 347
252 String specString = specLiteral.dartString.slowToString(); 348 String specString = specLiteral.dartString.slowToString();
253 349
254 resolveType(String typeString) { 350 void resolveType(String typeString) {
255 return _parseType( 351 return _parseType(
256 typeString, 352 typeString,
257 compiler, 353 compiler,
258 (name) => resolver.resolveTypeFromString(specLiteral, name), 354 (name) => resolver.resolveTypeFromString(specLiteral, name),
259 jsGlobalCall); 355 jsGlobalCall);
260 } 356 }
261 357
358 void setSideEffects(SideEffects newEffects) {
359 compiler.internalError(jsGlobalCall,
360 'Embedded global calls may not have any side-effect overwrites: '
361 '$specString');
362 }
363
262 processSpecString(compiler, jsGlobalCall, 364 processSpecString(compiler, jsGlobalCall,
263 specString, 365 specString,
366 setSideEffects: setSideEffects,
264 resolveType: resolveType, 367 resolveType: resolveType,
265 typesReturned: behavior.typesReturned, 368 typesReturned: behavior.typesReturned,
266 typesInstantiated: behavior.typesInstantiated, 369 typesInstantiated: behavior.typesInstantiated,
267 objectType: compiler.objectClass.computeType(compiler), 370 objectType: compiler.objectClass.computeType(compiler),
268 nullType: compiler.nullClass.computeType(compiler)); 371 nullType: compiler.nullClass.computeType(compiler));
269 372
270 return behavior; 373 return behavior;
271 } 374 }
272 375
273 static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) { 376 static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) {
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
397 FunctionType functionType = type; 500 FunctionType functionType = type;
398 _capture(functionType.returnType, compiler); 501 _capture(functionType.returnType, compiler);
399 for (DartType parameter in functionType.parameterTypes) { 502 for (DartType parameter in functionType.parameterTypes) {
400 _escape(parameter, compiler); 503 _escape(parameter, compiler);
401 } 504 }
402 } else { 505 } else {
403 typesInstantiated.add(type); 506 typesInstantiated.add(type);
404 } 507 }
405 } 508 }
406 509
407 static _parseType(String typeString, Compiler compiler, 510 static DartType _parseType(String typeString, Compiler compiler,
408 lookup(name), locationNodeOrElement) { 511 lookup(name), locationNodeOrElement) {
409 if (typeString == '=Object') return SpecialType.JsObject; 512 if (typeString == '=Object') return SpecialType.JsObject;
410 if (typeString == 'dynamic') { 513 if (typeString == 'dynamic') {
411 return const DynamicType(); 514 return const DynamicType();
412 } 515 }
413 DartType type = lookup(typeString); 516 DartType type = lookup(typeString);
414 if (type != null) return type; 517 if (type != null) return type;
415 518
416 int index = typeString.indexOf('<'); 519 int index = typeString.indexOf('<');
417 if (index < 1) { 520 if (index < 1) {
418 compiler.internalError( 521 compiler.internalError(
419 _errorNode(locationNodeOrElement, compiler), 522 _errorNode(locationNodeOrElement, compiler),
420 "Type '$typeString' not found."); 523 "Type '$typeString' not found.");
421 } 524 }
422 type = lookup(typeString.substring(0, index)); 525 type = lookup(typeString.substring(0, index));
423 if (type != null) { 526 if (type != null) {
424 // TODO(sra): Parse type parameters. 527 // TODO(sra): Parse type parameters.
425 return type; 528 return type;
426 } 529 }
427 compiler.internalError( 530 compiler.internalError(
428 _errorNode(locationNodeOrElement, compiler), 531 _errorNode(locationNodeOrElement, compiler),
429 "Type '$typeString' not found."); 532 "Type '$typeString' not found.");
430 } 533 }
431 534
432 static _errorNode(locationNodeOrElement, compiler) { 535 static _errorNode(locationNodeOrElement, compiler) {
433 if (locationNodeOrElement is Node) return locationNodeOrElement; 536 if (locationNodeOrElement is Node) return locationNodeOrElement;
434 return locationNodeOrElement.parseNode(compiler); 537 return locationNodeOrElement.parseNode(compiler);
435 } 538 }
436 } 539 }
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