Files
sdk/pkg/dev_compiler/lib/runtime/dart_logging_runtime.dart
T
Vijay Menon e4fdeb376d Fix logging test
Just updating the broken test.  The dart_runtime.dart type rules are still out of date.

R=leafp@google.com

Review URL: https://codereview.chromium.org/1045753003
2015-03-30 16:03:50 -07:00

166 lines
5.0 KiB
Dart

// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library dev_compiler.runtime.dart_logging_runtime;
import 'dart:mirrors' as mirrors;
import 'dart_runtime.dart' as rt;
export 'dart_runtime.dart' show Arity, getArity, type;
import 'package:stack_trace/stack_trace.dart';
// Logging / updating CastRecords for cases that alway pass in Dart and DDC
// is expensive. They are also less interesting, so filter out by default.
const bool _skipSuccess = true;
class CastRecord {
final Type runtimeType;
final Type staticType;
/// True if the dev_compiler would allow this cast. Otherwise false.
final bool soundCast;
/// True if Dart checked mode would allow this cast. Otherwise false.
final bool dartCast;
CastRecord(this.runtimeType, this.staticType, this.soundCast, this.dartCast);
}
// Register a handler to process CastRecords. The default (see below) just
// prints a summary at the end.
typedef void CastRecordHandler(String key, CastRecord record);
CastRecordHandler castRecordHandler = _record;
var _cache = <Type, Map<Type, CastRecord>>{};
Map<Type, CastRecord> _cacheGen() => <Type, CastRecord>{};
void _addToCache(Type runtimeType, Type staticType, CastRecord record) {
_cache.putIfAbsent(runtimeType, _cacheGen)[staticType] = record;
}
CastRecord _lookupInCache(Type runtimeType, Type staticType) {
var subcache = _cache[runtimeType];
if (subcache == null) return null;
return subcache[staticType];
}
var _successCache = <Type, Set<Type>>{};
dynamic cast(dynamic obj, Type fromType, Type staticType,
[String kind, String key, bool dartIs, bool isGround]) {
var runtimeType = obj.runtimeType;
// Short-circuit uninteresting cases.
if (_skipSuccess && _successCache.containsKey(staticType)) {
if (_successCache[staticType].contains(runtimeType)) {
return obj;
}
}
if (key == null) {
// If no key is past in, use the caller's frame as a key.
final trace = new Trace.current(1);
final frame = trace.frames.first;
key = frame.toString();
}
CastRecord record = _lookupInCache(runtimeType, staticType);
if (record == null) {
bool soundCast = true;
bool dartCast = true;
// TODO(vsm): Use instanceOf once we settle on nullability.
try {
rt.cast(obj, staticType);
} catch (e) {
soundCast = false;
}
if (obj == null) {
dartCast = true;
} else {
// TODO(vsm): We could avoid mirror code by requiring the caller to pass
// in obj is TypeLiteral as a parameter. We can't do that once we have a
// Type object instead.
final staticMirror = mirrors.reflectType(staticType);
final instanceMirror = mirrors.reflect(obj);
final classMirror = instanceMirror.type;
dartCast = classMirror.isSubtypeOf(staticMirror);
}
if (_skipSuccess && dartCast && soundCast) {
_successCache
.putIfAbsent(staticType, () => new Set<Type>())
.add(runtimeType);
return obj;
}
record = new CastRecord(runtimeType, staticType, soundCast, dartCast);
_addToCache(runtimeType, staticType, record);
}
castRecordHandler(key, record);
return obj;
}
dynamic wrap(Function build(Function _), Function f, Type fromType, Type toType,
String kind, String key, bool dartIs) {
if (f == null) return null;
return build(f);
}
// The default handler simply records all CastRecords and prints a summary
// at the end.
final _recordMap = new Map<String, List<CastRecord>>();
void _record(String key, CastRecord record) {
_recordMap.putIfAbsent(key, () => <CastRecord>[]).add(record);
}
String summary({bool clear: true}) {
final buffer = new StringBuffer();
_recordMap.forEach((String key, List<CastRecord> records) {
int success = 0;
int mismatch = 0;
int error = 0;
int failure = 0;
Type staticType = null;
var runtimeTypes = new Set<Type>();
for (var record in records) {
if (staticType == null) {
staticType = record.staticType;
} else {
// Are these canonicalized?
// assert(staticType == record.staticType);
}
runtimeTypes.add(record.runtimeType);
if (record.soundCast) {
if (record.dartCast) {
success++;
} else {
error++;
}
} else {
if (record.dartCast) {
mismatch++;
} else {
failure++;
}
}
}
final total = success + mismatch + error + failure;
assert(total != 0);
if (success < total) {
buffer.writeln('Key $key:');
buffer.writeln(' - static type: $staticType');
buffer.writeln(' - runtime types: $runtimeTypes');
final category = (String cat, int val) =>
buffer.writeln(' - $cat: $val (${val / total})');
category('success', success);
category('failure', failure);
category('mismatch', mismatch);
category('error', error);
}
});
if (clear) {
_recordMap.clear();
}
return buffer.toString();
}