Elliott Hughes | 2faa5f1 | 2012-01-30 14:42:07 -0800 | [diff] [blame] | 1 | /* |
| 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 Shapiro | 9b9ba28 | 2011-08-14 15:30:39 -0700 | [diff] [blame] | 16 | |
| 17 | #include "jni_internal.h" |
| 18 | |
| 19 | #include "assembler.h" |
Brian Carlstrom | 3320cf4 | 2011-10-04 14:58:28 -0700 | [diff] [blame] | 20 | #include "compiled_method.h" |
Carl Shapiro | 9b9ba28 | 2011-08-14 15:30:39 -0700 | [diff] [blame] | 21 | #include "object.h" |
| 22 | |
| 23 | namespace art { |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 24 | namespace x86 { |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 25 | |
| 26 | // Creates a function which invokes a managed method with an array of |
| 27 | // arguments. |
| 28 | // |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame^] | 29 | // Immediately after the call on X86, the environment looks like this: |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 30 | // |
| 31 | // [SP+0 ] = Return address |
Elliott Hughes | d9c67be | 2012-02-02 19:54:06 -0800 | [diff] [blame] | 32 | // [SP+4 ] = method pointer |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 33 | // [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 Hughes | 46f060a | 2012-03-09 17:36:50 -0800 | [diff] [blame] | 42 | CompiledInvokeStub* CreateInvokeStub(bool is_static, const char* shorty, uint32_t shorty_len) { |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame^] | 43 | UniquePtr<X86Assembler> assembler(down_cast<X86Assembler*>(Assembler::Create(kX86))); |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 44 | #define __ assembler-> |
Ian Rogers | 45619fc | 2012-02-29 11:15:25 -0800 | [diff] [blame] | 45 | size_t num_arg_array_bytes = NumArgArrayBytes(shorty, shorty_len); |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame^] | 46 | // 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 Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 49 | size_t pad_size = RoundUp(frame_size, kStackAlignment) - frame_size; |
| 50 | |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame^] | 51 | 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 Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 59 | |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame^] | 60 | // TODO: optimize the frame set up to avoid excessive SP math |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 61 | // Push padding |
| 62 | if (pad_size != 0) { |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame^] | 63 | __ subl(ESP, Immediate(pad_size)); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 64 | } |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 65 | // Push/copy arguments |
Ian Rogers | 0571d35 | 2011-11-03 19:51:38 -0700 | [diff] [blame] | 66 | for (size_t off = num_arg_array_bytes; off > 0; off -= kPointerSize) { |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame^] | 67 | 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 Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 74 | } |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame^] | 75 | // Backing space for receiver |
Ian Rogers | 0571d35 | 2011-11-03 19:51:38 -0700 | [diff] [blame] | 76 | if (!is_static) { |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame^] | 77 | __ pushl(Immediate(0)); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 78 | } |
Ian Rogers | ed8952f | 2011-08-19 17:11:22 -0700 | [diff] [blame] | 79 | // Push 0 as NULL Method* thereby terminating managed stack crawls |
| 80 | __ pushl(Immediate(0)); |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame^] | 81 | 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 Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 96 | |
Ian Rogers | 0571d35 | 2011-11-03 19:51:38 -0700 | [diff] [blame] | 97 | __ call(Address(EAX, Method::GetCodeOffset())); // Call code off of method |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame] | 98 | |
| 99 | // pop arguments up to the return address |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 100 | __ addl(ESP, Immediate(frame_size + pad_size - kPointerSize)); |
Ian Rogers | 0571d35 | 2011-11-03 19:51:38 -0700 | [diff] [blame] | 101 | char ch = shorty[0]; |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 102 | if (ch != 'V') { |
| 103 | // Load the result JValue pointer. |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame] | 104 | __ movl(ECX, Address(ESP, 20)); |
Ian Rogers | 0cfe1fb | 2011-08-26 03:29:44 -0700 | [diff] [blame] | 105 | switch (ch) { |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 106 | case 'D': |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame^] | 107 | __ movsd(Address(ECX, 0), XMM0); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 108 | break; |
| 109 | case 'F': |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame^] | 110 | __ movss(Address(ECX, 0), XMM0); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 111 | break; |
| 112 | case 'J': |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame] | 113 | __ movl(Address(ECX, 0), EAX); |
| 114 | __ movl(Address(ECX, 4), EDX); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 115 | break; |
| 116 | default: |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame] | 117 | __ movl(Address(ECX, 0), EAX); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 118 | break; |
| 119 | } |
| 120 | } |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 121 | __ ret(); |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 122 | // TODO: store native_entry in the stub table |
Brian Carlstrom | 3320cf4 | 2011-10-04 14:58:28 -0700 | [diff] [blame] | 123 | std::vector<uint8_t> code(assembler->CodeSize()); |
| 124 | MemoryRegion region(&code[0], code.size()); |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 125 | assembler->FinalizeInstructions(region); |
Brian Carlstrom | 3320cf4 | 2011-10-04 14:58:28 -0700 | [diff] [blame] | 126 | return new CompiledInvokeStub(code); |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 127 | #undef __ |
Carl Shapiro | 9b9ba28 | 2011-08-14 15:30:39 -0700 | [diff] [blame] | 128 | } |
| 129 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 130 | } // namespace x86 |
Carl Shapiro | 9b9ba28 | 2011-08-14 15:30:39 -0700 | [diff] [blame] | 131 | } // namespace art |
Elliott Hughes | 46f060a | 2012-03-09 17:36:50 -0800 | [diff] [blame] | 132 | |
| 133 | extern "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 | } |