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

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

Issue 1034263002: Parse more properties of native code fragments. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 8 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 | tests/compiler/dart2js/js_spec_string_test.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);
11 11
12 /// The type Object, but no subtypes: 12 /// The type Object, but no subtypes:
13 static const JsObject = const SpecialType._('=Object'); 13 static const JsObject = const SpecialType._('=Object');
14 14
15 int get hashCode => name.hashCode; 15 int get hashCode => name.hashCode;
16 } 16 }
17 17
18 /// Description of the exception behaviour of native code.
19 ///
20 /// TODO(sra): Replace with something that better supports specialization on
21 /// first argument properties.
22 class NativeThrowBehavior {
23 static const NativeThrowBehavior NEVER = const NativeThrowBehavior._(0);
24 static const NativeThrowBehavior MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS =
25 const NativeThrowBehavior._(1);
26 static const NativeThrowBehavior MAY = const NativeThrowBehavior._(2);
27 static const NativeThrowBehavior MUST = const NativeThrowBehavior._(3);
28
29 final int _bits;
30 const NativeThrowBehavior._(this._bits);
31
32 String toString() {
33 if (this == NEVER) return 'never';
34 if (this == MAY) return 'may';
35 if (this == MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS) return 'null(1)';
36 if (this == MUST) return 'must';
37 return 'NativeThrowBehavior($_bits)';
38 }
39 }
40
18 /** 41 /**
19 * A summary of the behavior of a native element. 42 * A summary of the behavior of a native element.
20 * 43 *
21 * Native code can return values of one type and cause native subtypes of 44 * Native code can return values of one type and cause native subtypes of
22 * another type to be instantiated. By default, we compute both from the 45 * another type to be instantiated. By default, we compute both from the
23 * declared type. 46 * declared type.
24 * 47 *
25 * A field might yield any native type that 'is' the field type. 48 * A field might yield any native type that 'is' the field type.
26 * 49 *
27 * A method might create and return instances of native subclasses of its 50 * A method might create and return instances of native subclasses of its
(...skipping 24 matching lines...) Expand all
52 75
53 /// [DartType]s or [SpecialType]s instantiated by the native element. 76 /// [DartType]s or [SpecialType]s instantiated by the native element.
54 final List typesInstantiated = []; 77 final List typesInstantiated = [];
55 78
56 // If this behavior is for a JS expression, [codeTemplate] contains the 79 // If this behavior is for a JS expression, [codeTemplate] contains the
57 // parsed tree. 80 // parsed tree.
58 js.Template codeTemplate; 81 js.Template codeTemplate;
59 82
60 final SideEffects sideEffects = new SideEffects.empty(); 83 final SideEffects sideEffects = new SideEffects.empty();
61 84
85 NativeThrowBehavior throwBehavior = NativeThrowBehavior.MAY;
86
87 bool isAllocation = false;
88 bool useGvn = false;
89
62 String toString() { 90 String toString() {
63 return 'NativeBehavior(returns: ${typesReturned}, ' 91 return 'NativeBehavior('
92 'returns: ${typesReturned}, '
64 'creates: ${typesInstantiated}, ' 93 'creates: ${typesInstantiated}, '
65 'sideEffects: ${sideEffects})'; 94 'sideEffects: ${sideEffects}, '
95 'throws: ${throwBehavior}'
96 '${isAllocation ? ", isAllocation" : ""}'
97 '${useGvn ? ", useGvn" : ""}'
98 ')';
66 } 99 }
67 100
68 101
69 /// Processes the type specification string of a call to JS and stores the 102 /// Processes the type specification string of a call to JS and stores the
70 /// result in the [typesReturned] and [typesInstantiated]. It furthermore 103 /// result in the [typesReturned] and [typesInstantiated]. It furthermore
71 /// computes the side effects, and, if given, invokes [setSideEffects] with 104 /// computes the side effects, and, if given, invokes [setSideEffects] with
72 /// the computed effects. If no side effects are encoded in the [specString] 105 /// the computed effects. If no side effects are encoded in the [specString]
73 /// the [setSideEffects] method is not invoked. 106 /// the [setSideEffects] method is not invoked.
74 /// 107 ///
75 /// Two forms of the string is supported: 108 /// Two forms of the string is supported:
109 ///
76 /// 1) A single type string of the form 'void', '', 'var' or 'T1|...|Tn' 110 /// 1) A single type string of the form 'void', '', 'var' or 'T1|...|Tn'
77 /// which defines the types returned and for the later form also created by 111 /// which defines the types returned and for the later form also created by
78 /// the call to JS. 112 /// the call to JS.
79 /// 2) A sequence of the form
80 /// '<type-tag>:<type-string>;<effect-tag>:<effect-string>'
81 /// where <type-tag> is either 'returns' or 'creates' and where
82 /// <type-string> is a type string like in 1). The type string marked by
83 /// 'returns' defines the types returned and 'creates' defines the types
84 /// created by the call to JS.
85 /// 113 ///
86 /// The <effect-tag> is either 'effects' or 'depends' and 114 /// 2) A sequence of <tag>:<value> pairs of the following kinds
87 /// <effect-string> is either 'all', 'none' or a comma-separated list of 115 ///
88 /// 'no-index', 'no-instance', 'no-static'. 116 /// <type-tag>:<type-string>
117 /// <effect-tag>:<effect-string>
118 /// throws:<throws-string>
119 /// gvn:<gvn-string>
120 /// new:<new-string>
121 ///
122 /// A <type-tag> is either 'returns' or 'creates' and <type-string> is a
123 /// type string like in 1). The type string marked by 'returns' defines the
124 /// types returned and 'creates' defines the types created by the call to
125 /// JS.
126 ///
127 /// An <effect-tag> is either 'effects' or 'depends' and <effect-string> is
128 /// either 'all', 'none' or a comma-separated list of 'no-index',
129 /// 'no-instance', 'no-static'.
89 /// 130 ///
90 /// The flag 'all' indicates that the call affects/depends on every 131 /// The flag 'all' indicates that the call affects/depends on every
91 /// side-effect. The flag 'none' indicates that the call does not affect 132 /// side-effect. The flag 'none' indicates that the call does not affect
92 /// (resp. depends on) anything. 133 /// (resp. depends on) anything.
93 /// 134 ///
94 /// 'no-index' indicates that the call does *not* do any array index-store 135 /// 'no-index' indicates that the call does *not* do any array index-store
95 /// (for 'effects'), or depends on any value in an array (for 'depends'). 136 /// (for 'effects'), or depends on any value in an array (for 'depends').
96 /// The flag 'no-instance' indicates that the call does not modify (resp. 137 /// The flag 'no-instance' indicates that the call does not modify (resp.
97 /// depends on) any instance variable. Similarly static variables are 138 /// depends on) any instance variable. Similarly static variables are
98 /// indicated with 'no-static'. The flags 'effects' and 'depends' must be 139 /// indicated with 'no-static'. The flags 'effects' and 'depends' must be
99 /// used in unison (either both are present or none is). 140 /// used in unison (either both are present or none is).
100 /// 141 ///
142 /// The <throws-string> values are 'never', 'may', 'must', and 'null(1)'.
143 /// The default if unspecified is 'may'. 'null(1)' means that the template
144 /// expression throws if and only if the first template parameter is `null`
145 /// or `undefined`.
146 /// TODO(sra): Can we simplify to must/may/never and add null(1) by
147 /// inspection as an orthogonal attribute?
148 ///
149 /// <gvn-string> values are 'true' and 'false'. The default if unspecified
150 /// is 'false'.
151 ///
152 /// <new-string> values are 'true' and 'false'. The default if unspecified
153 /// is 'false'. A 'true' value means that each evaluation returns a fresh
154 /// (new) object that cannot be unaliased with existing objects.
herhut 2015/04/08 07:43:33 Did you mean aliased here?
155 ///
101 /// Each tag kind (including the 'type-tag's) can only occur once in the 156 /// Each tag kind (including the 'type-tag's) can only occur once in the
102 /// sequence. 157 /// sequence.
103 /// 158 ///
104 /// [specString] is the specification string, [resolveType] resolves named 159 /// [specString] is the specification string, [resolveType] resolves named
105 /// types into type values, [typesReturned] and [typesInstantiated] collects 160 /// types into type values, [typesReturned] and [typesInstantiated] collects
106 /// the types defined by the specification string, and [objectType] and 161 /// the types defined by the specification string, and [objectType] and
107 /// [nullType] define the types for `Object` and `Null`, respectively. The 162 /// [nullType] define the types for `Object` and `Null`, respectively. The
108 /// latter is used for the type strings of the form '' and 'var'. 163 /// latter is used for the type strings of the form '' and 'var'.
109 // TODO(johnniwinther): Use ';' as a separator instead of a terminator. 164 /// [validTags] can be used to restrict which tags are accepted.
110 static void processSpecString( 165 static void processSpecString(
111 DiagnosticListener listener, 166 DiagnosticListener listener,
112 Spannable spannable, 167 Spannable spannable,
113 String specString, 168 String specString,
114 {void setSideEffects(SideEffects newEffects), 169 {Iterable<String> validTags,
170 void setSideEffects(SideEffects newEffects),
171 void setThrows(NativeThrowBehavior throwKind),
172 void setIsAllocation(bool isAllocation),
173 void setUseGvn(bool useGvn),
115 dynamic resolveType(String typeString), 174 dynamic resolveType(String typeString),
116 List typesReturned, List typesInstantiated, 175 List typesReturned,
176 List typesInstantiated,
117 objectType, nullType}) { 177 objectType, nullType}) {
118 178
179 const List<String> knownTags = const [
180 'creates', 'returns', 'depends', 'effects',
181 'throws', 'gvn', 'new'];
182
119 /// Resolve a type string of one of the three forms: 183 /// Resolve a type string of one of the three forms:
120 /// * 'void' - in which case [onVoid] is called, 184 /// * 'void' - in which case [onVoid] is called,
121 /// * '' or 'var' - in which case [onVar] is called, 185 /// * '' or 'var' - in which case [onVar] is called,
122 /// * 'T1|...|Tn' - in which case [onType] is called for each Ti. 186 /// * 'T1|...|Tn' - in which case [onType] is called for each resolved Ti.
123 void resolveTypesString(String typesString, 187 void resolveTypesString(String typesString,
124 {onVoid(), onVar(), onType(type)}) { 188 {onVoid(), onVar(), onType(type)}) {
125 // Various things that are not in fact types. 189 // Various things that are not in fact types.
126 if (typesString == 'void') { 190 if (typesString == 'void') {
127 if (onVoid != null) { 191 if (onVoid != null) {
128 onVoid(); 192 onVoid();
129 } 193 }
130 return; 194 return;
131 } 195 }
132 if (typesString == '' || typesString == 'var') { 196 if (typesString == '' || typesString == 'var') {
133 if (onVar != null) { 197 if (onVar != null) {
134 onVar(); 198 onVar();
135 } 199 }
136 return; 200 return;
137 } 201 }
138 for (final typeString in typesString.split('|')) { 202 for (final typeString in typesString.split('|')) {
139 onType(resolveType(typeString)); 203 onType(resolveType(typeString.trim()));
140 } 204 }
141 } 205 }
142 206
143 207 if (!specString.contains(';') && !specString.contains(':')) {
144 if (specString.contains(':')) { 208 // Form (1), types or pseudo-types like 'void' and 'var'.
145 /// Find and remove a substring of the form 'tag:<string>;' from 209 resolveTypesString(specString.trim(), onVar: () {
146 /// [specString].
147 String getTagString(String tag) {
148 String marker = '$tag:';
149 int startPos = specString.indexOf(marker);
150 if (startPos == -1) return null;
151 int endPos = specString.indexOf(';', startPos);
152 if (endPos == -1) return null;
153 String typeString =
154 specString.substring(startPos + marker.length, endPos);
155 specString = '${specString.substring(0, startPos)}'
156 '${specString.substring(endPos + 1)}'.trim();
157 return typeString;
158 }
159
160 String returns = getTagString('returns');
161 if (returns != null) {
162 resolveTypesString(returns, onVar: () {
163 typesReturned.add(objectType);
164 typesReturned.add(nullType);
165 }, onType: (type) {
166 typesReturned.add(type);
167 });
168 }
169
170 String creates = getTagString('creates');
171 if (creates != null) {
172 resolveTypesString(creates, onVoid: () {
173 listener.internalError(spannable,
174 "Invalid type string 'creates:$creates'");
175 }, onVar: () {
176 listener.internalError(spannable,
177 "Invalid type string 'creates:$creates'");
178 }, onType: (type) {
179 typesInstantiated.add(type);
180 });
181 }
182
183 String effects = getTagString('effects');
184 String depends = getTagString('depends');
185 if (effects != null && depends == null ||
186 effects == null && depends != null) {
187 listener.internalError(spannable,
188 "Invalid JS spec string. "
189 "'effects' and 'depends' must occur together.");
190 }
191
192 if (effects != null) {
193 SideEffects sideEffects = new SideEffects();
194 if (effects == "none") {
195 sideEffects.clearAllSideEffects();
196 } else if (effects == "all") {
197 // Don't do anything.
198 } else {
199 List<String> splitEffects = effects.split(",");
200 if (splitEffects.isEmpty) {
201 listener.internalError(spannable, "Missing side-effect flag.");
202 }
203 for (String effect in splitEffects) {
204 switch (effect) {
205 case "no-index":
206 sideEffects.clearChangesIndex();
207 break;
208 case "no-instance":
209 sideEffects.clearChangesInstanceProperty();
210 break;
211 case "no-static":
212 sideEffects.clearChangesStaticProperty();
213 break;
214 default:
215 listener.internalError(spannable,
216 "Unrecognized side-effect flag: $effect.");
217 }
218 }
219 }
220
221 if (depends == "none") {
222 sideEffects.clearAllDependencies();
223 } else if (depends == "all") {
224 // Don't do anything.
225 } else {
226 List<String> splitDependencies = depends.split(",");
227 if (splitDependencies.isEmpty) {
228 listener.internalError(spannable,
229 "Missing side-effect dependency flag.");
230 }
231 for (String dependency in splitDependencies) {
232 switch (dependency) {
233 case "no-index":
234 sideEffects.clearDependsOnIndexStore();
235 break;
236 case "no-instance":
237 sideEffects.clearDependsOnInstancePropertyStore();
238 break;
239 case "no-static":
240 sideEffects.clearDependsOnStaticPropertyStore();
241 break;
242 default:
243 listener.internalError(spannable,
244 "Unrecognized side-effect flag: $dependency.");
245 }
246 }
247 }
248
249 setSideEffects(sideEffects);
250 }
251
252 if (!specString.isEmpty) {
253 listener.internalError(spannable, "Invalid JS spec string.");
254 }
255 } else {
256 resolveTypesString(specString, onVar: () {
257 typesReturned.add(objectType); 210 typesReturned.add(objectType);
258 typesReturned.add(nullType); 211 typesReturned.add(nullType);
259 }, onType: (type) { 212 }, onType: (type) {
260 typesInstantiated.add(type); 213 typesInstantiated.add(type);
261 typesReturned.add(type); 214 typesReturned.add(type);
262 }); 215 });
216 return;
263 } 217 }
218
219 List<String> specs = specString.split(';')
220 .map((s) => s.trim())
221 .toList();
222 if (specs.last == "") specs.removeLast(); // Allow separator to terminate.
223
224 assert(validTags == null || validTags.toSet().removeAll(validTags).isEmpty);
225 if (validTags == null) validTags = knownTags;
226
227 Map<String, String> values = <String, String>{};
228
229 for (String spec in specs) {
230 List<String> tagAndValue = spec.split(':');
231 if (tagAndValue.length != 2) {
232 listener.internalError(spannable,
233 "Invalid <tag>:<value> pair '$spec'.");
234 }
235 String tag = tagAndValue[0].trim();
236 String value = tagAndValue[1].trim();
237
238 if (validTags.contains(tag)) {
239 if (values[tag] == null) {
240 values[tag] = value;
241 } else {
242 listener.internalError(spannable, "Duplicate tag '$tag'.");
243 }
244 } else {
245 if (knownTags.contains(tag)) {
246 listener.internalError(spannable, "Tag '$tag' is not valid here.");
247 } else {
248 listener.internalError(spannable, "Unknown tag '$tag'.");
249 }
250 }
251 }
252
253 // Enum-like tags are looked up in a map. True signature is:
254 //
255 // T tagValueLookup<T>(String tag, Map<String, T> map);
256 //
257 dynamic tagValueLookup(String tag, Map<String, dynamic> map) {
258 String tagString = values[tag];
259 if (tagString == null) return null;
260 var value = map[tagString];
261 if (value == null) {
262 listener.internalError(spannable,
263 "Unknown '$tag' specification: '$tagString'");
264 }
265 return value;
266 }
267
268 String returns = values['returns'];
269 if (returns != null) {
270 resolveTypesString(returns, onVar: () {
271 typesReturned.add(objectType);
272 typesReturned.add(nullType);
273 }, onType: (type) {
274 typesReturned.add(type);
275 });
276 }
277
278 String creates = values['creates'];
279 if (creates != null) {
280 resolveTypesString(creates, onVoid: () {
281 listener.internalError(spannable,
282 "Invalid type string 'creates:$creates'");
283 }, onVar: () {
284 listener.internalError(spannable,
285 "Invalid type string 'creates:$creates'");
286 }, onType: (type) {
287 typesInstantiated.add(type);
288 });
289 }
290
291 const throwsOption = const <String, NativeThrowBehavior>{
292 'never': NativeThrowBehavior.NEVER,
293 'null(1)': NativeThrowBehavior.MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS,
294 'may': NativeThrowBehavior.MAY,
295 'must': NativeThrowBehavior.MUST };
296
297 const boolOptions = const<String, bool>{'true': true, 'false': false};
298
299 SideEffects sideEffects = processEffects(listener, spannable,
300 values['effects'], values['depends']);
301 NativeThrowBehavior throwsKind = tagValueLookup('throws', throwsOption);
302 bool isAllocation = tagValueLookup('new', boolOptions);
303 bool useGvn = tagValueLookup('gvn', boolOptions);
304
305 if (isAllocation == true && useGvn == true) {
306 listener.internalError(spannable, "'new' and 'gvn' are incompatible");
307 }
308
309 if (sideEffects != null) setSideEffects(sideEffects);
310 if (throwsKind != null) setThrows(throwsKind);
311 if (isAllocation != null) setIsAllocation(isAllocation);
312 if (useGvn != null) setUseGvn(useGvn);
313 }
314
315 static SideEffects processEffects(
316 DiagnosticListener listener,
317 Spannable spannable,
318 String effects,
319 String depends) {
320
321 if (effects == null && depends == null) return null;
322
323 if (effects == null || depends == null) {
324 listener.internalError(spannable,
325 "Invalid JS spec string. "
326 "'effects' and 'depends' must occur together.");
327 return null;
328 }
329
330 SideEffects sideEffects = new SideEffects();
331 if (effects == "none") {
332 sideEffects.clearAllSideEffects();
333 } else if (effects == "all") {
334 // Don't do anything.
335 } else {
336 List<String> splitEffects = effects.split(",");
337 if (splitEffects.isEmpty) {
338 listener.internalError(spannable, "Missing side-effect flag.");
339 }
340 for (String effect in splitEffects) {
341 switch (effect) {
342 case "no-index":
343 sideEffects.clearChangesIndex();
344 break;
345 case "no-instance":
346 sideEffects.clearChangesInstanceProperty();
347 break;
348 case "no-static":
349 sideEffects.clearChangesStaticProperty();
350 break;
351 default:
352 listener.internalError(spannable,
353 "Unrecognized side-effect flag: '$effect'.");
354 }
355 }
356 }
357
358 if (depends == "none") {
359 sideEffects.clearAllDependencies();
360 } else if (depends == "all") {
361 // Don't do anything.
362 } else {
363 List<String> splitDependencies = depends.split(",");
364 if (splitDependencies.isEmpty) {
365 listener.internalError(spannable,
366 "Missing side-effect dependency flag.");
367 }
368 for (String dependency in splitDependencies) {
369 switch (dependency) {
370 case "no-index":
371 sideEffects.clearDependsOnIndexStore();
372 break;
373 case "no-instance":
374 sideEffects.clearDependsOnInstancePropertyStore();
375 break;
376 case "no-static":
377 sideEffects.clearDependsOnStaticPropertyStore();
378 break;
379 default:
380 listener.internalError(spannable,
381 "Unrecognized side-effect flag: '$dependency'.");
382 }
383 }
384 }
385
386 return sideEffects;
264 } 387 }
265 388
266 static NativeBehavior ofJsCall(Send jsCall, Compiler compiler, resolver) { 389 static NativeBehavior ofJsCall(Send jsCall, Compiler compiler, resolver) {
267 // The first argument of a JS-call is a string encoding various attributes 390 // The first argument of a JS-call is a string encoding various attributes
268 // of the code. 391 // of the code.
269 // 392 //
270 // 'Type1|Type2'. A union type. 393 // 'Type1|Type2'. A union type.
271 // '=Object'. A JavaScript Object, no subtype. 394 // '=Object'. A JavaScript Object, no subtype.
272 395
273 var argNodes = jsCall.arguments; 396 var argNodes = jsCall.arguments;
(...skipping 27 matching lines...) Expand all
301 jsCall); 424 jsCall);
302 } 425 }
303 426
304 bool sideEffectsAreEncodedInSpecString = false; 427 bool sideEffectsAreEncodedInSpecString = false;
305 428
306 void setSideEffects(SideEffects newEffects) { 429 void setSideEffects(SideEffects newEffects) {
307 sideEffectsAreEncodedInSpecString = true; 430 sideEffectsAreEncodedInSpecString = true;
308 behavior.sideEffects.setTo(newEffects); 431 behavior.sideEffects.setTo(newEffects);
309 } 432 }
310 433
434 bool throwBehaviorFromSpecString = false;
435 void setThrows(NativeThrowBehavior throwBehavior) {
436 throwBehaviorFromSpecString = true;
437 behavior.throwBehavior = throwBehavior;
438 }
439
440 void setIsAllocation(bool isAllocation) {
441 behavior.isAllocation = isAllocation;
442 }
443
444 void setUseGvn(bool useGvn) {
445 behavior.useGvn = useGvn;
446 }
447
311 processSpecString(compiler, jsCall, 448 processSpecString(compiler, jsCall,
312 specString, 449 specString,
313 setSideEffects: setSideEffects, 450 setSideEffects: setSideEffects,
314 resolveType: resolveType, 451 setThrows: setThrows,
315 typesReturned: behavior.typesReturned, 452 setIsAllocation: setIsAllocation,
316 typesInstantiated: behavior.typesInstantiated, 453 setUseGvn: setUseGvn,
317 objectType: compiler.objectClass.computeType(compiler), 454 resolveType: resolveType,
318 nullType: compiler.nullClass.computeType(compiler)); 455 typesReturned: behavior.typesReturned,
456 typesInstantiated: behavior.typesInstantiated,
457 objectType: compiler.objectClass.computeType(compiler),
458 nullType: compiler.nullClass.computeType(compiler));
319 459
320 if (!sideEffectsAreEncodedInSpecString) { 460 if (!sideEffectsAreEncodedInSpecString) {
321 new SideEffectsVisitor(behavior.sideEffects) 461 new SideEffectsVisitor(behavior.sideEffects)
322 .visit(behavior.codeTemplate.ast); 462 .visit(behavior.codeTemplate.ast);
323 } 463 }
324 464
465 // TODO(sra): Simplify [throwBehavior] using [sideEffects].
466
325 return behavior; 467 return behavior;
326 } 468 }
327 469
328 static NativeBehavior ofJsEmbeddedGlobalCall(Send jsGlobalCall, 470 static NativeBehavior ofJsEmbeddedGlobalCall(Send jsGlobalCall,
329 Compiler compiler, 471 Compiler compiler,
330 resolver) { 472 resolver) {
331 // The first argument of a JS-embedded global call is a string encoding 473 // The first argument of a JS-embedded global call is a string encoding
332 // the type of the code. 474 // the type of the code.
333 // 475 //
334 // 'Type1|Type2'. A union type. 476 // 'Type1|Type2'. A union type.
335 // '=Object'. A JavaScript Object, no subtype. 477 // '=Object'. A JavaScript Object, no subtype.
336 478
337 Link<Node> argNodes = jsGlobalCall.arguments; 479 Link<Node> argNodes = jsGlobalCall.arguments;
338 if (argNodes.isEmpty) { 480 if (argNodes.isEmpty) {
339 compiler.internalError(jsGlobalCall, 481 compiler.internalError(jsGlobalCall,
340 "JS embedded global expression has no type."); 482 "JS embedded global expression has no type.");
341 } 483 }
342 484
343 // We don't check the given name. That needs to be done at a later point. 485 // We don't check the given name. That needs to be done at a later point.
344 // This is, because we want to allow non-literals as names. 486 // This is, because we want to allow non-literals as names.
345 if (argNodes.tail.isEmpty) { 487 if (argNodes.tail.isEmpty) {
346 compiler.internalError(jsGlobalCall, 'Embedded Global is missing name'); 488 compiler.internalError(jsGlobalCall, 'Embedded Global is missing name.');
347 } 489 }
348 490
349 if (!argNodes.tail.tail.isEmpty) { 491 if (!argNodes.tail.tail.isEmpty) {
350 compiler.internalError(argNodes.tail.tail.head, 492 compiler.internalError(argNodes.tail.tail.head,
351 'Embedded Global has more than 2 arguments'); 493 'Embedded Global has more than 2 arguments');
352 } 494 }
353 495
354 LiteralString specLiteral = argNodes.head.asLiteralString(); 496 LiteralString specLiteral = argNodes.head.asLiteralString();
355 if (specLiteral == null) { 497 if (specLiteral == null) {
356 // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It 498 // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It
357 // is not very satisfactory because it does not work for void, dynamic. 499 // is not very satisfactory because it does not work for void, dynamic.
358 compiler.internalError(argNodes.head, "Unexpected first argument."); 500 compiler.internalError(argNodes.head, "Unexpected first argument.");
359 } 501 }
360 502
361 NativeBehavior behavior = new NativeBehavior(); 503 NativeBehavior behavior = new NativeBehavior();
362 504
363 String specString = specLiteral.dartString.slowToString(); 505 String specString = specLiteral.dartString.slowToString();
364 506
365 dynamic resolveType(String typeString) { 507 dynamic resolveType(String typeString) {
366 return _parseType( 508 return _parseType(
367 typeString, 509 typeString,
368 compiler, 510 compiler,
369 (name) => resolver.resolveTypeFromString(specLiteral, name), 511 (name) => resolver.resolveTypeFromString(specLiteral, name),
370 jsGlobalCall); 512 jsGlobalCall);
371 } 513 }
372 514
373 void setSideEffects(SideEffects newEffects) {
374 compiler.internalError(jsGlobalCall,
375 'Embedded global calls may not have any side-effect overwrites: '
376 '$specString');
377 }
378
379 processSpecString(compiler, jsGlobalCall, 515 processSpecString(compiler, jsGlobalCall,
380 specString, 516 specString,
381 setSideEffects: setSideEffects, 517 validTags: const ['returns', 'creates'],
382 resolveType: resolveType, 518 resolveType: resolveType,
383 typesReturned: behavior.typesReturned, 519 typesReturned: behavior.typesReturned,
384 typesInstantiated: behavior.typesInstantiated, 520 typesInstantiated: behavior.typesInstantiated,
385 objectType: compiler.objectClass.computeType(compiler), 521 objectType: compiler.objectClass.computeType(compiler),
386 nullType: compiler.nullClass.computeType(compiler)); 522 nullType: compiler.nullClass.computeType(compiler));
387 523
388 return behavior; 524 return behavior;
389 } 525 }
390 526
391 static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) { 527 static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) {
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
546 _errorNode(locationNodeOrElement, compiler), 682 _errorNode(locationNodeOrElement, compiler),
547 "Type '$typeString' not found."); 683 "Type '$typeString' not found.");
548 return null; 684 return null;
549 } 685 }
550 686
551 static _errorNode(locationNodeOrElement, compiler) { 687 static _errorNode(locationNodeOrElement, compiler) {
552 if (locationNodeOrElement is Node) return locationNodeOrElement; 688 if (locationNodeOrElement is Node) return locationNodeOrElement;
553 return locationNodeOrElement.parseNode(compiler); 689 return locationNodeOrElement.parseNode(compiler);
554 } 690 }
555 } 691 }
OLDNEW
« no previous file with comments | « no previous file | tests/compiler/dart2js/js_spec_string_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698