| Index: sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
|
| ===================================================================
|
| --- sdk/lib/_internal/compiler/implementation/ssa/optimize.dart (revision 15190)
|
| +++ sdk/lib/_internal/compiler/implementation/ssa/optimize.dart (working copy)
|
| @@ -44,6 +44,7 @@
|
| new SsaRedundantPhiEliminator(),
|
| new SsaDeadPhiEliminator(),
|
| new SsaConstantFolder(constantSystem, backend, work, types),
|
| + new SsaTypePropagator(compiler, types),
|
| new SsaGlobalValueNumberer(compiler, types),
|
| new SsaCodeMotion(),
|
| new SsaValueRangeAnalyzer(constantSystem, types, work),
|
| @@ -204,50 +205,12 @@
|
| return node;
|
| }
|
|
|
| - HInstruction visitInvokeInterceptor(HInvokeInterceptor node) {
|
| - // Try to recognize the length interceptor with input [:new List(int):].
|
| - if (node.isLengthGetter() && node.inputs[1] is HInvokeStatic) {
|
| - HInvokeStatic call = node.inputs[1];
|
| - if (isFixedSizeListConstructor(call)) {
|
| - return call.inputs[1];
|
| - }
|
| - }
|
| + HInstruction handleInterceptorCall(HInvokeDynamic node) {
|
| HInstruction input = node.inputs[1];
|
| - if (node.isLengthGetter()) {
|
| - if (input.isConstantString()) {
|
| - HConstant constantInput = input;
|
| - StringConstant constant = constantInput.constant;
|
| - return graph.addConstantInt(constant.length, constantSystem);
|
| - } else if (input.isConstantList()) {
|
| - HConstant constantInput = input;
|
| - ListConstant constant = constantInput.constant;
|
| - return graph.addConstantInt(constant.length, constantSystem);
|
| - } else if (input.isConstantMap()) {
|
| - HConstant constantInput = input;
|
| - MapConstant constant = constantInput.constant;
|
| - return graph.addConstantInt(constant.length, constantSystem);
|
| - }
|
| - }
|
| -
|
| if (input.isString(types)
|
| && node.selector.name == const SourceString('toString')) {
|
| return node.inputs[1];
|
| }
|
| -
|
| - if (!input.canBePrimitive(types) && node.selector.isCall()) {
|
| - bool transformToDynamicInvocation = true;
|
| - if (input.canBeNull(types)) {
|
| - // Check if the method exists on Null. If yes we must not transform
|
| - // the static interceptor call to a dynamic invocation.
|
| - // TODO(floitsch): get a list of methods that exist on 'null' and only
|
| - // bail out on them.
|
| - transformToDynamicInvocation = false;
|
| - }
|
| - if (transformToDynamicInvocation) {
|
| - return fromInterceptorToDynamicInvocation(node, node.selector);
|
| - }
|
| - }
|
| -
|
| return node;
|
| }
|
|
|
| @@ -271,6 +234,7 @@
|
| }
|
|
|
| HInstruction visitInvokeDynamic(HInvokeDynamic node) {
|
| + if (node.isInterceptorCall) return handleInterceptorCall(node);
|
| HType receiverType = types[node.receiver];
|
| if (receiverType.isExact()) {
|
| HBoundedType type = receiverType;
|
| @@ -592,7 +556,59 @@
|
| return compiler.world.locateSingleField(type, selector);
|
| }
|
|
|
| + HInstruction visitFieldGet(HFieldGet node) {
|
| + if (node.element == backend.jsArrayLength) {
|
| + if (node.receiver is HInvokeStatic) {
|
| + // Try to recognize the length getter with input [:new List(int):].
|
| + HInvokeStatic call = node.receiver;
|
| + if (isFixedSizeListConstructor(call)) {
|
| + return call.inputs[1];
|
| + }
|
| + }
|
| + }
|
| + return node;
|
| + }
|
| +
|
| + HInstruction optimizeLengthInterceptedCall(HInvokeDynamicGetter node) {
|
| + HInstruction actualReceiver = node.inputs[1];
|
| + if (actualReceiver.isIndexablePrimitive(types)) {
|
| + if (actualReceiver.isConstantString()) {
|
| + HConstant constantInput = actualReceiver;
|
| + StringConstant constant = constantInput.constant;
|
| + return graph.addConstantInt(constant.length, constantSystem);
|
| + } else if (actualReceiver.isConstantList()) {
|
| + HConstant constantInput = actualReceiver;
|
| + ListConstant constant = constantInput.constant;
|
| + return graph.addConstantInt(constant.length, constantSystem);
|
| + }
|
| + Element element;
|
| + bool isAssignable;
|
| + if (actualReceiver.isString(types)) {
|
| + element = backend.jsStringLength;
|
| + isAssignable = false;
|
| + } else {
|
| + element = backend.jsArrayLength;
|
| + isAssignable = !actualReceiver.isFixedArray(types);
|
| + }
|
| + HFieldGet result = new HFieldGet(
|
| + element, actualReceiver, isAssignable: isAssignable);
|
| + result.guaranteedType = HType.INTEGER;
|
| + types[result] = HType.INTEGER;
|
| + return result;
|
| + } else if (actualReceiver.isConstantMap()) {
|
| + HConstant constantInput = actualReceiver;
|
| + MapConstant constant = constantInput.constant;
|
| + return graph.addConstantInt(constant.length, constantSystem);
|
| + }
|
| + return node;
|
| + }
|
| +
|
| HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
|
| + if (node.selector.name == const SourceString('length')
|
| + && node.isInterceptorCall) {
|
| + return optimizeLengthInterceptedCall(node);
|
| + }
|
| +
|
| Element field =
|
| findConcreteFieldForDynamicAccess(node.receiver, node.selector);
|
| if (field == null) return node;
|
| @@ -655,18 +671,13 @@
|
| final String name = "SsaCheckInserter";
|
| HGraph graph;
|
| Element lengthInterceptor;
|
| - Selector lengthSelector;
|
|
|
| SsaCheckInserter(JavaScriptBackend backend,
|
| this.work,
|
| this.types,
|
| this.boundsChecked)
|
| : constantSystem = backend.constantSystem {
|
| - SourceString lengthString = const SourceString('length');
|
| - lengthSelector =
|
| - new Selector.getter(lengthString, work.element.getLibrary());
|
| - lengthInterceptor =
|
| - backend.builder.interceptors.getStaticInterceptor(lengthSelector);
|
| + lengthInterceptor = backend.jsArrayLength;
|
| }
|
|
|
| void visitGraph(HGraph graph) {
|
| @@ -686,10 +697,10 @@
|
| HBoundsCheck insertBoundsCheck(HInstruction node,
|
| HInstruction receiver,
|
| HInstruction index) {
|
| - HStatic interceptor = new HStatic(lengthInterceptor);
|
| - node.block.addBefore(node, interceptor);
|
| - HInvokeInterceptor length = new HInvokeInterceptor(
|
| - lengthSelector, <HInstruction>[interceptor, receiver], true);
|
| + bool isAssignable = !receiver.isFixedArray(types);
|
| + HFieldGet length =
|
| + new HFieldGet(lengthInterceptor, receiver, isAssignable: isAssignable);
|
| + length.guaranteedType = HType.INTEGER;
|
| types[length] = HType.INTEGER;
|
| node.block.addBefore(node, length);
|
|
|
| @@ -732,13 +743,6 @@
|
| node.changeUse(node.index, index);
|
| assert(node.isBuiltin(types));
|
| }
|
| -
|
| - void visitInvokeInterceptor(HInvokeInterceptor node) {
|
| - if (!node.isPopCall(types)) return;
|
| - if (boundsChecked.contains(node)) return;
|
| - HInstruction receiver = node.inputs[1];
|
| - insertBoundsCheck(node, receiver, graph.addConstantInt(0, constantSystem));
|
| - }
|
| }
|
|
|
| class SsaDeadCodeEliminator extends HGraphVisitor implements OptimizationPhase {
|
|
|