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