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