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 */ 30extern 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 */ 110static 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 */ 127static 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 */ 156static 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 */ 197static 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 */ 293static 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 */ 385static 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 */ 401static 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 */ 425static 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 */ 472static 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 490typedef union { 491 u4 arg; 492 float ff; 493} Convert32; 494 495typedef union { 496 u4 arg[2]; 497 s8 ll; 498 double dd; 499} Convert64; 500 501/* 502 * public static int abs(int) 503 */ 504static 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 */ 515static 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 */ 529static 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 */ 542static 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 */ 557static 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 */ 567static 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 */ 581static 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 */ 594static 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 */ 607static 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 623static 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 632static bool javaLangFloat_floatToRawIntBits(u4 arg0, u4 arg1, u4 arg2, u4 arg, 633 JValue* pResult) 634{ 635 pResult->i = arg0; 636 return true; 637} 638 639static 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 654static 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 664static 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 674static 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 */ 704const 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 */ 759bool 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 */ 772void dvmInlineNativeShutdown(void) 773{ 774 free(gDvm.inlinedMethods); 775} 776 777 778/* 779 * Get a pointer to the inlineops table. 780 */ 781const InlineOperation* dvmGetInlineOpsTable(void) 782{ 783 return gDvmInlineOpsTable; 784} 785 786/* 787 * Get the number of entries in the inlineops table. 788 */ 789int 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 */ 798bool 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 855skip_prof: 856 return (*gDvmInlineOpsTable[opIndex].func)(arg0, arg1, arg2, arg3, pResult); 857} 858