• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "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  */
org_apache_harmony_dalvik_NativeTestTarget_emptyInlineMethod(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)110 static 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  */
javaLangString_charAt(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)127 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 ((Object*) arg0 == NULL) {
135         dvmThrowNullPointerException(NULL);
136         return false;
137     }
138 
139     //ALOGI("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  */
badMatch(StringObject * thisStrObj,StringObject * compStrObj,int expectResult,int newResult,const char * compareType)158 static 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     ALOGE("%s expected %d got %d", compareType, expectResult, newResult);
184     ALOGE(" this (o=%d l=%d) '%s'", thisOffset, thisCount, thisStr);
185     ALOGE(" 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  */
javaLangString_compareTo(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)199 bool 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  */
javaLangString_equals(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)294 bool 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  */
javaLangString_length(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)403 bool javaLangString_length(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
404     JValue* pResult)
405 {
406     //ALOGI("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  */
javaLangString_isEmpty(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)421 bool javaLangString_isEmpty(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
422     JValue* pResult)
423 {
424     //ALOGI("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  */
indexOfCommon(Object * strObj,int ch,int start)447 static 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     //ALOGI("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     else if (start > count)
467         start = count;
468 
469 #if 0
470     /* 16-bit loop, simple */
471     while (start < count) {
472         if (chars[start] == ch)
473             return start;
474         start++;
475     }
476 #else
477     /* 16-bit loop, slightly better on ARM */
478     const u2* ptr = chars + start;
479     const u2* endPtr = chars + count;
480     while (ptr < endPtr) {
481         if (*ptr++ == ch)
482             return (ptr-1) - chars;
483     }
484 #endif
485 
486     return -1;
487 }
488 
489 /*
490  * public int indexOf(int c, int start)
491  *
492  * Scan forward through the string for a matching character.
493  * The character must be <= 0xffff; this method does not handle supplementary
494  * characters.
495  */
javaLangString_fastIndexOf_II(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)496 bool javaLangString_fastIndexOf_II(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
497     JValue* pResult)
498 {
499     /* null reference check on "this" */
500     if ((Object*) arg0 == NULL) {
501         dvmThrowNullPointerException(NULL);
502         return false;
503     }
504 
505     pResult->i = indexOfCommon((Object*) arg0, arg1, arg2);
506     return true;
507 }
508 
509 
510 /*
511  * ===========================================================================
512  *      java.lang.Math
513  * ===========================================================================
514  */
515 
516 union Convert32 {
517     u4 arg;
518     float ff;
519 };
520 
521 union Convert64 {
522     u4 arg[2];
523     s8 ll;
524     double dd;
525 };
526 
527 /*
528  * public static int abs(int)
529  */
javaLangMath_abs_int(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)530 bool javaLangMath_abs_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
531     JValue* pResult)
532 {
533     s4 val = (s4) arg0;
534     pResult->i = (val >= 0) ? val : -val;
535     return true;
536 }
537 
538 /*
539  * public static long abs(long)
540  */
javaLangMath_abs_long(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)541 bool javaLangMath_abs_long(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
542     JValue* pResult)
543 {
544     Convert64 convert;
545     convert.arg[0] = arg0;
546     convert.arg[1] = arg1;
547     s8 val = convert.ll;
548     pResult->j = (val >= 0) ? val : -val;
549     return true;
550 }
551 
552 /*
553  * public static float abs(float)
554  */
javaLangMath_abs_float(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)555 bool javaLangMath_abs_float(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
556     JValue* pResult)
557 {
558     Convert32 convert;
559     /* clear the sign bit; assumes a fairly common fp representation */
560     convert.arg = arg0 & 0x7fffffff;
561     pResult->f = convert.ff;
562     return true;
563 }
564 
565 /*
566  * public static double abs(double)
567  */
javaLangMath_abs_double(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)568 bool javaLangMath_abs_double(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
569     JValue* pResult)
570 {
571     Convert64 convert;
572     convert.arg[0] = arg0;
573     convert.arg[1] = arg1;
574     /* clear the sign bit in the (endian-dependent) high word */
575     convert.ll &= 0x7fffffffffffffffULL;
576     pResult->d = convert.dd;
577     return true;
578 }
579 
580 /*
581  * public static int min(int)
582  */
javaLangMath_min_int(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)583 bool javaLangMath_min_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
584     JValue* pResult)
585 {
586     pResult->i = ((s4) arg0 < (s4) arg1) ? arg0 : arg1;
587     return true;
588 }
589 
590 /*
591  * public static int max(int)
592  */
javaLangMath_max_int(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)593 bool javaLangMath_max_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
594     JValue* pResult)
595 {
596     pResult->i = ((s4) arg0 > (s4) arg1) ? arg0 : arg1;
597     return true;
598 }
599 
600 /*
601  * public static double sqrt(double)
602  *
603  * With ARM VFP enabled, gcc turns this into an fsqrtd instruction, followed
604  * by an fcmpd of the result against itself.  If it doesn't match (i.e.
605  * it's NaN), the libm sqrt() is invoked.
606  */
javaLangMath_sqrt(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)607 bool javaLangMath_sqrt(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 = sqrt(convert.dd);
614     return true;
615 }
616 
617 /*
618  * public static double cos(double)
619  */
javaLangMath_cos(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)620 bool javaLangMath_cos(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
621     JValue* pResult)
622 {
623     Convert64 convert;
624     convert.arg[0] = arg0;
625     convert.arg[1] = arg1;
626     pResult->d = cos(convert.dd);
627     return true;
628 }
629 
630 /*
631  * public static double sin(double)
632  */
javaLangMath_sin(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)633 bool javaLangMath_sin(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
634     JValue* pResult)
635 {
636     Convert64 convert;
637     convert.arg[0] = arg0;
638     convert.arg[1] = arg1;
639     pResult->d = sin(convert.dd);
640     return true;
641 }
642 
643 /*
644  * ===========================================================================
645  *      java.lang.Float
646  * ===========================================================================
647  */
648 
javaLangFloat_floatToIntBits(u4 arg0,u4 arg1,u4 arg2,u4 arg,JValue * pResult)649 bool javaLangFloat_floatToIntBits(u4 arg0, u4 arg1, u4 arg2, u4 arg,
650     JValue* pResult)
651 {
652     Convert32 convert;
653     convert.arg = arg0;
654     pResult->i = isnanf(convert.ff) ? 0x7fc00000 : arg0;
655     return true;
656 }
657 
javaLangFloat_floatToRawIntBits(u4 arg0,u4 arg1,u4 arg2,u4 arg,JValue * pResult)658 bool javaLangFloat_floatToRawIntBits(u4 arg0, u4 arg1, u4 arg2, u4 arg,
659     JValue* pResult)
660 {
661     pResult->i = arg0;
662     return true;
663 }
664 
javaLangFloat_intBitsToFloat(u4 arg0,u4 arg1,u4 arg2,u4 arg,JValue * pResult)665 bool javaLangFloat_intBitsToFloat(u4 arg0, u4 arg1, u4 arg2, u4 arg,
666     JValue* pResult)
667 {
668     Convert32 convert;
669     convert.arg = arg0;
670     pResult->f = convert.ff;
671     return true;
672 }
673 
674 /*
675  * ===========================================================================
676  *      java.lang.Double
677  * ===========================================================================
678  */
679 
javaLangDouble_doubleToLongBits(u4 arg0,u4 arg1,u4 arg2,u4 arg,JValue * pResult)680 bool javaLangDouble_doubleToLongBits(u4 arg0, u4 arg1, u4 arg2, u4 arg,
681     JValue* pResult)
682 {
683     Convert64 convert;
684     convert.arg[0] = arg0;
685     convert.arg[1] = arg1;
686     pResult->j = isnan(convert.dd) ? 0x7ff8000000000000LL : convert.ll;
687     return true;
688 }
689 
javaLangDouble_doubleToRawLongBits(u4 arg0,u4 arg1,u4 arg2,u4 arg,JValue * pResult)690 bool javaLangDouble_doubleToRawLongBits(u4 arg0, u4 arg1, u4 arg2,
691     u4 arg, JValue* pResult)
692 {
693     Convert64 convert;
694     convert.arg[0] = arg0;
695     convert.arg[1] = arg1;
696     pResult->j = convert.ll;
697     return true;
698 }
699 
javaLangDouble_longBitsToDouble(u4 arg0,u4 arg1,u4 arg2,u4 arg,JValue * pResult)700 bool javaLangDouble_longBitsToDouble(u4 arg0, u4 arg1, u4 arg2, u4 arg,
701     JValue* pResult)
702 {
703     Convert64 convert;
704     convert.arg[0] = arg0;
705     convert.arg[1] = arg1;
706     pResult->d = convert.dd;
707     return true;
708 }
709 
710 /*
711  * ===========================================================================
712  *      Infrastructure
713  * ===========================================================================
714  */
715 
716 /*
717  * Table of methods.
718  *
719  * The DEX optimizer uses the class/method/signature string fields to decide
720  * which calls it can trample.  The interpreter just uses the function
721  * pointer field.
722  *
723  * IMPORTANT: you must update DALVIK_VM_BUILD in DalvikVersion.h if you make
724  * changes to this table.
725  *
726  * NOTE: If present, the JIT will also need to know about changes
727  * to this table.  Update the NativeInlineOps enum in InlineNative.h and
728  * the dispatch code in compiler/codegen/<target>/Codegen.c.
729  */
730 const InlineOperation gDvmInlineOpsTable[] = {
731     { org_apache_harmony_dalvik_NativeTestTarget_emptyInlineMethod,
732         "Lorg/apache/harmony/dalvik/NativeTestTarget;",
733         "emptyInlineMethod", "()V" },
734 
735     { javaLangString_charAt, "Ljava/lang/String;", "charAt", "(I)C" },
736     { javaLangString_compareTo, "Ljava/lang/String;", "compareTo", "(Ljava/lang/String;)I" },
737     { javaLangString_equals, "Ljava/lang/String;", "equals", "(Ljava/lang/Object;)Z" },
738     { javaLangString_fastIndexOf_II, "Ljava/lang/String;", "fastIndexOf", "(II)I" },
739     { javaLangString_isEmpty, "Ljava/lang/String;", "isEmpty", "()Z" },
740     { javaLangString_length, "Ljava/lang/String;", "length", "()I" },
741 
742     { javaLangMath_abs_int, "Ljava/lang/Math;", "abs", "(I)I" },
743     { javaLangMath_abs_long, "Ljava/lang/Math;", "abs", "(J)J" },
744     { javaLangMath_abs_float, "Ljava/lang/Math;", "abs", "(F)F" },
745     { javaLangMath_abs_double, "Ljava/lang/Math;", "abs", "(D)D" },
746     { javaLangMath_min_int, "Ljava/lang/Math;", "min", "(II)I" },
747     { javaLangMath_max_int, "Ljava/lang/Math;", "max", "(II)I" },
748     { javaLangMath_sqrt, "Ljava/lang/Math;", "sqrt", "(D)D" },
749     { javaLangMath_cos, "Ljava/lang/Math;", "cos", "(D)D" },
750     { javaLangMath_sin, "Ljava/lang/Math;", "sin", "(D)D" },
751 
752     { javaLangFloat_floatToIntBits, "Ljava/lang/Float;", "floatToIntBits", "(F)I" },
753     { javaLangFloat_floatToRawIntBits, "Ljava/lang/Float;", "floatToRawIntBits", "(F)I" },
754     { javaLangFloat_intBitsToFloat, "Ljava/lang/Float;", "intBitsToFloat", "(I)F" },
755 
756     { javaLangDouble_doubleToLongBits, "Ljava/lang/Double;", "doubleToLongBits", "(D)J" },
757     { javaLangDouble_doubleToRawLongBits, "Ljava/lang/Double;", "doubleToRawLongBits", "(D)J" },
758     { javaLangDouble_longBitsToDouble, "Ljava/lang/Double;", "longBitsToDouble", "(J)D" },
759 
760     // These are implemented exactly the same in Math and StrictMath,
761     // so we can make the StrictMath calls fast too. Note that this
762     // isn't true in general!
763     { javaLangMath_abs_int, "Ljava/lang/StrictMath;", "abs", "(I)I" },
764     { javaLangMath_abs_long, "Ljava/lang/StrictMath;", "abs", "(J)J" },
765     { javaLangMath_abs_float, "Ljava/lang/StrictMath;", "abs", "(F)F" },
766     { javaLangMath_abs_double, "Ljava/lang/StrictMath;", "abs", "(D)D" },
767     { javaLangMath_min_int, "Ljava/lang/StrictMath;", "min", "(II)I" },
768     { javaLangMath_max_int, "Ljava/lang/StrictMath;", "max", "(II)I" },
769     { javaLangMath_sqrt, "Ljava/lang/StrictMath;", "sqrt", "(D)D" },
770 };
771 
772 /*
773  * Allocate some tables.
774  */
dvmInlineNativeStartup()775 bool dvmInlineNativeStartup()
776 {
777     gDvm.inlinedMethods =
778         (Method**) calloc(NELEM(gDvmInlineOpsTable), sizeof(Method*));
779     if (gDvm.inlinedMethods == NULL)
780         return false;
781 
782     return true;
783 }
784 
785 /*
786  * Free generated tables.
787  */
dvmInlineNativeShutdown()788 void dvmInlineNativeShutdown()
789 {
790     free(gDvm.inlinedMethods);
791 }
792 
793 
794 /*
795  * Get a pointer to the inlineops table.
796  */
dvmGetInlineOpsTable()797 const InlineOperation* dvmGetInlineOpsTable()
798 {
799     return gDvmInlineOpsTable;
800 }
801 
802 /*
803  * Get the number of entries in the inlineops table.
804  */
dvmGetInlineOpsTableLength()805 int dvmGetInlineOpsTableLength()
806 {
807     return NELEM(gDvmInlineOpsTable);
808 }
809 
dvmFindInlinableMethod(const char * classDescriptor,const char * methodName,const char * methodSignature)810 Method* dvmFindInlinableMethod(const char* classDescriptor,
811     const char* methodName, const char* methodSignature)
812 {
813     /*
814      * Find the class.
815      */
816     ClassObject* clazz = dvmFindClassNoInit(classDescriptor, NULL);
817     if (clazz == NULL) {
818         ALOGE("dvmFindInlinableMethod: can't find class '%s'",
819             classDescriptor);
820         dvmClearException(dvmThreadSelf());
821         return NULL;
822     }
823 
824     /*
825      * Method could be virtual or direct.  Try both.  Don't use
826      * the "hier" versions.
827      */
828     Method* method = dvmFindDirectMethodByDescriptor(clazz, methodName,
829         methodSignature);
830     if (method == NULL) {
831         method = dvmFindVirtualMethodByDescriptor(clazz, methodName,
832             methodSignature);
833     }
834     if (method == NULL) {
835         ALOGE("dvmFindInlinableMethod: can't find method %s.%s %s",
836             clazz->descriptor, methodName, methodSignature);
837         return NULL;
838     }
839 
840     /*
841      * Check that the method is appropriate for inlining.
842      */
843     if (!dvmIsFinalClass(clazz) && !dvmIsFinalMethod(method)) {
844         ALOGE("dvmFindInlinableMethod: can't inline non-final method %s.%s",
845             clazz->descriptor, method->name);
846         return NULL;
847     }
848     if (dvmIsSynchronizedMethod(method) ||
849             dvmIsDeclaredSynchronizedMethod(method)) {
850         ALOGE("dvmFindInlinableMethod: can't inline synchronized method %s.%s",
851             clazz->descriptor, method->name);
852         return NULL;
853     }
854 
855     return method;
856 }
857 
858 /*
859  * Populate the methods table on first use.  It's possible the class
860  * hasn't been resolved yet, so we need to do the full "calling the
861  * method for the first time" routine.  (It's probably okay to skip
862  * the access checks.)
863  *
864  * Currently assuming that we're only inlining stuff loaded by the
865  * bootstrap class loader.  This is a safe assumption for many reasons.
866  */
dvmResolveInlineNative(int opIndex)867 Method* dvmResolveInlineNative(int opIndex)
868 {
869     assert(opIndex >= 0 && opIndex < NELEM(gDvmInlineOpsTable));
870     Method* method = gDvm.inlinedMethods[opIndex];
871     if (method != NULL) {
872         return method;
873     }
874 
875     method = dvmFindInlinableMethod(
876         gDvmInlineOpsTable[opIndex].classDescriptor,
877         gDvmInlineOpsTable[opIndex].methodName,
878         gDvmInlineOpsTable[opIndex].methodSignature);
879 
880     if (method == NULL) {
881         /* We already reported the error. */
882         return NULL;
883     }
884 
885     gDvm.inlinedMethods[opIndex] = method;
886     IF_ALOGV() {
887         char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
888         ALOGV("Registered for profile: %s.%s %s",
889             method->clazz->descriptor, method->name, desc);
890         free(desc);
891     }
892 
893     return method;
894 }
895 
896 /*
897  * Make an inline call for the "debug" interpreter, used when the debugger
898  * or profiler is active.
899  */
dvmPerformInlineOp4Dbg(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult,int opIndex)900 bool dvmPerformInlineOp4Dbg(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
901     JValue* pResult, int opIndex)
902 {
903     Method* method = dvmResolveInlineNative(opIndex);
904     if (method == NULL) {
905         return (*gDvmInlineOpsTable[opIndex].func)(arg0, arg1, arg2, arg3,
906             pResult);
907     }
908 
909     Thread* self = dvmThreadSelf();
910     TRACE_METHOD_ENTER(self, method);
911     bool result = (*gDvmInlineOpsTable[opIndex].func)(arg0, arg1, arg2, arg3,
912         pResult);
913     TRACE_METHOD_EXIT(self, method);
914     return result;
915 }
916