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 | |
Brian Carlstrom | 3320cf4 | 2011-10-04 14:58:28 -0700 | [diff] [blame] | 17 | #include "compiled_method.h" |
Ian Rogers | 1212a02 | 2013-03-04 10:48:41 -0800 | [diff] [blame^] | 18 | #include "compiler/driver/compiler_driver.h" |
Ian Rogers | 2fa6b2e | 2012-10-17 00:10:17 -0700 | [diff] [blame] | 19 | #include "invoke_arg_array_builder.h" |
Ian Rogers | 81d425b | 2012-09-27 16:03:43 -0700 | [diff] [blame] | 20 | #include "jni_internal.h" |
Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 21 | #include "mirror/abstract_method.h" |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 22 | #include "oat/utils/assembler.h" |
| 23 | #include "oat/utils/x86/assembler_x86.h" |
Carl Shapiro | 9b9ba28 | 2011-08-14 15:30:39 -0700 | [diff] [blame] | 24 | |
| 25 | namespace art { |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 26 | namespace x86 { |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 27 | |
| 28 | // Creates a function which invokes a managed method with an array of |
| 29 | // arguments. |
| 30 | // |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 31 | // Immediately after the call on X86, the environment looks like this: |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 32 | // |
| 33 | // [SP+0 ] = Return address |
Elliott Hughes | d9c67be | 2012-02-02 19:54:06 -0800 | [diff] [blame] | 34 | // [SP+4 ] = method pointer |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 35 | // [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 Hughes | 46f060a | 2012-03-09 17:36:50 -0800 | [diff] [blame] | 44 | CompiledInvokeStub* CreateInvokeStub(bool is_static, const char* shorty, uint32_t shorty_len) { |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 45 | UniquePtr<X86Assembler> assembler(down_cast<X86Assembler*>(Assembler::Create(kX86))); |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 46 | #define __ assembler-> |
Ian Rogers | 45619fc | 2012-02-29 11:15:25 -0800 | [diff] [blame] | 47 | size_t num_arg_array_bytes = NumArgArrayBytes(shorty, shorty_len); |
Ian Rogers | b41b33b | 2012-03-20 14:22:54 -0700 | [diff] [blame] | 48 | // Size of frame = return address + saved EBX + Method* + possible receiver + arg array size |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 49 | // Note, space is left in the frame to flush arguments in registers back to out locations. |
Ian Rogers | b41b33b | 2012-03-20 14:22:54 -0700 | [diff] [blame] | 50 | size_t frame_size = 3 * kPointerSize + (is_static ? 0 : kPointerSize) + num_arg_array_bytes; |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 51 | size_t pad_size = RoundUp(frame_size, kStackAlignment) - frame_size; |
| 52 | |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 53 | Register rMethod = EAX; |
| 54 | __ movl(rMethod, Address(ESP, 4)); // EAX = method |
Ian Rogers | b41b33b | 2012-03-20 14:22:54 -0700 | [diff] [blame] | 55 | Register rReceiver = ECX; |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 56 | if (!is_static) { |
Ian Rogers | b41b33b | 2012-03-20 14:22:54 -0700 | [diff] [blame] | 57 | __ movl(rReceiver, Address(ESP, 8)); // ECX = receiver |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 58 | } |
Ian Rogers | b41b33b | 2012-03-20 14:22:54 -0700 | [diff] [blame] | 59 | // Save EBX |
| 60 | __ pushl(EBX); |
| 61 | Register rArgArray = EBX; |
| 62 | __ movl(rArgArray, Address(ESP, 20)); // EBX = arg array |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 63 | |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 64 | // TODO: optimize the frame set up to avoid excessive SP math |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 65 | // Push padding |
| 66 | if (pad_size != 0) { |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 67 | __ subl(ESP, Immediate(pad_size)); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 68 | } |
Elliott Hughes | 7740579 | 2012-03-15 15:22:12 -0700 | [diff] [blame] | 69 | // 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 Rogers | e44f47f | 2012-03-15 18:01:28 -0700 | [diff] [blame] | 79 | src_offset -= sizeof(JValue) / 2; |
Elliott Hughes | 7740579 | 2012-03-15 15:22:12 -0700 | [diff] [blame] | 80 | __ pushl(Address(rArgArray, src_offset)); |
Elliott Hughes | 7740579 | 2012-03-15 15:22:12 -0700 | [diff] [blame] | 81 | dst_offset -= kPointerSize; |
Ian Rogers | e44f47f | 2012-03-15 18:01:28 -0700 | [diff] [blame] | 82 | src_offset -= sizeof(JValue) / 2; |
Elliott Hughes | 7740579 | 2012-03-15 15:22:12 -0700 | [diff] [blame] | 83 | __ pushl(Address(rArgArray, src_offset)); |
Elliott Hughes | 7740579 | 2012-03-15 15:22:12 -0700 | [diff] [blame] | 84 | break; |
| 85 | default: |
| 86 | // Move the source pointer sizeof(JValue) and the destination pointer 32 bits. |
| 87 | dst_offset -= kPointerSize; |
Elliott Hughes | 7740579 | 2012-03-15 15:22:12 -0700 | [diff] [blame] | 88 | src_offset -= sizeof(JValue); |
Ian Rogers | e44f47f | 2012-03-15 18:01:28 -0700 | [diff] [blame] | 89 | __ pushl(Address(rArgArray, src_offset)); |
Elliott Hughes | 7740579 | 2012-03-15 15:22:12 -0700 | [diff] [blame] | 90 | break; |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 91 | } |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 92 | } |
Elliott Hughes | 7740579 | 2012-03-15 15:22:12 -0700 | [diff] [blame] | 93 | |
Ian Rogers | b41b33b | 2012-03-20 14:22:54 -0700 | [diff] [blame] | 94 | // Backing space for receiver. |
Ian Rogers | 0571d35 | 2011-11-03 19:51:38 -0700 | [diff] [blame] | 95 | if (!is_static) { |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 96 | __ pushl(Immediate(0)); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 97 | } |
Ian Rogers | b41b33b | 2012-03-20 14:22:54 -0700 | [diff] [blame] | 98 | // Push 0 as NULL Method* thereby terminating managed stack crawls. |
Ian Rogers | ed8952f | 2011-08-19 17:11:22 -0700 | [diff] [blame] | 99 | __ pushl(Immediate(0)); |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 100 | if (!is_static) { |
Ian Rogers | b41b33b | 2012-03-20 14:22:54 -0700 | [diff] [blame] | 101 | 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 Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 109 | } |
| 110 | } else { |
Ian Rogers | b41b33b | 2012-03-20 14:22:54 -0700 | [diff] [blame] | 111 | 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 Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 126 | } |
| 127 | } |
| 128 | } |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 129 | |
Ian Rogers | 2dd0e2c | 2013-01-24 12:42:14 -0800 | [diff] [blame] | 130 | __ call(Address(EAX, mirror::AbstractMethod::GetCodeOffset())); // Call code off of method |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame] | 131 | |
Ian Rogers | b41b33b | 2012-03-20 14:22:54 -0700 | [diff] [blame] | 132 | // 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 Rogers | 0571d35 | 2011-11-03 19:51:38 -0700 | [diff] [blame] | 136 | char ch = shorty[0]; |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 137 | if (ch != 'V') { |
| 138 | // Load the result JValue pointer. |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame] | 139 | __ movl(ECX, Address(ESP, 20)); |
Ian Rogers | 0cfe1fb | 2011-08-26 03:29:44 -0700 | [diff] [blame] | 140 | switch (ch) { |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 141 | case 'D': |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 142 | __ movsd(Address(ECX, 0), XMM0); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 143 | break; |
| 144 | case 'F': |
Ian Rogers | b5d09b2 | 2012-03-06 22:14:17 -0800 | [diff] [blame] | 145 | __ movss(Address(ECX, 0), XMM0); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 146 | break; |
| 147 | case 'J': |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame] | 148 | __ movl(Address(ECX, 0), EAX); |
| 149 | __ movl(Address(ECX, 4), EDX); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 150 | break; |
| 151 | default: |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame] | 152 | __ movl(Address(ECX, 0), EAX); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 153 | break; |
| 154 | } |
| 155 | } |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 156 | __ ret(); |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 157 | // TODO: store native_entry in the stub table |
Brian Carlstrom | 3320cf4 | 2011-10-04 14:58:28 -0700 | [diff] [blame] | 158 | std::vector<uint8_t> code(assembler->CodeSize()); |
| 159 | MemoryRegion region(&code[0], code.size()); |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 160 | assembler->FinalizeInstructions(region); |
Logan Chien | 598c513 | 2012-04-28 22:00:44 +0800 | [diff] [blame] | 161 | return new CompiledInvokeStub(kX86, code); |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 162 | #undef __ |
Carl Shapiro | 9b9ba28 | 2011-08-14 15:30:39 -0700 | [diff] [blame] | 163 | } |
| 164 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 165 | } // namespace x86 |
Carl Shapiro | 9b9ba28 | 2011-08-14 15:30:39 -0700 | [diff] [blame] | 166 | } // namespace art |
Elliott Hughes | 46f060a | 2012-03-09 17:36:50 -0800 | [diff] [blame] | 167 | |
Ian Rogers | 1212a02 | 2013-03-04 10:48:41 -0800 | [diff] [blame^] | 168 | extern "C" art::CompiledInvokeStub* ArtCreateX86InvokeStub(art::CompilerDriver& /*compiler*/, bool is_static, |
Ian Rogers | 57b86d4 | 2012-03-27 16:05:41 -0700 | [diff] [blame] | 169 | const char* shorty, uint32_t shorty_len) { |
Elliott Hughes | 46f060a | 2012-03-09 17:36:50 -0800 | [diff] [blame] | 170 | return art::x86::CreateInvokeStub(is_static, shorty, shorty_len); |
| 171 | } |