InlineNative.cpp revision 60fc806b679a3655c228b4093058c59941a49cfe
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 "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 */
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 */
127bool 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 */
158static 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 */
199bool 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 */
294bool 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 */
403bool 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 */
421bool 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 */
447static 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 */
494bool 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
514union Convert32 {
515    u4 arg;
516    float ff;
517};
518
519union Convert64 {
520    u4 arg[2];
521    s8 ll;
522    double dd;
523};
524
525/*
526 * public static int abs(int)
527 */
528bool 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 */
539bool 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 */
553bool 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 */
566bool 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 */
581bool 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 */
591bool 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 */
605bool 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 */
618bool 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 */
631bool 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
647bool 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
656bool javaLangFloat_floatToRawIntBits(u4 arg0, u4 arg1, u4 arg2, u4 arg,
657    JValue* pResult)
658{
659    pResult->i = arg0;
660    return true;
661}
662
663bool 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
678bool 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
688bool 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
698bool 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 */
728const 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 */
783bool 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 */
796void dvmInlineNativeShutdown()
797{
798    free(gDvm.inlinedMethods);
799}
800
801
802/*
803 * Get a pointer to the inlineops table.
804 */
805const InlineOperation* dvmGetInlineOpsTable()
806{
807    return gDvmInlineOpsTable;
808}
809
810/*
811 * Get the number of entries in the inlineops table.
812 */
813int dvmGetInlineOpsTableLength()
814{
815    return NELEM(gDvmInlineOpsTable);
816}
817
818Method* 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 */
875Method* 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 */
908bool 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