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

Side by Side Diff: frog/value.dart

Issue 8463027: Optimize boolean asserts (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: co19 status Created 9 years, 1 month 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) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 /** 5 /**
6 * Represents a meta-value for code generation. 6 * Represents a meta-value for code generation.
7 */ 7 */
8 class Value { 8 class Value {
9 /** The [Type] of the [Value]. */ 9 /** The [Type] of the [Value]. */
10 Type type; 10 Type type;
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 return member._set(context, node, this, value, isDynamic); 60 return member._set(context, node, this, value, isDynamic);
61 } else { 61 } else {
62 return invokeNoSuchMethod(context, 'set:$name', node, 62 return invokeNoSuchMethod(context, 'set:$name', node,
63 new Arguments(null, [value])); 63 new Arguments(null, [value]));
64 } 64 }
65 } 65 }
66 66
67 67
68 Value invoke(MethodGenerator context, String name, Node node, Arguments args, 68 Value invoke(MethodGenerator context, String name, Node node, Arguments args,
69 [bool isDynamic=false]) { 69 [bool isDynamic=false]) {
70 // TODO(jimhug): The != method is weird - understand it better. 70 // TODO(jmesserly): try to get rid of this code path. We're generating a
71 // synthetic != on Object (see DefinedType._createNotEqualMember) already.
72 // So it should be pretty easy to make this go away.
jimhug 2011/11/12 00:26:36 +1
71 if (_typeIsVarOrParameterType && name == '\$ne') { 73 if (_typeIsVarOrParameterType && name == '\$ne') {
72 if (args.values.length != 1) { 74 if (args.values.length != 1) {
73 world.warning('wrong number of arguments for !=', node.span); 75 world.warning('wrong number of arguments for !=', node.span);
74 } 76 }
77 // Ensure the == operator is generated, and get its type
78 var eq = invoke(context, '\$eq', node, args, isDynamic);
75 world.gen.corejs.useOperator('\$ne'); 79 world.gen.corejs.useOperator('\$ne');
76 return new Value(world.varType, '\$ne($code, ${args.values[0].code})', 80 return new Value(eq.type, '\$ne($code, ${args.values[0].code})',
77 node.span); 81 node.span);
78 } 82 }
79 83
80 // TODO(jmesserly): it'd be nice to remove these special cases 84 // TODO(jmesserly): it'd be nice to remove these special cases
81 // We could create a $call (and $ne) in world members, and have 85 // We could create a $call (and $ne) in world members, and have
82 // those guys handle the canInvoke/Invoke logic. 86 // those guys handle the canInvoke/Invoke logic.
83 87
84 // Note: this check is a little different than the one in canInvoke, because 88 // Note: this check is a little different than the one in canInvoke, because
85 // sometimes we need to call dynamically even if we found the $call method 89 // sometimes we need to call dynamically even if we found the $call method
86 // statically. 90 // statically.
87 91
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after
259 } 263 }
260 264
261 // TODO(jmesserly): remove the special case for "num" when our num handling 265 // TODO(jmesserly): remove the special case for "num" when our num handling
262 // is better. 266 // is better.
263 bool bothNum = type.isNum && toType.isNum; 267 bool bothNum = type.isNum && toType.isNum;
264 if (!checked || fromType.isSubtypeOf(toType) || bothNum) { 268 if (!checked || fromType.isSubtypeOf(toType) || bothNum) {
265 // No checks needed for a widening conversion. 269 // No checks needed for a widening conversion.
266 return this; 270 return this;
267 } 271 }
268 272
269 if (!toType.isSubtypeOf(type)) { 273 if (checked && !toType.isSubtypeOf(type)) {
270 // According to the static types, this conversion can't work. 274 // According to the static types, this conversion can't work.
271 convertWarning(toType, node); 275 convertWarning(toType, node);
272 } 276 }
273 277
274 // Generate a runtime checks if they're turned on, otherwise skip it. 278 // Generate a runtime checks if they're turned on, otherwise skip it.
275 if (options.enableTypeChecks) { 279 if (options.enableTypeChecks) {
276 return _typeAssert(context, toType, node); 280 return _typeAssert(context, toType, node);
277 } else { 281 } else {
278 return this; 282 return this;
279 } 283 }
280 } 284 }
281 285
282 // TODO(jmesserly): this generates an unnecessary check for the 90%
283 // case where the thing passed in was a non-overloaded == or != expression
284 // We'll want to eliminate these, probably by tracking non-null bools in the
285 // type system.
286 // This matches the interesting Boolean Conversion section of the spec.
287 Value convertToNonNullBool(MethodGenerator context, Node node) {
288 if (!type.isAssignable(world.boolType)) {
289 convertWarning(world.boolType, node);
290 }
291 if (!options.enableTypeChecks) {
292 // TODO(jimhug): If type != world.boolType, this should return
293 // this.code === true according to the spec.
294 return this;
295 } else {
296 // TODO(jmesserly): this is hacky.
297 if (code.startsWith('\$notnull_bool')) {
298 return this;
299 } else {
300 world.gen.corejs.useNotNullBool = true;
301 return new Value(world.boolType, '\$notnull_bool($code)', span);
302 }
303 }
304 }
305
306 bool _isDomCallback(toType) { 286 bool _isDomCallback(toType) {
307 return (toType.definition is FunctionTypeDefinition 287 return (toType.definition is FunctionTypeDefinition
308 && toType.library == world.dom); 288 && toType.library == world.dom);
309 } 289 }
310 290
311 Value _wrapDomCallback(Type toType, int arity) { 291 Value _wrapDomCallback(Type toType, int arity) {
312 return new Value(toType, '\$wrap_call\$$arity($code)', span); 292 return new Value(toType, '\$wrap_call\$$arity($code)', span);
313 } 293 }
314 294
315 /** 295 /**
(...skipping 22 matching lines...) Expand all
338 // TypeError. Alternatively we could define fallbacks on Object that throw. 318 // TypeError. Alternatively we could define fallbacks on Object that throw.
339 String check; 319 String check;
340 if (toType.isVoid) { 320 if (toType.isVoid) {
341 check = '\$assert_void($code)'; 321 check = '\$assert_void($code)';
342 if (toType.typeCheckCode == null) { 322 if (toType.typeCheckCode == null) {
343 toType.typeCheckCode = ''' 323 toType.typeCheckCode = '''
344 function \$assert_void(x) { 324 function \$assert_void(x) {
345 return x == null ? x : x.is\$void(); // throws TypeError 325 return x == null ? x : x.is\$void(); // throws TypeError
346 }'''; 326 }''';
347 } 327 }
328 } else if (toType == world.nonNullBool) {
329 // This could be made less of a special case
330 world.gen.corejs.useNotNullBool = true;
331 check = '\$notnull_bool($code)';
332
348 } else if (toType.library.isCore && toType.typeofName != null) { 333 } else if (toType.library.isCore && toType.typeofName != null) {
349 check = '\$assert_${toType.name}($code)'; 334 check = '\$assert_${toType.name}($code)';
350 335
351 if (toType.typeCheckCode == null) { 336 if (toType.typeCheckCode == null) {
352 toType.typeCheckCode = ''' 337 toType.typeCheckCode = '''
353 function \$assert_${toType.name}(x) { 338 function \$assert_${toType.name}(x) {
354 if (x == null || typeof(x) == "${toType.typeofName}") return x; 339 if (x == null || typeof(x) == "${toType.typeofName}") return x;
355 throw new TypeError("'" + x + "' is not a ${toType.name}."); 340 throw new TypeError("'" + x + "' is not a ${toType.name}.");
356 }'''; 341 }''';
357 } 342 }
(...skipping 17 matching lines...) Expand all
375 * - If it's a non-generic class, use instanceof. 360 * - If it's a non-generic class, use instanceof.
376 * - Otherwise add a fake member to test for. This value is generated 361 * - Otherwise add a fake member to test for. This value is generated
377 * as a function so that it can be called for a runtime failure. 362 * as a function so that it can be called for a runtime failure.
378 */ 363 */
379 Value instanceOf(MethodGenerator context, Type toType, SourceSpan span, 364 Value instanceOf(MethodGenerator context, Type toType, SourceSpan span,
380 [bool isTrue=true, bool forceCheck=false]) { 365 [bool isTrue=true, bool forceCheck=false]) {
381 // TODO(jimhug): Optimize away tests that will always pass unless 366 // TODO(jimhug): Optimize away tests that will always pass unless
382 // forceCheck is true. 367 // forceCheck is true.
383 if (toType.isVar) { 368 if (toType.isVar) {
384 world.error('can not resolve type', span); 369 world.error('can not resolve type', span);
385 return new EvaluatedValue(world.boolType, true, 'true', null); 370 return new EvaluatedValue(world.nonNullBool, true, 'true', null);
386 } 371 }
387 372
388 if (toType is ParameterType) { 373 if (toType is ParameterType) {
389 return new EvaluatedValue(world.boolType, true, 'true', null); 374 return new EvaluatedValue(world.nonNullBool, true, 'true', null);
390 } 375 }
391 376
392 String testCode = null; 377 String testCode = null;
393 if (toType.library.isCore) { 378 if (toType.library.isCore) {
394 var typeofName = toType.typeofName; 379 var typeofName = toType.typeofName;
395 if (typeofName != null) { 380 if (typeofName != null) {
396 testCode = "(typeof($code) ${isTrue ? '==' : '!='} '$typeofName')"; 381 testCode = "(typeof($code) ${isTrue ? '==' : '!='} '$typeofName')";
397 } 382 }
398 } 383 }
399 if (toType.isClass && toType is !ConcreteType) { 384 if (toType.isClass && toType is !ConcreteType) {
(...skipping 15 matching lines...) Expand all
415 // Add !! to convert to boolean. 400 // Add !! to convert to boolean.
416 // TODO(jimhug): only do this if needed 401 // TODO(jimhug): only do this if needed
417 testCode = '!!' + testCode; 402 testCode = '!!' + testCode;
418 } else { 403 } else {
419 // The single ! here nicely converts undefined to false and function 404 // The single ! here nicely converts undefined to false and function
420 // to true. 405 // to true.
421 testCode = '!' + testCode; 406 testCode = '!' + testCode;
422 } 407 }
423 if (this != temp) context.freeTemp(temp); 408 if (this != temp) context.freeTemp(temp);
424 } 409 }
425 return new Value(world.boolType, testCode, span); 410 return new Value(world.nonNullBool, testCode, span);
426 } 411 }
427 412
428 void convertWarning(Type toType, Node node) { 413 void convertWarning(Type toType, Node node) {
429 // TODO(jmesserly): better error messages for type conversion failures 414 // TODO(jmesserly): better error messages for type conversion failures
430 world.warning('type "${type.name}" is not assignable to "${toType.name}"', 415 world.warning('type "${type.name}" is not assignable to "${toType.name}"',
431 node.span); 416 node.span);
432 } 417 }
433 418
434 Value invokeNoSuchMethod(MethodGenerator context, String name, Node node, 419 Value invokeNoSuchMethod(MethodGenerator context, String name, Node node,
435 [Arguments args]) { 420 [Arguments args]) {
(...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after
683 668
684 // Then look for members in my library. 669 // Then look for members in my library.
685 member = home.library.lookup(name, span); 670 member = home.library.lookup(name, span);
686 if (member != null) { 671 if (member != null) {
687 return member; 672 return member;
688 } 673 }
689 674
690 return null; 675 return null;
691 } 676 }
692 } 677 }
OLDNEW
« frog/type.dart ('K') | « frog/type.dart ('k') | frog/world.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698