More features handled in kernel impact.

BUG=
R=het@google.com

Review URL: https://codereview.chromium.org/2329403003 .
This commit is contained in:
Johnni Winther 2016-09-16 12:52:47 +02:00
parent 6e62b8af9a
commit 4eca725670
9 changed files with 147 additions and 29 deletions

View file

@ -2825,9 +2825,6 @@ class JavaScriptImpactTransformer extends ImpactTransformer {
new TypeUse.instantiation(backend.coreTypes.nullType));
registerBackendImpact(transformed, impacts.nullLiteral);
break;
case Feature.INC_DEC_OPERATION:
registerBackendImpact(transformed, impacts.incDecOperation);
break;
case Feature.LAZY_FIELD:
registerBackendImpact(transformed, impacts.lazyField);
break;

View file

@ -306,16 +306,6 @@ class BackendImpacts {
return _constSymbol;
}
BackendImpact _incDecOperation;
BackendImpact get incDecOperation {
if (_incDecOperation == null) {
_incDecOperation =
_needsInt('Needed for the `+ 1` or `- 1` operation of ++/--.');
}
return _incDecOperation;
}
/// Helper for registering that `int` is needed.
BackendImpact _needsInt(String reason) {
// TODO(johnniwinther): Register [reason] for use in dump-info.

View file

@ -0,0 +1,45 @@
// Copyright (c) 2016, 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.
/// Helper for debug Kernel nodes.
library kernel.debug;
import 'package:kernel/kernel.dart';
import 'package:kernel/visitor.dart';
import '../util/util.dart' show Indentation, Tagging;
class DebugPrinter extends Visitor with Indentation, Tagging<Node> {
StringBuffer sb = new StringBuffer();
void visitNodeWithChildren(Node node, String type, [Map params]) {
openNode(node, type, params);
node.visitChildren(this);
closeNode();
}
@override
void defaultNode(Node node) {
visitNodeWithChildren(node, '${node.runtimeType}');
}
@override
void visitName(Name node) {
openAndCloseNode(node, '${node.runtimeType}',
{'name': node.name, 'library': node.library?.name});
}
@override
void visitIntLiteral(IntLiteral node) {
openAndCloseNode(node, '${node.runtimeType}', {'value': '${node.value}'});
}
/// Pretty-prints given node tree into string.
static String prettyPrint(Node node) {
var p = new DebugPrinter();
node.accept(p);
return p.sb.toString();
}
}

View file

@ -3409,7 +3409,7 @@ class ResolverVisitor extends MappingVisitor<ResolutionResult> {
? new PrefixStructure(semantics, operator)
: new PostfixStructure(semantics, operator);
registry.registerSendStructure(node, sendStructure);
registry.registerFeature(Feature.INC_DEC_OPERATION);
registry.registerConstantLiteral(new IntConstantExpression(1));
} else {
Node rhs = node.arguments.head;
visitExpression(rhs);

View file

@ -5,6 +5,7 @@
import 'package:kernel/ast.dart' as ir;
import '../common.dart';
import '../common/names.dart';
import '../compiler.dart';
import '../constants/values.dart';
import '../dart_types.dart';
@ -91,20 +92,26 @@ class KernelAstAdapter {
return new CallStructure(argumentCount, namedArguments);
}
Name getName(ir.Name name) {
return new Name(
name.name, name.isPrivate ? getElement(name.library) : null);
}
// TODO(het): Create the selector directly from the invocation
Selector getSelector(ir.InvocationExpression invocation) {
SelectorKind kind = Elements.isOperatorName(invocation.name.name)
? SelectorKind.OPERATOR
: SelectorKind.CALL;
if (invocation.name.name == '[]' || invocation.name.name == '[]=') {
kind = SelectorKind.INDEX;
Name name = getName(invocation.name);
SelectorKind kind;
if (Elements.isOperatorName(invocation.name.name)) {
if (name == Names.INDEX_NAME || name == Names.INDEX_SET_NAME) {
kind = SelectorKind.INDEX;
} else {
kind = SelectorKind.OPERATOR;
}
} else {
kind = SelectorKind.CALL;
}
ir.Name irName = invocation.name;
Name name = new Name(
irName.name, irName.isPrivate ? getElement(irName.library) : null);
CallStructure callStructure = getCallStructure(invocation.arguments);
return new Selector(kind, name, callStructure);
}

View file

@ -11,9 +11,11 @@ import '../dart_types.dart';
import '../elements/elements.dart';
import '../js_backend/backend.dart' show JavaScriptBackend;
import '../kernel/kernel.dart';
import '../kernel/kernel_debug.dart';
import '../kernel/kernel_visitor.dart';
import '../resolution/registry.dart' show ResolutionWorldImpactBuilder;
import '../universe/feature.dart';
import '../universe/selector.dart';
import '../universe/use.dart';
import 'kernel_ast_adapter.dart';
@ -211,8 +213,33 @@ class KernelImpactBuilder extends ir.Visitor {
new DynamicUse(astAdapter.getSelector(invocation), null));
}
@override
void visitPropertyGet(ir.PropertyGet node) {
node.receiver.accept(this);
impactBuilder.registerDynamicUse(new DynamicUse(
new Selector.getter(astAdapter.getName(node.name)), null));
}
@override
void visitPropertySet(ir.PropertySet node) {
node.receiver.accept(this);
node.value.accept(this);
impactBuilder.registerDynamicUse(new DynamicUse(
new Selector.setter(astAdapter.getName(node.name)), null));
}
@override
void visitNot(ir.Not not) {
not.operand.accept(this);
}
@override
void visitAssertStatement(ir.AssertStatement node) {
impactBuilder.registerFeature(
node.message != null ? Feature.ASSERT_WITH_MESSAGE : Feature.ASSERT);
node.visitChildren(this);
}
@override
void defaultNode(ir.Node node) => node.visitChildren(this);
}

View file

@ -43,9 +43,6 @@ enum Feature {
/// A field without an initializer.
FIELD_WITHOUT_INITIALIZER,
/// A ++/-- operation.
INC_DEC_OPERATION,
/// A field whose initialization is not a constant.
LAZY_FIELD,

View file

@ -30,6 +30,9 @@ const Map<String, List/*<String|MessageKind>*/> WHITE_LIST = const {
"Library 'package:async/async.dart' doesn't export a "
"'ForkableStream' declaration.",
],
"/utils.dart": const [
"Duplicated library name 'utils'.",
],
};
const List<String> SKIP_LIST = const <String>[

View file

@ -39,12 +39,25 @@ main() {
testNonEmptyMapLiteral();
testNot();
testUnaryMinus();
testConditional();
testPostInc(null);
testPostDec(null);
testPreInc(null);
testPreDec(null);
testIfThen();
testIfThenElse();
testTopLevelInvoke();
testTopLevelInvokeTyped();
testTopLevelField();
testTopLevelFieldTyped();
testDynamicInvoke(null);
testDynamicGet(null);
testDynamicSet(null);
testLocalWithInitializer();
testInvokeIndex(null);
testInvokeIndexSet(null);
testAssert();
testAssertWithMessage();
}
testEmpty() {}
@ -67,6 +80,11 @@ testEmptyMapLiteralConstant() => const {};
testNonEmptyMapLiteral() => {0: true};
testNot() => !false;
testUnaryMinus() => -1;
testConditional() => true ? 1 : '';
testPostInc(o) => o++;
testPostDec(o) => o--;
testPreInc(o) => ++o;
testPreDec(o) => --o;
testIfThen() {
if (false) return 42;
return 1;
@ -112,6 +130,30 @@ var topLevelField;
testTopLevelField() => topLevelField;
int topLevelFieldTyped;
testTopLevelFieldTyped() => topLevelFieldTyped;
testDynamicInvoke(o) {
o.f1(0);
o.f2(1);
o.f3(2, 3);
o.f4(4, 5, 6);
o.f5(7);
o.f6(8, b: 9);
o.f7(10, c: 11);
o.f8(12, b: 13, c: 14);
o.f9(15, c: 16, b: 17);
}
testDynamicGet(o) => o.foo;
testDynamicSet(o) => o.foo = 42;
testLocalWithInitializer() {
var l = 42;
}
testInvokeIndex(o) => o[42];
testInvokeIndexSet(o) => o[42] = null;
testAssert() {
assert(true);
}
testAssertWithMessage() {
assert(true, 'ok');
}
'''
};
@ -122,11 +164,21 @@ main(List<String> args) {
Compiler compiler = compilerFor(
entryPoint: entryPoint,
memorySourceFiles: SOURCE,
options: [Flags.analyzeOnly, Flags.useKernel]);
options:
[Flags.analyzeAll, Flags.useKernel, Flags.enableAssertMessage]);
compiler.resolution.retainCachesForTesting = true;
await compiler.run(entryPoint);
compiler.mainApp
.forEachLocalMember((element) => checkElement(compiler, element));
checkLibrary(compiler, compiler.mainApp);
});
}
void checkLibrary(Compiler compiler, LibraryElement library) {
library.forEachLocalMember((AstElement element) {
if (element.isClass) {
// TODO(johnniwinther): Handle class members.
} else {
checkElement(compiler, element);
}
});
}