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

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
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 =
floitsch 2015/04/07 15:35:16 ONLY_THROWS_IF_FIRST_ARGUMENT_IS_NULL ?
sra1 2015/04/07 17:59:47 I'd like to keep MUST/MAY/NEVER. This will be repl
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 orthongonal attribute?
floitsch 2015/04/07 15:35:16 orthogonal
sra1 2015/04/07 17:59:47 Thanks!
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.
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 restric
floitsch 2015/04/07 15:35:16 unfinished sentence.
sra1 2015/04/07 17:59:47 Done.
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 });
263 } 216 return;
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 String returns = values['returns'];
254 if (returns != null) {
255 resolveTypesString(returns, onVar: () {
256 typesReturned.add(objectType);
257 typesReturned.add(nullType);
258 }, onType: (type) {
259 typesReturned.add(type);
260 });
261 }
262
263 String creates = values['creates'];
264 if (creates != null) {
265 resolveTypesString(creates, onVoid: () {
266 listener.internalError(spannable,
267 "Invalid type string 'creates:$creates'");
268 }, onVar: () {
269 listener.internalError(spannable,
270 "Invalid type string 'creates:$creates'");
271 }, onType: (type) {
272 typesInstantiated.add(type);
273 });
274 }
275
276 SideEffects sideEffects = null;
277 NativeThrowBehavior throwsKind = null;
278 bool isAllocation = null;
279 bool useGvn = null;
280
281 String effects = values['effects'];
282 String depends = values['depends'];
283 if (effects != null || depends != null) {
284 sideEffects = processEffects(listener, spannable, effects, depends);
285 }
286
287 String throws = values['throws'];
288 if (throws != null) {
289 const map = const <String, NativeThrowBehavior>{
290 'never': NativeThrowBehavior.NEVER,
291 'null(1)': NativeThrowBehavior.MAY_THROW_ONLY_ON_FIRST_ARGUMENT_ACCESS,
292 'may': NativeThrowBehavior.MAY,
293 'must': NativeThrowBehavior.MUST };
294 throwsKind = map[throws];
295 if (throwsKind == null) {
296 listener.internalError(spannable,
297 "Unknown 'throws' specification '$throws'");
298 }
299 }
300
301 String newString = values['new'];
302 if (newString != null) {
303 const map = const<String, bool>{'true': true, 'false': false};
floitsch 2015/04/07 15:35:16 I'm not a fan of the map... if (newString != "true
sra1 2015/04/07 17:59:47 I have moved this to a helper.
304 isAllocation = map[newString];
305 if (isAllocation == null) {
306 listener.internalError(spannable,
307 "Unknown 'new' specification: '$newString'");
308 }
309 }
310
311 String gvn = values['gvn'];
312 if (gvn != null) {
313 const map = const<String, bool>{'true': true, 'false': false};
floitsch 2015/04/07 15:35:16 ditto.
sra1 2015/04/07 17:59:47 Done.
314 useGvn = map[gvn];
315 if (useGvn == null) {
316 listener.internalError(spannable,
317 "Unknown 'gvn' specification: '$gvn'");
318 }
319 }
320
321 if (isAllocation == true && useGvn == true) {
322 listener.internalError(spannable, "'new' and 'gvn' are incompatible");
323 }
324 if (sideEffects != null) setSideEffects(sideEffects);
325 if (throwsKind != null) setThrows(throwsKind);
326 if (isAllocation != null) setIsAllocation(isAllocation);
327 if (useGvn != null) setUseGvn(useGvn);
264 } 328 }
265 329
330 static SideEffects processEffects(
331 DiagnosticListener listener,
332 Spannable spannable,
333 String effects,
334 String depends) {
335
336 if (effects == null || depends == null) {
337 listener.internalError(spannable,
338 "Invalid JS spec string. "
339 "'effects' and 'depends' must occur together.");
340 return null;
341 }
342
343 SideEffects sideEffects = new SideEffects();
344 if (effects == "none") {
345 sideEffects.clearAllSideEffects();
346 } else if (effects == "all") {
347 // Don't do anything.
348 } else {
349 List<String> splitEffects = effects.split(",");
350 if (splitEffects.isEmpty) {
351 listener.internalError(spannable, "Missing side-effect flag.");
352 }
353 for (String effect in splitEffects) {
354 switch (effect) {
355 case "no-index":
356 sideEffects.clearChangesIndex();
357 break;
358 case "no-instance":
359 sideEffects.clearChangesInstanceProperty();
360 break;
361 case "no-static":
362 sideEffects.clearChangesStaticProperty();
363 break;
364 default:
365 listener.internalError(spannable,
366 "Unrecognized side-effect flag: '$effect'.");
367 }
368 }
369 }
370
371 if (depends == "none") {
372 sideEffects.clearAllDependencies();
373 } else if (depends == "all") {
374 // Don't do anything.
375 } else {
376 List<String> splitDependencies = depends.split(",");
377 if (splitDependencies.isEmpty) {
378 listener.internalError(spannable,
379 "Missing side-effect dependency flag.");
380 }
381 for (String dependency in splitDependencies) {
382 switch (dependency) {
383 case "no-index":
384 sideEffects.clearDependsOnIndexStore();
385 break;
386 case "no-instance":
387 sideEffects.clearDependsOnInstancePropertyStore();
388 break;
389 case "no-static":
390 sideEffects.clearDependsOnStaticPropertyStore();
391 break;
392 default:
393 listener.internalError(spannable,
394 "Unrecognized side-effect flag: '$dependency'.");
395 }
396 }
397 }
398
399 return sideEffects;
400 }
401
266 static NativeBehavior ofJsCall(Send jsCall, Compiler compiler, resolver) { 402 static NativeBehavior ofJsCall(Send jsCall, Compiler compiler, resolver) {
267 // The first argument of a JS-call is a string encoding various attributes 403 // The first argument of a JS-call is a string encoding various attributes
268 // of the code. 404 // of the code.
269 // 405 //
270 // 'Type1|Type2'. A union type. 406 // 'Type1|Type2'. A union type.
271 // '=Object'. A JavaScript Object, no subtype. 407 // '=Object'. A JavaScript Object, no subtype.
272 408
273 var argNodes = jsCall.arguments; 409 var argNodes = jsCall.arguments;
274 if (argNodes.isEmpty) { 410 if (argNodes.isEmpty) {
275 compiler.internalError(jsCall, "JS expression has no type."); 411 compiler.internalError(jsCall, "JS expression has no type.");
(...skipping 25 matching lines...) Expand all
301 jsCall); 437 jsCall);
302 } 438 }
303 439
304 bool sideEffectsAreEncodedInSpecString = false; 440 bool sideEffectsAreEncodedInSpecString = false;
305 441
306 void setSideEffects(SideEffects newEffects) { 442 void setSideEffects(SideEffects newEffects) {
307 sideEffectsAreEncodedInSpecString = true; 443 sideEffectsAreEncodedInSpecString = true;
308 behavior.sideEffects.setTo(newEffects); 444 behavior.sideEffects.setTo(newEffects);
309 } 445 }
310 446
447 bool throwBehaviorFromSpecString = false;
448 void setThrows(NativeThrowBehavior throwBehavior) {
449 throwBehaviorFromSpecString = true;
450 behavior.throwBehavior = throwBehavior;
451 }
452
453 void setIsAllocation(bool isAllocation) {
454 behavior.isAllocation = isAllocation;
455 }
456
457 void setUseGvn(bool useGvn) {
458 behavior.useGvn = useGvn;
459 }
460
311 processSpecString(compiler, jsCall, 461 processSpecString(compiler, jsCall,
312 specString, 462 specString,
313 setSideEffects: setSideEffects, 463 setSideEffects: setSideEffects,
314 resolveType: resolveType, 464 setThrows: setThrows,
315 typesReturned: behavior.typesReturned, 465 setIsAllocation: setIsAllocation,
316 typesInstantiated: behavior.typesInstantiated, 466 useGvn: useGvn,
317 objectType: compiler.objectClass.computeType(compiler), 467 resolveType: resolveType,
318 nullType: compiler.nullClass.computeType(compiler)); 468 typesReturned: behavior.typesReturned,
469 typesInstantiated: behavior.typesInstantiated,
470 objectType: compiler.objectClass.computeType(compiler),
471 nullType: compiler.nullClass.computeType(compiler));
319 472
320 if (!sideEffectsAreEncodedInSpecString) { 473 if (!sideEffectsAreEncodedInSpecString) {
321 new SideEffectsVisitor(behavior.sideEffects) 474 new SideEffectsVisitor(behavior.sideEffects)
322 .visit(behavior.codeTemplate.ast); 475 .visit(behavior.codeTemplate.ast);
323 } 476 }
324 477
478 // TODO(sra): Simplify [throwBehavior] using [sideEffects].
479
325 return behavior; 480 return behavior;
326 } 481 }
327 482
328 static NativeBehavior ofJsEmbeddedGlobalCall(Send jsGlobalCall, 483 static NativeBehavior ofJsEmbeddedGlobalCall(Send jsGlobalCall,
329 Compiler compiler, 484 Compiler compiler,
330 resolver) { 485 resolver) {
331 // The first argument of a JS-embedded global call is a string encoding 486 // The first argument of a JS-embedded global call is a string encoding
332 // the type of the code. 487 // the type of the code.
333 // 488 //
334 // 'Type1|Type2'. A union type. 489 // 'Type1|Type2'. A union type.
335 // '=Object'. A JavaScript Object, no subtype. 490 // '=Object'. A JavaScript Object, no subtype.
336 491
337 Link<Node> argNodes = jsGlobalCall.arguments; 492 Link<Node> argNodes = jsGlobalCall.arguments;
338 if (argNodes.isEmpty) { 493 if (argNodes.isEmpty) {
339 compiler.internalError(jsGlobalCall, 494 compiler.internalError(jsGlobalCall,
340 "JS embedded global expression has no type."); 495 "JS embedded global expression has no type.");
341 } 496 }
342 497
343 // We don't check the given name. That needs to be done at a later point. 498 // 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. 499 // This is, because we want to allow non-literals as names.
345 if (argNodes.tail.isEmpty) { 500 if (argNodes.tail.isEmpty) {
346 compiler.internalError(jsGlobalCall, 'Embedded Global is missing name'); 501 compiler.internalError(jsGlobalCall, 'Embedded Global is missing name.');
347 } 502 }
348 503
349 if (!argNodes.tail.tail.isEmpty) { 504 if (!argNodes.tail.tail.isEmpty) {
350 compiler.internalError(argNodes.tail.tail.head, 505 compiler.internalError(argNodes.tail.tail.head,
351 'Embedded Global has more than 2 arguments'); 506 'Embedded Global has more than 2 arguments');
352 } 507 }
353 508
354 LiteralString specLiteral = argNodes.head.asLiteralString(); 509 LiteralString specLiteral = argNodes.head.asLiteralString();
355 if (specLiteral == null) { 510 if (specLiteral == null) {
356 // TODO(sra): We could accept a type identifier? e.g. JS(bool, '1<2'). It 511 // 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. 512 // is not very satisfactory because it does not work for void, dynamic.
358 compiler.internalError(argNodes.head, "Unexpected first argument."); 513 compiler.internalError(argNodes.head, "Unexpected first argument.");
359 } 514 }
360 515
361 NativeBehavior behavior = new NativeBehavior(); 516 NativeBehavior behavior = new NativeBehavior();
362 517
363 String specString = specLiteral.dartString.slowToString(); 518 String specString = specLiteral.dartString.slowToString();
364 519
365 dynamic resolveType(String typeString) { 520 dynamic resolveType(String typeString) {
366 return _parseType( 521 return _parseType(
367 typeString, 522 typeString,
368 compiler, 523 compiler,
369 (name) => resolver.resolveTypeFromString(specLiteral, name), 524 (name) => resolver.resolveTypeFromString(specLiteral, name),
370 jsGlobalCall); 525 jsGlobalCall);
371 } 526 }
372 527
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, 528 processSpecString(compiler, jsGlobalCall,
380 specString, 529 specString,
381 setSideEffects: setSideEffects, 530 validTags: const ['returns', 'creates'],
382 resolveType: resolveType, 531 resolveType: resolveType,
383 typesReturned: behavior.typesReturned, 532 typesReturned: behavior.typesReturned,
384 typesInstantiated: behavior.typesInstantiated, 533 typesInstantiated: behavior.typesInstantiated,
385 objectType: compiler.objectClass.computeType(compiler), 534 objectType: compiler.objectClass.computeType(compiler),
386 nullType: compiler.nullClass.computeType(compiler)); 535 nullType: compiler.nullClass.computeType(compiler));
387 536
388 return behavior; 537 return behavior;
389 } 538 }
390 539
391 static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) { 540 static NativeBehavior ofMethod(FunctionElement method, Compiler compiler) {
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
546 _errorNode(locationNodeOrElement, compiler), 695 _errorNode(locationNodeOrElement, compiler),
547 "Type '$typeString' not found."); 696 "Type '$typeString' not found.");
548 return null; 697 return null;
549 } 698 }
550 699
551 static _errorNode(locationNodeOrElement, compiler) { 700 static _errorNode(locationNodeOrElement, compiler) {
552 if (locationNodeOrElement is Node) return locationNodeOrElement; 701 if (locationNodeOrElement is Node) return locationNodeOrElement;
553 return locationNodeOrElement.parseNode(compiler); 702 return locationNodeOrElement.parseNode(compiler);
554 } 703 }
555 } 704 }
OLDNEW
« no previous file with comments | « no previous file | tests/compiler/dart2js/js_spec_string_test.dart » ('j') | tests/compiler/dart2js/js_spec_string_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698