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 | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 31 | // Size of frame - spill of EDI + Method* + possible receiver + arg array |
| 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 | |
| 37 | __ pushl(EDI); // preserve EDI |
| 38 | __ movl(EDI, Address(ESP, 8)); // EDI = method |
| 39 | __ movl(EAX, Address(ESP, 12)); // EAX = receiver |
| 40 | __ movl(EDX, Address(ESP, 20)); // EDX = arg array |
| 41 | |
| 42 | // Push padding |
| 43 | if (pad_size != 0) { |
| 44 | __ addl(ESP, Immediate(-pad_size)); |
| 45 | } |
| 46 | |
| 47 | // Push/copy arguments |
| 48 | for (size_t off = method->NumArgArrayBytes(); off > 0; off -= kPointerSize) { |
| 49 | __ pushl(Address(EDX, off - kPointerSize)); |
| 50 | } |
| 51 | if (!method->IsStatic()) { |
| 52 | __ pushl(EAX); |
| 53 | } |
Ian Rogers | ed8952f | 2011-08-19 17:11:22 -0700 | [diff] [blame] | 54 | // Push 0 as NULL Method* thereby terminating managed stack crawls |
| 55 | __ pushl(Immediate(0)); |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 56 | __ call(Address(EDI, method->GetCodeOffset())); // Call code off of method |
| 57 | |
| 58 | // pop arguments and padding up to saved EDI |
| 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. |
| 63 | __ movl(EDI, Address(ESP, 24)); |
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': |
| 66 | __ fstpl(Address(EDI, 0)); |
| 67 | break; |
| 68 | case 'F': |
| 69 | __ fstps(Address(EDI, 0)); |
| 70 | break; |
| 71 | case 'J': |
| 72 | __ movl(Address(EDI, 0), EAX); |
| 73 | __ movl(Address(EDI, 4), EDX); |
| 74 | break; |
| 75 | default: |
| 76 | __ movl(Address(EDI, 0), EAX); |
| 77 | break; |
| 78 | } |
| 79 | } |
Ian Rogers | 0cfe1fb | 2011-08-26 03:29:44 -0700 | [diff] [blame] | 80 | __ popl(EDI); // restore EDI |
Ian Rogers | cdd1d2d | 2011-08-18 09:58:17 -0700 | [diff] [blame] | 81 | __ ret(); |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 82 | // TODO: store native_entry in the stub table |
| 83 | ByteArray* code = ByteArray::Alloc(assembler->CodeSize()); |
| 84 | MemoryRegion region(code->GetData(), code->GetLength()); |
| 85 | assembler->FinalizeInstructions(region); |
| 86 | method->SetInvokeStub(code); |
| 87 | CHECK(method->GetInvokeStub() != NULL); |
| 88 | #undef __ |
Carl Shapiro | 9b9ba28 | 2011-08-14 15:30:39 -0700 | [diff] [blame] | 89 | } |
| 90 | |
Ian Rogers | 2c8f653 | 2011-09-02 17:16:34 -0700 | [diff] [blame] | 91 | } // namespace x86 |
Carl Shapiro | 9b9ba28 | 2011-08-14 15:30:39 -0700 | [diff] [blame] | 92 | } // namespace art |