Carl Shapiro | 9b9ba28 | 2011-08-14 15:30:39 -0700 | [diff] [blame] | 1 | // Copyright 2011 Google Inc. All Rights Reserved. |
Carl Shapiro | 9b9ba28 | 2011-08-14 15:30:39 -0700 | [diff] [blame] | 2 | |
| 3 | #include "jni_internal.h" |
| 4 | |
| 5 | #include "assembler.h" |
| 6 | #include "object.h" |
| 7 | |
| 8 | namespace art { |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 9 | namespace x86 { |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 10 | |
| 11 | // Creates a function which invokes a managed method with an array of |
| 12 | // arguments. |
| 13 | // |
| 14 | // Immediately after the call, the environment looks like this: |
| 15 | // |
| 16 | // [SP+0 ] = Return address |
| 17 | // [SP+4 ]= method pointer |
| 18 | // [SP+8 ] = receiver pointer or NULL for static methods |
| 19 | // [SP+12] = (managed) thread pointer |
| 20 | // [SP+16] = argument array or NULL for no argument methods |
| 21 | // [SP+20] = JValue* result or NULL for void returns |
| 22 | // |
| 23 | // As the JNI call has already transitioned the thread into the |
| 24 | // "running" state the remaining responsibilities of this routine are |
| 25 | // to save the native registers and set up the managed registers. On |
| 26 | // return, the return value must be store into the result JValue. |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 27 | void X86CreateInvokeStub(Method* method) { |
| 28 | UniquePtr<X86Assembler> assembler( |
| 29 | down_cast<X86Assembler*>(Assembler::Create(kX86))); |
| 30 | #define __ assembler-> |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame^] | 31 | // Size of frame - return address + Method* + possible receiver + arg array |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 32 | size_t frame_size = (2 * kPointerSize) + |
| 33 | (method->IsStatic() ? 0 : kPointerSize) + |
| 34 | method->NumArgArrayBytes(); |
| 35 | size_t pad_size = RoundUp(frame_size, kStackAlignment) - frame_size; |
| 36 | |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame^] | 37 | __ movl(EAX, Address(ESP, 4)); // EAX = method |
| 38 | __ movl(ECX, Address(ESP, 8)); // ECX = receiver |
| 39 | __ movl(EDX, Address(ESP, 16)); // EDX = arg array |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 40 | |
| 41 | // Push padding |
| 42 | if (pad_size != 0) { |
| 43 | __ addl(ESP, Immediate(-pad_size)); |
| 44 | } |
| 45 | |
| 46 | // Push/copy arguments |
| 47 | for (size_t off = method->NumArgArrayBytes(); off > 0; off -= kPointerSize) { |
| 48 | __ pushl(Address(EDX, off - kPointerSize)); |
| 49 | } |
| 50 | if (!method->IsStatic()) { |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame^] | 51 | __ pushl(ECX); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 52 | } |
Ian Rogers | ed8952f | 2011-08-19 17:11:22 -0700 | [diff] [blame] | 53 | // Push 0 as NULL Method* thereby terminating managed stack crawls |
| 54 | __ pushl(Immediate(0)); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 55 | |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame^] | 56 | __ call(Address(EAX, method->GetCodeOffset())); // Call code off of method |
| 57 | |
| 58 | // pop arguments up to the return address |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 59 | __ addl(ESP, Immediate(frame_size + pad_size - kPointerSize)); |
Brian Carlstrom | 2ed6739 | 2011-09-09 14:53:28 -0700 | [diff] [blame] | 60 | char ch = method->GetShorty()->CharAt(0); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 61 | if (ch != 'V') { |
| 62 | // Load the result JValue pointer. |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame^] | 63 | __ movl(ECX, Address(ESP, 20)); |
Ian Rogers | 0cfe1fb | 2011-08-26 03:29:44 -0700 | [diff] [blame] | 64 | switch (ch) { |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 65 | case 'D': |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame^] | 66 | __ fstpl(Address(ECX, 0)); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 67 | break; |
| 68 | case 'F': |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame^] | 69 | __ fstps(Address(ECX, 0)); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 70 | break; |
| 71 | case 'J': |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame^] | 72 | __ movl(Address(ECX, 0), EAX); |
| 73 | __ movl(Address(ECX, 4), EDX); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 74 | break; |
| 75 | default: |
Ian Rogers | 67375ac | 2011-09-14 00:55:44 -0700 | [diff] [blame^] | 76 | __ movl(Address(ECX, 0), EAX); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 77 | break; |
| 78 | } |
| 79 | } |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 80 | __ ret(); |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 81 | // TODO: store native_entry in the stub table |
| 82 | ByteArray* code = ByteArray::Alloc(assembler->CodeSize()); |
| 83 | MemoryRegion region(code->GetData(), code->GetLength()); |
| 84 | assembler->FinalizeInstructions(region); |
| 85 | method->SetInvokeStub(code); |
| 86 | CHECK(method->GetInvokeStub() != NULL); |
| 87 | #undef __ |
Carl Shapiro | 9b9ba28 | 2011-08-14 15:30:39 -0700 | [diff] [blame] | 88 | } |
| 89 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 90 | } // namespace x86 |
Carl Shapiro | 9b9ba28 | 2011-08-14 15:30:39 -0700 | [diff] [blame] | 91 | } // namespace art |