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