OSDN Git Service

am 2ff7a674: am 979baaea: Deprecate many of the accidentally-published APIs in dalvik...
[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.
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 }