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