blob: 6b4162bc7965b77f15294c395082f1bc292de9b8 [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 <algorithm>
6
7#include "assembler.h"
8#include "object.h"
9
10#define __ assembler->
11
12namespace art {
13
14// Creates a function which invokes a managed method with an array of
15// arguments.
16//
17// At the time of call, the environment looks something like this:
18//
19// R0 = method pointer
20// R1 = receiver pointer or NULL for static methods
21// R2 = (managed) thread pointer
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070022// R3 = argument array or NULL for no argument methods
23// [SP] = JValue* result or NULL for void returns
Carl Shapiro9b9ba282011-08-14 15:30:39 -070024//
25// As the JNI call has already transitioned the thread into the
26// "running" state the remaining responsibilities of this routine are
27// to save the native register value and restore the managed thread
28// register and transfer arguments from the array into register and on
29// the stack, if needed. On return, the thread register must be
30// shuffled and the return value must be store into the result JValue.
31void CreateInvokeStub(Assembler* assembler, Method* method) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070032 // Size of frame - spill of R9/LR + Method* + possible receiver + arg array
33 size_t unpadded_frame_size = (3 * kPointerSize) +
34 (method->IsStatic() ? 0 : kPointerSize) +
35 method->NumArgArrayBytes();
36 size_t frame_size = RoundUp(unpadded_frame_size, kStackAlignment);
Carl Shapiro9b9ba282011-08-14 15:30:39 -070037
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070038 // Spill R9 and LR
Carl Shapiro9b9ba282011-08-14 15:30:39 -070039 RegList save = (1 << R9);
40 __ PushList(save | (1 << LR));
41
Carl Shapiro9b9ba282011-08-14 15:30:39 -070042 // Move the managed thread pointer into R9.
43 __ mov(R9, ShifterOperand(R2));
44
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070045 // Move frame down for arguments less 2 pushed values above
46 __ AddConstant(SP, -frame_size + (2 * kPointerSize));
47
48 // Can either get 3 or 2 arguments into registers
49 size_t reg_bytes = (method->IsStatic() ? 3 : 2) * kPointerSize;
50 // Bytes passed by stack
51 size_t stack_bytes;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -070052 if (method->NumArgArrayBytes() > reg_bytes) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070053 stack_bytes = method->NumArgArrayBytes() - reg_bytes;
54 } else {
55 stack_bytes = 0;
56 reg_bytes = method->NumArgArrayBytes();
57 }
58
Ian Rogersed8952f2011-08-19 17:11:22 -070059 // Method* at bottom of frame is null thereby terminating managed stack crawls
60 __ LoadImmediate(IP, 0, AL);
61 __ StoreToOffset(kStoreWord, IP, SP, 0);
62
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070063 // Copy values by stack
Ian Rogers0cfe1fb2011-08-26 03:29:44 -070064 for (size_t off = 0; off < stack_bytes; off += kPointerSize) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070065 // we're displaced off of r3 by bytes that'll go in registers
66 int r3_offset = reg_bytes + off;
67 __ LoadFromOffset(kLoadWord, IP, R3, r3_offset);
68
69 // we're displaced off of the arguments by the spill space for the incoming
70 // arguments and the Method*
71 int sp_offset = reg_bytes + kPointerSize + off;
72 __ StoreToOffset(kStoreWord, IP, SP, sp_offset);
Carl Shapiro9b9ba282011-08-14 15:30:39 -070073 }
74
75 // Move all the register arguments into place.
76 if (method->IsStatic()) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070077 if (reg_bytes > 0) {
Carl Shapiro9b9ba282011-08-14 15:30:39 -070078 __ LoadFromOffset(kLoadWord, R1, R3, 0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070079 if (reg_bytes > 4) {
80 __ LoadFromOffset(kLoadWord, R2, R3, 4);
81 if (reg_bytes > 8) {
82 __ LoadFromOffset(kLoadWord, R3, R3, 8);
83 }
84 }
Carl Shapiro9b9ba282011-08-14 15:30:39 -070085 }
86 } else {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070087 if (reg_bytes > 0) {
Carl Shapiro9b9ba282011-08-14 15:30:39 -070088 __ LoadFromOffset(kLoadWord, R2, R3, 0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070089 if (reg_bytes > 4) {
90 __ LoadFromOffset(kLoadWord, R3, R3, 4);
91 }
Carl Shapiro9b9ba282011-08-14 15:30:39 -070092 }
93 }
94
Carl Shapiro9b9ba282011-08-14 15:30:39 -070095 // Load the code pointer we are about to call.
Ian Rogers0cfe1fb2011-08-26 03:29:44 -070096 __ LoadFromOffset(kLoadWord, IP, R0, method->GetCodeOffset().Int32Value());
Carl Shapiro9b9ba282011-08-14 15:30:39 -070097
98 // Do the call.
99 __ blx(IP);
100
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700101 // If the method returns a value, store it to the result pointer.
102 char ch = method->GetShorty()[0];
103 if (ch != 'V') {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700104 // Load the result JValue pointer of the stub caller's out args.
105 __ LoadFromOffset(kLoadWord, IP, SP, frame_size);
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700106 if (ch == 'D' || ch == 'J') {
107 __ StoreToOffset(kStoreWordPair, R0, IP, 0);
108 } else {
109 __ StoreToOffset(kStoreWord, R0, IP, 0);
110 }
111 }
112
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700113 // Remove the frame less the spilled R9 and LR
114 __ AddConstant(SP, frame_size - (2 * kPointerSize));
115
116 // Pop R9 and the LR into PC
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700117 __ PopList(save | (1 << PC));
118}
119
120} // namespace art