blob: 58d066417373f5030b2b99938bbb894eb4e20ddc [file] [log] [blame]
Elliott Hughes2faa5f12012-01-30 14:42:07 -08001/*
2 * Copyright (C) 2011 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 */
Carl Shapiro9b9ba282011-08-14 15:30:39 -070016
Brian Carlstrom3320cf42011-10-04 14:58:28 -070017#include "compiled_method.h"
Ian Rogers1212a022013-03-04 10:48:41 -080018#include "compiler/driver/compiler_driver.h"
Ian Rogers2fa6b2e2012-10-17 00:10:17 -070019#include "invoke_arg_array_builder.h"
Ian Rogers81d425b2012-09-27 16:03:43 -070020#include "jni_internal.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080021#include "mirror/abstract_method.h"
Ian Rogers57b86d42012-03-27 16:05:41 -070022#include "oat/utils/assembler.h"
23#include "oat/utils/x86/assembler_x86.h"
Carl Shapiro9b9ba282011-08-14 15:30:39 -070024
25namespace art {
Ian Rogers2c8f6532011-09-02 17:16:34 -070026namespace x86 {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070027
28// Creates a function which invokes a managed method with an array of
29// arguments.
30//
Ian Rogersb5d09b22012-03-06 22:14:17 -080031// Immediately after the call on X86, the environment looks like this:
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070032//
33// [SP+0 ] = Return address
Elliott Hughesd9c67be2012-02-02 19:54:06 -080034// [SP+4 ] = method pointer
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070035// [SP+8 ] = receiver pointer or NULL for static methods
36// [SP+12] = (managed) thread pointer
37// [SP+16] = argument array or NULL for no argument methods
38// [SP+20] = JValue* result or NULL for void returns
39//
40// As the JNI call has already transitioned the thread into the
41// "running" state the remaining responsibilities of this routine are
42// to save the native registers and set up the managed registers. On
43// return, the return value must be store into the result JValue.
Elliott Hughes46f060a2012-03-09 17:36:50 -080044CompiledInvokeStub* CreateInvokeStub(bool is_static, const char* shorty, uint32_t shorty_len) {
Ian Rogersb5d09b22012-03-06 22:14:17 -080045 UniquePtr<X86Assembler> assembler(down_cast<X86Assembler*>(Assembler::Create(kX86)));
Ian Rogers2c8f6532011-09-02 17:16:34 -070046#define __ assembler->
Ian Rogers45619fc2012-02-29 11:15:25 -080047 size_t num_arg_array_bytes = NumArgArrayBytes(shorty, shorty_len);
Ian Rogersb41b33b2012-03-20 14:22:54 -070048 // Size of frame = return address + saved EBX + Method* + possible receiver + arg array size
Ian Rogersb5d09b22012-03-06 22:14:17 -080049 // Note, space is left in the frame to flush arguments in registers back to out locations.
Ian Rogersb41b33b2012-03-20 14:22:54 -070050 size_t frame_size = 3 * kPointerSize + (is_static ? 0 : kPointerSize) + num_arg_array_bytes;
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070051 size_t pad_size = RoundUp(frame_size, kStackAlignment) - frame_size;
52
Ian Rogersb5d09b22012-03-06 22:14:17 -080053 Register rMethod = EAX;
54 __ movl(rMethod, Address(ESP, 4)); // EAX = method
Ian Rogersb41b33b2012-03-20 14:22:54 -070055 Register rReceiver = ECX;
Ian Rogersb5d09b22012-03-06 22:14:17 -080056 if (!is_static) {
Ian Rogersb41b33b2012-03-20 14:22:54 -070057 __ movl(rReceiver, Address(ESP, 8)); // ECX = receiver
Ian Rogersb5d09b22012-03-06 22:14:17 -080058 }
Ian Rogersb41b33b2012-03-20 14:22:54 -070059 // Save EBX
60 __ pushl(EBX);
61 Register rArgArray = EBX;
62 __ movl(rArgArray, Address(ESP, 20)); // EBX = arg array
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070063
Ian Rogersb5d09b22012-03-06 22:14:17 -080064 // TODO: optimize the frame set up to avoid excessive SP math
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070065 // Push padding
66 if (pad_size != 0) {
Ian Rogersb5d09b22012-03-06 22:14:17 -080067 __ subl(ESP, Immediate(pad_size));
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070068 }
Elliott Hughes77405792012-03-15 15:22:12 -070069 // Push/copy arguments.
70 size_t arg_count = (shorty_len - 1);
71 size_t dst_offset = num_arg_array_bytes;
72 size_t src_offset = arg_count * sizeof(JValue);
73 for (size_t i = shorty_len - 1; i > 0; --i) {
74 switch (shorty[i]) {
75 case 'D':
76 case 'J':
77 // Move both pointers 64 bits.
78 dst_offset -= kPointerSize;
Ian Rogerse44f47f2012-03-15 18:01:28 -070079 src_offset -= sizeof(JValue) / 2;
Elliott Hughes77405792012-03-15 15:22:12 -070080 __ pushl(Address(rArgArray, src_offset));
Elliott Hughes77405792012-03-15 15:22:12 -070081 dst_offset -= kPointerSize;
Ian Rogerse44f47f2012-03-15 18:01:28 -070082 src_offset -= sizeof(JValue) / 2;
Elliott Hughes77405792012-03-15 15:22:12 -070083 __ pushl(Address(rArgArray, src_offset));
Elliott Hughes77405792012-03-15 15:22:12 -070084 break;
85 default:
86 // Move the source pointer sizeof(JValue) and the destination pointer 32 bits.
87 dst_offset -= kPointerSize;
Elliott Hughes77405792012-03-15 15:22:12 -070088 src_offset -= sizeof(JValue);
Ian Rogerse44f47f2012-03-15 18:01:28 -070089 __ pushl(Address(rArgArray, src_offset));
Elliott Hughes77405792012-03-15 15:22:12 -070090 break;
Ian Rogersb5d09b22012-03-06 22:14:17 -080091 }
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070092 }
Elliott Hughes77405792012-03-15 15:22:12 -070093
Ian Rogersb41b33b2012-03-20 14:22:54 -070094 // Backing space for receiver.
Ian Rogers0571d352011-11-03 19:51:38 -070095 if (!is_static) {
Ian Rogersb5d09b22012-03-06 22:14:17 -080096 __ pushl(Immediate(0));
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070097 }
Ian Rogersb41b33b2012-03-20 14:22:54 -070098 // Push 0 as NULL Method* thereby terminating managed stack crawls.
Ian Rogersed8952f2011-08-19 17:11:22 -070099 __ pushl(Immediate(0));
Ian Rogersb5d09b22012-03-06 22:14:17 -0800100 if (!is_static) {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700101 if (shorty_len > 1) {
102 // Receiver already in ECX, pass remaining 2 args in EDX and EBX.
103 __ movl(EDX, Address(rArgArray, 0));
104 if (shorty[1] == 'D' || shorty[1] == 'J') {
105 __ movl(EBX, Address(rArgArray, sizeof(JValue) / 2));
106 } else if (shorty_len > 2) {
107 __ movl(EBX, Address(rArgArray, sizeof(JValue)));
108 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800109 }
110 } else {
Ian Rogersb41b33b2012-03-20 14:22:54 -0700111 if (shorty_len > 1) {
112 // Pass remaining 3 args in ECX, EDX and EBX.
113 __ movl(ECX, Address(rArgArray, 0));
114 if (shorty[1] == 'D' || shorty[1] == 'J') {
115 __ movl(EDX, Address(rArgArray, sizeof(JValue) / 2));
116 if (shorty_len > 2) {
117 __ movl(EBX, Address(rArgArray, sizeof(JValue)));
118 }
119 } else if (shorty_len > 2) {
120 __ movl(EDX, Address(rArgArray, sizeof(JValue)));
121 if (shorty[2] == 'D' || shorty[2] == 'J') {
122 __ movl(EBX, Address(rArgArray, sizeof(JValue) + (sizeof(JValue) / 2)));
123 } else {
124 __ movl(EBX, Address(rArgArray, sizeof(JValue) + sizeof(JValue)));
125 }
Ian Rogersb5d09b22012-03-06 22:14:17 -0800126 }
127 }
128 }
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700129
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800130 __ call(Address(EAX, mirror::AbstractMethod::GetCodeOffset())); // Call code off of method
Ian Rogers67375ac2011-09-14 00:55:44 -0700131
Ian Rogersb41b33b2012-03-20 14:22:54 -0700132 // Pop arguments up to EBX and the return address.
133 __ addl(ESP, Immediate(frame_size + pad_size - (2 * kPointerSize)));
134 // Restore EBX.
135 __ popl(EBX);
Ian Rogers0571d352011-11-03 19:51:38 -0700136 char ch = shorty[0];
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700137 if (ch != 'V') {
138 // Load the result JValue pointer.
Ian Rogers67375ac2011-09-14 00:55:44 -0700139 __ movl(ECX, Address(ESP, 20));
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700140 switch (ch) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700141 case 'D':
Ian Rogersb5d09b22012-03-06 22:14:17 -0800142 __ movsd(Address(ECX, 0), XMM0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700143 break;
144 case 'F':
Ian Rogersb5d09b22012-03-06 22:14:17 -0800145 __ movss(Address(ECX, 0), XMM0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700146 break;
147 case 'J':
Ian Rogers67375ac2011-09-14 00:55:44 -0700148 __ movl(Address(ECX, 0), EAX);
149 __ movl(Address(ECX, 4), EDX);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700150 break;
151 default:
Ian Rogers67375ac2011-09-14 00:55:44 -0700152 __ movl(Address(ECX, 0), EAX);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700153 break;
154 }
155 }
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700156 __ ret();
Ian Rogers2c8f6532011-09-02 17:16:34 -0700157 // TODO: store native_entry in the stub table
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700158 std::vector<uint8_t> code(assembler->CodeSize());
159 MemoryRegion region(&code[0], code.size());
Ian Rogers2c8f6532011-09-02 17:16:34 -0700160 assembler->FinalizeInstructions(region);
Logan Chien598c5132012-04-28 22:00:44 +0800161 return new CompiledInvokeStub(kX86, code);
Ian Rogers2c8f6532011-09-02 17:16:34 -0700162#undef __
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700163}
164
Ian Rogers2c8f6532011-09-02 17:16:34 -0700165} // namespace x86
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700166} // namespace art
Elliott Hughes46f060a2012-03-09 17:36:50 -0800167
Ian Rogers1212a022013-03-04 10:48:41 -0800168extern "C" art::CompiledInvokeStub* ArtCreateX86InvokeStub(art::CompilerDriver& /*compiler*/, bool is_static,
Ian Rogers57b86d42012-03-27 16:05:41 -0700169 const char* shorty, uint32_t shorty_len) {
Elliott Hughes46f060a2012-03-09 17:36:50 -0800170 return art::x86::CreateInvokeStub(is_static, shorty, shorty_len);
171}