summaryrefslogblamecommitdiff
path: root/sources/scala/tools/nsc/backend/ScalaPrimitives.scala
blob: e53014c514739bc3f548b0e78186d3e604fa9a0a (plain) (tree)
1
2
3
4
5
6
7
8
9




                            
       


                                
































































































































































































                                                                                      
                    



                               
                             










                                                   

                                





































                                                         
                            






















                                                      
                             






















                                                       
                            






















                                                      
                           






















                                                     
                            






















                                                      
                            















                                                       






























                                                                                      



















                                                                             



                                







                                                            
 

















































































                                                                        


















































                                                                                 




                                                    

















                                                                  












                                                                          
                          

















                                                  
                                                         













                                                          
                                                     













                                                          
                                                         









                                                          
/* NSC -- new scala compiler
 * Copyright 2005 LAMP/EPFL
 * @author  Martin Odersky
 */

// $Id$

package scala.tools.nsc.backend;

import scala.tools.nsc.backend.icode._;

import scala.collection.mutable.{Map, HashMap};

/**
 * Scala primitive operations are represented as methods in Any and
 * AnyVal subclasses. Here we demultiplex them by providing a mapping
 * from their symbols to integers. Different methods exist for
 * different value types, but with the same meaning (like plus, minus,
 * etc.). They will all be mapped to the same int.
 *
 * Note: The three equal methods have the following semantics:
 *       - "==" checks for null, and if non-null, calls java.lang.Object.equals
 *              (class: Any; modifier: final). Primitive: EQ
 *       - "eq" usual reference comparison
 *              (class: AnyRef; modifier: final). Primitive: ID
 *       - "equals" user-defined equality (Java semantics)
 *              (class: Object; modifier: none). Primitive: EQUALS
 *
 * Inspired from the scalac compiler.
 */
abstract class ScalaPrimitives {
  val global: Global;

  import global._;
  import definitions._;
  import global.icodes._;

  // Arithmetic unary operations
  final val POS = 1;                          // +x
  final val NEG = 2;                          // -x
  final val NOT = 3;                          // ~x

  // Arithmetic binary operations
  final val ADD = 10;                          // x + y
  final val SUB = 11;                          // x - y
  final val MUL = 12;                          // x * y
  final val DIV = 13;                          // x / y
  final val MOD = 14;                          // x % y

  // Bitwise operations
  final val OR  = 20;                          // x | y
  final val XOR = 21;                          // x ^ y
  final val AND = 22;                          // x & y

  // Shift operations
  final val LSL = 30;                          // x << y
  final val LSR = 31;                          // x >>> y
  final val ASR = 32;                          // x >> y

  // Comparison operations
  final val ID = 40;                           // x eq y
  final val NI = 41;                           // x ne y
  final val EQ = 42;                           // x == y
  final val NE = 43;                           // x != y
  final val LT = 44;                           // x < y
  final val LE = 45;                           // x <= y
  final val GE = 46;                           // x > y
  final val GT = 47;                           // x >= y

  // Boolean unary operations
  final val ZNOT = 50;                         // !x

  // Boolean binary operations
  final val ZOR = 60;                          // x || y
  final val ZAND = 61;                         // x && y

  // Array operations
  final val LENGTH = 70;                       // x.length
  final val APPLY  = 71;                       // x(y)
  final val UPDATE = 72;                       // x(y) = z

  // Any operations
  final val IS = 80;                           // x.is[y]
  final val AS = 81;                           // x.as[y]
  final val EQUALS = 82;                       // x.equals(y)
  final val HASHCODE = 83;                     // x.hashcode()
  final val TOSTRING = 84;                     // x.toString()
  final val ISERASED = 85;                     // x.is$erased[y]
  final val ASERASED = 86;                     // x.as$erased[y]

  // AnyRef operations
  final val SYNCHRONIZED = 90;                 // x.synchronized(y)

  // String operations
  final val CONCAT = 100;                       // String.valueOf(x)+String.valueOf(y)

  // coercions
  final val COERCE = 101;

  // RunTime operations
  final val BOX = 110;                          // RunTime.box_<X>(x)
  final val UNBOX = 111;                        // RunTime.unbox_<X>(x)
  final val NEW_ZARRAY = 112;                   // RunTime.zarray(x)
  final val NEW_BARRAY = 113;                   // RunTime.barray(x)
  final val NEW_SARRAY = 114;                   // RunTime.sarray(x)
  final val NEW_CARRAY = 115;                   // RunTime.carray(x)
  final val NEW_IARRAY = 116;                   // RunTime.iarray(x)
  final val NEW_LARRAY = 117;                   // RunTime.larray(x)
  final val NEW_FARRAY = 118;                   // RunTime.farray(x)
  final val NEW_DARRAY = 119;                   // RunTime.darray(x)
  final val NEW_OARRAY = 120;                   // RunTime.oarray(x)

  final val ZARRAY_LENGTH = 131;                // RunTime.zarray_length(x)
  final val BARRAY_LENGTH = 132;                // RunTime.barray_length(x)
  final val SARRAY_LENGTH = 133;                // RunTime.sarray_length(x)
  final val CARRAY_LENGTH = 134;                // RunTime.carray_length(x)
  final val IARRAY_LENGTH = 135;                // RunTime.iarray_length(x)
  final val LARRAY_LENGTH = 136;                // RunTime.larray_length(x)
  final val FARRAY_LENGTH = 137;                // RunTime.farray_length(x)
  final val DARRAY_LENGTH = 138;                // RunTime.darray_length(x)
  final val OARRAY_LENGTH = 139;                // RunTime.oarray_length(x)

  final val ZARRAY_GET = 140;                   // RunTime.zarray_get(x,y)
  final val BARRAY_GET = 141;                   // RunTime.barray_get(x,y)
  final val SARRAY_GET = 142;                   // RunTime.sarray_get(x,y)
  final val CARRAY_GET = 143;                   // RunTime.carray_get(x,y)
  final val IARRAY_GET = 144;                   // RunTime.iarray_get(x,y)
  final val LARRAY_GET = 145;                   // RunTime.larray_get(x,y)
  final val FARRAY_GET = 146;                   // RunTime.farray_get(x,y)
  final val DARRAY_GET = 147;                   // RunTime.darray_get(x,y)
  final val OARRAY_GET = 148;                   // RunTime.oarray_get(x,y)

  final val ZARRAY_SET = 150;                   // RunTime.zarray(x,y,z)
  final val BARRAY_SET = 151;                   // RunTime.barray(x,y,z)
  final val SARRAY_SET = 152;                   // RunTime.sarray(x,y,z)
  final val CARRAY_SET = 153;                   // RunTime.carray(x,y,z)
  final val IARRAY_SET = 154;                   // RunTime.iarray(x,y,z)
  final val LARRAY_SET = 155;                   // RunTime.larray(x,y,z)
  final val FARRAY_SET = 156;                   // RunTime.farray(x,y,z)
  final val DARRAY_SET = 157;                   // RunTime.darray(x,y,z)
  final val OARRAY_SET = 158;                   // RunTime.oarray(x,y,z)

  final val B2B = 200;                          // RunTime.b2b(x)
  final val B2S = 201;                          // RunTime.b2s(x)
  final val B2C = 202;                          // RunTime.b2c(x)
  final val B2I = 203;                          // RunTime.b2i(x)
  final val B2L = 204;                          // RunTime.b2l(x)
  final val B2F = 205;                          // RunTime.b2f(x)
  final val B2D = 206;                          // RunTime.b2d(x)

  final val S2B = 210;                          // RunTime.s2b(x)
  final val S2S = 211;                          // RunTime.s2s(x)
  final val S2C = 212;                          // RunTime.s2c(x)
  final val S2I = 213;                          // RunTime.s2i(x)
  final val S2L = 214;                          // RunTime.s2l(x)
  final val S2F = 215;                          // RunTime.s2f(x)
  final val S2D = 216;                          // RunTime.s2d(x)

  final val C2B = 220;                          // RunTime.c2b(x)
  final val C2S = 221;                          // RunTime.c2s(x)
  final val C2C = 222;                          // RunTime.c2c(x)
  final val C2I = 223;                          // RunTime.c2i(x)
  final val C2L = 224;                          // RunTime.c2l(x)
  final val C2F = 225;                          // RunTime.c2f(x)
  final val C2D = 226;                          // RunTime.c2d(x)

  final val I2B = 230;                          // RunTime.i2b(x)
  final val I2S = 231;                          // RunTime.i2s(x)
  final val I2C = 232;                          // RunTime.i2c(x)
  final val I2I = 233;                          // RunTime.i2i(x)
  final val I2L = 234;                          // RunTime.i2l(x)
  final val I2F = 235;                          // RunTime.i2f(x)
  final val I2D = 236;                          // RunTime.i2d(x)

  final val L2B = 240;                          // RunTime.l2b(x)
  final val L2S = 241;                          // RunTime.l2s(x)
  final val L2C = 242;                          // RunTime.l2c(x)
  final val L2I = 243;                          // RunTime.l2i(x)
  final val L2L = 244;                          // RunTime.l2l(x)
  final val L2F = 245;                          // RunTime.l2f(x)
  final val L2D = 246;                          // RunTime.l2d(x)

  final val F2B = 250;                          // RunTime.f2b(x)
  final val F2S = 251;                          // RunTime.f2s(x)
  final val F2C = 252;                          // RunTime.f2c(x)
  final val F2I = 253;                          // RunTime.f2i(x)
  final val F2L = 254;                          // RunTime.f2l(x)
  final val F2F = 255;                          // RunTime.f2f(x)
  final val F2D = 256;                          // RunTime.f2d(x)

  final val D2B = 260;                          // RunTime.d2b(x)
  final val D2S = 261;                          // RunTime.d2s(x)
  final val D2C = 262;                          // RunTime.d2c(x)
  final val D2I = 263;                          // RunTime.d2i(x)
  final val D2L = 264;                          // RunTime.d2l(x)
  final val D2F = 265;                          // RunTime.d2f(x)
  final val D2D = 266;                          // RunTime.d2d(x)


  private var primitives: Map[Symbol, Int] = _;

  /** Initialize the primitive map */
  def init: Unit = {
    primitives = new HashMap();

    // scala.Any
    addPrimitive(Any_==, EQ);
    addPrimitive(Any_!=, NE);
    addPrimitive(Any_equals, EQUALS);
    addPrimitive(Any_hashCode, HASHCODE);
    addPrimitive(Any_toString, TOSTRING);
    addPrimitive(Any_isInstanceOf, IS);
    addPrimitive(Any_asInstanceOf, AS);
    addPrimitive(Any_isInstanceOfErased, ISERASED);
    addPrimitive(Any_asInstanceOfErased, ASERASED);

    // java.lang.Object
    addPrimitive(Object_eq, ID);
    addPrimitive(Object_ne, NI);
    addPrimitive(Object_==, EQ);
    addPrimitive(Object_!=, NE);
    addPrimitive(Object_synchronized, SYNCHRONIZED);
    addPrimitive(Object_isInstanceOf, IS);
    addPrimitive(Object_asInstanceOf, AS);
    addPrimitive(Object_equals, EQUALS);
    addPrimitive(Object_hashCode, HASHCODE);
    addPrimitive(Object_toString, TOSTRING);

    // java.lang.String
    addPrimitive(String_+, CONCAT);

    // scala.Array
    addPrimitives(ArrayClass, nme.length, LENGTH);
    addPrimitives(ArrayClass, nme.apply, APPLY);
    addPrimitives(ArrayClass, nme.update, UPDATE);

    // scala.Unit
    addPrimitives(UnitClass, nme.EQ, EQ);
    addPrimitives(UnitClass, nme.NE, NE);
    addPrimitives(UnitClass, nme.equals_, EQUALS);
    addPrimitives(UnitClass, nme.hashCode_, HASHCODE);
    addPrimitives(UnitClass, nme.toString_, TOSTRING);
    // what about Unit.value()?

    // scala.Boolean
    addPrimitives(BooleanClass, nme.EQ, EQ);
    addPrimitives(BooleanClass, nme.NE, NE);
    addPrimitives(BooleanClass, nme.equals_, EQUALS);
    addPrimitives(BooleanClass, nme.hashCode_, HASHCODE);
    addPrimitives(BooleanClass, nme.toString_, TOSTRING);
    addPrimitive(Boolean_not, ZNOT);
    addPrimitive(Boolean_or, ZOR);
    addPrimitive(Boolean_and, ZAND);
    addPrimitives(BooleanClass, nme.OR, OR);
    addPrimitives(BooleanClass, nme.AND, AND);
    addPrimitives(BooleanClass, nme.XOR, XOR);
    addPrimitives(BooleanClass, nme.ADD, CONCAT);

    // scala.Byte
    addCoercions(ByteClass);
    addPrimitives(ByteClass, nme.EQ, EQ);
    addPrimitives(ByteClass, nme.NE, NE);
    addPrimitives(ByteClass, nme.equals_, EQUALS);
    addPrimitives(ByteClass, nme.hashCode_, HASHCODE);
    addPrimitives(ByteClass, nme.toString_, TOSTRING);
    addPrimitives(ByteClass, nme.NOT, NOT);
    addPrimitives(ByteClass, nme.ADD, ADD);
    addPrimitives(ByteClass, nme.SUB, SUB);
    addPrimitives(ByteClass, nme.MUL, MUL);
    addPrimitives(ByteClass, nme.DIV, DIV);
    addPrimitives(ByteClass, nme.MOD, MOD);
    addPrimitives(ByteClass, nme.LT, LT);
    addPrimitives(ByteClass, nme.LE, LE);
    addPrimitives(ByteClass, nme.GT, GT);
    addPrimitives(ByteClass, nme.GE, GE);
    addPrimitives(ByteClass, nme.XOR, XOR);
    addPrimitives(ByteClass, nme.OR, OR);
    addPrimitives(ByteClass, nme.AND, AND);
    addPrimitives(ByteClass, nme.LSL, LSL);
    addPrimitives(ByteClass, nme.LSR, LSR);
    addPrimitives(ByteClass, nme.ASR, ASR);

    // scala.Short
    addCoercions(ShortClass);
    addPrimitives(ShortClass, nme.EQ, EQ);
    addPrimitives(ShortClass, nme.NE, NE);
    addPrimitives(ShortClass, nme.equals_, EQUALS);
    addPrimitives(ShortClass, nme.hashCode_, HASHCODE);
    addPrimitives(ShortClass, nme.toString_, TOSTRING);
    addPrimitives(ShortClass, nme.NOT, NOT);
    addPrimitives(ShortClass, nme.ADD, ADD);
    addPrimitives(ShortClass, nme.SUB, SUB);
    addPrimitives(ShortClass, nme.MUL, MUL);
    addPrimitives(ShortClass, nme.DIV, DIV);
    addPrimitives(ShortClass, nme.MOD, MOD);
    addPrimitives(ShortClass, nme.LT, LT);
    addPrimitives(ShortClass, nme.LE, LE);
    addPrimitives(ShortClass, nme.GT, GT);
    addPrimitives(ShortClass, nme.GE, GE);
    addPrimitives(ShortClass, nme.XOR, XOR);
    addPrimitives(ShortClass, nme.OR, OR);
    addPrimitives(ShortClass, nme.AND, AND);
    addPrimitives(ShortClass, nme.LSL, LSL);
    addPrimitives(ShortClass, nme.LSR, LSR);
    addPrimitives(ShortClass, nme.ASR, ASR);

    // scala.Char
    addCoercions(CharClass);
    addPrimitives(CharClass, nme.EQ, EQ);
    addPrimitives(CharClass, nme.NE, NE);
    addPrimitives(CharClass, nme.equals_, EQUALS);
    addPrimitives(CharClass, nme.hashCode_, HASHCODE);
    addPrimitives(CharClass, nme.toString_, TOSTRING);
    addPrimitives(CharClass, nme.NOT, NOT);
    addPrimitives(CharClass, nme.ADD, ADD);
    addPrimitives(CharClass, nme.SUB, SUB);
    addPrimitives(CharClass, nme.MUL, MUL);
    addPrimitives(CharClass, nme.DIV, DIV);
    addPrimitives(CharClass, nme.MOD, MOD);
    addPrimitives(CharClass, nme.LT, LT);
    addPrimitives(CharClass, nme.LE, LE);
    addPrimitives(CharClass, nme.GT, GT);
    addPrimitives(CharClass, nme.GE, GE);
    addPrimitives(CharClass, nme.XOR, XOR);
    addPrimitives(CharClass, nme.OR, OR);
    addPrimitives(CharClass, nme.AND, AND);
    addPrimitives(CharClass, nme.LSL, LSL);
    addPrimitives(CharClass, nme.LSR, LSR);
    addPrimitives(CharClass, nme.ASR, ASR);

    // scala.Int
    addCoercions(IntClass);
    addPrimitives(IntClass, nme.EQ, EQ);
    addPrimitives(IntClass, nme.NE, NE);
    addPrimitives(IntClass, nme.equals_, EQUALS);
    addPrimitives(IntClass, nme.hashCode_, HASHCODE);
    addPrimitives(IntClass, nme.toString_, TOSTRING);
    addPrimitives(IntClass, nme.NOT, NOT);
    addPrimitives(IntClass, nme.ADD, ADD);
    addPrimitives(IntClass, nme.SUB, SUB);
    addPrimitives(IntClass, nme.MUL, MUL);
    addPrimitives(IntClass, nme.DIV, DIV);
    addPrimitives(IntClass, nme.MOD, MOD);
    addPrimitives(IntClass, nme.LT, LT);
    addPrimitives(IntClass, nme.LE, LE);
    addPrimitives(IntClass, nme.GT, GT);
    addPrimitives(IntClass, nme.GE, GE);
    addPrimitives(IntClass, nme.XOR, XOR);
    addPrimitives(IntClass, nme.OR, OR);
    addPrimitives(IntClass, nme.AND, AND);
    addPrimitives(IntClass, nme.LSL, LSL);
    addPrimitives(IntClass, nme.LSR, LSR);
    addPrimitives(IntClass, nme.ASR, ASR);

    // scala.Long
    addCoercions(LongClass);
    addPrimitives(LongClass, nme.EQ, EQ);
    addPrimitives(LongClass, nme.NE, NE);
    addPrimitives(LongClass, nme.equals_, EQUALS);
    addPrimitives(LongClass, nme.hashCode_, HASHCODE);
    addPrimitives(LongClass, nme.toString_, TOSTRING);
    addPrimitives(LongClass, nme.NOT, NOT);
    addPrimitives(LongClass, nme.ADD, ADD);
    addPrimitives(LongClass, nme.SUB, SUB);
    addPrimitives(LongClass, nme.MUL, MUL);
    addPrimitives(LongClass, nme.DIV, DIV);
    addPrimitives(LongClass, nme.MOD, MOD);
    addPrimitives(LongClass, nme.LT, LT);
    addPrimitives(LongClass, nme.LE, LE);
    addPrimitives(LongClass, nme.GT, GT);
    addPrimitives(LongClass, nme.GE, GE);
    addPrimitives(LongClass, nme.XOR, XOR);
    addPrimitives(LongClass, nme.OR, OR);
    addPrimitives(LongClass, nme.AND, AND);
    addPrimitives(LongClass, nme.LSL, LSL);
    addPrimitives(LongClass, nme.LSR, LSR);
    addPrimitives(LongClass, nme.ASR, ASR);

    // scala.Float
    addCoercion(FloatClass);
    addPrimitives(FloatClass, nme.EQ, EQ);
    addPrimitives(FloatClass, nme.NE, NE);
    addPrimitives(FloatClass, nme.equals_, EQUALS);
    addPrimitives(FloatClass, nme.hashCode_, HASHCODE);
    addPrimitives(FloatClass, nme.toString_, TOSTRING);
    addPrimitives(FloatClass, nme.ADD, ADD);
    addPrimitives(FloatClass, nme.SUB, SUB);
    addPrimitives(FloatClass, nme.MUL, DIV);
    addPrimitives(FloatClass, nme.DIV, DIV);
    addPrimitives(FloatClass, nme.MOD, MOD);
    addPrimitives(FloatClass, nme.LT, LT);
    addPrimitives(FloatClass, nme.LE, LE);
    addPrimitives(FloatClass, nme.GT, GT);
    addPrimitives(FloatClass, nme.GE, GE);

    // scala.Double
    addPrimitives(DoubleClass, nme.EQ, EQ);
    addPrimitives(DoubleClass, nme.NE, NE);
    addPrimitives(DoubleClass, nme.equals_, EQUALS);
    addPrimitives(DoubleClass, nme.hashCode_, HASHCODE);
    addPrimitives(DoubleClass, nme.toString_, TOSTRING);
    addPrimitives(DoubleClass, nme.ADD, ADD);
    addPrimitives(DoubleClass, nme.SUB, SUB);
    addPrimitives(DoubleClass, nme.MUL, DIV);
    addPrimitives(DoubleClass, nme.DIV, DIV);
    addPrimitives(DoubleClass, nme.MOD, MOD);
    addPrimitives(DoubleClass, nme.LT, LT);
    addPrimitives(DoubleClass, nme.LE, LE);
    addPrimitives(DoubleClass, nme.GT, GT);
    addPrimitives(DoubleClass, nme.GE, GE);

    // and the type map!
    initPrimitiveTypeMap;
  }

  /** Add a primitive operation to the map */
  def addPrimitive(s: Symbol, code: Int): Unit = {
    assert(!(primitives contains s), "Duplicate primitive " + s);
    primitives += s -> code;
  }

  def addPrimitives(cls: Symbol, method: Name, code: Int): Unit = {
    val tpe = cls.info;
    val sym = tpe.member(method);
    sym.info match {
      case OverloadedType(pre, alternatives) =>
        log("Adding " + alternatives.length + " overloads for " + sym.fullNameString);
        code match {
          case SUB =>
            alternatives foreach ((s) =>
              if (s.info.paramTypes.length == 0)
                addPrimitive(s, NEG); // unary
              else
                addPrimitive(s, code));

          case ADD =>
            alternatives foreach ((s) =>
              if (s.info.paramTypes.length == 0)
                addPrimitive(s, POS);    // unary
              else if (s.info.paramTypes.head == definitions.StringClass.tpe)
                addPrimitive(s, CONCAT); // string concatenation
              else
                addPrimitive(s, code));

          case _ =>
            alternatives foreach ((s) => addPrimitive(s, code));
        }

      case _ =>
        addPrimitive(sym, code);
    }
  }

  def addCoercion(cls: Symbol) = {
    assert(cls == FloatClass,
           "Only scala.Double has non-overloaded 'coerce'");
    val method = cls.info.member(nme.coerce);
    addPrimitive(method, F2D);
  }

  def addCoercions(cls: Symbol): Unit = {
    val OverloadedType(_, coercions) = cls.info.member(nme.coerce).info;
    if (cls == ByteClass)
      coercions foreach ((m) =>
        if (m.info.resultType == ShortClass.tpe)
          addPrimitive(m, B2S)
        else if (m.info.resultType == IntClass.tpe)
          addPrimitive(m, B2I)
        else if (m.info.resultType == LongClass.tpe)
          addPrimitive(m, B2L)
        else if (m.info.resultType == FloatClass.tpe)
          addPrimitive(m, B2F)
        else if (m.info.resultType == DoubleClass.tpe)
          addPrimitive(m, B2D)
        else
          abort("Unknown coercion method: " + m.info)
      )
    else if (cls == ShortClass)
        coercions foreach ((m) =>
          if (m.info.resultType == IntClass.tpe)
            addPrimitive(m, S2I)
          else if (m.info.resultType == LongClass.tpe)
            addPrimitive(m, S2L)
          else if (m.info.resultType == FloatClass.tpe)
            addPrimitive(m, S2F)
          else if (m.info.resultType == DoubleClass.tpe)
            addPrimitive(m, S2D)
          else
            abort("Unknown coercion method: " + m.fullNameString)
        )
    else if (cls == CharClass)
        coercions foreach ((m) =>
          if (m.info.resultType == IntClass.tpe)
            addPrimitive(m, C2I)
          else if (m.info.resultType == LongClass.tpe)
            addPrimitive(m, C2L)
          else if (m.info.resultType == FloatClass.tpe)
            addPrimitive(m, C2F)
          else if (m.info.resultType == DoubleClass.tpe)
            addPrimitive(m, C2D)
          else
            abort("Unknown coercion method: " + m.fullNameString)
        )
    else if (cls == IntClass)
        coercions foreach ((m) =>
          if (m.info.resultType == LongClass.tpe)
            addPrimitive(m, I2L)
          else if (m.info.resultType == FloatClass.tpe)
            addPrimitive(m, I2F)
          else if (m.info.resultType == DoubleClass.tpe)
            addPrimitive(m, I2D)
          else
            abort("Unknown coercion method: " + m.fullNameString)
        )
    else if (cls == LongClass)
        coercions foreach ((m) =>
          if (m.info.resultType == FloatClass.tpe)
            addPrimitive(m, L2F)
          else if (m.info.resultType == DoubleClass.tpe)
            addPrimitive(m, L2D)
          else
            abort("Unknown coercion method: " + m.fullNameString)
        )
    else if (cls == FloatClass)
        coercions foreach ((m) =>
          if (m.info.resultType == DoubleClass.tpe)
            addPrimitive(m, F2D)
          else
            abort("Unknown coercion method: " + m.fullNameString)
        )
    else
        abort("Unknown value type: " + cls.fullNameString);
  }

  def isCoercion(code: Int): Boolean = code match {
    case B2S | B2I | B2L | B2F | B2D |
               S2I | S2L | S2F | S2D |
               C2I | C2L | C2F | C2D |
                     I2L | I2F | I2D |
                           L2F | L2D |
                                 F2D   => true;
    case _ => false;
  }

  /** Check whether the given operation code is an array operation. */
  def isArrayOp(code: Int): Boolean =
    isArrayNew(code) | isArrayLength(code) | isArrayGet(code) | isArraySet(code);

  def isArrayNew(code: Int): Boolean = code match {
    case NEW_ZARRAY | NEW_BARRAY | NEW_SARRAY | NEW_CARRAY |
         NEW_IARRAY | NEW_LARRAY | NEW_FARRAY | NEW_DARRAY |
         NEW_OARRAY => true;
    case _ => false;
  }

  def isArrayLength(code: Int): Boolean = code match {
    case ZARRAY_LENGTH | BARRAY_LENGTH | SARRAY_LENGTH | CARRAY_LENGTH |
         IARRAY_LENGTH | LARRAY_LENGTH | FARRAY_LENGTH | DARRAY_LENGTH |
         OARRAY_LENGTH | LENGTH => true;
    case _ => false;
  }

  def isArrayGet(code: Int): Boolean = code match {
    case ZARRAY_GET | BARRAY_GET | SARRAY_GET | CARRAY_GET |
         IARRAY_GET | LARRAY_GET | FARRAY_GET | DARRAY_GET |
         OARRAY_GET | APPLY => true;
    case _ => false;
  }

  def isArraySet(code: Int): Boolean = code match {
    case ZARRAY_SET | BARRAY_SET | SARRAY_SET | CARRAY_SET |
         IARRAY_SET | LARRAY_SET | FARRAY_SET | DARRAY_SET |
         OARRAY_SET | UPDATE => true;
    case _ => false;
  }

  /** Check whether the given code is a comparison operator */
  def isComparisonOp(code: Int): Boolean = code match {
    case ID | NI | EQ | NE |
         LT | LE | GT | GE => true;

    case _ => false;
  }

  def isArithmeticOp(code: Int): Boolean = code match {
    case POS | NEG | NOT => true; // unary
    case ADD | SUB | MUL |
         DIV | MOD       => true; // binary
    case OR  | XOR | AND |
         LSL | LSR | ASR => true; // bitwise
    case _ => false;
  }

  def isLogicalOp(code: Int): Boolean = code match {
    case ZNOT | ZAND | ZOR => true;
    case _ => false;
  }

  def isShiftOp(code: Int): Boolean = code match {
    case LSL | LSR | ASR => true;
    case _ => false;
  }

  def isBitwiseOp(code: Int): Boolean = code match {
    case OR | XOR | AND => true;
    case _ => false;
  }

  def isPrimitive(sym: Symbol): Boolean = primitives contains sym;

  /** Return the code for the givem symbol. */
  def getPrimitive(sym: Symbol): Int = {
    assert(isPrimitive(sym), "Unkown primitive " + sym);
    primitives(sym);
  }

  /**
   * Return the primitive code of the given operation. If the
   * operation is an array get/set, we inspect the type of the receiver
   * to demux the operation.
   *
   * @param fun The method symbol
   * @param tpe The type of the receiver object. It is used only for array
   *            operations
   */
  def getPrimitive(fun: Symbol, tpe: Type): Int = {
    import definitions._;
    val code = getPrimitive(fun);

    var elem: Type = null;
    tpe match {
      case TypeRef(_, sym, _elem :: Nil)
           if (sym == ArrayClass) => elem = _elem;
      case _ => ();
    }

    code match {

      case APPLY =>
        toTypeKind(elem) match {
          case BOOL    => ZARRAY_GET;
          case BYTE    => BARRAY_GET;
          case SHORT   => SARRAY_GET;
          case CHAR    => CARRAY_GET;
          case INT     => IARRAY_GET;
          case LONG    => LARRAY_GET;
          case FLOAT   => FARRAY_GET;
          case DOUBLE  => DARRAY_GET;
          case REFERENCE(_) | ARRAY(_)     => OARRAY_GET;
          case _ =>
          abort("Unexpected array element type: " + elem);
        }

      case UPDATE =>
        toTypeKind(elem) match {
          case BOOL    => ZARRAY_SET;
          case BYTE    => BARRAY_SET;
          case SHORT   => SARRAY_SET;
          case CHAR    => CARRAY_SET;
          case INT     => IARRAY_SET;
          case LONG    => LARRAY_SET;
          case FLOAT   => FARRAY_SET;
          case DOUBLE  => DARRAY_SET;
          case REFERENCE(_) | ARRAY(_) => OARRAY_SET;
          case _ =>
          abort("Unexpected array element type: " + elem);
        }

      case LENGTH =>
        toTypeKind(elem) match {
          case BOOL    => ZARRAY_LENGTH;
          case BYTE    => BARRAY_LENGTH;
          case SHORT   => SARRAY_LENGTH;
          case CHAR    => CARRAY_LENGTH;
          case INT     => IARRAY_LENGTH;
          case LONG    => LARRAY_LENGTH;
          case FLOAT   => FARRAY_LENGTH;
          case DOUBLE  => DARRAY_LENGTH;
          case REFERENCE(_) | ARRAY(_)  => OARRAY_LENGTH;
          case _ =>
          abort("Unexpected array element type: " + elem);
        }

      case _ =>
      code;
    }
  }

}