blob: ba13de75b030817221717c6cbebee8913835b546 [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"
Brian Carlstrom3320cf42011-10-04 14:58:28 -07008#include "compiled_method.h"
Carl Shapiro9b9ba282011-08-14 15:30:39 -07009#include "object.h"
10
Carl Shapiro9b9ba282011-08-14 15:30:39 -070011namespace art {
Ian Rogers2c8f6532011-09-02 17:16:34 -070012namespace arm {
Carl Shapiro9b9ba282011-08-14 15:30:39 -070013
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.
Brian Carlstrom3320cf42011-10-04 14:58:28 -070031CompiledInvokeStub* ArmCreateInvokeStub(const Method* method) {
Ian Rogers2c8f6532011-09-02 17:16:34 -070032 UniquePtr<ArmAssembler> assembler(
33 down_cast<ArmAssembler*>(Assembler::Create(kArm)));
34#define __ assembler->
buzbeec1f45042011-09-21 16:03:19 -070035 // Size of frame - spill of R4,R9/LR + Method* + possible receiver + arg array
36 size_t unpadded_frame_size = (4 * kPointerSize) +
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070037 (method->IsStatic() ? 0 : kPointerSize) +
38 method->NumArgArrayBytes();
39 size_t frame_size = RoundUp(unpadded_frame_size, kStackAlignment);
Carl Shapiro9b9ba282011-08-14 15:30:39 -070040
buzbeec1f45042011-09-21 16:03:19 -070041 // Spill R4,R9 and LR
42 RegList save = (1 << R9) | (1 << R4);
Carl Shapiro9b9ba282011-08-14 15:30:39 -070043 __ PushList(save | (1 << LR));
44
Carl Shapiro9b9ba282011-08-14 15:30:39 -070045 // Move the managed thread pointer into R9.
46 __ mov(R9, ShifterOperand(R2));
47
buzbeec1f45042011-09-21 16:03:19 -070048 // Move frame down for arguments less 3 pushed values above
49 __ AddConstant(SP, -frame_size + (3 * kPointerSize));
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070050
51 // Can either get 3 or 2 arguments into registers
52 size_t reg_bytes = (method->IsStatic() ? 3 : 2) * kPointerSize;
53 // Bytes passed by stack
54 size_t stack_bytes;
Ian Rogers0cfe1fb2011-08-26 03:29:44 -070055 if (method->NumArgArrayBytes() > reg_bytes) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070056 stack_bytes = method->NumArgArrayBytes() - reg_bytes;
57 } else {
58 stack_bytes = 0;
59 reg_bytes = method->NumArgArrayBytes();
60 }
61
Ian Rogersed8952f2011-08-19 17:11:22 -070062 // Method* at bottom of frame is null thereby terminating managed stack crawls
63 __ LoadImmediate(IP, 0, AL);
64 __ StoreToOffset(kStoreWord, IP, SP, 0);
65
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070066 // Copy values by stack
Ian Rogers0cfe1fb2011-08-26 03:29:44 -070067 for (size_t off = 0; off < stack_bytes; off += kPointerSize) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070068 // we're displaced off of r3 by bytes that'll go in registers
69 int r3_offset = reg_bytes + off;
70 __ LoadFromOffset(kLoadWord, IP, R3, r3_offset);
71
72 // we're displaced off of the arguments by the spill space for the incoming
Shih-wei Liao7d2b1412011-09-05 19:29:47 -070073 // arguments, the Method* and possibly the receiver
74 int sp_offset = reg_bytes + (method->IsStatic() ? 1 : 2) * kPointerSize + off;
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070075 __ StoreToOffset(kStoreWord, IP, SP, sp_offset);
Carl Shapiro9b9ba282011-08-14 15:30:39 -070076 }
77
78 // Move all the register arguments into place.
79 if (method->IsStatic()) {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070080 if (reg_bytes > 0) {
Carl Shapiro9b9ba282011-08-14 15:30:39 -070081 __ LoadFromOffset(kLoadWord, R1, R3, 0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070082 if (reg_bytes > 4) {
83 __ LoadFromOffset(kLoadWord, R2, R3, 4);
84 if (reg_bytes > 8) {
85 __ LoadFromOffset(kLoadWord, R3, R3, 8);
86 }
87 }
Carl Shapiro9b9ba282011-08-14 15:30:39 -070088 }
89 } else {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070090 if (reg_bytes > 0) {
Carl Shapiro9b9ba282011-08-14 15:30:39 -070091 __ LoadFromOffset(kLoadWord, R2, R3, 0);
Ian Rogerscdd1d2d2011-08-18 09:58:17 -070092 if (reg_bytes > 4) {
93 __ LoadFromOffset(kLoadWord, R3, R3, 4);
94 }
Carl Shapiro9b9ba282011-08-14 15:30:39 -070095 }
96 }
97
Carl Shapiro9b9ba282011-08-14 15:30:39 -070098 // Load the code pointer we are about to call.
Ian Rogers0cfe1fb2011-08-26 03:29:44 -070099 __ LoadFromOffset(kLoadWord, IP, R0, method->GetCodeOffset().Int32Value());
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700100
101 // Do the call.
102 __ blx(IP);
103
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700104 // If the method returns a value, store it to the result pointer.
Brian Carlstrom2ed67392011-09-09 14:53:28 -0700105 char ch = method->GetShorty()->CharAt(0);
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700106 if (ch != 'V') {
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700107 // Load the result JValue pointer of the stub caller's out args.
108 __ LoadFromOffset(kLoadWord, IP, SP, frame_size);
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700109 if (ch == 'D' || ch == 'J') {
110 __ StoreToOffset(kStoreWordPair, R0, IP, 0);
111 } else {
112 __ StoreToOffset(kStoreWord, R0, IP, 0);
113 }
114 }
115
buzbeec1f45042011-09-21 16:03:19 -0700116 // Remove the frame less the spilled R4, R9 and LR
117 __ AddConstant(SP, frame_size - (3 * kPointerSize));
Ian Rogerscdd1d2d2011-08-18 09:58:17 -0700118
buzbeec1f45042011-09-21 16:03:19 -0700119 // Pop R4, R9 and the LR into PC
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700120 __ PopList(save | (1 << PC));
Ian Rogers2c8f6532011-09-02 17:16:34 -0700121 // TODO: store native_entry in the stub table
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700122 std::vector<uint8_t> code(assembler->CodeSize());
123 MemoryRegion region(&code[0], code.size());
Ian Rogers2c8f6532011-09-02 17:16:34 -0700124 assembler->FinalizeInstructions(region);
Brian Carlstrom3320cf42011-10-04 14:58:28 -0700125 return new CompiledInvokeStub(code);
Ian Rogers2c8f6532011-09-02 17:16:34 -0700126#undef __
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700127}
128
Ian Rogers2c8f6532011-09-02 17:16:34 -0700129} // namespace arm
Carl Shapiro9b9ba282011-08-14 15:30:39 -0700130} // namespace art