| Index: lib/compiler/implementation/ssa/optimize.dart
|
| ===================================================================
|
| --- lib/compiler/implementation/ssa/optimize.dart (revision 6727)
|
| +++ lib/compiler/implementation/ssa/optimize.dart (working copy)
|
| @@ -151,16 +151,73 @@
|
| }
|
|
|
| HInstruction visitInvokeInterceptor(HInvokeInterceptor node) {
|
| - if (node.name == const SourceString('length') &&
|
| - node.inputs[1].isConstantString()) {
|
| - HConstant input = node.inputs[1];
|
| - StringConstant constant = input.constant;
|
| - DartString string = constant.value;
|
| - return graph.addConstantInt(string.length);
|
| + if (node.isLengthGetter()) {
|
| + HInstruction input = node.inputs[1];
|
| + if (input.isConstantString()) {
|
| + StringConstant constant = input.constant;
|
| + return graph.addConstantInt(constant.length);
|
| + } else if (input.isConstantList()) {
|
| + ListConstant constant = input.constant;
|
| + return graph.addConstantInt(constant.length);
|
| + } else if (input.isConstantMap()) {
|
| + MapConstant constant = input.constant;
|
| + return graph.addConstantInt(constant.length);
|
| + }
|
| }
|
| return node;
|
| }
|
|
|
| + HInstruction visitInvokeDynamic(HInvokeDynamic node) {
|
| + HType receiverType = node.receiver.propagatedType;
|
| + if (receiverType.isNonPrimitive()) {
|
| + HNonPrimitiveType type = receiverType;
|
| + Element element = type.lookupMember(node.name);
|
| + // TODO(ngeoffray): Also fold if it's a getter or variable.
|
| + if (element != null && element.isFunction()) {
|
| + FunctionElement method = element;
|
| + FunctionParameters parameters = method.computeParameters(compiler);
|
| + if (node.selector.applies(parameters)) {
|
| + if (parameters.optionalParameterCount == 0) {
|
| + node.element = element;
|
| + }
|
| + // TODO(ngeoffray): If the method has optional parameters,
|
| + // we should pass the default values here.
|
| + }
|
| + }
|
| + }
|
| + return node;
|
| + }
|
| +
|
| + HInstruction fromInterceptorToDynamicInvocation(
|
| + HInvokeStatic node, SourceString methodName) {
|
| + HNonPrimitiveType type = node.inputs[1].propagatedType;
|
| + Element element = type.lookupMember(methodName);
|
| + HInvokeDynamicMethod result = new HInvokeDynamicMethod(
|
| + node.selector,
|
| + methodName,
|
| + node.inputs.getRange(1, node.inputs.length - 1));
|
| + result.element = element;
|
| + return result;
|
| + }
|
| +
|
| + HInstruction visitIndex(HIndex node) {
|
| + if (node.receiver.isNonPrimitive()) {
|
| + SourceString methodName = Elements.constructOperatorName(
|
| + const SourceString('operator'), const SourceString('[]'));
|
| + return fromInterceptorToDynamicInvocation(node, methodName);
|
| + }
|
| + return node;
|
| + }
|
| +
|
| + HInstruction visitIndexAssign(HIndexAssign node) {
|
| + if (node.receiver.isNonPrimitive()) {
|
| + SourceString methodName = Elements.constructOperatorName(
|
| + const SourceString('operator'), const SourceString('[]='));
|
| + return fromInterceptorToDynamicInvocation(node, methodName);
|
| + }
|
| + return node;
|
| + }
|
| +
|
| HInstruction visitInvokeBinary(HInvokeBinary node) {
|
| HInstruction left = node.left;
|
| HInstruction right = node.right;
|
| @@ -171,19 +228,49 @@
|
| Constant folded = operation.fold(op1.constant, op2.constant);
|
| if (folded !== null) return graph.addConstant(folded);
|
| }
|
| +
|
| + if (left.isNonPrimitive() && node.operation.isUserDefinable()) {
|
| + SourceString methodName = Elements.constructOperatorName(
|
| + const SourceString('operator'), node.operation.name);
|
| + return fromInterceptorToDynamicInvocation(node, methodName);
|
| + }
|
| return node;
|
| }
|
|
|
| HInstruction visitEquals(HEquals node) {
|
| HInstruction left = node.left;
|
| HInstruction right = node.right;
|
| - if (!left.isConstant() && right.isConstantNull()) {
|
| - // TODO(floitsch): cache interceptors.
|
| - HStatic target = new HStatic(
|
| - compiler.builder.interceptors.getEqualsNullInterceptor());
|
| - node.block.addBefore(node,target);
|
| - return new HEquals(target, node.left, node.right);
|
| +
|
| + if (left.isConstant() && right.isConstant()) {
|
| + return visitInvokeBinary(node);
|
| }
|
| +
|
| + if (right.isConstantNull()) {
|
| + if (left.propagatedType.isUseful()) {
|
| + return graph.addConstantBool(false);
|
| + } else {
|
| + // TODO(floitsch): cache interceptors.
|
| + HStatic target = new HStatic(
|
| + compiler.builder.interceptors.getEqualsNullInterceptor());
|
| + node.block.addBefore(node,target);
|
| + return new HEquals(target, node.left, node.right);
|
| + }
|
| + }
|
| +
|
| + if (left.isNonPrimitive()) {
|
| + // If the left-hand side is guaranteed to be a non-primitive
|
| + // type and and it does not define operator==, we can just emit
|
| + // an identity check.
|
| + HNonPrimitiveType type = left.propagatedType;
|
| + Element element = type.lookupMember(Namer.OPERATOR_EQUALS);
|
| + if (element === null) {
|
| + // TODO(floitsch): cache interceptors.
|
| + HStatic target = new HStatic(
|
| + compiler.builder.interceptors.getTripleEqualsInterceptor());
|
| + return new HIdentity(target, left, right);
|
| + }
|
| + }
|
| +
|
| // All other cases are dealt with by the [visitInvokeBinary].
|
| return visitInvokeBinary(node);
|
| }
|
|
|