summaryrefslogtreecommitdiff
path: root/vm/arch/x86/Call386ABI.S
blob: c98876c749b339be3c17ee95e82bf3d6acd1490d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * JNI method invocation.  This is used to call a C/C++ JNI method.  The
 * argument list has to be pushed onto the native stack according to
 * local calling conventions.
 *
 * This version supports 32-bit x86
 */

/*
Function prototype:

void dvmPlatformInvoke(void* pEnv, ClassObject* clazz, int argInfo, int argc,
    const u4* argv, const char* signature, void* func, JValue* pReturn)

The method we are calling has the form:

  return_type func(JNIEnv* pEnv, ClassObject* clazz, ...)
    -or-
  return_type func(JNIEnv* pEnv, Object* this, ...)

We receive a collection of 32-bit values which correspond to arguments from
the interpreter (e.g. float occupies one, double occupies two).  It's up to
us to convert these into local calling conventions.
*/

/*
x86 notes:

The native code expects arguments on the stack, pushed from right to left.
This matches what Dalvik is passing here.

EAX, EDX and ECX are scratch.

4-byte alignment is required for long long and double, so we won't pad

Non-FP return types <= 4 bytes come back in EAX
Non-FP return types of 8 bytes come back in EAX:EDX, with lsw in EAX.
Float and double returned on top of FP stack.

*/

    .text
    .global dvmPlatformInvoke
    .type   dvmPlatformInvoke, @function

/*
 * On entry:
 *  [ 8]  arg0  JNIEnv (can be left alone)
 *  [12]  arg1  clazz (NULL for virtual method calls, non-NULL for static)
 *  [16]  arg2  arg info
 *  [20]  arg3  argc
 *  [24]  arg4  argv
 *  [28]  arg5  short signature
 *  [32]  arg6  func
 *  [36]  arg7  pReturn
 *
 * For a virtual method call, the "this" reference is in argv[0].
 *
 * argInfo (32-bit int) layout:
 *   SRRRZZZZ ZZZZZZZZ AAAAAAAA AAAAAAAA
 *
 *   Z - reserved
 *   S - if set, argInfo hints are invalid
 *   R - return type enumeration (see jniInternal.h)
 *       VOID   -> 0
 *       FLOAT  -> 1
 *       DOUBLE -> 2
 *       S8     -> 3
 *       S4     -> 4
 *   A - size of the variable argument block in 32-bit words
 *
 */
dvmPlatformInvoke:
/* Establish the frame pointer, spill & align to 16b */
    pushl    %ebp
    movl     %esp,%ebp
    pushl    %edi
    pushl    %esi
    pushl    %ebx
    subl     $12,%esp
/* For 386 ABI, argInfo hints should always be valid.  Abort if not. */
    movl     16(%ebp),%ebx
    testl    %ebx,%ebx
    js       dvmAbort
/* Get the size of the variable region and grow (preserving alignment) */
    movl     %ebx,%ecx
    leal     12(,%ecx,4),%ecx
    andl     $0x0003FFF0,%ecx
    subl     %ecx,%esp
/* Handle this/class */
    movl     8(%ebp),%ecx
    movl     12(%ebp),%eax
    movl     24(%ebp),%esi
    testl    %eax,%eax
    jne      isClass
    movl     (%esi),%eax
    addl     $4,%esi
isClass:
    pushl    %eax
    pushl    %ecx
/* Now, copy the variable arguments region */
    movl     %ebx,%ecx
    andl     $0x0000FFFF,%ecx
    leal     8(%esp),%edi
    cld
    rep
    movsd
/* Ready to go - call the native code */
    call     *32(%ebp)
/* Store the result. */
    sarl      $28,%ebx
    /* Is void? */
    testl     %ebx,%ebx
    je       cleanUpAndExit
    movl     36(%ebp),%ecx
    /* Is FP? */
    cmpl     $2,%ebx
    jle      isFP
    cmpl     $4,%ebx  /* smaller than 32-bits? */
    jg       isSmall
storeRetval:
    /* Blindly storing 64-bits won't hurt 32-bit case */
    movl     %eax,(%ecx)
    movl     %edx,4(%ecx)
    jmp      cleanUpAndExit
isSmall:
    cmpl     $7,%ebx  /* S1? */
    jne      checkShort
    movsbl   %al,%eax
    movl     %eax,(%ecx)
    jmp      cleanUpAndExit
checkShort:
    cmpl     $6,%ebx  /* U2? */
    jne      isSignedShort
    movzwl   %ax,%eax
    movl     %eax,(%ecx)
    jmp      cleanUpAndExit
isSignedShort:
    /* Must be S2 */
    movswl   %ax,%eax
    movl     %eax,(%ecx)
    jmp      cleanUpAndExit
isFP:
    /* Is Float? */
    cmpl    $1,%ebx
    je       saveFloat
    fstpl    (%ecx)
    jmp      cleanUpAndExit
saveFloat:
    fstps    (%ecx)
cleanUpAndExit:
    leal     -12(%ebp),%esp
    pop      %ebx
    pop      %esi
    pop      %edi
    pop      %ebp
    ret
    .size    dvmPlatformInvoke, .-dvmPlatformInvoke
    .section .note.GNU-stack,"",@progbits