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 |