OSDN Git Service

am d312ee58: am 02e04f8b: Merge change 22871 into eclair
[android-x86/dalvik.git] / vm / InlineNative.c
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.  Must also be kept in sync with NativeInlineOps
637  * enum in InlineNative.h.
638  */
639 const InlineOperation gDvmInlineOpsTable[] = {
640     { org_apache_harmony_dalvik_NativeTestTarget_emptyInlineMethod,
641         "Lorg/apache/harmony/dalvik/NativeTestTarget;",
642         "emptyInlineMethod", "()V" },
643
644     { javaLangString_charAt,
645         "Ljava/lang/String;", "charAt", "(I)C" },
646     { javaLangString_compareTo,
647         "Ljava/lang/String;", "compareTo", "(Ljava/lang/String;)I" },
648     { javaLangString_equals,
649         "Ljava/lang/String;", "equals", "(Ljava/lang/Object;)Z" },
650     { javaLangString_indexOf_I,
651         "Ljava/lang/String;", "indexOf", "(I)I" },
652     { javaLangString_indexOf_II,
653         "Ljava/lang/String;", "indexOf", "(II)I" },
654     { javaLangString_length,
655         "Ljava/lang/String;", "length", "()I" },
656
657     { javaLangMath_abs_int,
658         "Ljava/lang/Math;", "abs", "(I)I" },
659     { javaLangMath_abs_long,
660         "Ljava/lang/Math;", "abs", "(J)J" },
661     { javaLangMath_abs_float,
662         "Ljava/lang/Math;", "abs", "(F)F" },
663     { javaLangMath_abs_double,
664         "Ljava/lang/Math;", "abs", "(D)D" },
665     { javaLangMath_min_int,
666         "Ljava/lang/Math;", "min", "(II)I" },
667     { javaLangMath_max_int,
668         "Ljava/lang/Math;", "max", "(II)I" },
669     { javaLangMath_sqrt,
670         "Ljava/lang/Math;", "sqrt", "(D)D" },
671     { javaLangMath_cos,
672         "Ljava/lang/Math;", "cos", "(D)D" },
673     { javaLangMath_sin,
674         "Ljava/lang/Math;", "sin", "(D)D" },
675 };
676
677 /*
678  * Allocate some tables.
679  */
680 bool dvmInlineNativeStartup(void)
681 {
682 #ifdef WITH_PROFILER
683     gDvm.inlinedMethods =
684         (Method**) calloc(NELEM(gDvmInlineOpsTable), sizeof(Method*));
685     if (gDvm.inlinedMethods == NULL)
686         return false;
687 #endif
688
689     return true;
690 }
691
692 /*
693  * Free generated tables.
694  */
695 void dvmInlineNativeShutdown(void)
696 {
697 #ifdef WITH_PROFILER
698     free(gDvm.inlinedMethods);
699 #endif
700 }
701
702
703 /*
704  * Get a pointer to the inlineops table.
705  */
706 const InlineOperation* dvmGetInlineOpsTable(void)
707 {
708     return gDvmInlineOpsTable;
709 }
710
711 /*
712  * Get the number of entries in the inlineops table.
713  */
714 int dvmGetInlineOpsTableLength(void)
715 {
716     return NELEM(gDvmInlineOpsTable);
717 }
718
719 /*
720  * Make an inline call for the "debug" interpreter, used when the debugger
721  * or profiler is active.
722  */
723 bool dvmPerformInlineOp4Dbg(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
724     JValue* pResult, int opIndex)
725 {
726     Thread* self = dvmThreadSelf();
727     bool result;
728
729     assert(opIndex >= 0 && opIndex < NELEM(gDvmInlineOpsTable));
730
731 #ifdef WITH_PROFILER
732     /*
733      * Populate the methods table on first use.  It's possible the class
734      * hasn't been resolved yet, so we need to do the full "calling the
735      * method for the first time" routine.  (It's probably okay to skip
736      * the access checks.)
737      *
738      * Currently assuming that we're only inlining stuff loaded by the
739      * bootstrap class loader.  This is a safe assumption for many reasons.
740      */
741     Method* method = gDvm.inlinedMethods[opIndex];
742     if (method == NULL) {
743         ClassObject* clazz;
744         
745         clazz = dvmFindClassNoInit(
746                 gDvmInlineOpsTable[opIndex].classDescriptor, NULL);
747         if (clazz == NULL) {
748             LOGW("Warning: can't find class '%s'\n", clazz->descriptor);
749             goto skip_prof;
750         }
751         method = dvmFindDirectMethodByDescriptor(clazz,
752                     gDvmInlineOpsTable[opIndex].methodName,
753                     gDvmInlineOpsTable[opIndex].methodSignature);
754         if (method == NULL)
755             method = dvmFindVirtualMethodByDescriptor(clazz,
756                         gDvmInlineOpsTable[opIndex].methodName,
757                         gDvmInlineOpsTable[opIndex].methodSignature);
758         if (method == NULL) {
759             LOGW("Warning: can't find method %s.%s %s\n",
760                 clazz->descriptor,
761                 gDvmInlineOpsTable[opIndex].methodName,
762                 gDvmInlineOpsTable[opIndex].methodSignature);
763             goto skip_prof;
764         }
765
766         gDvm.inlinedMethods[opIndex] = method;
767         IF_LOGV() {
768             char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
769             LOGV("Registered for profile: %s.%s %s\n",
770                 method->clazz->descriptor, method->name, desc);
771             free(desc);
772         }
773     }
774
775     TRACE_METHOD_ENTER(self, method);
776     result = (*gDvmInlineOpsTable[opIndex].func)(arg0, arg1, arg2, arg3,
777                 pResult);
778     TRACE_METHOD_EXIT(self, method);
779     return result;
780
781 skip_prof:
782 #endif
783     return (*gDvmInlineOpsTable[opIndex].func)(arg0, arg1, arg2, arg3, pResult);
784 }
785