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 * JNI method invocation. This is used to call a C/C++ JNI method. The
19 * argument list has to be pushed onto the native stack according to
20 * local calling conventions.
21 *
22 * This version supports the MIPS O32 ABI.
23 */
24
25 /* TODO: this is candidate for consolidation of similar code from ARM. */
26
27 #include "Dalvik.h"
28 #include "libdex/DexClass.h"
29
30 #include <stdlib.h>
31 #include <stddef.h>
32 #include <sys/stat.h>
33
34
35 /*
36 * The class loader will associate with each method a 32-bit info word
37 * (jniArgInfo) to support JNI calls. The high order 4 bits of this word
38 * are the same for all targets, while the lower 28 are used for hints to
39 * allow accelerated JNI bridge transfers.
40 *
41 * jniArgInfo (32-bit int) layout:
42 *
43 * SRRRHHHH HHHHHHHH HHHHHHHH HHHHHHHH
44 *
45 * S - if set, ignore the hints and do things the hard way (scan signature)
46 * R - return-type enumeration
47 * H - target-specific hints (see below for details)
48 *
49 * This function produces mips-specific hints - specifically a description
50 * of padding required to keep all 64-bit parameters properly aligned.
51 *
52 * MIPS JNI hint format(Same as ARM)
53 *
54 * LLLL FFFFFFFF FFFFFFFF FFFFFFFF
55 *
56 * L - number of double-words of storage required on the stack (0-30 words)
57 * F - pad flag -- if set, the stack increases 8 bytes, else the stack increases 4 bytes
58 * after copying 32 bits args into stack. (little different from ARM)
59 *
60 * If there are too many arguments to construct valid hints, this function will
61 * return a result with the S bit set.
62 */
dvmPlatformInvokeHints(const DexProto * proto)63 u4 dvmPlatformInvokeHints(const DexProto* proto)
64 {
65
66 const char* sig = dexProtoGetShorty(proto);
67 int padFlags, jniHints;
68 char sigByte;
69 int stackOffset, padMask, hints;
70
71 stackOffset = padFlags = 0;
72 padMask = 0x00000001;
73
74 /* Skip past the return type */
75 sig++;
76
77 while (true) {
78 sigByte = *(sig++);
79
80 if (sigByte == '\0')
81 break;
82
83 if (sigByte == 'D' || sigByte == 'J') {
84 if ((stackOffset & 1) != 0) {
85 padFlags |= padMask;
86 stackOffset++;
87 padMask <<= 1;
88 }
89 stackOffset += 2;
90 padMask <<= 2;
91 } else {
92 stackOffset++;
93 padMask <<= 1;
94 }
95 }
96
97 jniHints = 0;
98
99 if (stackOffset > DALVIK_JNI_COUNT_SHIFT) {
100 /* too big for "fast" version */
101 jniHints = DALVIK_JNI_NO_ARG_INFO;
102 } else {
103 assert((padFlags & (0xffffffff << DALVIK_JNI_COUNT_SHIFT)) == 0);
104 /*
105 * StackOffset includes the space for a2/a3. However we have reserved
106 * 16 bytes on stack in CallO32.S, so we should subtract 2 from stackOffset.
107 */
108 stackOffset -= 2;
109 if (stackOffset < 0)
110 stackOffset = 0;
111 jniHints |= ((stackOffset+1) / 2) << DALVIK_JNI_COUNT_SHIFT;
112 jniHints |= padFlags;
113 }
114
115 return jniHints;
116 }
117