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 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  * Remember that these functions are executing while the thread is in
     62  * the "RUNNING" state, not the "NATIVE" state.  If you perform a blocking
     63  * operation you can stall the entire VM if the GC or debugger wants to
     64  * suspend the thread.  Since these are arguably native implementations
     65  * rather than VM internals, prefer NATIVE to VMWAIT if you want to change
     66  * the thread state.
     67  *
     68  * Always write results to 32-bit or 64-bit fields in "pResult", e.g. do
     69  * not write boolean results to pResult->z.  The interpreter expects
     70  * 32 or 64 bits to be set.
     71  *
     72  * Inline op methods return "false" if an exception was thrown, "true" if
     73  * everything went well.
     74  *
     75  * DO NOT provide implementations of methods that can be overridden by a
     76  * subclass, as polymorphism does not work correctly.  For safety you should
     77  * only provide inline functions for classes/methods declared "final".
     78  *
     79  * It's best to avoid inlining the overridden version of a method.  For
     80  * example, String.hashCode() is inherited from Object.hashCode().  Code
     81  * calling String.hashCode() through an Object reference will run the
     82  * "slow" version, while calling it through a String reference gets
     83  * the inlined version.  It's best to have just one version unless there
     84  * are clear performance gains.
     85  *
     86  * Because the actual method is not called, debugger breakpoints on these
     87  * methods will not happen.  (TODO: have the code here find the original
     88  * method and call it when the debugger is active.)  Additional steps have
     89  * been taken to allow method profiling to produce correct results.
     90  */
     91 
     92 
     93 /*
     94  * ===========================================================================
     95  *      org.apache.harmony.dalvik.NativeTestTarget
     96  * ===========================================================================
     97  */
     98 
     99 /*
    100  * public static void emptyInlineMethod
    101  *
    102  * This exists only for benchmarks.
    103  */
    104 static bool org_apache_harmony_dalvik_NativeTestTarget_emptyInlineMethod(
    105     u4 arg0, u4 arg1, u4 arg2, u4 arg3, JValue* pResult)
    106 {
    107     // do nothing
    108     return true;
    109 }
    110 
    111 
    112 /*
    113  * ===========================================================================
    114  *      java.lang.String
    115  * ===========================================================================
    116  */
    117 
    118 /*
    119  * public char charAt(int index)
    120  */
    121 static bool javaLangString_charAt(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    122     JValue* pResult)
    123 {
    124     int count, offset;
    125     ArrayObject* chars;
    126 
    127     /* null reference check on "this" */
    128     if (!dvmValidateObject((Object*) arg0))
    129         return false;
    130 
    131     //LOGI("String.charAt this=0x%08x index=%d\n", arg0, arg1);
    132     count = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT);
    133     if ((s4) arg1 < 0 || (s4) arg1 >= count) {
    134         dvmThrowException("Ljava/lang/StringIndexOutOfBoundsException;", NULL);
    135         return false;
    136     } else {
    137         offset = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_OFFSET);
    138         chars = (ArrayObject*)
    139             dvmGetFieldObject((Object*) arg0, STRING_FIELDOFF_VALUE);
    140 
    141         pResult->i = ((const u2*) chars->contents)[arg1 + offset];
    142         return true;
    143     }
    144 }
    145 
    146 #ifdef CHECK_MEMCMP16
    147 /*
    148  * Utility function when we're evaluating alternative implementations.
    149  */
    150 static void badMatch(StringObject* thisStrObj, StringObject* compStrObj,
    151     int expectResult, int newResult, const char* compareType)
    152 {
    153     ArrayObject* thisArray;
    154     ArrayObject* compArray;
    155     const char* thisStr;
    156     const char* compStr;
    157     int thisOffset, compOffset, thisCount, compCount;
    158 
    159     thisCount =
    160         dvmGetFieldInt((Object*) thisStrObj, STRING_FIELDOFF_COUNT);
    161     compCount =
    162         dvmGetFieldInt((Object*) compStrObj, STRING_FIELDOFF_COUNT);
    163     thisOffset =
    164         dvmGetFieldInt((Object*) thisStrObj, STRING_FIELDOFF_OFFSET);
    165     compOffset =
    166         dvmGetFieldInt((Object*) compStrObj, STRING_FIELDOFF_OFFSET);
    167     thisArray = (ArrayObject*)
    168         dvmGetFieldObject((Object*) thisStrObj, STRING_FIELDOFF_VALUE);
    169     compArray = (ArrayObject*)
    170         dvmGetFieldObject((Object*) compStrObj, STRING_FIELDOFF_VALUE);
    171 
    172     thisStr = dvmCreateCstrFromString(thisStrObj);
    173     compStr = dvmCreateCstrFromString(compStrObj);
    174 
    175     LOGE("%s expected %d got %d\n", compareType, expectResult, newResult);
    176     LOGE(" this (o=%d l=%d) '%s'\n", thisOffset, thisCount, thisStr);
    177     LOGE(" comp (o=%d l=%d) '%s'\n", compOffset, compCount, compStr);
    178     dvmPrintHexDumpEx(ANDROID_LOG_INFO, LOG_TAG,
    179         ((const u2*) thisArray->contents) + thisOffset, thisCount*2,
    180         kHexDumpLocal);
    181     dvmPrintHexDumpEx(ANDROID_LOG_INFO, LOG_TAG,
    182         ((const u2*) compArray->contents) + compOffset, compCount*2,
    183         kHexDumpLocal);
    184     dvmAbort();
    185 }
    186 #endif
    187 
    188 /*
    189  * public int compareTo(String s)
    190  */
    191 static bool javaLangString_compareTo(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    192     JValue* pResult)
    193 {
    194     /*
    195      * Null reference check on "this".  Normally this is performed during
    196      * the setup of the virtual method call.  We need to do it before
    197      * anything else.  While we're at it, check out the other string,
    198      * which must also be non-null.
    199      */
    200     if (!dvmValidateObject((Object*) arg0) ||
    201         !dvmValidateObject((Object*) arg1))
    202     {
    203         return false;
    204     }
    205 
    206     /* quick test for comparison with itself */
    207     if (arg0 == arg1) {
    208         pResult->i = 0;
    209         return true;
    210     }
    211 
    212     /*
    213      * This would be simpler and faster if we promoted StringObject to
    214      * a full representation, lining up the C structure fields with the
    215      * actual object fields.
    216      */
    217     int thisCount, thisOffset, compCount, compOffset;
    218     ArrayObject* thisArray;
    219     ArrayObject* compArray;
    220     const u2* thisChars;
    221     const u2* compChars;
    222     int i, minCount, countDiff;
    223 
    224     thisCount = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT);
    225     compCount = dvmGetFieldInt((Object*) arg1, STRING_FIELDOFF_COUNT);
    226     countDiff = thisCount - compCount;
    227     minCount = (countDiff < 0) ? thisCount : compCount;
    228     thisOffset = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_OFFSET);
    229     compOffset = dvmGetFieldInt((Object*) arg1, STRING_FIELDOFF_OFFSET);
    230     thisArray = (ArrayObject*)
    231         dvmGetFieldObject((Object*) arg0, STRING_FIELDOFF_VALUE);
    232     compArray = (ArrayObject*)
    233         dvmGetFieldObject((Object*) arg1, STRING_FIELDOFF_VALUE);
    234     thisChars = ((const u2*) thisArray->contents) + thisOffset;
    235     compChars = ((const u2*) compArray->contents) + compOffset;
    236 
    237 #ifdef HAVE__MEMCMP16
    238     /*
    239      * Use assembly version, which returns the difference between the
    240      * characters.  The annoying part here is that 0x00e9 - 0xffff != 0x00ea,
    241      * because the interpreter converts the characters to 32-bit integers
    242      * *without* sign extension before it subtracts them (which makes some
    243      * sense since "char" is unsigned).  So what we get is the result of
    244      * 0x000000e9 - 0x0000ffff, which is 0xffff00ea.
    245      */
    246     int otherRes = __memcmp16(thisChars, compChars, minCount);
    247 # ifdef CHECK_MEMCMP16
    248     for (i = 0; i < minCount; i++) {
    249         if (thisChars[i] != compChars[i]) {
    250             pResult->i = (s4) thisChars[i] - (s4) compChars[i];
    251             if (pResult->i != otherRes) {
    252                 badMatch((StringObject*) arg0, (StringObject*) arg1,
    253                     pResult->i, otherRes, "compareTo");
    254             }
    255             return true;
    256         }
    257     }
    258 # endif
    259     if (otherRes != 0) {
    260         pResult->i = otherRes;
    261         return true;
    262     }
    263 
    264 #else
    265     /*
    266      * Straightforward implementation, examining 16 bits at a time.  Compare
    267      * the characters that overlap, and if they're all the same then return
    268      * the difference in lengths.
    269      */
    270     for (i = 0; i < minCount; i++) {
    271         if (thisChars[i] != compChars[i]) {
    272             pResult->i = (s4) thisChars[i] - (s4) compChars[i];
    273             return true;
    274         }
    275     }
    276 #endif
    277 
    278     pResult->i = countDiff;
    279     return true;
    280 }
    281 
    282 /*
    283  * public boolean equals(Object anObject)
    284  */
    285 static bool javaLangString_equals(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    286     JValue* pResult)
    287 {
    288     /*
    289      * Null reference check on "this".
    290      */
    291     if (!dvmValidateObject((Object*) arg0))
    292         return false;
    293 
    294     /* quick test for comparison with itself */
    295     if (arg0 == arg1) {
    296         pResult->i = true;
    297         return true;
    298     }
    299 
    300     /*
    301      * See if the other object is also a String.
    302      *
    303      * str.equals(null) is expected to return false, presumably based on
    304      * the results of the instanceof test.
    305      */
    306     if (arg1 == 0 || ((Object*) arg0)->clazz != ((Object*) arg1)->clazz) {
    307         pResult->i = false;
    308         return true;
    309     }
    310 
    311     /*
    312      * This would be simpler and faster if we promoted StringObject to
    313      * a full representation, lining up the C structure fields with the
    314      * actual object fields.
    315      */
    316     int thisCount, thisOffset, compCount, compOffset;
    317     ArrayObject* thisArray;
    318     ArrayObject* compArray;
    319     const u2* thisChars;
    320     const u2* compChars;
    321     int i;
    322 
    323     /* quick length check */
    324     thisCount = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT);
    325     compCount = dvmGetFieldInt((Object*) arg1, STRING_FIELDOFF_COUNT);
    326     if (thisCount != compCount) {
    327         pResult->i = false;
    328         return true;
    329     }
    330 
    331     thisOffset = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_OFFSET);
    332     compOffset = dvmGetFieldInt((Object*) arg1, STRING_FIELDOFF_OFFSET);
    333     thisArray = (ArrayObject*)
    334         dvmGetFieldObject((Object*) arg0, STRING_FIELDOFF_VALUE);
    335     compArray = (ArrayObject*)
    336         dvmGetFieldObject((Object*) arg1, STRING_FIELDOFF_VALUE);
    337     thisChars = ((const u2*) thisArray->contents) + thisOffset;
    338     compChars = ((const u2*) compArray->contents) + compOffset;
    339 
    340 #ifdef HAVE__MEMCMP16
    341     pResult->i = (__memcmp16(thisChars, compChars, thisCount) == 0);
    342 # ifdef CHECK_MEMCMP16
    343     int otherRes = (memcmp(thisChars, compChars, thisCount * 2) == 0);
    344     if (pResult->i != otherRes) {
    345         badMatch((StringObject*) arg0, (StringObject*) arg1,
    346             otherRes, pResult->i, "equals-1");
    347     }
    348 # endif
    349 #else
    350     /*
    351      * Straightforward implementation, examining 16 bits at a time.  The
    352      * direction of the loop doesn't matter, and starting at the end may
    353      * give us an advantage when comparing certain types of strings (e.g.
    354      * class names).
    355      *
    356      * We want to go forward for benchmarks against __memcmp16 so we get a
    357      * meaningful comparison when the strings don't match (could also test
    358      * with palindromes).
    359      */
    360     //for (i = 0; i < thisCount; i++)
    361     for (i = thisCount-1; i >= 0; --i)
    362     {
    363         if (thisChars[i] != compChars[i]) {
    364             pResult->i = false;
    365             return true;
    366         }
    367     }
    368     pResult->i = true;
    369 #endif
    370 
    371     return true;
    372 }
    373 
    374 /*
    375  * public int length()
    376  */
    377 static bool javaLangString_length(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    378     JValue* pResult)
    379 {
    380     //LOGI("String.length this=0x%08x pResult=%p\n", arg0, pResult);
    381 
    382     /* null reference check on "this" */
    383     if (!dvmValidateObject((Object*) arg0))
    384         return false;
    385 
    386     pResult->i = dvmGetFieldInt((Object*) arg0, STRING_FIELDOFF_COUNT);
    387     return true;
    388 }
    389 
    390 /*
    391  * Determine the index of the first character matching "ch".  The string
    392  * to search is described by "chars", "offset", and "count".
    393  *
    394  * The "ch" parameter is allowed to be > 0xffff.  Our Java-language
    395  * implementation does not currently handle this, so neither do we.
    396  *
    397  * The "start" parameter must be clamped to [0..count].
    398  *
    399  * Returns -1 if no match is found.
    400  */
    401 static inline int indexOfCommon(Object* strObj, int ch, int start)
    402 {
    403     //if ((ch & 0xffff) != ch)        /* 32-bit code point */
    404     //    return -1;
    405 
    406     /* pull out the basic elements */
    407     ArrayObject* charArray =
    408         (ArrayObject*) dvmGetFieldObject(strObj, STRING_FIELDOFF_VALUE);
    409     const u2* chars = (const u2*) charArray->contents;
    410     int offset = dvmGetFieldInt(strObj, STRING_FIELDOFF_OFFSET);
    411     int count = dvmGetFieldInt(strObj, STRING_FIELDOFF_COUNT);
    412     //LOGI("String.indexOf(0x%08x, 0x%04x, %d) off=%d count=%d\n",
    413     //    (u4) strObj, ch, start, offset, count);
    414 
    415     /* factor out the offset */
    416     chars += offset;
    417 
    418     if (start < 0)
    419         start = 0;
    420 
    421 #if 0
    422     /* 16-bit loop, simple */
    423     while (start < count) {
    424         if (chars[start] == ch)
    425             return start;
    426         start++;
    427     }
    428 #else
    429     /* 16-bit loop, slightly better on ARM */
    430     const u2* ptr = chars + start;
    431     const u2* endPtr = chars + count;
    432     while (ptr < endPtr) {
    433         if (*ptr++ == ch)
    434             return (ptr-1) - chars;
    435     }
    436 #endif
    437 
    438     return -1;
    439 }
    440 
    441 /*
    442  * public int indexOf(int c)
    443  *
    444  * Scan forward through the string for a matching character.
    445  */
    446 static bool javaLangString_indexOf_I(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    447     JValue* pResult)
    448 {
    449     /* null reference check on "this" */
    450     if (!dvmValidateObject((Object*) arg0))
    451         return false;
    452 
    453     pResult->i = indexOfCommon((Object*) arg0, arg1, 0);
    454     return true;
    455 }
    456 
    457 /*
    458  * public int indexOf(int c, int start)
    459  *
    460  * Scan forward through the string for a matching character.
    461  */
    462 static bool javaLangString_indexOf_II(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    463     JValue* pResult)
    464 {
    465     /* null reference check on "this" */
    466     if (!dvmValidateObject((Object*) arg0))
    467         return false;
    468 
    469     pResult->i = indexOfCommon((Object*) arg0, arg1, arg2);
    470     return true;
    471 }
    472 
    473 
    474 /*
    475  * ===========================================================================
    476  *      java.lang.Math
    477  * ===========================================================================
    478  */
    479 
    480 /*
    481  * public static int abs(int)
    482  */
    483 static bool javaLangMath_abs_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    484     JValue* pResult)
    485 {
    486     s4 val = (s4) arg0;
    487     pResult->i = (val >= 0) ? val : -val;
    488     return true;
    489 }
    490 
    491 /*
    492  * public static long abs(long)
    493  */
    494 static bool javaLangMath_abs_long(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    495     JValue* pResult)
    496 {
    497     union {
    498         u4 arg[2];
    499         s8 ll;
    500     } convert;
    501 
    502     convert.arg[0] = arg0;
    503     convert.arg[1] = arg1;
    504     s8 val = convert.ll;
    505     pResult->j = (val >= 0) ? val : -val;
    506     return true;
    507 }
    508 
    509 /*
    510  * public static float abs(float)
    511  */
    512 static bool javaLangMath_abs_float(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    513     JValue* pResult)
    514 {
    515     union {
    516         u4 arg;
    517         float ff;
    518     } convert;
    519 
    520     /* clear the sign bit; assumes a fairly common fp representation */
    521     convert.arg = arg0 & 0x7fffffff;
    522     pResult->f = convert.ff;
    523     return true;
    524 }
    525 
    526 /*
    527  * public static double abs(double)
    528  */
    529 static bool javaLangMath_abs_double(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    530     JValue* pResult)
    531 {
    532     union {
    533         u4 arg[2];
    534         s8 ll;
    535         double dd;
    536     } convert;
    537 
    538     /* clear the sign bit in the (endian-dependent) high word */
    539     convert.arg[0] = arg0;
    540     convert.arg[1] = arg1;
    541     convert.ll &= 0x7fffffffffffffffULL;
    542     pResult->d = convert.dd;
    543     return true;
    544 }
    545 
    546 /*
    547  * public static int min(int)
    548  */
    549 static bool javaLangMath_min_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    550     JValue* pResult)
    551 {
    552     pResult->i = ((s4) arg0 < (s4) arg1) ? arg0 : arg1;
    553     return true;
    554 }
    555 
    556 /*
    557  * public static int max(int)
    558  */
    559 static bool javaLangMath_max_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    560     JValue* pResult)
    561 {
    562     pResult->i = ((s4) arg0 > (s4) arg1) ? arg0 : arg1;
    563     return true;
    564 }
    565 
    566 /*
    567  * public static double sqrt(double)
    568  *
    569  * With ARM VFP enabled, gcc turns this into an fsqrtd instruction, followed
    570  * by an fcmpd of the result against itself.  If it doesn't match (i.e.
    571  * it's NaN), the libm sqrt() is invoked.
    572  */
    573 static bool javaLangMath_sqrt(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    574     JValue* pResult)
    575 {
    576     union {
    577         u4 arg[2];
    578         double dd;
    579     } convert;
    580 
    581     convert.arg[0] = arg0;
    582     convert.arg[1] = arg1;
    583     pResult->d = sqrt(convert.dd);
    584     return true;
    585 }
    586 
    587 /*
    588  * public static double cos(double)
    589  */
    590 static bool javaLangMath_cos(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    591     JValue* pResult)
    592 {
    593     union {
    594         u4 arg[2];
    595         double dd;
    596     } convert;
    597 
    598     convert.arg[0] = arg0;
    599     convert.arg[1] = arg1;
    600     pResult->d = cos(convert.dd);
    601     return true;
    602 }
    603 
    604 /*
    605  * public static double sin(double)
    606  */
    607 static bool javaLangMath_sin(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    608     JValue* pResult)
    609 {
    610     union {
    611         u4 arg[2];
    612         double dd;
    613     } convert;
    614 
    615     convert.arg[0] = arg0;
    616     convert.arg[1] = arg1;
    617     pResult->d = sin(convert.dd);
    618     return true;
    619 }
    620 
    621 
    622 /*
    623  * ===========================================================================
    624  *      Infrastructure
    625  * ===========================================================================
    626  */
    627 
    628 /*
    629  * Table of methods.
    630  *
    631  * The DEX optimizer uses the class/method/signature string fields to decide
    632  * which calls it can trample.  The interpreter just uses the function
    633  * pointer field.
    634  *
    635  * IMPORTANT: you must update DALVIK_VM_BUILD in DalvikVersion.h if you make
    636  * changes to this table.
    637  *
    638  * NOTE: If present, the JIT will also need to know about changes
    639  * to this table.  Update the NativeInlineOps enum in InlineNative.h and
    640  * the dispatch code in compiler/codegen/<target>/Codegen.c.
    641  */
    642 const InlineOperation gDvmInlineOpsTable[] = {
    643     { org_apache_harmony_dalvik_NativeTestTarget_emptyInlineMethod,
    644         "Lorg/apache/harmony/dalvik/NativeTestTarget;",
    645         "emptyInlineMethod", "()V" },
    646 
    647     { javaLangString_charAt,
    648         "Ljava/lang/String;", "charAt", "(I)C" },
    649     { javaLangString_compareTo,
    650         "Ljava/lang/String;", "compareTo", "(Ljava/lang/String;)I" },
    651     { javaLangString_equals,
    652         "Ljava/lang/String;", "equals", "(Ljava/lang/Object;)Z" },
    653     { javaLangString_indexOf_I,
    654         "Ljava/lang/String;", "indexOf", "(I)I" },
    655     { javaLangString_indexOf_II,
    656         "Ljava/lang/String;", "indexOf", "(II)I" },
    657     { javaLangString_length,
    658         "Ljava/lang/String;", "length", "()I" },
    659 
    660     { javaLangMath_abs_int,
    661         "Ljava/lang/Math;", "abs", "(I)I" },
    662     { javaLangMath_abs_long,
    663         "Ljava/lang/Math;", "abs", "(J)J" },
    664     { javaLangMath_abs_float,
    665         "Ljava/lang/Math;", "abs", "(F)F" },
    666     { javaLangMath_abs_double,
    667         "Ljava/lang/Math;", "abs", "(D)D" },
    668     { javaLangMath_min_int,
    669         "Ljava/lang/Math;", "min", "(II)I" },
    670     { javaLangMath_max_int,
    671         "Ljava/lang/Math;", "max", "(II)I" },
    672     { javaLangMath_sqrt,
    673         "Ljava/lang/Math;", "sqrt", "(D)D" },
    674     { javaLangMath_cos,
    675         "Ljava/lang/Math;", "cos", "(D)D" },
    676     { javaLangMath_sin,
    677         "Ljava/lang/Math;", "sin", "(D)D" },
    678 };
    679 
    680 /*
    681  * Allocate some tables.
    682  */
    683 bool dvmInlineNativeStartup(void)
    684 {
    685 #ifdef WITH_PROFILER
    686     gDvm.inlinedMethods =
    687         (Method**) calloc(NELEM(gDvmInlineOpsTable), sizeof(Method*));
    688     if (gDvm.inlinedMethods == NULL)
    689         return false;
    690 #endif
    691 
    692     return true;
    693 }
    694 
    695 /*
    696  * Free generated tables.
    697  */
    698 void dvmInlineNativeShutdown(void)
    699 {
    700 #ifdef WITH_PROFILER
    701     free(gDvm.inlinedMethods);
    702 #endif
    703 }
    704 
    705 
    706 /*
    707  * Get a pointer to the inlineops table.
    708  */
    709 const InlineOperation* dvmGetInlineOpsTable(void)
    710 {
    711     return gDvmInlineOpsTable;
    712 }
    713 
    714 /*
    715  * Get the number of entries in the inlineops table.
    716  */
    717 int dvmGetInlineOpsTableLength(void)
    718 {
    719     return NELEM(gDvmInlineOpsTable);
    720 }
    721 
    722 /*
    723  * Make an inline call for the "debug" interpreter, used when the debugger
    724  * or profiler is active.
    725  */
    726 bool dvmPerformInlineOp4Dbg(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
    727     JValue* pResult, int opIndex)
    728 {
    729     Thread* self = dvmThreadSelf();
    730     bool result;
    731 
    732     assert(opIndex >= 0 && opIndex < NELEM(gDvmInlineOpsTable));
    733 
    734 #ifdef WITH_PROFILER
    735     /*
    736      * Populate the methods table on first use.  It's possible the class
    737      * hasn't been resolved yet, so we need to do the full "calling the
    738      * method for the first time" routine.  (It's probably okay to skip
    739      * the access checks.)
    740      *
    741      * Currently assuming that we're only inlining stuff loaded by the
    742      * bootstrap class loader.  This is a safe assumption for many reasons.
    743      */
    744     Method* method = gDvm.inlinedMethods[opIndex];
    745     if (method == NULL) {
    746         ClassObject* clazz;
    747 
    748         clazz = dvmFindClassNoInit(
    749                 gDvmInlineOpsTable[opIndex].classDescriptor, NULL);
    750         if (clazz == NULL) {
    751             LOGW("Warning: can't find class '%s'\n", clazz->descriptor);
    752             goto skip_prof;
    753         }
    754         method = dvmFindDirectMethodByDescriptor(clazz,
    755                     gDvmInlineOpsTable[opIndex].methodName,
    756                     gDvmInlineOpsTable[opIndex].methodSignature);
    757         if (method == NULL)
    758             method = dvmFindVirtualMethodByDescriptor(clazz,
    759                         gDvmInlineOpsTable[opIndex].methodName,
    760                         gDvmInlineOpsTable[opIndex].methodSignature);
    761         if (method == NULL) {
    762             LOGW("Warning: can't find method %s.%s %s\n",
    763                 clazz->descriptor,
    764                 gDvmInlineOpsTable[opIndex].methodName,
    765                 gDvmInlineOpsTable[opIndex].methodSignature);
    766             goto skip_prof;
    767         }
    768 
    769         gDvm.inlinedMethods[opIndex] = method;
    770         IF_LOGV() {
    771             char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
    772             LOGV("Registered for profile: %s.%s %s\n",
    773                 method->clazz->descriptor, method->name, desc);
    774             free(desc);
    775         }
    776     }
    777 
    778     TRACE_METHOD_ENTER(self, method);
    779     result = (*gDvmInlineOpsTable[opIndex].func)(arg0, arg1, arg2, arg3,
    780                 pResult);
    781     TRACE_METHOD_EXIT(self, method);
    782     return result;
    783 
    784 skip_prof:
    785 #endif
    786     return (*gDvmInlineOpsTable[opIndex].func)(arg0, arg1, arg2, arg3, pResult);
    787 }
    788