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