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 */
org_apache_harmony_dalvik_NativeTestTarget_emptyInlineMethod(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)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 */
javaLangString_charAt(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)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, gDvm.offJavaLangString_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, gDvm.offJavaLangString_offset);
138 chars = (ArrayObject*)
139 dvmGetFieldObject((Object*) arg0, gDvm.offJavaLangString_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 */
badMatch(StringObject * thisStrObj,StringObject * compStrObj,int expectResult,int newResult,const char * compareType)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, gDvm.offJavaLangString_count);
161 compCount =
162 dvmGetFieldInt((Object*) compStrObj, gDvm.offJavaLangString_count);
163 thisOffset =
164 dvmGetFieldInt((Object*) thisStrObj, gDvm.offJavaLangString_offset);
165 compOffset =
166 dvmGetFieldInt((Object*) compStrObj, gDvm.offJavaLangString_offset);
167 thisArray = (ArrayObject*)
168 dvmGetFieldObject((Object*) thisStrObj, gDvm.offJavaLangString_value);
169 compArray = (ArrayObject*)
170 dvmGetFieldObject((Object*) compStrObj, gDvm.offJavaLangString_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 */
javaLangString_compareTo(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)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, gDvm.offJavaLangString_count);
225 compCount = dvmGetFieldInt((Object*) arg1, gDvm.offJavaLangString_count);
226 countDiff = thisCount - compCount;
227 minCount = (countDiff < 0) ? thisCount : compCount;
228 thisOffset = dvmGetFieldInt((Object*) arg0, gDvm.offJavaLangString_offset);
229 compOffset = dvmGetFieldInt((Object*) arg1, gDvm.offJavaLangString_offset);
230 thisArray = (ArrayObject*)
231 dvmGetFieldObject((Object*) arg0, gDvm.offJavaLangString_value);
232 compArray = (ArrayObject*)
233 dvmGetFieldObject((Object*) arg1, gDvm.offJavaLangString_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 */
javaLangString_equals(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)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, gDvm.offJavaLangString_count);
325 compCount = dvmGetFieldInt((Object*) arg1, gDvm.offJavaLangString_count);
326 if (thisCount != compCount) {
327 pResult->i = false;
328 return true;
329 }
330
331 thisOffset = dvmGetFieldInt((Object*) arg0, gDvm.offJavaLangString_offset);
332 compOffset = dvmGetFieldInt((Object*) arg1, gDvm.offJavaLangString_offset);
333 thisArray = (ArrayObject*)
334 dvmGetFieldObject((Object*) arg0, gDvm.offJavaLangString_value);
335 compArray = (ArrayObject*)
336 dvmGetFieldObject((Object*) arg1, gDvm.offJavaLangString_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 */
javaLangString_length(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)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, gDvm.offJavaLangString_count);
387 return true;
388 }
389
390
391 /*
392 * ===========================================================================
393 * java.lang.Math
394 * ===========================================================================
395 */
396
397 /*
398 * public static int abs(int)
399 */
javaLangMath_abs_int(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)400 static bool javaLangMath_abs_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
401 JValue* pResult)
402 {
403 s4 val = (s4) arg0;
404 pResult->i = (val >= 0) ? val : -val;
405 return true;
406 }
407
408 /*
409 * public static long abs(long)
410 */
javaLangMath_abs_long(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)411 static bool javaLangMath_abs_long(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
412 JValue* pResult)
413 {
414 union {
415 u4 arg[2];
416 s8 ll;
417 } convert;
418
419 convert.arg[0] = arg0;
420 convert.arg[1] = arg1;
421 s8 val = convert.ll;
422 pResult->j = (val >= 0) ? val : -val;
423 return true;
424 }
425
426 /*
427 * public static float abs(float)
428 */
javaLangMath_abs_float(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)429 static bool javaLangMath_abs_float(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
430 JValue* pResult)
431 {
432 union {
433 u4 arg;
434 float ff;
435 } convert;
436
437 /* clear the sign bit; assumes a fairly common fp representation */
438 convert.arg = arg0 & 0x7fffffff;
439 pResult->f = convert.ff;
440 return true;
441 }
442
443 /*
444 * public static double abs(double)
445 */
javaLangMath_abs_double(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)446 static bool javaLangMath_abs_double(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
447 JValue* pResult)
448 {
449 union {
450 u4 arg[2];
451 s8 ll;
452 double dd;
453 } convert;
454
455 /* clear the sign bit in the (endian-dependent) high word */
456 convert.arg[0] = arg0;
457 convert.arg[1] = arg1;
458 convert.ll &= 0x7fffffffffffffffULL;
459 pResult->d = convert.dd;
460 return true;
461 }
462
463 /*
464 * public static int min(int)
465 */
javaLangMath_min_int(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)466 static bool javaLangMath_min_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
467 JValue* pResult)
468 {
469 pResult->i = ((s4) arg0 < (s4) arg1) ? arg0 : arg1;
470 return true;
471 }
472
473 /*
474 * public static int max(int)
475 */
javaLangMath_max_int(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)476 static bool javaLangMath_max_int(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
477 JValue* pResult)
478 {
479 pResult->i = ((s4) arg0 > (s4) arg1) ? arg0 : arg1;
480 return true;
481 }
482
483 /*
484 * public static double sqrt(double)
485 *
486 * With ARM VFP enabled, gcc turns this into an fsqrtd instruction, followed
487 * by an fcmpd of the result against itself. If it doesn't match (i.e.
488 * it's NaN), the libm sqrt() is invoked.
489 */
javaLangMath_sqrt(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)490 static bool javaLangMath_sqrt(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
491 JValue* pResult)
492 {
493 union {
494 u4 arg[2];
495 double dd;
496 } convert;
497
498 convert.arg[0] = arg0;
499 convert.arg[1] = arg1;
500 pResult->d = sqrt(convert.dd);
501 return true;
502 }
503
504 /*
505 * public static double cos(double)
506 */
javaLangMath_cos(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)507 static bool javaLangMath_cos(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
508 JValue* pResult)
509 {
510 union {
511 u4 arg[2];
512 double dd;
513 } convert;
514
515 convert.arg[0] = arg0;
516 convert.arg[1] = arg1;
517 pResult->d = cos(convert.dd);
518 return true;
519 }
520
521 /*
522 * public static double sin(double)
523 */
javaLangMath_sin(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult)524 static bool javaLangMath_sin(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
525 JValue* pResult)
526 {
527 union {
528 u4 arg[2];
529 double dd;
530 } convert;
531
532 convert.arg[0] = arg0;
533 convert.arg[1] = arg1;
534 pResult->d = sin(convert.dd);
535 return true;
536 }
537
538
539 /*
540 * ===========================================================================
541 * Infrastructure
542 * ===========================================================================
543 */
544
545 /*
546 * Table of methods.
547 *
548 * The DEX optimizer uses the class/method/signature string fields to decide
549 * which calls it can trample. The interpreter just uses the function
550 * pointer field.
551 *
552 * IMPORTANT: you must update DALVIK_VM_BUILD in DalvikVersion.h if you make
553 * changes to this table. Must also be kept in sync with NativeInlineOps
554 * enum in InlineNative.h.
555 */
556 const InlineOperation gDvmInlineOpsTable[] = {
557 { org_apache_harmony_dalvik_NativeTestTarget_emptyInlineMethod,
558 "Lorg/apache/harmony/dalvik/NativeTestTarget;",
559 "emptyInlineMethod", "()V" },
560
561 { javaLangString_charAt,
562 "Ljava/lang/String;", "charAt", "(I)C" },
563 { javaLangString_compareTo,
564 "Ljava/lang/String;", "compareTo", "(Ljava/lang/String;)I" },
565 { javaLangString_equals,
566 "Ljava/lang/String;", "equals", "(Ljava/lang/Object;)Z" },
567 { javaLangString_length,
568 "Ljava/lang/String;", "length", "()I" },
569
570 { javaLangMath_abs_int,
571 "Ljava/lang/Math;", "abs", "(I)I" },
572 { javaLangMath_abs_long,
573 "Ljava/lang/Math;", "abs", "(J)J" },
574 { javaLangMath_abs_float,
575 "Ljava/lang/Math;", "abs", "(F)F" },
576 { javaLangMath_abs_double,
577 "Ljava/lang/Math;", "abs", "(D)D" },
578 { javaLangMath_min_int,
579 "Ljava/lang/Math;", "min", "(II)I" },
580 { javaLangMath_max_int,
581 "Ljava/lang/Math;", "max", "(II)I" },
582 { javaLangMath_sqrt,
583 "Ljava/lang/Math;", "sqrt", "(D)D" },
584 { javaLangMath_cos,
585 "Ljava/lang/Math;", "cos", "(D)D" },
586 { javaLangMath_sin,
587 "Ljava/lang/Math;", "sin", "(D)D" },
588 };
589
590
591 /*
592 * Allocate some tables.
593 */
dvmInlineNativeStartup(void)594 bool dvmInlineNativeStartup(void)
595 {
596 #ifdef WITH_PROFILER
597 gDvm.inlinedMethods =
598 (Method**) calloc(NELEM(gDvmInlineOpsTable), sizeof(Method*));
599 if (gDvm.inlinedMethods == NULL)
600 return false;
601 #endif
602
603 return true;
604 }
605
606 /*
607 * Free generated tables.
608 */
dvmInlineNativeShutdown(void)609 void dvmInlineNativeShutdown(void)
610 {
611 #ifdef WITH_PROFILER
612 free(gDvm.inlinedMethods);
613 #endif
614 }
615
616
617 /*
618 * Get a pointer to the inlineops table.
619 */
dvmGetInlineOpsTable(void)620 const InlineOperation* dvmGetInlineOpsTable(void)
621 {
622 return gDvmInlineOpsTable;
623 }
624
625 /*
626 * Get the number of entries in the inlineops table.
627 */
dvmGetInlineOpsTableLength(void)628 int dvmGetInlineOpsTableLength(void)
629 {
630 return NELEM(gDvmInlineOpsTable);
631 }
632
633 /*
634 * Make an inline call for the "debug" interpreter, used when the debugger
635 * or profiler is active.
636 */
dvmPerformInlineOp4Dbg(u4 arg0,u4 arg1,u4 arg2,u4 arg3,JValue * pResult,int opIndex)637 bool dvmPerformInlineOp4Dbg(u4 arg0, u4 arg1, u4 arg2, u4 arg3,
638 JValue* pResult, int opIndex)
639 {
640 Thread* self = dvmThreadSelf();
641 bool result;
642
643 assert(opIndex >= 0 && opIndex < NELEM(gDvmInlineOpsTable));
644
645 #ifdef WITH_PROFILER
646 /*
647 * Populate the methods table on first use. It's possible the class
648 * hasn't been resolved yet, so we need to do the full "calling the
649 * method for the first time" routine. (It's probably okay to skip
650 * the access checks.)
651 *
652 * Currently assuming that we're only inlining stuff loaded by the
653 * bootstrap class loader. This is a safe assumption for many reasons.
654 */
655 Method* method = gDvm.inlinedMethods[opIndex];
656 if (method == NULL) {
657 ClassObject* clazz;
658
659 clazz = dvmFindClassNoInit(
660 gDvmInlineOpsTable[opIndex].classDescriptor, NULL);
661 if (clazz == NULL) {
662 LOGW("Warning: can't find class '%s'\n", clazz->descriptor);
663 goto skip_prof;
664 }
665 method = dvmFindDirectMethodByDescriptor(clazz,
666 gDvmInlineOpsTable[opIndex].methodName,
667 gDvmInlineOpsTable[opIndex].methodSignature);
668 if (method == NULL)
669 method = dvmFindVirtualMethodByDescriptor(clazz,
670 gDvmInlineOpsTable[opIndex].methodName,
671 gDvmInlineOpsTable[opIndex].methodSignature);
672 if (method == NULL) {
673 LOGW("Warning: can't find method %s.%s %s\n",
674 clazz->descriptor,
675 gDvmInlineOpsTable[opIndex].methodName,
676 gDvmInlineOpsTable[opIndex].methodSignature);
677 goto skip_prof;
678 }
679
680 gDvm.inlinedMethods[opIndex] = method;
681 IF_LOGV() {
682 char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
683 LOGV("Registered for profile: %s.%s %s\n",
684 method->clazz->descriptor, method->name, desc);
685 free(desc);
686 }
687 }
688
689 TRACE_METHOD_ENTER(self, method);
690 result = (*gDvmInlineOpsTable[opIndex].func)(arg0, arg1, arg2, arg3,
691 pResult);
692 TRACE_METHOD_EXIT(self, method);
693 return result;
694
695 skip_prof:
696 #endif
697 return (*gDvmInlineOpsTable[opIndex].func)(arg0, arg1, arg2, arg3, pResult);
698 }
699