| // 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(); |
| |
| TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, |
| Compiler compiler) { |
| Selector selector = instruction.selector; |
| TypeMask type = TypeMaskFactory.inferredTypeForSelector(selector, compiler); |
| instruction.sideEffects = compiler.world.getSideEffectsOfSelector(selector); |
| if (!instruction.sideEffects.hasSideEffects()) { |
| instruction.setUseGvn(); |
| } else { |
| instruction.clearUseGvn(); |
| } |
| return type; |
| } |
| |
| HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| Compiler compiler) { |
| return null; |
| } |
| |
| Operation operation(ConstantSystem constantSystem) => null; |
| |
| static InvokeDynamicSpecializer lookupSpecializer(Selector selector) { |
| if (selector.kind == SelectorKind.INDEX) { |
| return selector.name == '[]' |
| ? const IndexSpecializer() |
| : const IndexAssignSpecializer(); |
| } else if (selector.kind == SelectorKind.OPERATOR) { |
| if (selector.name == 'unary-') { |
| return const UnaryNegateSpecializer(); |
| } else if (selector.name == '~') { |
| return const BitNotSpecializer(); |
| } else if (selector.name == '+') { |
| return const AddSpecializer(); |
| } else if (selector.name == '-') { |
| return const SubtractSpecializer(); |
| } else if (selector.name == '*') { |
| return const MultiplySpecializer(); |
| } else if (selector.name == '/') { |
| return const DivideSpecializer(); |
| } else if (selector.name == '~/') { |
| return const TruncatingDivideSpecializer(); |
| } else if (selector.name == '%') { |
| return const ModuloSpecializer(); |
| } else if (selector.name == '>>') { |
| return const ShiftRightSpecializer(); |
| } else if (selector.name == '<<') { |
| return const ShiftLeftSpecializer(); |
| } else if (selector.name == '&') { |
| return const BitAndSpecializer(); |
| } else if (selector.name == '|') { |
| return const BitOrSpecializer(); |
| } else if (selector.name == '^') { |
| return const BitXorSpecializer(); |
| } else if (selector.name == '==') { |
| return const EqualsSpecializer(); |
| } else if (selector.name == '<') { |
| return const LessSpecializer(); |
| } else if (selector.name == '<=') { |
| return const LessEqualSpecializer(); |
| } else if (selector.name == '>') { |
| return const GreaterSpecializer(); |
| } else if (selector.name == '>=') { |
| return const GreaterEqualSpecializer(); |
| } |
| } |
| return const InvokeDynamicSpecializer(); |
| } |
| } |
| |
| class IndexAssignSpecializer extends InvokeDynamicSpecializer { |
| const IndexAssignSpecializer(); |
| |
| HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| Compiler compiler) { |
| if (instruction.inputs[1].isMutableIndexable(compiler)) { |
| if (!instruction.inputs[2].isInteger(compiler) |
| && compiler.enableTypeAssertions) { |
| // We want the right checked mode error. |
| return null; |
| } |
| return new HIndexAssign(instruction.inputs[1], |
| instruction.inputs[2], |
| instruction.inputs[3], |
| instruction.selector); |
| } |
| return null; |
| } |
| } |
| |
| class IndexSpecializer extends InvokeDynamicSpecializer { |
| const IndexSpecializer(); |
| |
| HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| Compiler compiler) { |
| if (!instruction.inputs[1].isIndexablePrimitive(compiler)) return null; |
| if (!instruction.inputs[2].isInteger(compiler) |
| && compiler.enableTypeAssertions) { |
| // We want the right checked mode error. |
| return null; |
| } |
| TypeMask receiverType = |
| instruction.getDartReceiver(compiler).instructionType; |
| Selector refined = new TypedSelector(receiverType, instruction.selector); |
| TypeMask type = TypeMaskFactory.inferredTypeForSelector(refined, compiler); |
| return new HIndex( |
| instruction.inputs[1], instruction.inputs[2], |
| instruction.selector, type); |
| } |
| } |
| |
| class BitNotSpecializer extends InvokeDynamicSpecializer { |
| const BitNotSpecializer(); |
| |
| UnaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.bitNot; |
| } |
| |
| TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, |
| Compiler compiler) { |
| // All bitwise operations on primitive types either produce an |
| // integer or throw an error. |
| JavaScriptBackend backend = compiler.backend; |
| if (instruction.inputs[1].isPrimitiveOrNull(compiler)) { |
| return backend.uint32Type; |
| } |
| return super.computeTypeFromInputTypes(instruction, compiler); |
| } |
| |
| HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| Compiler compiler) { |
| JavaScriptBackend backend = compiler.backend; |
| HInstruction input = instruction.inputs[1]; |
| if (input.isNumber(compiler)) { |
| return new HBitNot(input, instruction.selector, |
| computeTypeFromInputTypes(instruction, compiler)); |
| } |
| return null; |
| } |
| } |
| |
| class UnaryNegateSpecializer extends InvokeDynamicSpecializer { |
| const UnaryNegateSpecializer(); |
| |
| UnaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.negate; |
| } |
| |
| TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, |
| Compiler compiler) { |
| TypeMask operandType = instruction.inputs[1].instructionType; |
| if (instruction.inputs[1].isNumberOrNull(compiler)) return operandType; |
| return super.computeTypeFromInputTypes(instruction, compiler); |
| } |
| |
| HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| Compiler compiler) { |
| HInstruction input = instruction.inputs[1]; |
| if (input.isNumber(compiler)) { |
| return new HNegate(input, instruction.selector, input.instructionType); |
| } |
| return null; |
| } |
| } |
| |
| abstract class BinaryArithmeticSpecializer extends InvokeDynamicSpecializer { |
| const BinaryArithmeticSpecializer(); |
| |
| TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, |
| Compiler compiler) { |
| HInstruction left = instruction.inputs[1]; |
| HInstruction right = instruction.inputs[2]; |
| JavaScriptBackend backend = compiler.backend; |
| if (left.isIntegerOrNull(compiler) && right.isIntegerOrNull(compiler)) { |
| return backend.intType; |
| } |
| if (left.isNumberOrNull(compiler)) { |
| if (left.isDoubleOrNull(compiler) || right.isDoubleOrNull(compiler)) { |
| return backend.doubleType; |
| } |
| return backend.numType; |
| } |
| return super.computeTypeFromInputTypes(instruction, compiler); |
| } |
| |
| bool isBuiltin(HInvokeDynamic instruction, Compiler compiler) { |
| return instruction.inputs[1].isNumber(compiler) |
| && instruction.inputs[2].isNumber(compiler); |
| } |
| |
| HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| Compiler compiler) { |
| if (isBuiltin(instruction, compiler)) { |
| HInstruction builtin = newBuiltinVariant(instruction, compiler); |
| if (builtin != null) return builtin; |
| // Even if there is no builtin equivalent instruction, we know |
| // the instruction does not have any side effect, and that it |
| // can be GVN'ed. |
| clearAllSideEffects(instruction); |
| } |
| return null; |
| } |
| |
| void clearAllSideEffects(HInstruction instruction) { |
| instruction.sideEffects.clearAllSideEffects(); |
| instruction.sideEffects.clearAllDependencies(); |
| instruction.setUseGvn(); |
| } |
| |
| bool inputsArePositiveIntegers(HInstruction instruction, Compiler compiler) { |
| HInstruction left = instruction.inputs[1]; |
| HInstruction right = instruction.inputs[2]; |
| JavaScriptBackend backend = compiler.backend; |
| return left.isPositiveIntegerOrNull(compiler) |
| && right.isPositiveIntegerOrNull(compiler); |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, Compiler compiler); |
| |
| Selector renameToOptimizedSelector(String name, |
| Selector selector, |
| Compiler compiler) { |
| if (selector.name == name) return selector; |
| return new TypedSelector( |
| selector.mask, |
| new Selector(SelectorKind.CALL, |
| name, |
| compiler.interceptorsLibrary, |
| selector.argumentCount)); |
| } |
| } |
| |
| class AddSpecializer extends BinaryArithmeticSpecializer { |
| const AddSpecializer(); |
| |
| TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, |
| Compiler compiler) { |
| if (inputsArePositiveIntegers(instruction, compiler)) { |
| JavaScriptBackend backend = compiler.backend; |
| return backend.positiveIntType; |
| } |
| return super.computeTypeFromInputTypes(instruction, compiler); |
| } |
| |
| BinaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.add; |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, |
| Compiler compiler) { |
| return new HAdd( |
| instruction.inputs[1], instruction.inputs[2], |
| instruction.selector, computeTypeFromInputTypes(instruction, compiler)); |
| } |
| } |
| |
| class DivideSpecializer extends BinaryArithmeticSpecializer { |
| const DivideSpecializer(); |
| |
| BinaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.divide; |
| } |
| |
| TypeMask computeTypeFromInputTypes(HInstruction instruction, |
| Compiler compiler) { |
| HInstruction left = instruction.inputs[1]; |
| JavaScriptBackend backend = compiler.backend; |
| if (left.isNumberOrNull(compiler)) { |
| return backend.doubleType; |
| } |
| return super.computeTypeFromInputTypes(instruction, compiler); |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, |
| Compiler compiler) { |
| JavaScriptBackend backend = compiler.backend; |
| return new HDivide( |
| instruction.inputs[1], instruction.inputs[2], |
| instruction.selector, backend.doubleType); |
| } |
| } |
| |
| class ModuloSpecializer extends BinaryArithmeticSpecializer { |
| const ModuloSpecializer(); |
| |
| TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, |
| Compiler compiler) { |
| if (inputsArePositiveIntegers(instruction, compiler)) { |
| JavaScriptBackend backend = compiler.backend; |
| return backend.positiveIntType; |
| } |
| return super.computeTypeFromInputTypes(instruction, compiler); |
| } |
| |
| BinaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.modulo; |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, |
| Compiler compiler) { |
| // Modulo cannot be mapped to the native operator (different semantics). |
| return null; |
| } |
| } |
| |
| class MultiplySpecializer extends BinaryArithmeticSpecializer { |
| const MultiplySpecializer(); |
| |
| BinaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.multiply; |
| } |
| |
| TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, |
| Compiler compiler) { |
| if (inputsArePositiveIntegers(instruction, compiler)) { |
| JavaScriptBackend backend = compiler.backend; |
| return backend.positiveIntType; |
| } |
| return super.computeTypeFromInputTypes(instruction, compiler); |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, |
| Compiler compiler) { |
| return new HMultiply( |
| instruction.inputs[1], instruction.inputs[2], |
| instruction.selector, computeTypeFromInputTypes(instruction, compiler)); |
| } |
| } |
| |
| class SubtractSpecializer extends BinaryArithmeticSpecializer { |
| const SubtractSpecializer(); |
| |
| BinaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.subtract; |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, |
| Compiler compiler) { |
| return new HSubtract( |
| instruction.inputs[1], instruction.inputs[2], |
| instruction.selector, computeTypeFromInputTypes(instruction, compiler)); |
| } |
| } |
| |
| class TruncatingDivideSpecializer extends BinaryArithmeticSpecializer { |
| const TruncatingDivideSpecializer(); |
| |
| BinaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.truncatingDivide; |
| } |
| |
| TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, |
| Compiler compiler) { |
| if (inputsArePositiveIntegers(instruction, compiler)) { |
| JavaScriptBackend backend = compiler.backend; |
| return backend.positiveIntType; |
| } |
| return super.computeTypeFromInputTypes(instruction, compiler); |
| } |
| |
| bool isNotZero(HInstruction instruction, Compiler compiler) { |
| if (!instruction.isConstantInteger()) return false; |
| HConstant rightConstant = instruction; |
| IntConstant intConstant = rightConstant.constant; |
| int count = intConstant.value; |
| return count != 0; |
| } |
| |
| HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| Compiler compiler) { |
| HInstruction left = instruction.inputs[1]; |
| HInstruction right = instruction.inputs[2]; |
| if (isBuiltin(instruction, compiler)) { |
| if (right.isPositiveInteger(compiler) && isNotZero(right, compiler)) { |
| if (left.isUInt31(compiler)) { |
| return newBuiltinVariant(instruction, compiler); |
| } |
| // We can call _tdivFast because the rhs is a 32bit integer |
| // and not 0, nor -1. |
| instruction.selector = renameToOptimizedSelector( |
| '_tdivFast', instruction.selector, compiler); |
| } |
| clearAllSideEffects(instruction); |
| } |
| return null; |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, |
| Compiler compiler) { |
| return new HTruncatingDivide( |
| instruction.inputs[1], instruction.inputs[2], |
| instruction.selector, computeTypeFromInputTypes(instruction, compiler)); |
| } |
| } |
| |
| abstract class BinaryBitOpSpecializer extends BinaryArithmeticSpecializer { |
| const BinaryBitOpSpecializer(); |
| |
| TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, |
| Compiler compiler) { |
| // All bitwise operations on primitive types either produce an |
| // integer or throw an error. |
| HInstruction left = instruction.inputs[1]; |
| JavaScriptBackend backend = compiler.backend; |
| if (left.isPrimitiveOrNull(compiler)) { |
| return backend.uint32Type; |
| } |
| return super.computeTypeFromInputTypes(instruction, compiler); |
| } |
| |
| bool argumentLessThan32(HInstruction instruction) { |
| if (!instruction.isConstantInteger()) return false; |
| HConstant rightConstant = instruction; |
| IntConstant intConstant = rightConstant.constant; |
| int count = intConstant.value; |
| return count >= 0 && count <= 31; |
| } |
| |
| bool isPositive(HInstruction instruction, Compiler compiler) { |
| // TODO: We should use the value range analysis. Currently, ranges |
| // are discarded just after the analysis. |
| return instruction.isPositiveInteger(compiler); |
| } |
| } |
| |
| class ShiftLeftSpecializer extends BinaryBitOpSpecializer { |
| const ShiftLeftSpecializer(); |
| |
| BinaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.shiftLeft; |
| } |
| |
| HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| Compiler compiler) { |
| HInstruction left = instruction.inputs[1]; |
| HInstruction right = instruction.inputs[2]; |
| if (left.isNumber(compiler)) { |
| if (argumentLessThan32(right)) { |
| return newBuiltinVariant(instruction, compiler); |
| } |
| // Even if there is no builtin equivalent instruction, we know |
| // the instruction does not have any side effect, and that it |
| // can be GVN'ed. |
| clearAllSideEffects(instruction); |
| Selector selector = instruction.selector; |
| if (isPositive(right, compiler)) { |
| instruction.selector = renameToOptimizedSelector( |
| '_shlPositive', instruction.selector, compiler); |
| } |
| } |
| return null; |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, |
| Compiler compiler) { |
| JavaScriptBackend backend = compiler.backend; |
| return new HShiftLeft( |
| instruction.inputs[1], instruction.inputs[2], |
| instruction.selector, computeTypeFromInputTypes(instruction, compiler)); |
| } |
| } |
| |
| class ShiftRightSpecializer extends BinaryBitOpSpecializer { |
| const ShiftRightSpecializer(); |
| |
| TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, |
| Compiler compiler) { |
| HInstruction left = instruction.inputs[1]; |
| HInstruction right = instruction.inputs[2]; |
| JavaScriptBackend backend = compiler.backend; |
| if (left.isUInt32(compiler)) return left.instructionType; |
| return super.computeTypeFromInputTypes(instruction, compiler); |
| } |
| |
| HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| Compiler compiler) { |
| HInstruction left = instruction.inputs[1]; |
| HInstruction right = instruction.inputs[2]; |
| if (left.isNumber(compiler)) { |
| if (argumentLessThan32(right) && isPositive(left, compiler)) { |
| return newBuiltinVariant(instruction, compiler); |
| } |
| // Even if there is no builtin equivalent instruction, we know |
| // the instruction does not have any side effect, and that it |
| // can be GVN'ed. |
| clearAllSideEffects(instruction); |
| if (isPositive(right, compiler) && isPositive(left, compiler)) { |
| instruction.selector = renameToOptimizedSelector( |
| '_shrBothPositive', instruction.selector, compiler); |
| } else if (isPositive(left, compiler) && right.isNumber(compiler)) { |
| instruction.selector = renameToOptimizedSelector( |
| '_shrReceiverPositive', instruction.selector, compiler); |
| } else if (isPositive(right, compiler)) { |
| instruction.selector = renameToOptimizedSelector( |
| '_shrOtherPositive', instruction.selector, compiler); |
| } |
| } |
| return null; |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, |
| Compiler compiler) { |
| JavaScriptBackend backend = compiler.backend; |
| return new HShiftRight( |
| instruction.inputs[1], instruction.inputs[2], |
| instruction.selector, computeTypeFromInputTypes(instruction, compiler)); |
| } |
| |
| BinaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.shiftRight; |
| } |
| } |
| |
| class BitOrSpecializer extends BinaryBitOpSpecializer { |
| const BitOrSpecializer(); |
| |
| BinaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.bitOr; |
| } |
| |
| TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, |
| Compiler compiler) { |
| HInstruction left = instruction.inputs[1]; |
| HInstruction right = instruction.inputs[2]; |
| JavaScriptBackend backend = compiler.backend; |
| if (left.isUInt31(compiler) && right.isUInt31(compiler)) { |
| return backend.uint31Type; |
| } |
| return super.computeTypeFromInputTypes(instruction, compiler); |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, |
| Compiler compiler) { |
| JavaScriptBackend backend = compiler.backend; |
| return new HBitOr( |
| instruction.inputs[1], instruction.inputs[2], |
| instruction.selector, computeTypeFromInputTypes(instruction, compiler)); |
| } |
| } |
| |
| class BitAndSpecializer extends BinaryBitOpSpecializer { |
| const BitAndSpecializer(); |
| |
| BinaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.bitAnd; |
| } |
| |
| TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, |
| Compiler compiler) { |
| HInstruction left = instruction.inputs[1]; |
| HInstruction right = instruction.inputs[2]; |
| JavaScriptBackend backend = compiler.backend; |
| if (left.isUInt31(compiler) || right.isUInt31(compiler)) { |
| return backend.uint31Type; |
| } |
| return super.computeTypeFromInputTypes(instruction, compiler); |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, |
| Compiler compiler) { |
| JavaScriptBackend backend = compiler.backend; |
| return new HBitAnd( |
| instruction.inputs[1], instruction.inputs[2], |
| instruction.selector, computeTypeFromInputTypes(instruction, compiler)); |
| } |
| } |
| |
| class BitXorSpecializer extends BinaryBitOpSpecializer { |
| const BitXorSpecializer(); |
| |
| BinaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.bitXor; |
| } |
| |
| TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, |
| Compiler compiler) { |
| HInstruction left = instruction.inputs[1]; |
| HInstruction right = instruction.inputs[2]; |
| JavaScriptBackend backend = compiler.backend; |
| if (left.isUInt31(compiler) && right.isUInt31(compiler)) { |
| return backend.uint31Type; |
| } |
| return super.computeTypeFromInputTypes(instruction, compiler); |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, |
| Compiler compiler) { |
| JavaScriptBackend backend = compiler.backend; |
| return new HBitXor( |
| instruction.inputs[1], instruction.inputs[2], |
| instruction.selector, computeTypeFromInputTypes(instruction, compiler)); |
| } |
| } |
| |
| abstract class RelationalSpecializer extends InvokeDynamicSpecializer { |
| const RelationalSpecializer(); |
| |
| TypeMask computeTypeFromInputTypes(HInvokeDynamic instruction, |
| Compiler compiler) { |
| JavaScriptBackend backend = compiler.backend; |
| if (instruction.inputs[1].isPrimitiveOrNull(compiler)) { |
| return backend.boolType; |
| } |
| return super.computeTypeFromInputTypes(instruction, compiler); |
| } |
| |
| HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| Compiler compiler) { |
| HInstruction left = instruction.inputs[1]; |
| HInstruction right = instruction.inputs[2]; |
| if (left.isNumber(compiler) && right.isNumber(compiler)) { |
| return newBuiltinVariant(instruction, compiler); |
| } |
| return null; |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, Compiler compiler); |
| } |
| |
| class EqualsSpecializer extends RelationalSpecializer { |
| const EqualsSpecializer(); |
| |
| HInstruction tryConvertToBuiltin(HInvokeDynamic instruction, |
| Compiler compiler) { |
| HInstruction left = instruction.inputs[1]; |
| HInstruction right = instruction.inputs[2]; |
| TypeMask instructionType = left.instructionType; |
| if (right.isConstantNull() || left.isPrimitiveOrNull(compiler)) { |
| return newBuiltinVariant(instruction, compiler); |
| } |
| Selector selector = |
| new TypedSelector(instructionType, instruction.selector); |
| World world = compiler.world; |
| JavaScriptBackend backend = compiler.backend; |
| Iterable<Element> matches = world.allFunctions.filter(selector); |
| // This test relies the on `Object.==` and `Interceptor.==` always being |
| // implemented because if the selector matches by subtype, it still will be |
| // a regular object or an interceptor. |
| if (matches.every(backend.isDefaultEqualityImplementation)) { |
| return newBuiltinVariant(instruction, compiler); |
| } |
| return null; |
| } |
| |
| BinaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.equal; |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, |
| Compiler compiler) { |
| JavaScriptBackend backend = compiler.backend; |
| return new HIdentity( |
| instruction.inputs[1], instruction.inputs[2], |
| instruction.selector, backend.boolType); |
| } |
| } |
| |
| class LessSpecializer extends RelationalSpecializer { |
| const LessSpecializer(); |
| |
| BinaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.less; |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, |
| Compiler compiler) { |
| JavaScriptBackend backend = compiler.backend; |
| return new HLess( |
| instruction.inputs[1], instruction.inputs[2], |
| instruction.selector, backend.boolType); |
| } |
| } |
| |
| class GreaterSpecializer extends RelationalSpecializer { |
| const GreaterSpecializer(); |
| |
| BinaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.greater; |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, |
| Compiler compiler) { |
| JavaScriptBackend backend = compiler.backend; |
| return new HGreater( |
| instruction.inputs[1], instruction.inputs[2], |
| instruction.selector, backend.boolType); |
| } |
| } |
| |
| class GreaterEqualSpecializer extends RelationalSpecializer { |
| const GreaterEqualSpecializer(); |
| |
| BinaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.greaterEqual; |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, |
| Compiler compiler) { |
| JavaScriptBackend backend = compiler.backend; |
| return new HGreaterEqual( |
| instruction.inputs[1], instruction.inputs[2], |
| instruction.selector, backend.boolType); |
| } |
| } |
| |
| class LessEqualSpecializer extends RelationalSpecializer { |
| const LessEqualSpecializer(); |
| |
| BinaryOperation operation(ConstantSystem constantSystem) { |
| return constantSystem.lessEqual; |
| } |
| |
| HInstruction newBuiltinVariant(HInvokeDynamic instruction, |
| Compiler compiler) { |
| JavaScriptBackend backend = compiler.backend; |
| return new HLessEqual( |
| instruction.inputs[1], instruction.inputs[2], |
| instruction.selector, backend.boolType); |
| } |
| } |