blob: bd6643ef7dab3dbe50077a4266e9cc9841119f56 [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
17#include "jni_internal.h"
18
19#include "assembler.h"
Brian Carlstrom3320cf42011-10-04 14:58:28 -070020#include "compiled_method.h"
Carl Shapiro9b9ba282011-08-14 15:30:39 -070021#include "object.h"
22
23namespace art {
Ian Rogers2c8f6532011-09-02 17:16:34 -070024namespace x86 {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070025
26// Creates a function which invokes a managed method with an array of
27// arguments.
28//
Ian Rogersb5d09b22012-03-06 22:14:17 -080029// Immediately after the call on X86, the environment looks like this:
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070030//
31// [SP+0 ] = Return address
Elliott Hughesd9c67be2012-02-02 19:54:06 -080032// [SP+4 ] = method pointer
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070033// [SP+8 ] = receiver pointer or NULL for static methods
34// [SP+12] = (managed) thread pointer
35// [SP+16] = argument array or NULL for no argument methods
36// [SP+20] = JValue* result or NULL for void returns
37//
38// As the JNI call has already transitioned the thread into the
39// "running" state the remaining responsibilities of this routine are
40// to save the native registers and set up the managed registers. On
41// return, the return value must be store into the result JValue.
Elliott Hughes46f060a2012-03-09 17:36:50 -080042CompiledInvokeStub* CreateInvokeStub(bool is_static, const char* shorty, uint32_t shorty_len) {
Ian Rogersb5d09b22012-03-06 22:14:17 -080043 UniquePtr<X86Assembler> assembler(down_cast<X86Assembler*>(Assembler::Create(kX86)));
Ian Rogers2c8f6532011-09-02 17:16:34 -070044#define __ assembler->
Ian Rogers45619fc2012-02-29 11:15:25 -080045 size_t num_arg_array_bytes = NumArgArrayBytes(shorty, shorty_len);
Ian Rogersb5d09b22012-03-06 22:14:17 -080046 // Size of frame = return address + Method* + possible receiver + arg array size
47 // Note, space is left in the frame to flush arguments in registers back to out locations.
48 size_t frame_size = 2 * kPointerSize + (is_static ? 0 : kPointerSize) + num_arg_array_bytes;
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070049 size_t pad_size = RoundUp(frame_size, kStackAlignment) - frame_size;
50
Ian Rogersb5d09b22012-03-06 22:14:17 -080051 Register rMethod = EAX;
52 __ movl(rMethod, Address(ESP, 4)); // EAX = method
53 Register rReceiver = EDX;
54 if (!is_static) {
55 __ movl(rReceiver, Address(ESP, 8)); // EDX = receiver
56 }
57 Register rArgArray = ECX;
58 __ movl(rArgArray, Address(ESP, 16)); // ECX = arg array
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070059
Ian Rogersb5d09b22012-03-06 22:14:17 -080060 // TODO: optimize the frame set up to avoid excessive SP math
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070061 // Push padding
62 if (pad_size != 0) {
Ian Rogersb5d09b22012-03-06 22:14:17 -080063 __ subl(ESP, Immediate(pad_size));
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070064 }
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070065 // Push/copy arguments
Ian Rogers0571d352011-11-03 19:51:38 -070066 for (size_t off = num_arg_array_bytes; off > 0; off -= kPointerSize) {
Ian Rogersb5d09b22012-03-06 22:14:17 -080067 if (off > ((is_static ? 2 : 1) * kPointerSize)) {
68 // Copy argument
69 __ pushl(Address(rArgArray, off - kPointerSize));
70 } else {
71 // Space for argument passed in register
72 __ pushl(Immediate(0));
73 }
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070074 }
Ian Rogersb5d09b22012-03-06 22:14:17 -080075 // Backing space for receiver
Ian Rogers0571d352011-11-03 19:51:38 -070076 if (!is_static) {
Ian Rogersb5d09b22012-03-06 22:14:17 -080077 __ pushl(Immediate(0));
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070078 }
Ian Rogersed8952f2011-08-19 17:11:22 -070079 // Push 0 as NULL Method* thereby terminating managed stack crawls
80 __ pushl(Immediate(0));
Ian Rogersb5d09b22012-03-06 22:14:17 -080081 if (!is_static) {
82 if (num_arg_array_bytes >= static_cast<size_t>(kPointerSize)) {
83 // Receiver already in EDX, pass 1st arg in ECX
84 __ movl(ECX, Address(rArgArray, 0));
85 }
86 } else {
87 if (num_arg_array_bytes >= static_cast<size_t>(kPointerSize)) {
88 // Pass 1st arg in EDX
89 __ movl(EDX, Address(rArgArray, 0));
90 if (num_arg_array_bytes >= static_cast<size_t>(2* kPointerSize)) {
91 // Pass 2nd arg in ECX
92 __ movl(ECX, Address(rArgArray, kPointerSize));
93 }
94 }
95 }
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070096
Ian Rogers0571d352011-11-03 19:51:38 -070097 __ call(Address(EAX, Method::GetCodeOffset())); // Call code off of method
Ian Rogers67375ac2011-09-14 00:55:44 -070098
99 // pop arguments up to the return address
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700100 __ addl(ESP, Immediate(frame_size + pad_size - kPointerSize));
Ian Rogers0571d352011-11-03 19:51:38 -0700101 char ch = shorty[0];
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700102 if (ch != 'V') {
103 // Load the result JValue pointer.
Ian Rogers67375ac2011-09-14 00:55:44 -0700104 __ movl(ECX, Address(ESP, 20));
Ian Rogers0cfe1fb2011-08-26 03:29:44 -0700105 switch (ch) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700106 case 'D':
Ian Rogersb5d09b22012-03-06 22:14:17 -0800107 __ movsd(Address(ECX, 0), XMM0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700108 break;
109 case 'F':
Ian Rogersb5d09b22012-03-06 22:14:17 -0800110 __ movss(Address(ECX, 0), XMM0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700111 break;
112 case 'J':
Ian Rogers67375ac2011-09-14 00:55:44 -0700113 __ movl(Address(ECX, 0), EAX);
114 __ movl(Address(ECX, 4), EDX);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700115 break;
116 default:
Ian Rogers67375ac2011-09-14 00:55:44 -0700117 __ movl(Address(ECX, 0), EAX);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700118 break;
119 }
120 }
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700121 __ ret();
Ian Rogers2c8f6532011-09-02 17:16:34 -0700122 // TODO: store native_entry in the stub table
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700123 std::vector<uint8_t> code(assembler->CodeSize());
124 MemoryRegion region(&code[0], code.size());
Ian Rogers2c8f6532011-09-02 17:16:34 -0700125 assembler->FinalizeInstructions(region);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700126 return new CompiledInvokeStub(code);
Ian Rogers2c8f6532011-09-02 17:16:34 -0700127#undef __
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700128}
129
Ian Rogers2c8f6532011-09-02 17:16:34 -0700130} // namespace x86
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700131} // namespace art
Elliott Hughes46f060a2012-03-09 17:36:50 -0800132
133extern "C" art::CompiledInvokeStub* ArtCreateInvokeStub(bool is_static, const char* shorty, uint32_t shorty_len) {
134 return art::x86::CreateInvokeStub(is_static, shorty, shorty_len);
135}