Index: sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart |
=================================================================== |
--- sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart (revision 0) |
+++ sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart (revision 0) |
@@ -0,0 +1,173 @@ |
+// Copyright (c) 2013, 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. |
+ |
+part of ssa; |
+ |
+/** |
+ * [InvokeDynamicSpecializer] and its subclasses are helpers to |
+ * optimize intercepted dynamic calls. It knows what input types |
+ * would be beneficial for performance, and how to change a invoke |
+ * dynamic to a builtin instruction (e.g. HIndex, HBitNot). |
+ */ |
+class InvokeDynamicSpecializer { |
+ const InvokeDynamicSpecializer(); |
+ |
+ HType computeDesiredTypeForInput(HInvokeDynamicMethod instruction, |
+ HInstruction input, |
+ HTypeMap types, |
+ Compiler compiler) { |
+ return HType.UNKNOWN; |
+ } |
+ |
+ HType computeTypeFromInputTypes(HInvokeDynamicMethod instruction, |
+ HTypeMap types, |
+ Compiler compiler) { |
+ return HType.UNKNOWN; |
+ } |
+ |
+ HInstruction tryConvertToBuiltin(HInvokeDynamicMethod instruction, |
+ HTypeMap types) { |
+ return null; |
+ } |
+ |
+ static InvokeDynamicSpecializer lookupSpecializer(Selector selector) { |
+ if (selector.kind == SelectorKind.INDEX) { |
+ return selector.name == const SourceString('[]') |
+ ? const IndexSpecializer() |
+ : const IndexAssignSpecializer(); |
+ } else if (selector.kind == SelectorKind.OPERATOR) { |
+ if (selector.name == const SourceString('unary-')) { |
+ return const UnaryNegateSpecializer(); |
+ } else if (selector.name == const SourceString('~')) { |
+ return const BitNotSpecializer(); |
+ } |
+ } |
+ return const InvokeDynamicSpecializer(); |
+ } |
+} |
+ |
+class IndexAssignSpecializer extends InvokeDynamicSpecializer { |
+ const IndexAssignSpecializer(); |
+ |
+ HType computeDesiredTypeForInput(HInvokeDynamicMethod instruction, |
+ HInstruction input, |
+ HTypeMap types, |
+ Compiler compiler) { |
+ HInstruction index = instruction.inputs[2]; |
+ if (input == instruction.inputs[1] && |
+ (index.isTypeUnknown(types) || index.isNumber(types))) { |
+ return HType.MUTABLE_ARRAY; |
+ } |
+ // The index should be an int when the receiver is a string or array. |
+ // However it turns out that inserting an integer check in the optimized |
+ // version is cheaper than having another bailout case. This is true, |
+ // because the integer check will simply throw if it fails. |
+ return HType.UNKNOWN; |
+ } |
+ |
+ HInstruction tryConvertToBuiltin(HInvokeDynamicMethod instruction, |
+ HTypeMap types) { |
+ if (instruction.inputs[1].isMutableArray(types)) { |
+ return new HIndexAssign(instruction.inputs[1], |
+ instruction.inputs[2], |
+ instruction.inputs[3]); |
+ } |
+ return null; |
+ } |
+} |
+ |
+class IndexSpecializer extends InvokeDynamicSpecializer { |
+ const IndexSpecializer(); |
+ |
+ HType computeDesiredTypeForInput(HInvokeDynamicMethod instruction, |
+ HInstruction input, |
+ HTypeMap types, |
+ Compiler compiler) { |
+ HInstruction index = instruction.inputs[2]; |
+ if (input == instruction.inputs[1] && |
+ (index.isTypeUnknown(types) || index.isNumber(types))) { |
+ return HType.INDEXABLE_PRIMITIVE; |
+ } |
+ // The index should be an int when the receiver is a string or array. |
+ // However it turns out that inserting an integer check in the optimized |
+ // version is cheaper than having another bailout case. This is true, |
+ // because the integer check will simply throw if it fails. |
+ return HType.UNKNOWN; |
+ } |
+ |
+ HInstruction tryConvertToBuiltin(HInvokeDynamicMethod instruction, |
+ HTypeMap types) { |
+ if (instruction.inputs[1].isIndexablePrimitive(types)) { |
+ return new HIndex(instruction.inputs[1], instruction.inputs[2]); |
+ } |
+ return null; |
+ } |
+} |
+ |
+class BitNotSpecializer extends InvokeDynamicSpecializer { |
+ const BitNotSpecializer(); |
+ |
+ HType computeDesiredTypeForInput(HInvokeDynamicMethod instruction, |
+ HInstruction input, |
+ HTypeMap types, |
+ Compiler compiler) { |
+ if (input == instruction.inputs[1]) { |
+ HType propagatedType = types[instruction]; |
+ if (propagatedType.isUnknown() || propagatedType.isNumber()) { |
+ return HType.INTEGER; |
+ } |
+ } |
+ return HType.UNKNOWN; |
+ } |
+ |
+ HType computeTypeFromInputTypes(HInvokeDynamicMethod instruction, |
+ HTypeMap types, |
+ Compiler compiler) { |
+ // All bitwise operations on primitive types either produce an |
+ // integer or throw an error. |
+ if (instruction.inputs[1].isPrimitive(types)) return HType.INTEGER; |
+ return HType.UNKNOWN; |
+ } |
+ |
+ HInstruction tryConvertToBuiltin(HInvokeDynamicMethod instruction, |
+ HTypeMap types) { |
+ HInstruction input = instruction.inputs[1]; |
+ if (input.isNumber(types)) return new HBitNot(input); |
+ return null; |
+ } |
+} |
+ |
+class UnaryNegateSpecializer extends InvokeDynamicSpecializer { |
+ const UnaryNegateSpecializer(); |
+ |
+ HType computeDesiredTypeForInput(HInvokeDynamicMethod instruction, |
+ HInstruction input, |
+ HTypeMap types, |
+ Compiler compiler) { |
+ if (input == instruction.inputs[1]) { |
+ HType propagatedType = types[instruction]; |
+ // If the outgoing type should be a number (integer, double or both) we |
+ // want the outgoing type to be the input too. |
+ // If we don't know the outgoing type we try to make it a number. |
+ if (propagatedType.isNumber()) return propagatedType; |
+ if (propagatedType.isUnknown()) return HType.NUMBER; |
+ } |
+ return HType.UNKNOWN; |
+ } |
+ |
+ HType computeTypeFromInputTypes(HInvokeDynamicMethod instruction, |
+ HTypeMap types, |
+ Compiler compiler) { |
+ HType operandType = types[instruction.inputs[1]]; |
+ if (operandType.isNumber()) return operandType; |
+ return HType.UNKNOWN; |
+ } |
+ |
+ HInstruction tryConvertToBuiltin(HInvokeDynamicMethod instruction, |
+ HTypeMap types) { |
+ HInstruction input = instruction.inputs[1]; |
+ if (input.isNumber(types)) return new HNegate(input); |
+ return null; |
+ } |
+} |