| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 library ddc.runtime.dart_logging_runtime; | 5 library dev_compiler.runtime.dart_logging_runtime; |
| 6 | 6 |
| 7 import 'dart:mirrors' as mirrors; | 7 import 'dart:mirrors' as mirrors; |
| 8 | 8 |
| 9 import 'dart_runtime.dart' as rt; | 9 import 'dart_runtime.dart' as rt; |
| 10 export 'dart_runtime.dart' show Arity, getArity, type; | 10 export 'dart_runtime.dart' show Arity, getArity, type; |
| 11 | 11 |
| 12 import 'package:stack_trace/stack_trace.dart'; | 12 import 'package:stack_trace/stack_trace.dart'; |
| 13 | 13 |
| 14 // Logging / updating CastRecords for cases that alway pass in Dart and DDC | 14 // Logging / updating CastRecords for cases that alway pass in Dart and DDC |
| 15 // is expensive. They are also less interesting, so filter out by default. | 15 // is expensive. They are also less interesting, so filter out by default. |
| 16 const bool _skipSuccess = true; | 16 const bool _skipSuccess = true; |
| 17 | 17 |
| 18 class CastRecord { | 18 class CastRecord { |
| 19 final Type runtimeType; | 19 final Type runtimeType; |
| 20 final Type staticType; | 20 final Type staticType; |
| 21 final bool ddcSuccess; | |
| 22 final bool dartSuccess; | |
| 23 | 21 |
| 24 CastRecord( | 22 /// True if the dev_compiler would allow this cast. Otherwise false. |
| 25 this.runtimeType, this.staticType, this.ddcSuccess, this.dartSuccess); | 23 final bool soundCast; |
| 24 |
| 25 /// True if Dart checked mode would allow this cast. Otherwise false. |
| 26 final bool dartCast; |
| 27 |
| 28 CastRecord(this.runtimeType, this.staticType, this.soundCast, this.dartCast); |
| 26 } | 29 } |
| 27 | 30 |
| 28 // Register a handler to process CastRecords. The default (see below) just | 31 // Register a handler to process CastRecords. The default (see below) just |
| 29 // prints a summary at the end. | 32 // prints a summary at the end. |
| 30 typedef void CastRecordHandler(String key, CastRecord record); | 33 typedef void CastRecordHandler(String key, CastRecord record); |
| 31 CastRecordHandler castRecordHandler = _record; | 34 CastRecordHandler castRecordHandler = _record; |
| 32 | 35 |
| 33 var _cache = <Type, Map<Type, CastRecord>>{}; | 36 var _cache = <Type, Map<Type, CastRecord>>{}; |
| 34 | 37 |
| 35 Map<Type, CastRecord> _cacheGen() => <Type, CastRecord>{}; | 38 Map<Type, CastRecord> _cacheGen() => <Type, CastRecord>{}; |
| (...skipping 22 matching lines...) Expand all Loading... |
| 58 | 61 |
| 59 if (key == null) { | 62 if (key == null) { |
| 60 // If no key is past in, use the caller's frame as a key. | 63 // If no key is past in, use the caller's frame as a key. |
| 61 final trace = new Trace.current(1); | 64 final trace = new Trace.current(1); |
| 62 final frame = trace.frames.first; | 65 final frame = trace.frames.first; |
| 63 key = frame.toString(); | 66 key = frame.toString(); |
| 64 } | 67 } |
| 65 | 68 |
| 66 CastRecord record = _lookupInCache(runtimeType, staticType); | 69 CastRecord record = _lookupInCache(runtimeType, staticType); |
| 67 if (record == null) { | 70 if (record == null) { |
| 68 bool ddcSuccess = true; | 71 bool soundCast = true; |
| 69 bool dartSuccess = true; | 72 bool dartCast = true; |
| 70 // TODO(vsm): Use instanceOf once we settle on nullability. | 73 // TODO(vsm): Use instanceOf once we settle on nullability. |
| 71 try { | 74 try { |
| 72 rt.cast(obj, staticType); | 75 rt.cast(obj, staticType); |
| 73 } catch (e) { | 76 } catch (e) { |
| 74 ddcSuccess = false; | 77 soundCast = false; |
| 75 } | 78 } |
| 76 if (obj == null) { | 79 if (obj == null) { |
| 77 dartSuccess = true; | 80 dartCast = true; |
| 78 } else { | 81 } else { |
| 79 // TODO(vsm): We could avoid mirror code by requiring the caller to pass | 82 // TODO(vsm): We could avoid mirror code by requiring the caller to pass |
| 80 // in obj is TypeLiteral as a parameter. We can't do that once we have a | 83 // in obj is TypeLiteral as a parameter. We can't do that once we have a |
| 81 // Type object instead. | 84 // Type object instead. |
| 82 final staticMirror = mirrors.reflectType(staticType); | 85 final staticMirror = mirrors.reflectType(staticType); |
| 83 final instanceMirror = mirrors.reflect(obj); | 86 final instanceMirror = mirrors.reflect(obj); |
| 84 final classMirror = instanceMirror.type; | 87 final classMirror = instanceMirror.type; |
| 85 dartSuccess = classMirror.isSubtypeOf(staticMirror); | 88 dartCast = classMirror.isSubtypeOf(staticMirror); |
| 86 } | 89 } |
| 87 if (_skipSuccess && dartSuccess && ddcSuccess) { | 90 if (_skipSuccess && dartCast && soundCast) { |
| 88 _successCache | 91 _successCache |
| 89 .putIfAbsent(staticType, () => new Set<Type>()) | 92 .putIfAbsent(staticType, () => new Set<Type>()) |
| 90 .add(runtimeType); | 93 .add(runtimeType); |
| 91 return obj; | 94 return obj; |
| 92 } | 95 } |
| 93 record = new CastRecord(runtimeType, staticType, ddcSuccess, dartSuccess); | 96 record = new CastRecord(runtimeType, staticType, soundCast, dartCast); |
| 94 _addToCache(runtimeType, staticType, record); | 97 _addToCache(runtimeType, staticType, record); |
| 95 } | 98 } |
| 96 castRecordHandler(key, record); | 99 castRecordHandler(key, record); |
| 97 return obj; | 100 return obj; |
| 98 } | 101 } |
| 99 | 102 |
| 100 dynamic wrap(Function build(Function _), Function f, Type fromType, Type toType, | 103 dynamic wrap(Function build(Function _), Function f, Type fromType, Type toType, |
| 101 String kind, String key, bool dartIs) { | 104 String kind, String key, bool dartIs) { |
| 102 if (f == null) return null; | 105 if (f == null) return null; |
| 103 return build(f); | 106 return build(f); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 120 Type staticType = null; | 123 Type staticType = null; |
| 121 var runtimeTypes = new Set<Type>(); | 124 var runtimeTypes = new Set<Type>(); |
| 122 for (var record in records) { | 125 for (var record in records) { |
| 123 if (staticType == null) { | 126 if (staticType == null) { |
| 124 staticType = record.staticType; | 127 staticType = record.staticType; |
| 125 } else { | 128 } else { |
| 126 // Are these canonicalized? | 129 // Are these canonicalized? |
| 127 // assert(staticType == record.staticType); | 130 // assert(staticType == record.staticType); |
| 128 } | 131 } |
| 129 runtimeTypes.add(record.runtimeType); | 132 runtimeTypes.add(record.runtimeType); |
| 130 if (record.ddcSuccess) { | 133 if (record.soundCast) { |
| 131 if (record.dartSuccess) { | 134 if (record.dartCast) { |
| 132 success++; | 135 success++; |
| 133 } else { | 136 } else { |
| 134 error++; | 137 error++; |
| 135 } | 138 } |
| 136 } else { | 139 } else { |
| 137 if (record.dartSuccess) { | 140 if (record.dartCast) { |
| 138 mismatch++; | 141 mismatch++; |
| 139 } else { | 142 } else { |
| 140 failure++; | 143 failure++; |
| 141 } | 144 } |
| 142 } | 145 } |
| 143 } | 146 } |
| 144 final total = success + mismatch + error + failure; | 147 final total = success + mismatch + error + failure; |
| 145 assert(total != 0); | 148 assert(total != 0); |
| 146 if (success < total) { | 149 if (success < total) { |
| 147 buffer.writeln('Key $key:'); | 150 buffer.writeln('Key $key:'); |
| 148 buffer.writeln(' - static type: $staticType'); | 151 buffer.writeln(' - static type: $staticType'); |
| 149 buffer.writeln(' - runtime types: $runtimeTypes'); | 152 buffer.writeln(' - runtime types: $runtimeTypes'); |
| 150 final category = (String cat, int val) => | 153 final category = (String cat, int val) => |
| 151 buffer.writeln(' - $cat: $val (${val / total})'); | 154 buffer.writeln(' - $cat: $val (${val / total})'); |
| 152 category('success', success); | 155 category('success', success); |
| 153 category('failure', failure); | 156 category('failure', failure); |
| 154 category('mismatch', mismatch); | 157 category('mismatch', mismatch); |
| 155 category('error', error); | 158 category('error', error); |
| 156 } | 159 } |
| 157 }); | 160 }); |
| 158 if (clear) { | 161 if (clear) { |
| 159 _recordMap.clear(); | 162 _recordMap.clear(); |
| 160 } | 163 } |
| 161 return buffer.toString(); | 164 return buffer.toString(); |
| 162 } | 165 } |
| OLD | NEW |