blob: e126b6e7ed64f7acd11ee7b4362cff879d9c2eec [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;
52 if( method->NumArgArrayBytes() > reg_bytes){
53 stack_bytes = method->NumArgArrayBytes() - reg_bytes;
54 } else {
55 stack_bytes = 0;
56 reg_bytes = method->NumArgArrayBytes();
57 }
58
59 // Copy values by stack
60 for(size_t off = 0; off < stack_bytes; off += kPointerSize) {
61 // we're displaced off of r3 by bytes that'll go in registers
62 int r3_offset = reg_bytes + off;
63 __ LoadFromOffset(kLoadWord, IP, R3, r3_offset);
64
65 // we're displaced off of the arguments by the spill space for the incoming
66 // arguments and the Method*
67 int sp_offset = reg_bytes + kPointerSize + off;
68 __ StoreToOffset(kStoreWord, IP, SP, sp_offset);
Carl Shapiro9b9ba282011-08-14 15:30:39 -070069 }
70
71 // Move all the register arguments into place.
72 if (method->IsStatic()) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070073 if (reg_bytes > 0) {
Carl Shapiro9b9ba282011-08-14 15:30:39 -070074 __ LoadFromOffset(kLoadWord, R1, R3, 0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070075 if (reg_bytes > 4) {
76 __ LoadFromOffset(kLoadWord, R2, R3, 4);
77 if (reg_bytes > 8) {
78 __ LoadFromOffset(kLoadWord, R3, R3, 8);
79 }
80 }
Carl Shapiro9b9ba282011-08-14 15:30:39 -070081 }
82 } else {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070083 if (reg_bytes > 0) {
Carl Shapiro9b9ba282011-08-14 15:30:39 -070084 __ LoadFromOffset(kLoadWord, R2, R3, 0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070085 if (reg_bytes > 4) {
86 __ LoadFromOffset(kLoadWord, R3, R3, 4);
87 }
Carl Shapiro9b9ba282011-08-14 15:30:39 -070088 }
89 }
90
Carl Shapiro9b9ba282011-08-14 15:30:39 -070091 // Load the code pointer we are about to call.
92 __ LoadFromOffset(kLoadWord, IP, R0, method->GetCodeOffset());
93
94 // Do the call.
95 __ blx(IP);
96
Carl Shapiro9b9ba282011-08-14 15:30:39 -070097 // If the method returns a value, store it to the result pointer.
98 char ch = method->GetShorty()[0];
99 if (ch != 'V') {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700100 // Load the result JValue pointer of the stub caller's out args.
101 __ LoadFromOffset(kLoadWord, IP, SP, frame_size);
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700102 if (ch == 'D' || ch == 'J') {
103 __ StoreToOffset(kStoreWordPair, R0, IP, 0);
104 } else {
105 __ StoreToOffset(kStoreWord, R0, IP, 0);
106 }
107 }
108
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700109 // Remove the frame less the spilled R9 and LR
110 __ AddConstant(SP, frame_size - (2 * kPointerSize));
111
112 // Pop R9 and the LR into PC
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700113 __ PopList(save | (1 << PC));
114}
115
116} // namespace art