blob: a096da062c7791116dc2b04bd2965517774f483b [file] [log] [blame]
Carl Shapiro9b9ba282011-08-14 15:30:39 -07001// Copyright 2011 Google Inc. All Rights Reserved.
Carl Shapiro9b9ba282011-08-14 15:30:39 -07002
3#include "jni_internal.h"
4
5#include "assembler.h"
6#include "object.h"
7
8namespace art {
Ian Rogers2c8f6532011-09-02 17:16:34 -07009namespace x86 {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070010
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 Rogers2c8f6532011-09-02 17:16:34 -070027void X86CreateInvokeStub(Method* method) {
28 UniquePtr<X86Assembler> assembler(
29 down_cast<X86Assembler*>(Assembler::Create(kX86)));
30#define __ assembler->
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070031 // 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 Rogersed8952f2011-08-19 17:11:22 -070054 // Push 0 as NULL Method* thereby terminating managed stack crawls
55 __ pushl(Immediate(0));
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070056 __ 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 Carlstrom2ed67392011-09-09 14:53:28 -070060 char ch = method->GetShorty()->CharAt(0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070061 if (ch != 'V') {
62 // Load the result JValue pointer.
63 __ movl(EDI, Address(ESP, 24));
Ian Rogers0cfe1fb2011-08-26 03:29:44 -070064 switch (ch) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070065 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 Rogers0cfe1fb2011-08-26 03:29:44 -070080 __ popl(EDI); // restore EDI
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070081 __ ret();
Ian Rogers2c8f6532011-09-02 17:16:34 -070082 // 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 Shapiro9b9ba282011-08-14 15:30:39 -070089}
90
Ian Rogers2c8f6532011-09-02 17:16:34 -070091} // namespace x86
Carl Shapiro9b9ba282011-08-14 15:30:39 -070092} // namespace art