// Copyright (c) 2018, 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. library vm.bytecode.recognized_methods; import 'package:kernel/ast.dart'; import 'package:kernel/type_environment.dart' show TypeEnvironment; import 'dbc.dart'; class RecognizedMethods { static const binaryIntOps = { '+': Opcode.kAddInt, '-': Opcode.kSubInt, '*': Opcode.kMulInt, '~/': Opcode.kTruncDivInt, '%': Opcode.kModInt, '&': Opcode.kBitAndInt, '|': Opcode.kBitOrInt, '^': Opcode.kBitXorInt, '<<': Opcode.kShlInt, '>>': Opcode.kShrInt, '==': Opcode.kCompareIntEq, '>': Opcode.kCompareIntGt, '<': Opcode.kCompareIntLt, '>=': Opcode.kCompareIntGe, '<=': Opcode.kCompareIntLe, }; final TypeEnvironment typeEnv; RecognizedMethods(this.typeEnv); DartType staticType(Expression expr) { // TODO(dartbug.com/34496): Remove this ugly try/catch once // getStaticType() is reliable. try { return expr.getStaticType(typeEnv); } catch (e) { return const DynamicType(); } } bool isInt(Expression expr) => staticType(expr) == typeEnv.intType; Opcode specializedBytecodeFor(MethodInvocation node) { final args = node.arguments; if (!args.named.isEmpty) { return null; } final Expression receiver = node.receiver; final String selector = node.name.name; switch (args.positional.length) { case 0: return specializedBytecodeForUnaryOp(selector, receiver); case 1: return specializedBytecodeForBinaryOp( selector, receiver, args.positional.single); default: return null; } } Opcode specializedBytecodeForUnaryOp(String selector, Expression arg) { if (selector == 'unary-' && isInt(arg)) { return Opcode.kNegateInt; } return null; } Opcode specializedBytecodeForBinaryOp( String selector, Expression a, Expression b) { if (selector == '==' && (a is NullLiteral || b is NullLiteral)) { return Opcode.kEqualsNull; } if (isInt(a) && isInt(b)) { return binaryIntOps[selector]; } return null; } }