Home | History | Annotate | Download | only in vm
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*
     18  * Inlined native functions.  These definitions replace interpreted or
     19  * native implementations at runtime; "intrinsic" might be a better word.
     20  */
     21 #include "Dalvik.h"
     22 
     23 #include <math.h>
     24 
     25 #ifdef HAVE__MEMCMP16
     26 /* hand-coded assembly implementation, available on some platforms */
     27 //#warning "trying memcmp16"
     28 //#define CHECK_MEMCMP16
     29 /* "count" is in 16-bit units */
     30 extern "C" u4 __memcmp16(const u2* s0, const u2* s1, size_t count);
     31 #endif
     32 
     33 /*
     34  * Some notes on "inline" functions.
     35  *
     36  * These are NOT simply native implementations.  A full method definition
     37  * must still be provided.  Depending on the flags passed into the VM
     38  * at runtime, the original or inline version may be selected by the
     39  * DEX optimizer.
     40  *
     41  * PLEASE DO NOT use this as the default location for native methods.
     42  * The difference between this and an "internal native" static method
     43  * call on a 200MHz ARM 9 is roughly 370ns vs. 700ns.  The code here
     44  * "secretly replaces" the other method, so you can't avoid having two
     45  * implementations.  Since the DEX optimizer mode can't be known ahead
     46  * of time, both implementations must be correct and complete.
     47  *
     48  * The only stuff that really needs to be here are methods that
     49  * are high-volume or must be low-overhead, e.g. certain String/Math
     50  * methods and some java.util.concurrent.atomic operations.
     51  *
     52  * Normally, a class is loaded and initialized the first time a static
     53  * method is invoked.  This property is NOT preserved here.  If you need
     54  * to access a static field in a class, you must ensure initialization
     55  * yourself (cheap/easy way is to check the resolved-methods table, and
     56  * resolve the method if it hasn't been).
     57  *
     58  * DO NOT replace "synchronized" methods.  We do not support method
     59  * synchronization here.
     60  *
     61  * DO NOT perform any allocations or do anything that could cause a
     62  * garbage collection.  The method arguments are not visible to the GC
     63  * and will not be pinned or updated when memory blocks move.  You are
     64  * allowed to allocate and throw an exception so long as you only do so
     65  * immediately before returning.
     66  *
     67  * Remember that these functions are executing while the thread is in
     68  * the "RUNNING" state, not the "NATIVE" state.  If you perform a blocking
     69  * operation you can stall the entire VM if the GC or debugger wants to
     70  * suspend the thread.  Since these are arguably native implementations
     71  * rather than VM internals, prefer NATIVE to VMWAIT if you want to change
     72  * the thread state.
     73  *
     74  * Always write results to 32-bit or 64-bit fields in "pResult", e.g. do
     75  * not write boolean results to pResult->z.  The interpreter expects
     76  * 32 or 64 bits to be set.
     77  *
     78  * Inline op methods return "false" if an exception was thrown, "true" if
     79  * everything went well.
     80  *
     81  * DO NOT provide implementations of methods that can be overridden by a
     82  * subclass, as polymorphism does not work correctly.  For safety you should
     83  * only provide inline functions for classes/methods declared "final".
     84  *
     85  * It's best to avoid inlining the overridden version of a method.  For
     86  * example, String.hashCode() is inherited from Object.hashCode().  Code
     87  * calling String.hashCode() through an Object reference will run the
     88  * "slow" version, while calling it through a String reference gets
     89  * the inlined version.  It's best to have just one version unless there
     90  * are clear performance gains.
     91  *
     92  * Because the actual method is not called, debugger breakpoints on these
     93  * methods will not happen.  (TODO: have the code here find the original
     94  * method and call it when the debugger is active.)  Additional steps have
     95  * been taken to allow method profiling to produce correct results.
     96  */
     97 
     98 
     99 /*
    100  * ===========================================================================
    101  *      org.apache.harmony.dalvik.NativeTestTarget
    102  * ===========================================================================
    103  */
    104 
    105 /*
    106  * public static void emptyInlineMethod
    107  *
    108  * This exists only for benchmarks.
    109  */
    110 static bool org_apache_harmony_dalvik_NativeTestTarget_emptyInlineMethod(
    111     u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
    112 {
    113     // do nothing
    114     return true;
    115 }
    116 
    117 
    118 /*
    119  * ===========================================================================
    120  *      java.lang.String
    121  * ===========================================================================
    122  */
    123 
    124 /*
    125  * public char charAt(int index)
    126  */
    127 bool javaLangString_charAt(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    128     JValue* pResult)
    129 {
    130     int count, offset;
    131     ArrayObject* chars;
    132 
    133     /* null reference check on "this" */
    134     if ((Object*) arg0 == NULL) {
    135         dvmThrowNullPointerException(NULL);
    136         return false;
    137     }
    138 
    139     //LOGI("String.charAt this=0x%08x index=%d", arg0, arg1);
    140     count = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT);
    141     if ((s4) arg1 < 0 || (s4) arg1 >= count) {
    142         dvmThrowStringIndexOutOfBoundsExceptionWithIndex(count, arg1);
    143         return false;
    144     } else {
    145         offset = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_OFFSET);
    146         chars = (ArrayObject*)
    147             dvmGetFieldObject((Object*) arg0, STRING_FIELDOFF_VALUE);
    148 
    149         pResult->i = ((const u2*)(void*)chars->contents)[arg1 + offset];
    150         return true;
    151     }
    152 }
    153 
    154 #ifdef CHECK_MEMCMP16
    155 /*
    156  * Utility function when we're evaluating alternative implementations.
    157  */
    158 static void badMatch(StringObject* thisStrObj, StringObject* compStrObj,
    159     int expectResult, int newResult, const char* compareType)
    160 {
    161     ArrayObject* thisArray;
    162     ArrayObject* compArray;
    163     const char* thisStr;
    164     const char* compStr;
    165     int thisOffset, compOffset, thisCount, compCount;
    166 
    167     thisCount =
    168         dvmGetFieldInt((Object*) thisStrObj, STRING_FIELDOFF_COUNT);
    169     compCount =
    170         dvmGetFieldInt((Object*) compStrObj, STRING_FIELDOFF_COUNT);
    171     thisOffset =
    172         dvmGetFieldInt((Object*) thisStrObj, STRING_FIELDOFF_OFFSET);
    173     compOffset =
    174         dvmGetFieldInt((Object*) compStrObj, STRING_FIELDOFF_OFFSET);
    175     thisArray = (ArrayObject*)
    176         dvmGetFieldObject((Object*) thisStrObj, STRING_FIELDOFF_VALUE);
    177     compArray = (ArrayObject*)
    178         dvmGetFieldObject((Object*) compStrObj, STRING_FIELDOFF_VALUE);
    179 
    180     thisStr = dvmCreateCstrFromString(thisStrObj);
    181     compStr = dvmCreateCstrFromString(compStrObj);
    182 
    183     LOGE("%s expected %d got %d", compareType, expectResult, newResult);
    184     LOGE(" this (o=%d l=%d) '%s'", thisOffset, thisCount, thisStr);
    185     LOGE(" comp (o=%d l=%d) '%s'", compOffset, compCount, compStr);
    186     dvmPrintHexDumpEx(ANDROID_LOG_INFO, LOG_TAG,
    187         ((const u2*) thisArray->contents) + thisOffset, thisCount*2,
    188         kHexDumpLocal);
    189     dvmPrintHexDumpEx(ANDROID_LOG_INFO, LOG_TAG,
    190         ((const u2*) compArray->contents) + compOffset, compCount*2,
    191         kHexDumpLocal);
    192     dvmAbort();
    193 }
    194 #endif
    195 
    196 /*
    197  * public int compareTo(String s)
    198  */
    199 bool javaLangString_compareTo(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    200     JValue* pResult)
    201 {
    202     /*
    203      * Null reference check on "this".  Normally this is performed during
    204      * the setup of the virtual method call.  We need to do it before
    205      * anything else.  While we're at it, check out the other string,
    206      * which must also be non-null.
    207      */
    208     if ((Object*) arg0 == NULL || (Object*) arg1 == NULL) {
    209         dvmThrowNullPointerException(NULL);
    210         return false;
    211     }
    212 
    213     /* quick test for comparison with itself */
    214     if (arg0 == arg1) {
    215         pResult->i = 0;
    216         return true;
    217     }
    218 
    219     /*
    220      * This would be simpler and faster if we promoted StringObject to
    221      * a full representation, lining up the C structure fields with the
    222      * actual object fields.
    223      */
    224     int thisCount, thisOffset, compCount, compOffset;
    225     ArrayObject* thisArray;
    226     ArrayObject* compArray;
    227     const u2* thisChars;
    228     const u2* compChars;
    229     int minCount, countDiff;
    230 
    231     thisCount = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT);
    232     compCount = dvmGetFieldInt((Object*) arg1, STRING_FIELDOFF_COUNT);
    233     countDiff = thisCount - compCount;
    234     minCount = (countDiff < 0) ? thisCount : compCount;
    235     thisOffset = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_OFFSET);
    236     compOffset = dvmGetFieldInt((Object*) arg1, STRING_FIELDOFF_OFFSET);
    237     thisArray = (ArrayObject*)
    238         dvmGetFieldObject((Object*) arg0, STRING_FIELDOFF_VALUE);
    239     compArray = (ArrayObject*)
    240         dvmGetFieldObject((Object*) arg1, STRING_FIELDOFF_VALUE);
    241     thisChars = ((const u2*)(void*)thisArray->contents) + thisOffset;
    242     compChars = ((const u2*)(void*)compArray->contents) + compOffset;
    243 
    244 #ifdef HAVE__MEMCMP16
    245     /*
    246      * Use assembly version, which returns the difference between the
    247      * characters.  The annoying part here is that 0x00e9 - 0xffff != 0x00ea,
    248      * because the interpreter converts the characters to 32-bit integers
    249      * *without* sign extension before it subtracts them (which makes some
    250      * sense since "char" is unsigned).  So what we get is the result of
    251      * 0x000000e9 - 0x0000ffff, which is 0xffff00ea.
    252      */
    253     int otherRes = __memcmp16(thisChars, compChars, minCount);
    254 # ifdef CHECK_MEMCMP16
    255     int i;
    256     for (i = 0; i < minCount; i++) {
    257         if (thisChars[i] != compChars[i]) {
    258             pResult->i = (s4) thisChars[i] - (s4) compChars[i];
    259             if (pResult->i != otherRes) {
    260                 badMatch((StringObject*) arg0, (StringObject*) arg1,
    261                     pResult->i, otherRes, "compareTo");
    262             }
    263             return true;
    264         }
    265     }
    266 # endif
    267     if (otherRes != 0) {
    268         pResult->i = otherRes;
    269         return true;
    270     }
    271 
    272 #else
    273     /*
    274      * Straightforward implementation, examining 16 bits at a time.  Compare
    275      * the characters that overlap, and if they're all the same then return
    276      * the difference in lengths.
    277      */
    278     int i;
    279     for (i = 0; i < minCount; i++) {
    280         if (thisChars[i] != compChars[i]) {
    281             pResult->i = (s4) thisChars[i] - (s4) compChars[i];
    282             return true;
    283         }
    284     }
    285 #endif
    286 
    287     pResult->i = countDiff;
    288     return true;
    289 }
    290 
    291 /*
    292  * public boolean equals(Object anObject)
    293  */
    294 bool javaLangString_equals(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    295     JValue* pResult)
    296 {
    297     /*
    298      * Null reference check on "this".
    299      */
    300     if ((Object*) arg0 == NULL) {
    301         dvmThrowNullPointerException(NULL);
    302         return false;
    303     }
    304 
    305     /* quick test for comparison with itself */
    306     if (arg0 == arg1) {
    307         pResult->i = true;
    308         return true;
    309     }
    310 
    311     /*
    312      * See if the other object is also a String.
    313      *
    314      * str.equals(null) is expected to return false, presumably based on
    315      * the results of the instanceof test.
    316      */
    317     if (arg1 == 0 || ((Object*) arg0)->clazz != ((Object*) arg1)->clazz) {
    318         pResult->i = false;
    319         return true;
    320     }
    321 
    322     /*
    323      * This would be simpler and faster if we promoted StringObject to
    324      * a full representation, lining up the C structure fields with the
    325      * actual object fields.
    326      */
    327     int thisCount, thisOffset, compCount, compOffset;
    328     ArrayObject* thisArray;
    329     ArrayObject* compArray;
    330     const u2* thisChars;
    331     const u2* compChars;
    332 
    333     /* quick length check */
    334     thisCount = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT);
    335     compCount = dvmGetFieldInt((Object*) arg1, STRING_FIELDOFF_COUNT);
    336     if (thisCount != compCount) {
    337         pResult->i = false;
    338         return true;
    339     }
    340 
    341     /*
    342      * You may, at this point, be tempted to pull out the hashCode fields
    343      * and compare them.  If both fields have been initialized, and they
    344      * are not equal, we can return false immediately.
    345      *
    346      * However, the hashCode field is often not set.  If it is set,
    347      * there's an excellent chance that the String is being used as a key
    348      * in a hashed data structure (e.g. HashMap).  That data structure has
    349      * already made the comparison and determined that the hashes are equal,
    350      * making a check here redundant.
    351      *
    352      * It's not clear that checking the hashes will be a win in "typical"
    353      * use cases.  We err on the side of simplicity and ignore them.
    354      */
    355 
    356     thisOffset = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_OFFSET);
    357     compOffset = dvmGetFieldInt((Object*) arg1, STRING_FIELDOFF_OFFSET);
    358     thisArray = (ArrayObject*)
    359         dvmGetFieldObject((Object*) arg0, STRING_FIELDOFF_VALUE);
    360     compArray = (ArrayObject*)
    361         dvmGetFieldObject((Object*) arg1, STRING_FIELDOFF_VALUE);
    362     thisChars = ((const u2*)(void*)thisArray->contents) + thisOffset;
    363     compChars = ((const u2*)(void*)compArray->contents) + compOffset;
    364 
    365 #ifdef HAVE__MEMCMP16
    366     pResult->i = (__memcmp16(thisChars, compChars, thisCount) == 0);
    367 # ifdef CHECK_MEMCMP16
    368     int otherRes = (memcmp(thisChars, compChars, thisCount * 2) == 0);
    369     if (pResult->i != otherRes) {
    370         badMatch((StringObject*) arg0, (StringObject*) arg1,
    371             otherRes, pResult->i, "equals-1");
    372     }
    373 # endif
    374 #else
    375     /*
    376      * Straightforward implementation, examining 16 bits at a time.  The
    377      * direction of the loop doesn't matter, and starting at the end may
    378      * give us an advantage when comparing certain types of strings (e.g.
    379      * class names).
    380      *
    381      * We want to go forward for benchmarks against __memcmp16 so we get a
    382      * meaningful comparison when the strings don't match (could also test
    383      * with palindromes).
    384      */
    385     int i;
    386     //for (i = 0; i < thisCount; i++)
    387     for (i = thisCount-1; i >= 0; --i)
    388     {
    389         if (thisChars[i] != compChars[i]) {
    390             pResult->i = false;
    391             return true;
    392         }
    393     }
    394     pResult->i = true;
    395 #endif
    396 
    397     return true;
    398 }
    399 
    400 /*
    401  * public int length()
    402  */
    403 bool javaLangString_length(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    404     JValue* pResult)
    405 {
    406     //LOGI("String.length this=0x%08x pResult=%p", arg0, pResult);
    407 
    408     /* null reference check on "this" */
    409     if ((Object*) arg0 == NULL) {
    410         dvmThrowNullPointerException(NULL);
    411         return false;
    412     }
    413 
    414     pResult->i = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT);
    415     return true;
    416 }
    417 
    418 /*
    419  * public boolean isEmpty()
    420  */
    421 bool javaLangString_isEmpty(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    422     JValue* pResult)
    423 {
    424     //LOGI("String.isEmpty this=0x%08x pResult=%p", arg0, pResult);
    425 
    426     /* null reference check on "this" */
    427     if ((Object*) arg0 == NULL) {
    428         dvmThrowNullPointerException(NULL);
    429         return false;
    430     }
    431 
    432     pResult->i = (dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT) == 0);
    433     return true;
    434 }
    435 
    436 /*
    437  * Determine the index of the first character matching "ch".  The string
    438  * to search is described by "chars", "offset", and "count".
    439  *
    440  * The character must be <= 0xffff. Supplementary characters are handled in
    441  * Java.
    442  *
    443  * The "start" parameter must be clamped to [0..count].
    444  *
    445  * Returns -1 if no match is found.
    446  */
    447 static inline int indexOfCommon(Object* strObj, int ch, int start)
    448 {
    449     //if ((ch & 0xffff) != ch)        /* 32-bit code point */
    450     //    return -1;
    451 
    452     /* pull out the basic elements */
    453     ArrayObject* charArray =
    454         (ArrayObject*) dvmGetFieldObject(strObj, STRING_FIELDOFF_VALUE);
    455     const u2* chars = (const u2*)(void*)charArray->contents;
    456     int offset = dvmGetFieldInt(strObj, STRING_FIELDOFF_OFFSET);
    457     int count = dvmGetFieldInt(strObj, STRING_FIELDOFF_COUNT);
    458     //LOGI("String.indexOf(0x%08x, 0x%04x, %d) off=%d count=%d",
    459     //    (u4) strObj, ch, start, offset, count);
    460 
    461     /* factor out the offset */
    462     chars += offset;
    463 
    464     if (start < 0)
    465         start = 0;
    466 
    467 #if 0
    468     /* 16-bit loop, simple */
    469     while (start < count) {
    470         if (chars[start] == ch)
    471             return start;
    472         start++;
    473     }
    474 #else
    475     /* 16-bit loop, slightly better on ARM */
    476     const u2* ptr = chars + start;
    477     const u2* endPtr = chars + count;
    478     while (ptr < endPtr) {
    479         if (*ptr++ == ch)
    480             return (ptr-1) - chars;
    481     }
    482 #endif
    483 
    484     return -1;
    485 }
    486 
    487 /*
    488  * public int indexOf(int c, int start)
    489  *
    490  * Scan forward through the string for a matching character.
    491  * The character must be <= 0xffff; this method does not handle supplementary
    492  * characters.
    493  */
    494 bool javaLangString_fastIndexOf_II(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    495     JValue* pResult)
    496 {
    497     /* null reference check on "this" */
    498     if ((Object*) arg0 == NULL) {
    499         dvmThrowNullPointerException(NULL);
    500         return false;
    501     }
    502 
    503     pResult->i = indexOfCommon((Object*) arg0, arg1, arg2);
    504     return true;
    505 }
    506 
    507 
    508 /*
    509  * ===========================================================================
    510  *      java.lang.Math
    511  * ===========================================================================
    512  */
    513 
    514 union Convert32 {
    515     u4 arg;
    516     float ff;
    517 };
    518 
    519 union Convert64 {
    520     u4 arg[2];
    521     s8 ll;
    522     double dd;
    523 };
    524 
    525 /*
    526  * public static int abs(int)
    527  */
    528 bool javaLangMath_abs_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    529     JValue* pResult)
    530 {
    531     s4 val = (s4) arg0;
    532     pResult->i = (val >= 0) ? val : -val;
    533     return true;
    534 }
    535 
    536 /*
    537  * public static long abs(long)
    538  */
    539 bool javaLangMath_abs_long(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    540     JValue* pResult)
    541 {
    542     Convert64 convert;
    543     convert.arg[0] = arg0;
    544     convert.arg[1] = arg1;
    545     s8 val = convert.ll;
    546     pResult->j = (val >= 0) ? val : -val;
    547     return true;
    548 }
    549 
    550 /*
    551  * public static float abs(float)
    552  */
    553 bool javaLangMath_abs_float(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    554     JValue* pResult)
    555 {
    556     Convert32 convert;
    557     /* clear the sign bit; assumes a fairly common fp representation */
    558     convert.arg = arg0 & 0x7fffffff;
    559     pResult->f = convert.ff;
    560     return true;
    561 }
    562 
    563 /*
    564  * public static double abs(double)
    565  */
    566 bool javaLangMath_abs_double(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    567     JValue* pResult)
    568 {
    569     Convert64 convert;
    570     convert.arg[0] = arg0;
    571     convert.arg[1] = arg1;
    572     /* clear the sign bit in the (endian-dependent) high word */
    573     convert.ll &= 0x7fffffffffffffffULL;
    574     pResult->d = convert.dd;
    575     return true;
    576 }
    577 
    578 /*
    579  * public static int min(int)
    580  */
    581 bool javaLangMath_min_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    582     JValue* pResult)
    583 {
    584     pResult->i = ((s4) arg0 < (s4) arg1) ? arg0 : arg1;
    585     return true;
    586 }
    587 
    588 /*
    589  * public static int max(int)
    590  */
    591 bool javaLangMath_max_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    592     JValue* pResult)
    593 {
    594     pResult->i = ((s4) arg0 > (s4) arg1) ? arg0 : arg1;
    595     return true;
    596 }
    597 
    598 /*
    599  * public static double sqrt(double)
    600  *
    601  * With ARM VFP enabled, gcc turns this into an fsqrtd instruction, followed
    602  * by an fcmpd of the result against itself.  If it doesn't match (i.e.
    603  * it's NaN), the libm sqrt() is invoked.
    604  */
    605 bool javaLangMath_sqrt(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    606     JValue* pResult)
    607 {
    608     Convert64 convert;
    609     convert.arg[0] = arg0;
    610     convert.arg[1] = arg1;
    611     pResult->d = sqrt(convert.dd);
    612     return true;
    613 }
    614 
    615 /*
    616  * public static double cos(double)
    617  */
    618 bool javaLangMath_cos(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    619     JValue* pResult)
    620 {
    621     Convert64 convert;
    622     convert.arg[0] = arg0;
    623     convert.arg[1] = arg1;
    624     pResult->d = cos(convert.dd);
    625     return true;
    626 }
    627 
    628 /*
    629  * public static double sin(double)
    630  */
    631 bool javaLangMath_sin(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    632     JValue* pResult)
    633 {
    634     Convert64 convert;
    635     convert.arg[0] = arg0;
    636     convert.arg[1] = arg1;
    637     pResult->d = sin(convert.dd);
    638     return true;
    639 }
    640 
    641 /*
    642  * ===========================================================================
    643  *      java.lang.Float
    644  * ===========================================================================
    645  */
    646 
    647 bool javaLangFloat_floatToIntBits(u4 arg0, u4 arg1, u4 arg2, u4 arg,
    648     JValue* pResult)
    649 {
    650     Convert32 convert;
    651     convert.arg = arg0;
    652     pResult->i = isnanf(convert.ff) ? 0x7fc00000 : arg0;
    653     return true;
    654 }
    655 
    656 bool javaLangFloat_floatToRawIntBits(u4 arg0, u4 arg1, u4 arg2, u4 arg,
    657     JValue* pResult)
    658 {
    659     pResult->i = arg0;
    660     return true;
    661 }
    662 
    663 bool javaLangFloat_intBitsToFloat(u4 arg0, u4 arg1, u4 arg2, u4 arg,
    664     JValue* pResult)
    665 {
    666     Convert32 convert;
    667     convert.arg = arg0;
    668     pResult->f = convert.ff;
    669     return true;
    670 }
    671 
    672 /*
    673  * ===========================================================================
    674  *      java.lang.Double
    675  * ===========================================================================
    676  */
    677 
    678 bool javaLangDouble_doubleToLongBits(u4 arg0, u4 arg1, u4 arg2, u4 arg,
    679     JValue* pResult)
    680 {
    681     Convert64 convert;
    682     convert.arg[0] = arg0;
    683     convert.arg[1] = arg1;
    684     pResult->j = isnan(convert.dd) ? 0x7ff8000000000000LL : convert.ll;
    685     return true;
    686 }
    687 
    688 bool javaLangDouble_doubleToRawLongBits(u4 arg0, u4 arg1, u4 arg2,
    689     u4 arg, JValue* pResult)
    690 {
    691     Convert64 convert;
    692     convert.arg[0] = arg0;
    693     convert.arg[1] = arg1;
    694     pResult->j = convert.ll;
    695     return true;
    696 }
    697 
    698 bool javaLangDouble_longBitsToDouble(u4 arg0, u4 arg1, u4 arg2, u4 arg,
    699     JValue* pResult)
    700 {
    701     Convert64 convert;
    702     convert.arg[0] = arg0;
    703     convert.arg[1] = arg1;
    704     pResult->d = convert.dd;
    705     return true;
    706 }
    707 
    708 /*
    709  * ===========================================================================
    710  *      Infrastructure
    711  * ===========================================================================
    712  */
    713 
    714 /*
    715  * Table of methods.
    716  *
    717  * The DEX optimizer uses the class/method/signature string fields to decide
    718  * which calls it can trample.  The interpreter just uses the function
    719  * pointer field.
    720  *
    721  * IMPORTANT: you must update DALVIK_VM_BUILD in DalvikVersion.h if you make
    722  * changes to this table.
    723  *
    724  * NOTE: If present, the JIT will also need to know about changes
    725  * to this table.  Update the NativeInlineOps enum in InlineNative.h and
    726  * the dispatch code in compiler/codegen/<target>/Codegen.c.
    727  */
    728 const InlineOperation gDvmInlineOpsTable[] = {
    729     { org_apache_harmony_dalvik_NativeTestTarget_emptyInlineMethod,
    730         "Lorg/apache/harmony/dalvik/NativeTestTarget;",
    731         "emptyInlineMethod", "()V" },
    732 
    733     { javaLangString_charAt,
    734         "Ljava/lang/String;", "charAt", "(I)C" },
    735     { javaLangString_compareTo,
    736         "Ljava/lang/String;", "compareTo", "(Ljava/lang/String;)I" },
    737     { javaLangString_equals,
    738         "Ljava/lang/String;", "equals", "(Ljava/lang/Object;)Z" },
    739     { javaLangString_fastIndexOf_II,
    740         "Ljava/lang/String;", "fastIndexOf", "(II)I" },
    741     { javaLangString_isEmpty,
    742         "Ljava/lang/String;", "isEmpty", "()Z" },
    743     { javaLangString_length,
    744         "Ljava/lang/String;", "length", "()I" },
    745 
    746     { javaLangMath_abs_int,
    747         "Ljava/lang/Math;", "abs", "(I)I" },
    748     { javaLangMath_abs_long,
    749         "Ljava/lang/Math;", "abs", "(J)J" },
    750     { javaLangMath_abs_float,
    751         "Ljava/lang/Math;", "abs", "(F)F" },
    752     { javaLangMath_abs_double,
    753         "Ljava/lang/Math;", "abs", "(D)D" },
    754     { javaLangMath_min_int,
    755         "Ljava/lang/Math;", "min", "(II)I" },
    756     { javaLangMath_max_int,
    757         "Ljava/lang/Math;", "max", "(II)I" },
    758     { javaLangMath_sqrt,
    759         "Ljava/lang/Math;", "sqrt", "(D)D" },
    760     { javaLangMath_cos,
    761         "Ljava/lang/Math;", "cos", "(D)D" },
    762     { javaLangMath_sin,
    763         "Ljava/lang/Math;", "sin", "(D)D" },
    764 
    765     { javaLangFloat_floatToIntBits,
    766         "Ljava/lang/Float;", "floatToIntBits", "(F)I" },
    767     { javaLangFloat_floatToRawIntBits,
    768         "Ljava/lang/Float;", "floatToRawIntBits", "(F)I" },
    769     { javaLangFloat_intBitsToFloat,
    770         "Ljava/lang/Float;", "intBitsToFloat", "(I)F" },
    771 
    772     { javaLangDouble_doubleToLongBits,
    773         "Ljava/lang/Double;", "doubleToLongBits", "(D)J" },
    774     { javaLangDouble_doubleToRawLongBits,
    775         "Ljava/lang/Double;", "doubleToRawLongBits", "(D)J" },
    776     { javaLangDouble_longBitsToDouble,
    777         "Ljava/lang/Double;", "longBitsToDouble", "(J)D" },
    778 };
    779 
    780 /*
    781  * Allocate some tables.
    782  */
    783 bool dvmInlineNativeStartup()
    784 {
    785     gDvm.inlinedMethods =
    786         (Method**) calloc(NELEM(gDvmInlineOpsTable), sizeof(Method*));
    787     if (gDvm.inlinedMethods == NULL)
    788         return false;
    789 
    790     return true;
    791 }
    792 
    793 /*
    794  * Free generated tables.
    795  */
    796 void dvmInlineNativeShutdown()
    797 {
    798     free(gDvm.inlinedMethods);
    799 }
    800 
    801 
    802 /*
    803  * Get a pointer to the inlineops table.
    804  */
    805 const InlineOperation* dvmGetInlineOpsTable()
    806 {
    807     return gDvmInlineOpsTable;
    808 }
    809 
    810 /*
    811  * Get the number of entries in the inlineops table.
    812  */
    813 int dvmGetInlineOpsTableLength()
    814 {
    815     return NELEM(gDvmInlineOpsTable);
    816 }
    817 
    818 Method* dvmFindInlinableMethod(const char* classDescriptor,
    819     const char* methodName, const char* methodSignature)
    820 {
    821     /*
    822      * Find the class.
    823      */
    824     ClassObject* clazz = dvmFindClassNoInit(classDescriptor, NULL);
    825     if (clazz == NULL) {
    826         LOGE("dvmFindInlinableMethod: can't find class '%s'",
    827             classDescriptor);
    828         dvmClearException(dvmThreadSelf());
    829         return NULL;
    830     }
    831 
    832     /*
    833      * Method could be virtual or direct.  Try both.  Don't use
    834      * the "hier" versions.
    835      */
    836     Method* method = dvmFindDirectMethodByDescriptor(clazz, methodName,
    837         methodSignature);
    838     if (method == NULL) {
    839         method = dvmFindVirtualMethodByDescriptor(clazz, methodName,
    840             methodSignature);
    841     }
    842     if (method == NULL) {
    843         LOGE("dvmFindInlinableMethod: can't find method %s.%s %s",
    844             clazz->descriptor, methodName, methodSignature);
    845         return NULL;
    846     }
    847 
    848     /*
    849      * Check that the method is appropriate for inlining.
    850      */
    851     if (!dvmIsFinalClass(clazz) && !dvmIsFinalMethod(method)) {
    852         LOGE("dvmFindInlinableMethod: can't inline non-final method %s.%s",
    853             clazz->descriptor, method->name);
    854         return NULL;
    855     }
    856     if (dvmIsSynchronizedMethod(method) ||
    857             dvmIsDeclaredSynchronizedMethod(method)) {
    858         LOGE("dvmFindInlinableMethod: can't inline synchronized method %s.%s",
    859             clazz->descriptor, method->name);
    860         return NULL;
    861     }
    862 
    863     return method;
    864 }
    865 
    866 /*
    867  * Populate the methods table on first use.  It's possible the class
    868  * hasn't been resolved yet, so we need to do the full "calling the
    869  * method for the first time" routine.  (It's probably okay to skip
    870  * the access checks.)
    871  *
    872  * Currently assuming that we're only inlining stuff loaded by the
    873  * bootstrap class loader.  This is a safe assumption for many reasons.
    874  */
    875 Method* dvmResolveInlineNative(int opIndex)
    876 {
    877     assert(opIndex >= 0 && opIndex < NELEM(gDvmInlineOpsTable));
    878     Method* method = gDvm.inlinedMethods[opIndex];
    879     if (method != NULL) {
    880         return method;
    881     }
    882 
    883     method = dvmFindInlinableMethod(
    884         gDvmInlineOpsTable[opIndex].classDescriptor,
    885         gDvmInlineOpsTable[opIndex].methodName,
    886         gDvmInlineOpsTable[opIndex].methodSignature);
    887 
    888     if (method == NULL) {
    889         /* We already reported the error. */
    890         return NULL;
    891     }
    892 
    893     gDvm.inlinedMethods[opIndex] = method;
    894     IF_LOGV() {
    895         char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
    896         LOGV("Registered for profile: %s.%s %s",
    897             method->clazz->descriptor, method->name, desc);
    898         free(desc);
    899     }
    900 
    901     return method;
    902 }
    903 
    904 /*
    905  * Make an inline call for the "debug" interpreter, used when the debugger
    906  * or profiler is active.
    907  */
    908 bool dvmPerformInlineOp4Dbg(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    909     JValue* pResult, int opIndex)
    910 {
    911     Method* method = dvmResolveInlineNative(opIndex);
    912     if (method == NULL) {
    913         return (*gDvmInlineOpsTable[opIndex].func)(arg0, arg1, arg2, arg3,
    914             pResult);
    915     }
    916 
    917     Thread* self = dvmThreadSelf();
    918     TRACE_METHOD_ENTER(self, method);
    919     bool result = (*gDvmInlineOpsTable[opIndex].func)(arg0, arg1, arg2, arg3,
    920         pResult);
    921     TRACE_METHOD_EXIT(self, method);
    922     return result;
    923 }
    924