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